SendMessage (WM_COPYDATA) + write + string

I want to send a record that right now has only a string, but I will add more variables. This is my first time working with recordings, so this is probably a dumb question. But why does this work:

type TDataPipe = record WindowTitle: String[255]; end; var Data: TDataPipe; copyDataStruct : TCopyDataStruct; begin Data.WindowTitle:= String(PChar(HookedMessage.lParam)); copyDataStruct.dwData := 0; copyDataStruct.cbData := SizeOf(Data); copyDataStruct.lpData := @Data; SendMessage(FindWindow('TForm1', nil), WM_COPYDATA, Integer(hInstance), Integer(@copyDataStruct)); end; 

The host:

 type TDataPipe = record WindowTitle: String[255]; end; procedure TForm1.WMCopyData(var Msg: TWMCopyData); var sampleRecord : TDataPipe; begin sampleRecord.WindowTitle:= TDataPipe(Msg.CopyDataStruct.lpData^).WindowTitle; Memo1.Lines.Add(sampleRecord.WindowTitle); end; 

Why, if in a post I use:

 WindowTitle: String; //removed the fixed size 

and on the sending side I use:

 Data.WindowTitle:= PChar(HookedMessage.lParam); //removed String() 

is he just not coming?

I get access violations / application freezes ...

Scenario: the sending side is a DLL connected using SetWindowsHookEx, the receiving side is a simple exe that loads / is called SetWindowsHookEx ...

+5
source share
1 answer

A String[255] is a fixed 256-byte block of memory where character data is stored directly in this memory. Thus, it is safe to somehow transfer across process boundaries without serialization.

A String , on the other hand, is a dynamic type. It simply contains a pointer to character data that is stored elsewhere in memory. Thus, you cannot pass String as-is across the boundaries of the process, all you will pass is the value of the pointer, which has no meaning for the receiving process. You must serialize String data into a flat format that can be safely transferred and handle the deserialization process. For instance:

Sending Party:

 type PDataPipe = ^TDataPipe; TDataPipe = record WindowTitleLen: Integer; WindowTitleData: array[0..0] of Char; //WindowTitleData: array[0..WindowTitleLen-1] of Char; end; var Wnd: HWND; s: String; Data: PDataPipe; DataLen: Integer; copyDataStruct : TCopyDataStruct; begin Wnd := FindWindow('TForm1', nil); if Wnd = 0 then Exit; s := PChar(HookedMessage.lParam); DataLen := SizeOf(Integer) + (SizeOf(Char) * Length(s)); GetMem(Data, DataLen); try Data.WindowTitleLen := Length(s); StrMove(Data.WindowTitleData, PChar(s), Length(s)); copyDataStruct.dwData := ...; // see notes further below copyDataStruct.cbData := DataLen; copyDataStruct.lpData := Data; SendMessage(Wnd, WM_COPYDATA, 0, LPARAM(@copyDataStruct)); finally FreeMem(Data); end; end; 

The host:

 type PDataPipe = ^TDataPipe; TDataPipe = record WindowTitleLen: Integer; WindowTitleData: array[0..0] of Char; //WindowTitleData: array[0..WindowTitleLen-1] of Char; end; procedure TForm1.WMCopyData(var Msg: TWMCopyData); var Data: PDataPipe; s: string; begin Data := PDataPipe(Msg.CopyDataStruct.lpData); SetString(s, Data.WindowTitleData, Data.WindowTitleLen); Memo1.Lines.Add(s); end; 

Moreover, in any situation, you really need to assign your own identification number in the copyDataStruct.dwData field. VCL itself uses WM_COPYDATA internally, so you do not want these messages to be confused with yours, and vice versa. You can use RegisterWindowMessage() to create a unique identifier to avoid conflicts with the identifiers used by other WM_COPYDATA users:

 var dwMyCopyDataID: DWORD; ... var ... copyDataStruct : TCopyDataStruct; begin ... copyDataStruct.dwData := dwMyCopyDataID; ... end; ... initialization dwMyCopyDataID := RegisterWindowMessage('MyCopyDataID'); 

 var dwMyCopyDataID: DWORD; ... procedure TForm1.WMCopyData(var Msg: TWMCopyData); var ... begin if Msg.CopyDataStruct.dwData = dwMyCopyDataID then begin ... end else inherited; end; ... initialization dwMyCopyDataID := RegisterWindowMessage('MyCopyDataID'); 

Finally, the WPARAM HINSTANCE parameter is HWND , not HINSTANCE . If the sender does not have its own HWND , just pass 0. Do not pass the sender variable HINSTANCE .

+8
source

Source: https://habr.com/ru/post/1243436/


All Articles