String[255]
является фиксированным 256-байтовым блоком памяти, где символьные данные хранятся непосредственно в этой памяти. Таким образом, безопасно проходить через все границы процесса без сериализации.
A String
, с другой стороны, является динамическим типом. Он просто содержит указатель на символьные данные, которые хранятся в другом месте в памяти. Таким образом, вы не можете передать String
как есть через границы процесса, все, что вы должны передать, - это значение указателя, которое не имеет смысла для процесса получения. Вы должны сериализовать данные String
в плоский формат, который можно безопасно передать, и процесс десериализации осуществляется приемом. Например:
отправляющая сторона:
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;
Получая сторона:
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;
Это, как говорится, в любой ситуации, вы действительно должны назначить свой собственный номер пользовательского идентификатора на copyDataStruct.dwData
поле. Сам VCL использует внутри себя WM_COPYDATA
, поэтому вы не хотите, чтобы эти сообщения были сбиты с толку, и наоборот. Вы можете использовать RegisterWindowMessage()
, чтобы создать уникальный идентификатор, чтобы избежать конфликтов с идентификаторами, используемыми другими WM_COPYDATA
пользователей:
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');
Наконец, параметр WM_COPYDATA
WPARAM
является HWND
, не HINSTANCE
. Если у отправителя нет своего HWND
, просто пройдите 0. Не передавайте переменную HInstance
вашего отправителя.
Отличный ответ! Еще раз спасибо, всегда с полными и информативными ответами. – LessStress