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 .