Programmkommunikation ohne Netzwerk

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Programmkommunikation ohne Netzwerk

Beitrag von ts-soft »

Hier gehts um Kommunikation von 2 Programmen auf dem selben Rechner,
über RegisterWindowMessage und #WM_CopyData.

Ich hab das jetzt in Client und Server aufgeteilt in dem Beispiel, das ist aber
nicht notwendig, beide können Daten senden und empfangen, nur eben die
Callbacks erweitern.

Ich hoffe mal, die Kommentare sind ausreichend :wink:
Der "Sender"

Code: Alles auswählen

; German forum: http://www.purebasic.fr/german/viewtopic.php?p=152509#152509
; Author: ts-soft
; Date: 20. May 2007
; OS: Windows
; Demo: No

Enumeration ; PrivatMessages
  #GetHwnd
  #SendHwnd
  #SomeValue
  #CloseMessage
  ; ...
EndEnumeration

Enumeration ; Gadgets
  #lblText
  #txtText
  #btnText
  #lblValue
  #txtValue
  #btnValue
EndEnumeration

; wir registrieren unsere Message
Global MyMessage.l = RegisterWindowMessage_("MyOwnMessage")
Global hWndClient.l

Procedure MyWindowCallback(WindowID, Message, wParam, lParam)
  Protected Result.l = #PB_ProcessPureBasicEvents
  Select Message
    Case MyMessage
      Select wParam
        Case #SendHwnd ; der Client sende sein Fensterhandle
          hWndClient = lParam
          DisableGadget(#btnText, #False)
          DisableGadget(#btnValue, #False)
          SetWindowTitle(0, "Sender")
       EndSelect
  EndSelect
  ProcedureReturn Result
EndProcedure

Procedure SendData(Message.s)
  Protected cd.COPYDATASTRUCT
  cd\dwData = 0 ; hier könnte man versch. Werte für versch. Datentypen einsetzen
  cd\cbData = (Len(Message) + 1) * SizeOf(Character); wir verwenden nur Strings und geben hier die länge an
  cd\lpData = @Message ; databuffer ; der string in die Struktur
  SendMessage_(hWndClient, #WM_COPYDATA ,WindowID(0), cd) ; und raus damit ;)
EndProcedure

Define.s value
Define.l timeout = 500

If OpenWindow(0, #PB_Ignore, #PB_Ignore, 200, 160, "Sender, wait for client") And CreateGadgetList(WindowID(0))
  SetWindowCallback(@MyWindowCallback())

  TextGadget(#lblText, 10, 12, 75, 20, "Text to send:")
  StringGadget(#txtText, 90, 10, 100, 20, "")
  ButtonGadget(#btnText, 50, 40, 100, 20, "Send Text")
  DisableGadget(#btnText, #True)
  TextGadget(#lblValue, 10, 102, 75, 20, "Value to send:")
  StringGadget(#txtValue, 90, 100, 100, 20, "", #PB_String_Numeric)
  ButtonGadget(#btnValue, 50, 130, 100, 20, "Send Value")
  DisableGadget(#btnValue, #True)

  While WindowEvent() : Wend

  Repeat

    Select WaitWindowEvent(timeout)
      Case #PB_Event_CloseWindow
        PostMessage_(#HWND_BROADCAST, MyMessage, #CloseMessage, 0)
        Break

      Case #PB_Event_Gadget

        Select EventGadget()
          Case #btnText
            value = GetGadgetText(#txtText)
            If value <> ""
              SendData(value)
            EndIf
          Case #btnValue
            value = GetGadgetText(#txtValue)
            If value <> ""
              SendMessage_(#HWND_BROADCAST, MyMessage, #SomeValue, Val(value))
            EndIf
        EndSelect

      Default
        If timeout
          If Not hWndClient ; wir warten noch auf den Clienten
            SendMessage_(#HWND_BROADCAST, MyMessage, #GetHwnd, 0)
          Else
            timout = 0
          EndIf
        EndIf
    EndSelect

  ForEver
EndIf
und hier der Client:

Code: Alles auswählen

; German forum: http://www.purebasic.fr/german/viewtopic.php?p=152509#152509
; Author: ts-soft
; Date: 20. May 2007
; OS: Windows
; Demo: No

Enumeration ; PrivatMessages
  #GetHwnd
  #SendHwnd
  #SomeValue
  #CloseMessage
  ; ...
EndEnumeration

Global MyMessage.l = RegisterWindowMessage_("MyOwnMessage")

Procedure MyWindowCallback(WindowID, Message, wParam, lParam)
  Protected Result.l = #PB_ProcessPureBasicEvents
  Protected *cd.COPYDATASTRUCT
  Select Message
    Case MyMessage
      Select wParam
        Case #GetHwnd ; der Sender erwartet mein Fensterhandle, also raus damit
          SendMessage_(#HWND_BROADCAST, MyMessage, #SendHwnd, WindowID(0))
        Case #SomeValue ; wir haben einen Zahlenwert erhalten
          If IsGadget(0)
            SetGadgetText(0, Str(lParam))
          EndIf
        Case #CloseMessage
          End 
      EndSelect
    Case #WM_COPYDATA ; der Sender hat einen String übermittelt
      *cd = lParam
      If IsGadget(0)
        SetGadgetText(0, PeekS(*cd\lpData))
      EndIf
  EndSelect

  ProcedureReturn Result
EndProcedure

If OpenWindow(0, #PB_Ignore, #PB_Ignore, 200, 40, "Client") And CreateGadgetList(WindowID(0))
  SetWindowCallback(@MyWindowCallback())
  TextGadget(0, 10, 10, 180, 20, "", #PB_Text_Center | #PB_Text_Border)
 
  While WaitWindowEvent() <> #PB_Event_CloseWindow : Wend

EndIf 
Copydata wird nur verwendet um auch Texte problemlos auszutauschen.

Ich hoffe mal, es kann jemand gebrauchen :)

// Edit
Unnötige Enumeration im clienten entfernt
und SendData ist jetzt Unicode-tauglich (beide müssen gleichen
Compilerschalter verwenden!)
// Edit
Hab jetzt noch das beenden des Clienten hinzugefügt, wenn der Sender
geschlossen wird
Zuletzt geändert von ts-soft am 21.05.2007 03:45, insgesamt 5-mal geändert.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
mk-soft
Beiträge: 3845
Registriert: 24.11.2004 13:12
Wohnort: Germany

Beitrag von mk-soft »

:allright:

Schönes Beispiel. Geht einfacher als mit Pipes

FF :wink:
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
legion
Beiträge: 467
Registriert: 08.10.2006 18:04
Computerausstattung: Intel Core i5-6500 @ 4x 3.6GHz mit Windows 10 Pro, Intel Core-i7 mit Ubuntu 18.04 bionic, x86_64 Linux 4.18.0-16-generic, Microsoft Surface Pro - Windows 10 Pro
Wohnort: Wien
Kontaktdaten:

Beitrag von legion »

Super Sache !
Kommt wie gerufen !
Kann ich für meine DLL gut gebrauchen.
Danke !

Gruß Legion
PB 5.71 LTS Windows 10 Pro & Ubuntu 18.04.2 LTS & Linux Mint 19.3
-----------------------------------------------------
Alles ist, wie man glaubt, dass es ist!
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

Schön wenns gefällt, ich finde es auch oft sinnvoller als mit pipes, mailslots usw.
legion hat geschrieben:Kann ich für meine DLL gut gebrauchen.
Danke !

Gruß Legion
Für DLLs ist es weniger sinnvoll. weil erstens haben die einen gemeinsamen
Memory mit der Anwendung und eine DLL hat meist auch kein Fensterhandle.

Da reichen dann Messages über #WM_USER + bla
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
Leonhard
Beiträge: 602
Registriert: 01.03.2006 21:25

Beitrag von Leonhard »

Mir ist da grad nen Bug im Code aufgefallen:

Wenn man 'Hallo, Welt!' sendet, bekommt man 'Hallo, '- und ein paar kästchen zurück. Das kommt immer im Unicode-Modus.

Mfg

leonhard
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

Leonhard hat geschrieben:Mir ist da grad nen Bug im Code aufgefallen:

Wenn man 'Hallo, Welt!' sendet, bekommt man 'Hallo, '- und ein paar kästchen zurück. Das kommt immer im Unicode-Modus.

Mfg

leonhard
Hab das nur auf die schnelle reinimprovisiert :mrgreen:
Danke für den Hinweis, fehlende Klammern ergänzt!
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
legion
Beiträge: 467
Registriert: 08.10.2006 18:04
Computerausstattung: Intel Core i5-6500 @ 4x 3.6GHz mit Windows 10 Pro, Intel Core-i7 mit Ubuntu 18.04 bionic, x86_64 Linux 4.18.0-16-generic, Microsoft Surface Pro - Windows 10 Pro
Wohnort: Wien
Kontaktdaten:

Beitrag von legion »

ts-soft hat geschrieben: Für DLLs ist es weniger sinnvoll. weil erstens haben die einen gemeinsamen
Memory mit der Anwendung und eine DLL hat meist auch kein Fensterhandle.
Da reichen dann Messages über #WM_USER + bla
Danke für die Info !

Lg. Legion
PB 5.71 LTS Windows 10 Pro & Ubuntu 18.04.2 LTS & Linux Mint 19.3
-----------------------------------------------------
Alles ist, wie man glaubt, dass es ist!
Benutzeravatar
Tafkadasom2k5
Beiträge: 1578
Registriert: 13.08.2005 14:31
Kontaktdaten:

Beitrag von Tafkadasom2k5 »

ts-soft hat geschrieben:Für DLLs ist es weniger sinnvoll. weil erstens haben die einen gemeinsamen
Memory mit der Anwendung und eine DLL hat meist auch kein Fensterhandle.
Trotzdem kann es doch sein, dass sich dasnn Messages überschneiden..?

Von daher wäre es bei DLLs schon wichtig, die Nachricht von Windows registrieren zu lassen.

Wenn man eine Include benutzt dann wäre es was Anderes, weil man dann ja selber Kontrolle über verfügbare Konstanten hat, aber bei DLLs?
Ich würde bei DLLs wirklich über registerMessage_() auf die sichere Seite übergehen. Und unter Umständne sogar der komfortableren- wenn man nämlich eine Nachricht von der DLL empfangen soll, und das schlägt fehl wegen so eines Konstanten-Fehlers, dann wäre das eine Menge Aufwand, bis man den Fehler findet...

(oder sehe ich das völlig falsch, bzw von einem falschen Gesichtspunkt?
Wenn, dann bitte ich hiermit um AUfklärung ;)
Im Normalfall bin ich auch nicht lernresistent :mrgreen:)

Gr33tz
Tafkadasom2k5
OpenNetworkConnection() hat geschrieben:Versucht eine Verbindung mit dem angegebenen Server aufzubauen. 'ServerName$' kann eine IP-Adresse oder ein voller Name sein (z.B.: "127.0.0.1" oder "ftp.home.net").
php-freak hat geschrieben:Ich hab die IP von google auch ned rausgefunden!
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

Eine DLL kann doch simpel #WM_USER + irgendwas nehmen, in wParam das
handle des Controls in lPararm der Wert. So machen es die meisten Controls,
die aus DLLs kommen, ist das einfachste. Dafür Messages Registrieren und
durchs ganze System zu jagen ist überflüssig :mrgreen:
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Antworten