Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Probleme beim Empfangen mittels WM_COPYDATA (https://www.delphipraxis.net/209895-probleme-beim-empfangen-mittels-wm_copydata.html)

PitterS80 5. Feb 2022 16:14

Probleme beim Empfangen mittels WM_COPYDATA
 
Hallo!
Bis letzte Woche hatte ich noch Delphi 10.3 genutzt und bin jetzt auf 10.4 umgestiegen.
Leider funktioniert mein Quellcode jetzt nicht mehr so, wie er eigentlich sollte.
Ich will nur eine Instanz meiner Software zulassen und bei nochmaligem Aufruf einen String an die bestehende Instanz übergeben.

So sieht's beim Sender aus:
Delphi-Quellcode:
      // Parameter-String an Ur-Instanz senden
      Data.dwData := C_KEY;
      Data.cbData := (Length(Parms)+1) * SizeOf(Char);
      Data.lpData := PChar(Parms);
      MyHandle:=FindWindow(nil, PChar(APP_NAME));
      if MyHandle<>0 then SendMessage(MyHandle, WM_COPYDATA, LongInt(MyHandle), LongInt(@Data));
      CloseHandle(MyHandle);
Und so beim Empfänger:
Delphi-Quellcode:
procedure TForm1.WMCopyData(var Msg: TWMCopyData);
var
  sInput:  String;
begin
  try
    if Msg.CopyDataStruct.dwData = C_KEY then begin
      // Neue Daten empfangen
      sInput:=PChar(Msg.CopyDataStruct.lpData);
    end;
  except
    on E: Exception do
    Protokoll('WMCopyData;FEHLER;beim Einlesen des Strings - ' + E.Message);
  end;
end;
Im Protokoll habe ich hinterher immer folgende Fehlermeldung stehen:
WMCopyData;FEHLER;beim Einlesen des Strings - Zugriffsverletzung bei Adresse 0082EBC0 in Modul 'PushService7.exe'. Lesen von Adresse 00000000

Das Senden der Daten scheint ja schonmal nicht ganz verkehrt zu sein - zumindest C_KEY als Identifier kommt ja an.
Beim Senden werden auch keine Exceptions ausgelöst - nur beim Empfangen.

Irgendwie stehe ich jetzt gerade ein wenig auf dem Schlauch...
Hat einer von euch einen Tipp für mich?

Klaus01 5. Feb 2022 16:42

AW: Probleme beim Empfangen mittels WM_COPYDATA
 
.. ist die neue Instanz schon beendet (der pointer auf den String also nicht mehr valide)wenn die Nachricht bei der alten Instanz ankommt?

Grüße
Klaus

PitterS80 5. Feb 2022 16:56

AW: Probleme beim Empfangen mittels WM_COPYDATA
 
Ja, die neue Instanz sendet den String und wird dann beendet.

Gausi 5. Feb 2022 17:01

AW: Probleme beim Empfangen mittels WM_COPYDATA
 
In der (recht alten, aber funktionierenden) oneinst.pas, die ich dazu verwende, wird beim Aufbau der WM_COPYDATA-Message nicht nur einfach der Pointer zum String übergeben, sondern es werden explizit die Daten kopiert. Mich wundert ehrlich gesagt ein wenig, dass dein alter Code überhaupt funktioniert ...

Delphi-Quellcode:
Data.lpData := ParamStrToBlob(Data.cbData);

// mit

function ParamStrToBlob(out cbData: DWORD): Pointer;
var
  Loop: Integer;
  pStr: PChar;
begin
  cbData := Length(ParamStr(1)) * SizeOf(Char) + 4; { gleich inklusive #0#0 }
  for Loop := 2 to ParamCount do
    cbData := cbData + DWORD(Length(ParamStr(Loop)) * SizeOf(Char) + 2);
  Result := GetMemory(cbData);
  ZeroMemory(Result, cbData);
  pStr := Result;
  for Loop := 1 to ParamCount do
  begin
    lstrcpy(pStr, PChar(ParamStr(Loop)));
    pStr := @pStr[lstrlen(pStr) + 1];
  end;
end;
Ich hoffe, diese Variante funktioniert mit 10.4 weiter, wenn ich in den nächsten 30 Tagen umsteigen muss ...

BerndS 5. Feb 2022 17:33

AW: Probleme beim Empfangen mittels WM_COPYDATA
 
Ist denn der record als packed definiert? Wenn nicht sollte die Einstellung (Ausrichtung...) von 10.4 mit 10.3 übereinstimmen.
Die Daten sollten eigentlich beim Empfang noch gültig sein, da Sendmessage und nicht Postmessage verwendet wird.

PitterS80 5. Feb 2022 20:15

AW: Probleme beim Empfangen mittels WM_COPYDATA
 
Zitat:

In der (recht alten, aber funktionierenden) oneinst.pas, die ich dazu verwende, wird beim Aufbau der WM_COPYDATA-Message nicht nur einfach der Pointer zum String übergeben, sondern es werden explizit die Daten kopiert. Mich wundert ehrlich gesagt ein wenig, dass dein alter Code überhaupt funktioniert ...

Delphi-Quellcode:
Data.lpData := ParamStrToBlob(Data.cbData);

// mit

function ParamStrToBlob(out cbData: DWORD): Pointer;
var
  Loop: Integer;
  pStr: PChar;
begin
  cbData := Length(ParamStr(1)) * SizeOf(Char) + 4; { gleich inklusive #0#0 }
  for Loop := 2 to ParamCount do
    cbData := cbData + DWORD(Length(ParamStr(Loop)) * SizeOf(Char) + 2);
  Result := GetMemory(cbData);
  ZeroMemory(Result, cbData);
  pStr := Result;
  for Loop := 1 to ParamCount do
  begin
    lstrcpy(pStr, PChar(ParamStr(Loop)));
    pStr := @pStr[lstrlen(pStr) + 1];
  end;
end;
Ich hoffe, diese Variante funktioniert mit 10.4 weiter, wenn ich in den nächsten 30 Tagen umsteigen muss ...
Habe ich ausprobiert, funktioniert aber leider auch nicht. Immer noch die selbe Meldung. Irgendwie scheint es da irgendwo den Pointer zu schrotten...

Zitat:

Ist denn der record als packed definiert? Wenn nicht sollte die Einstellung (Ausrichtung...) von 10.4 mit 10.3 übereinstimmen.
Die Daten sollten eigentlich beim Empfang noch gültig sein, da Sendmessage und nicht Postmessage verwendet wird.
Kannst du mir da einen Tipp geben, wo ich das nachschauen kann? Hab in den letzten 20 Jahren nicht viel mit Delphi gemacht (war damals noch Delphi 4) und muss mich erstmal wieder reinfuchsen...

venice2 5. Feb 2022 21:31

AW: Probleme beim Empfangen mittels WM_COPYDATA
 
Hmmm..

Delphi-Quellcode:
var
  gCDS: COPYDATASTRUCT;
  gSOP: TSOP64; // my Record
const
  dwData_GetPluginName = 6;
64 Bit Anwendung..
Delphi-Quellcode:
function GetPluginDescription(WindowHandle: HWND): string;
begin
  SetLength(Result, SendMessage(WindowHandle, WM_GETTEXTLENGTH, 0, 0));
  if Result <> '' then
    SendMessage(WindowHandle, WM_GETTEXT, Length(Result) + 1, LPARAM(PWideChar(Result)));
end;

procedure SOP_GetPluginName;
begin

  if (gp.hSOPlugin <> 0) then
  begin
    gCDS.dwData := dwData_GetPluginName;
    gCDS.cbData := SizeOf(gSOP);
    gCDS.lpData := @gSOP;
    SendMessage(gp.hSOPlugin, WM_COPYDATA, WPARAM(gP.MainHandle), LPARAM(@gCDS));
  end;

  Description := GetPluginDescription(gP.MainHandle);
end;
32 Bit Anwendung..
Delphi-Quellcode:
function GetPluginName(handle: HVIS): PWideChar; stdcall;
begin

  Result := '';
  if handle <> 0 then
  begin
    Result := PWideChar(WideString(VisInfo^.VisPointer^.PluginName));
  end;
end;
Delphi-Quellcode:
var
  pCDS: PCopyDataStruct;
Delphi-Quellcode:
    WM_COPYDATA:
      begin
        pCDS := Pointer(lP); // LP pointer auf die CopyDataStruct
        case pCDS.dwData of

          dwData_GetPluginName:
            begin
              PluginName := GetPluginName(VisHandle);
              StrPCopy(aTemp, string(PluginName));
              SendMessage(wp, WM_SETTEXT, SizeOf(aTemp), LPARAM(@aTemp));
            end;
        end;
Nur als Denkanstoß.

Uwe Raabe 5. Feb 2022 21:55

AW: Probleme beim Empfangen mittels WM_COPYDATA
 
Zitat:

Zitat von Klaus01 (Beitrag 1501738)
.. ist die neue Instanz schon beendet (der pointer auf den String also nicht mehr valide)wenn die Nachricht bei der alten Instanz ankommt?

Das hier SendMessage verwendet wird, wartet der aufrufende Prozess auf die Abarbeitung der Message bevor er weitermacht.

himitsu 5. Feb 2022 23:09

AW: Probleme beim Empfangen mittels WM_COPYDATA
 
Egal, Zeiger in anderen Prozessen sind eh da düben nichts wert.

Darum gibt es ja WM_COPYDATA, welches einen angegebenen Speicherblock in den anderen Prozess kopiert, damit man ihn drüben lesen kann.


Alternatov GlobalAlloc und das Handle sharen
oder MemoryMappedFiles
oder Streams
oder ...

Zitat:

Zitat von PitterS80 (Beitrag 1501736)
Delphi-Quellcode:
      MyHandle:=FindWindow(nil, PChar(APP_NAME));
      ...
      CloseHandle(MyHandle);

Wieso versuchst du das "Handle" MyHandle (HWND nicht HANDLE) freizugeben, was vom FindWindow kommt?

Da du vom CloseHandle die Rückgabewerte nicht prüfst und so nicht mitbekommst, dass es dir einen Fehler um die Ohren versucht zu werfen

und da du zum Glück die falsche Funktion zum Freigeben von HWND benutzt, welche nämlich DestroyWindow (nicht CloseHandle) ist
...
eigentlich hättest du das Fenster gelöscht, wenn es funktioniert hätte.

PitterS80 6. Feb 2022 11:11

AW: Probleme beim Empfangen mittels WM_COPYDATA
 
Manchmal steht man einfach nur wie der Ochs' vor'm Berg...
Ich hatte eine bestehende, einwandfrei funktionierende Anwendung und wollte diese weiterentwickeln.
Dafür habe ich natürlich das Projekt kopiert.
Um dann aber die neue Anwendung parallel zur alten testen zu können, habe ich einerseits den myGUID für den Mutex neu generiert und den C_KEY als Identifier für WM_COPYDATA.
Bei letzterem habe ich wohl Mist gebaut...
Mit dem ursprünglichen Wert funktioniert es wieder.

Trotzdem vielen Dank für eure Hilfe!

venice2 6. Feb 2022 11:17

AW: Probleme beim Empfangen mittels WM_COPYDATA
 
Zitat:

Zitat von PitterS80 (Beitrag 1501762)
Manchmal steht man einfach nur wie der Ochs' vor'm Berg...
Ich hatte eine bestehende, einwandfrei funktionierende Anwendung und wollte diese weiterentwickeln.
Dafür habe ich natürlich das Projekt kopiert.
Um dann aber die neue Anwendung parallel zur alten testen zu können, habe ich einerseits den myGUID für den Mutex neu generiert und den C_KEY als Identifier für WM_COPYDATA.
Bei letzterem habe ich wohl Mist gebaut...
Mit dem ursprünglichen Wert funktioniert es wieder.

Trotzdem vielen Dank für eure Hilfe!

Trotz allem.
Wie himitsu schon sagte ist
Delphi-Quellcode:
CloseHandle(MyHandle);

falsch!

BerndS 7. Feb 2022 07:10

AW: Probleme beim Empfangen mittels WM_COPYDATA
 
Bei meiner Vermutung, dass das Problem mit der record Ausrichtung zu tun haben könnte, habe ich übersehen das
Data von Typ TWMCopyData ist. Dieser ist in der unit Winapi.Messages definiert ist. Hier werden alle Records mit {$ALIGN ON} ausgerichtet, wobei ich in der Hilfe von 10.4 dazu kein passende Beschreibung gefunden habe.
Könnte das {$A1} entsprechen?

Uwe Raabe 7. Feb 2022 09:15

AW: Probleme beim Empfangen mittels WM_COPYDATA
 
{$ALIGN ON} entspricht {$A+} und somit {$ALIGN 8}. Siehe hier: Align fields (Delphi)

BerndS 7. Feb 2022 10:25

AW: Probleme beim Empfangen mittels WM_COPYDATA
 
@Uwe, Danke für den Link. Das Default/Vorgabe = A8 entspricht steht ja in der Hilfe. Das ON = Default ist, konnte ich nicht aus der Hilfe entnehmen. :oops:

Uwe Raabe 7. Feb 2022 10:47

AW: Probleme beim Empfangen mittels WM_COPYDATA
 
Zitat:

Zitat von BerndS (Beitrag 1501824)
Das ON = Default ist, konnte ich nicht aus der Hilfe entnehmen.

Deswegen schrieb ich ja auch
Zitat:

Zitat von Uwe Raabe (Beitrag 1501818)
{$ALIGN ON} entspricht {$A+}



Alle Zeitangaben in WEZ +1. Es ist jetzt 14:53 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