如何使用SendMessage在两个应用程序之间发送数据?

时间:2015-06-10 13:16:36

标签: delphi winapi

我有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后,它什么也没做。

1 个答案:

答案 0 :(得分:4)

如评论中所述,您必须将SendMessageWM_COPYDATA一起使用。主要原因是邮件发件人负责清理用于传输的资源。如上所述in the documentation

  

接收应用程序应将数据视为只读。 lParam参数仅在处理消息期间有效。接收应用程序不应释放lParam引用的内存。如果接收应用程序必须在SendMessage返回后访问数据,则必须将数据复制到本地缓冲区。

唯一可行的方法是,如果消息发送方等待接收方处理消息并返回结果。否则,发件人无法知道何时释放这些资源是安全的。

PostMessage是异步的并立即返回,因此这根本不可行。 SendMessage将阻塞,直到接收方处理消息并分配返回值。

这里传递一个指向堆栈分配(局部变量)记录@DataStruct的指针。此外,您还传递一个指向字符串的指针,该字符串是一个局部变量。如果使用PostMessage,此方法将立即返回 - 堆栈位置(对于类似记录的值类型)将变为无效并且容易被覆盖。字符串存在于堆上,但是引用计数,在这种情况下,将在方法返回时释放。

解决方案是始终确保将SendMessageWM_COPYDATA一起使用。