Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi WM_COPYDATA & Array of Strings = Müll (https://www.delphipraxis.net/126575-wm_copydata-array-strings-%3D-muell.html)

turboPASCAL 28. Dez 2008 17:10


WM_COPYDATA & Array of Strings = Müll
 
Hi,

ich habe da mal ein Problemchen an dem ich schon den ganzen halben Tag sitze,
und das Problem ist das "Verschicken" eines dyn. Array of String.

Ich habe schon ein paar Varianten durch die leider nicht funktionieren wollen.

Beispel:

Delphi-Quellcode:
type
  TParamList = array of string;


// --- Sender ---
//...
    hMainFormWnd := FindWindow('TForm1', 'Test - Application');
    //...
    begin
      if hMainFormWnd <> 0 then
      begin
        CPData.dwData := 0;
        CPData.cbData := sizeof(ParamList);
        CPData.lpData := @ParamList[0];
        SendMessage(hMainFormWnd, WM_COPYDATA, WPARAM(Application.Handle), LPARAM(@CPData));
      end;
    end;
//...

// --- Empfänger ----
procedure TForm1.WMCopyData(var Msg: TWMCopyData);
var
  aParamList: TParamList;
  i, len, size: integer;
begin
  len := Msg.CopyDataStruct^.dwData;
  //size := Msg.CopyDataStruct^.cbData;
  Setlength(aParamList, len);
  aParamList := TParamList(Msg.CopyDataStruct^.lpData);


  for i := 0 to len-1 do
    ListBox1.Items.Add(aParamList[i]);
end;
Leider kommt beim Empfänger immer nur Müll an.

quendolineDD 28. Dez 2008 17:13

Re: WM_COPYDATA & Array of Strings = Müll
 
Intern ist ein String doch auch nur ein Zeiger auf Speicherbereich und enthält noch zusätzlich die Länge des Strings ... Nehm mal ein array of char.
Zumindest hatte ich das Problem bei der Implementierung von IPC über NamedPipes.

alzaimar 28. Dez 2008 17:54

Re: WM_COPYDATA & Array of Strings = Müll
 
Ich würde das ganze über einen Memorystream lösen.
Schreiben:
1. Länge des Strings als 4-Byte-Integer in den Stream schreiben
2. Den Inhalt des Strings
3. In die Copydata-Struktur die Länge des Streams (Stream.Size) sowie die Adresse (Stream.Memory)
4. WM_COPYDATA-Message verschicken

Lesen:
1. MemoryStream instanitiieren und Zeiger zuweisen
2. 4-Byte Integer lesen und einen String mit SetLength (String, Länge) alloziieren
3. <Länge> Bytes aus dem Stream in den String lesen
4. Freuen, das es so einfach ist

turboPASCAL 28. Dez 2008 18:07

Re: WM_COPYDATA & Array of Strings = Müll
 
Isch abe garkeine TMemoryStreame. ;) ( Wäre ja zu einfach.)

Bald geb ichs auf und neme ein statisches Array. :(

alzaimar 28. Dez 2008 18:12

Re: WM_COPYDATA & Array of Strings = Müll
 
Zitat:

Zitat von turboPASCAL
Isch abe garkeine TMemoryStreame. ;) ( Wäre ja zu einfach.)

Du vielleicht nicht, aber dein Delphi. Oder hast Du auch kein Delphi? Alternativ kannst du auch ein Byte-Array nehmen und dort die zu übertragende Information hineinkopieren. Und Bytearrays hat nun wirklich Jeder.

turboPASCAL 28. Dez 2008 18:15

Re: WM_COPYDATA & Array of Strings = Müll
 
Mehr oder weniger für nonVCL optimiert. Daher keine Classes.

Reinhard Kern 28. Dez 2008 18:19

Re: WM_COPYDATA & Array of Strings = Müll
 
Hallo,

1. Strings mit Längenangabe sind Pascal-spezifisch, gibts in C usw. nicht.
2. Variable Strings sind Delphi-spezifisch...
3. Variables Array mit variablen Strings gibts in anderen Sprachen dreimal nicht.

Und überhaupt sind Daten, die aus einem Zeiger und vom System dynamisch verwaltetem Speicher bestehen zum Datenaustausch herzlich ungeeignet.

Für alle Programmierer ausser Delphianer wären nullterminierte C-Strings die natürliche Datenform und als Array eine Folge davon mit Doppel-0 als Abschluss. So arbeitet WIN32 intern und auch Copydata dürfte damit keine Probleme haben. Ich verwende daher für den Verkehr mit der Aussenwelt gleich PChar oder wandle bei Bedarf um, anstatt mich mit TStrings u.ä. zu verrenken.

Gruss Reinhard

jbg 28. Dez 2008 18:23

Re: WM_COPYDATA & Array of Strings = Müll
 
Um den Code mal mit Zahlen auszudrücken:
Zitat:

Delphi-Quellcode:
        CPData.cbData := sizeof(ParamList);
        CPData.lpData := @ParamList[0];

SizeOf(ParamList) liefert 4 zurück (da ParamList ein Zeiger auf ein dyn. Array ist)
@ParamList[0]: zeigt auf den ersten Zeiger auf einen String => Du kopierst die Zeiger von deinem Adressraum in Zeiger im anderen Adressraum, wo sie ins Nirvana zeigen. Die eigentlichen Stringdaten werden hierbei nicht kopiert.

Ein array of string ist (grob beschrieben) nichts anderes als:
Delphi-Quellcode:
type
  PStringArray = ^TStringArray
  TStringArray = array[0..MaxInt div SizeOf(Pointer) - 1] of string
was wiederum (grob beschrieben) nichts anderes ist als
Delphi-Quellcode:
type
  PStringArray = ^TStringArray
  TStringArray = array[0..MaxInt div SizeOf(Pointer) - 1] of PChar
Und wenn du das an WM_COPYDATA übergibst, werden halt nur die Zeiger statt der Daten kopiert. Also ist ein MemoryStream wohl die einfachste Variante das Problem zu lösen. Oder du schickst die Strings einzeln rüber.

alzaimar 28. Dez 2008 18:24

Re: WM_COPYDATA & Array of Strings = Müll
 
Bei Copydata gibst Du einen Speicherbereich und eine Länge an. Wie Du die Daten dort hineinschreibst, bleibt dir überlassen. Wenn es nur ein einziger String ist, dann geht das so:
Delphi-Quellcode:
CPData.dwData := 0;
CPData.cbData := Length (MyString);
CPData.lpData := @MyString[1];
SendMessage(hMainFormWnd, WM_COPYDATA, WPARAM(Application.Handle), LPARAM(@CPData));
Wenn man mehr verschicken will, z.B. Strukturen, muss man die irgendwie serialisieren. Dazu könnte man dann neben Memorystreams auch sowas wie JSON oder XML verwenden, beide sind Standards, wobei JSON weniger Footprint / Overhead erzeugt. Aber, ach, dann wächst die Anwendung ja wieder um ein paar Kb. Und das geht bei nonVCL ja nun wirklich nicht. :stupid: Heutzutage programmiert man ja auch wie vor 40 Jahren, oder wie ein C-Eremit. :roll:

Aber eine Fräge hätt ich nöch: Wenn nonVCL sich auf die Visual Control Library bezieht, wieso verzichtest Du dann auf TMemoryStream? MemoryStreams sind doch nun wirklich unsichtbar. Non-Visuell sozusagen... :gruebel:

turboPASCAL 28. Dez 2008 18:34

Re: WM_COPYDATA & Array of Strings = Müll
 
"C-Eremit." :lol:

Naja, MemoryStream könnte ich mir batsteln aber dann bräucht ich mich ja nicht mer mit dem "array of string" herumärgern.

Zitat:

Delphi-Quellcode:
CPData.lpData := @MyString[1];

Ich habe schon einiges versucht, nur das noch nicht.


Zitat:

Zitat von alzaimar
Aber eine Fräge hätt ich nöch: Wenn nonVCL sich auf die Visual Control Library bezieht, wieso verzichtest Du dann auf TMemoryStream? MemoryStreams sind doch nun wirklich unsichtbar. Non-Visuell sozusagen... :gruebel:

Der Dateigrösse wegen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:48 Uhr.
Seite 1 von 2  1 2      

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