gpt4 book ai didi

delphi - SendMessage(WM_COPYDATA) + 记录 + 字符串

转载 作者:行者123 更新时间:2023-12-03 15:07:26 29 4
gpt4 key购买 nike

我想发送一条记录,目前只有一个字符串,但我将添加更多变量。这是我第一次处理记录,所以这可能是一个愚蠢的问题。但是,为什么这有效:

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;

接收方:

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;

为什么如果记录在案,我会使用:

WindowTitle: String; //removed the fixed size

在发送端我使用:

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

根本就不行?

我遇到访问冲突/应用程序卡住...

场景是:发送端是一个使用 SetWindowsHookEx Hook 的 DLL,接收端是一个加载/调用 SetWindowsHookEx 的简单 exe...

最佳答案

String[255] 是一个固定的 256 字节内存块,字符数据直接存储在该内存中。因此,无需序列化即可安全地按原样跨进程边界传递。

另一方面,

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;

话虽这么说,在任何一种情况下,您确实应该将自己的自定义 ID 号分配给 copyDataStruct.dwData 字段。 VCL 本身在内部使用 WM_COPYDATA,因此您不希望这些消息与您的消息混淆,反之亦然。您可以使用 RegisterWindowMessage() 创建唯一 ID,以避免与其他 WM_COPYDATA 用户使用的 ID 发生冲突:

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_COPYDATAWPARAM 参数是 HWND,而不是 HINSTANCE。如果发送者没有自己的 HWND,则只需传递 0。不要传递发送者的 HInstance 变量。

关于delphi - SendMessage(WM_COPYDATA) + 记录 + 字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35516347/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com