我有2个应用程序 - 经理使用此代码:
procedure TForm1.CopyData(var Msg: TWMCopyData);
var sMsg: String;
begin
if IsIconic(Application.Handle) then Application.Restore;
sMsg := PWideChar(Msg.CopyDataStruct.lpData);
Caption := Caption+'#'+sMsg;
Msg.Result := 123;
end;
procedure TForm1.Button1Click(Sender: TObject);
const
WM_MY_MESSAGE = WM_USER + 1;
var
h: HWND;
begin
Caption := 'X';
h := FindWindow('TForm1', 'Client');
if not IsWindow(h) then Exit;
Caption := Caption+'@';
SendMessage(h, WM_MY_MESSAGE, 123, 321);
end;
和客户:
procedure TForm1.WndProc(var Message: TMessage);
const
WM_MY_MESSAGE = WM_USER + 1;
var DataStruct: CopyDataStruct;
S: String;
h: HWND;
begin
inherited;
if Message.Msg <> WM_MY_MESSAGE then Exit;
h := FindWindow('TForm1', 'Manager');
if not IsWindow(h) then Exit;
Message.Result := 123;
S := Edit2.Text + '@' + Edit1.Text;
DataStruct.dwData := 0;
DataStruct.cbData := 2*Length(S)+1;
DataStruct.lpData := PWideChar(S);
Caption := Caption + '#';
PostMessage(h, WM_CopyData, Form1.handle, integer(@DataStruct));
end;
代码有效但只有一次。 管理器发送2个整数:123和321作为&#34;唤醒&#34;给客户的消息。 客户端通过发送Edit1 + Edit2的内容进行响应。 然后管理器获取此数据并显示其标题。
为什么它只能运作一次?在我再次单击Button1后,它什么也没做。
答案 0 :(得分:4)
如评论中所述,您必须将SendMessage
与WM_COPYDATA
一起使用。主要原因是邮件发件人负责清理用于传输的资源。如上所述in the documentation:
接收应用程序应将数据视为只读。 lParam参数仅在处理消息期间有效。接收应用程序不应释放lParam引用的内存。如果接收应用程序必须在SendMessage返回后访问数据,则必须将数据复制到本地缓冲区。
唯一可行的方法是,如果消息发送方等待接收方处理消息并返回结果。否则,发件人无法知道何时释放这些资源是安全的。
PostMessage
是异步的并立即返回,因此这根本不可行。 SendMessage
将阻塞,直到接收方处理消息并分配返回值。
这里传递一个指向堆栈分配(局部变量)记录@DataStruct
的指针。此外,您还传递一个指向字符串的指针,该字符串是一个局部变量。如果使用PostMessage
,此方法将立即返回 - 堆栈位置(对于类似记录的值类型)将变为无效并且容易被覆盖。字符串存在于堆上,但是引用计数,在这种情况下,将在方法返回时释放。
解决方案是始终确保将SendMessage
与WM_COPYDATA
一起使用。