Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Datentransfer zwischen Programmen (https://www.delphipraxis.net/199473-datentransfer-zwischen-programmen.html)

Tom-Tom 25. Jan 2019 15:04

Datentransfer zwischen Programmen
 
Hallo,

ich versuche, zwischen zwei Delphi Programmen Daten via "BroadcastSystemMessage" zu versenden.

Delphi-Quellcode:

// im FormCreate definiere ich meine Veriable
MSG_SHOW_ADDRESS := RegisterWindowMessage('ShowAddress');

// Hier der Ausschnitt aus der Methode zum Versenden..
var
  dwRecipient : DWord;
begin
  dwRecipient := BSM_APPLICATIONS;
  BroadcastSystemMessage(BSF_POSTMESSAGE, @dwRecipient, MSG_SHOW_ADDRESS, myKndNr, 0);
end;

Auf der Empfängerseite läufts auch geschmeidig mit :

Delphi-Quellcode:
  If Message.Msg = MSG_ADD_ADDRESS
    Then
      ShowMessage (InttoStr(Message.wParam));

Soweit so gut.

Jetzt kommt das Problem:


Eine Intergerzahl zu übertragen ist recht trivial. Kann man das auch mit einem Record machen ?

Die Idee hinter dem Senden:

Delphi-Quellcode:
  T_Adresse = Record
                Keycode  : String[20];
                Anrede   : String[10];
                Titel    : String[30];
                Vorname  : String[30];
                Nachname : String[30];
                Adresse2  : String[30];
                Strasse  : String[30];
                Hausnr   : String[30];
                PLZ      : String[10];
                Ort      : String[30];
              End;

   P_Adresse= ^T_Adresse;




procedure TForm1.Button2Click(Sender: TObject);
VAR A : P_Adresse;
begin
  New(A);
  A.Keycode  := 'SA01-02';
  A.Anrede   := 'Frau';
  A.Vorname  := 'Maxi';

  Senden (Integer(@A));
end;



procedure TForm1.Senden(X: Integer);
var
  dwRecipient : DWord;
begin
  dwRecipient := BSM_APPLICATIONS;
  BroadcastSystemMessage(BSF_POSTMESSAGE, @dwRecipient, MSG_ADD_ADDRESS, X, 0);
end;

und auf der Empfangenseite:

Delphi-Quellcode:

procedure TForm2.WndProc(var Message: TMessage);
VAR A : P_Adresse;
begin
  if Message.Msg = MSG_ADD_ADDRESS
    then
      Begin
        New(A);
        A := @Message.wparam;
        ShowMessage('ADRESSE HINZUFÜGEN !!!' + A^.Vorname);
      End;
  inherited;
end;
Wie zu erwarten - sonst würde der Post hier nicht stehen - klappt das nicht.

Mir stellt sich hier folgende Frage :

Klappt es nicht, weil ich einen Fehler beim Pointerhandling mache oder kann es evtl. gar nicht funktionieren, da ich zwischen 2 Programmen keinen "Speicherbereich" übergeben kann ?

Für eine Idee wäre ich sehr dankbar !

Tom

Bernhard Geyer 25. Jan 2019 16:34

AW: Datentransfer zwischen Programmen
 
Übertragung von Daten per Windows-Messages geht nur mit WM_COPYDATA

Neutral General 25. Jan 2019 16:39

AW: Datentransfer zwischen Programmen
 
Ich würde den Austausch von Daten zwischen zwei Programmen heutzutage generell nicht mehr Windows Messages machen.
Persönlich finde ich glaube ich eine Kommunikation über TCP am elegantesten und vllt. sogar am einfachsten.

Der schöne Günther 25. Jan 2019 16:42

AW: Datentransfer zwischen Programmen
 
Hallo und Herzlich Willkommen in den Heiligen Hallen des Wissens und des Wahnsinns :love:

Mit einem einfachen Delphi-Integer hat es unter 32 Bit zufällig geklappt da
Delphi-Quellcode:
WPARAM
bzw.
Delphi-Quellcode:
LPARAM
definiert ist als
Delphi-Quellcode:
LONG_PTR
. Unter 32 Bit sind das 4 Byte, ebenso wie ein
Delphi-Quellcode:
Integer
unter Delphi (Quelle).

Wenn es jetzt um einen Record geht bleibt nur die Möglichkeit einen Zeiger auf diesen Speicherbereich über den LPARAM/WPARAM auszutauschen. Leider (oder auch: Zum Glück) hast du mit deiner Vermutung
Zitat:

kann es evtl. gar nicht funktionieren, da ich zwischen 2 Programmen keinen "Speicherbereich" übergeben kann ?
Recht - Ein Prozess kann nicht einfach in den Daten eines anderen Prozesses wühlen.

Natürlich ist es möglich nun genau das zu tun, dafür scheint man etwas mit einer WM_COPYDATA-Nachricht vorher anstellen zu müssen.

Es ist sicher auch irgendwo eine Geschmacksfrage, es gibt ja so viele Möglichkeiten für Interprozesskommunikation (IPC) unter Windows. Das mit
Delphi-Quellcode:
WM_COPYDATA
ist eine von vielen. - Aber ich persönlich würde Kommunikation zwischen 2 Prozessen nicht über Messages machen - Es sei denn du hast ganz bestimmte Anforderungen wie super-niedrige Latenz oder super-hohen Durchsatz.

Ich persönlich kann mich nicht mehr erinnern wann ich das letzte mal IPC nicht über Sockets gemacht habe - Ein Programm hat einen Netzwerksocket offen und lauscht, das andere verbindet sich und schickt. Das ist nicht nur leichter zu debuggen, es funktioniert auch praktisch ohne Mehraufwand über Rechner- und Betriebssystemgrenzen hinweg. Aber klar, das wäre nicht so "schnell" wie blanken Speicher auszutauschen.


Hoffentlich hilft dir das ein bisschen weiter, ich habe mit WM_COPYDATA oder Shared Memory (eine weitere Möglichkeit) noch nie etwas gemacht...

Dennis07 25. Jan 2019 16:44

AW: Datentransfer zwischen Programmen
 
Kurze Strings sind Managed Types, sprich, sie haben eine Referenzzählung und werden initialisiert.
Das bedeutet, dass sie am Ende der Routine freigegeben werden. Du brauchst PChar.
Außerdem solltest du Pointer immer nach NativeInt und nicht nach Integer casten, denn Integer ist immer 32 Bit (auch auf 64-Bit Systemen), was dort zu Fehlern führt.

Fritzew 25. Jan 2019 20:15

AW: Datentransfer zwischen Programmen
 
Entschuldigung Dennis

Diese Aussage ist schlicht falsch.

Zitat:

Zitat von Dennis07 (Beitrag 1424149)
Kurze Strings sind Managed Types, sprich, sie haben eine Referenzzählung und werden initialisiert.
Das bedeutet, dass sie am Ende der Routine freigegeben werden.

kurze Strings sind keine Managed Types, sondern klar definierte Typen.
Ein Shortstring kann maximal 255 Zeichen aufnehmen.
Du kannst das als Array of Ansichar betrachten, wobei in Array[0] die länge steht.

String[xx] is eine kürzere Version davon.
Ein String[20] z.b ist 21 Byte gross in [0] steht die Aktuelle Länge im Rest die Daten.
Deshalb haben wir in Delphi (Windows) immer noch Strings die mit Index ab 1 arbeiten

Dennis07 25. Jan 2019 23:26

AW: Datentransfer zwischen Programmen
 
Ja richtig. Hä, ich weiß aber jetzt nicht wie das im Widerspruch zu dem von mir gesagten stehen soll.
Versuch es mal mit PChars. Also bei mir funktioniert das bisher immer ohne Probleme.

peterbelow 26. Jan 2019 13:02

AW: Datentransfer zwischen Programmen
 
Wenn Du Daten per Message an eine andere Anwendung übergeben willst ist WM_COPYDATA die einzige generelle Methode, wie schon in einigen der anderen Antworten gesagt. Die Message bekommt von Windows eine Sonderbehandlung um die übermittelten Daten aus dem Addressbereich des Senders in den des Empfängers zu kopieren. Allerdings sollte man diese Message tunlichst nicht per BroadcastMessage an *alle* Fenster verschicken, sondern gezielt an dass Message-Handle des Empfängers.
Ich habe in meinem Archiv einen alten Post zu dem Thema gefunden, der Dir vielleicht den Einstieg erleichtert. Die Frage war damals, wie man für eine Anwendung, von der nur eine Instanz zur Zeit laufen soll, Parameter auf der Kommandozeile von einer 2. Instanz an die erste schickt, bevor die 2. sich beendet.


I take it you want to pass the commandline from a second instance of your program to the already running first instance.

Open the projects DPR file (Project|View source) and add this line immediately after the Begin of the main block:

If Alreadyrunning Then Exit;

Then scroll up and add this function after the Uses clause:

Function AlreadyRunning: Boolean;
Var
wnd: HWND;
S: String;
copydata: TCopyDataStruct;
Begin
wnd:= FindWindow('TMyAppsMainformclass', Nil );
Result := wnd <> 0;
If Result and (ParamCount > 0) Then Begin
S:= ParamStr(1);
With copydata Do Begin
dwData := 0;
cbData := Sizeof(Char)*(Length(S)+1); {Need to transfer terminating #0 as well}
lpData := @S[1];
End;
SendMessage( wnd, WM_COPYDATA, 0, LPARAM( @copydata ));
End;
End;

Note that you need to make sure the main form class for your application has a reasonably unique name, so FindWindow finds the correct window.

The second change needed is made to the main form class itself. It needs a handler for the WM_COPYDATA message.

private
{ Private declarations }
procedure WMCopyData(Var msg: TWMCopyData); message WM_COPYDATA;

Procedure TMyAppsMainformclass.WMCopyData(Var msg: TWMCopyData);
Var
param : String;
Begin
param := PChar(msg.CopyDataStruct^.lpData);
...process param
End;

Tom-Tom 28. Jan 2019 07:32

AW: Datentransfer zwischen Programmen
 
Hallo an alle,

vielen Dank für Eure Anregungen und den Beispielcode. Ich werde es aus Kompatibilitätsgründen erst mit der PChar Variante versuchen, ansonsten müsste ich zig vorhandene PlugIns umschreiben.
(Es handelt sich bei den beiden "Programmen" um PlugIns, die mit dem Hauptprogramm kommunizieren sollen. Bislang wurden nur Integer Werte übergeben.)

Also, nochmals DANKE !

Tom-Tom


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:37 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz