使用WM_COPYDATA跨进程发送数据

进程之间通讯的几种方法:

在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯。常用的方法有

使用内存映射文件
通过共享内存DLL共享内存
使用SendMessage向另一进程发送WM_COPYDATA消息

比起前两种的复杂实现来,WM_COPYDATA消息无疑是一种经济实惠的一中方法。WM_COPYDATA消息的主要目的是允许在进程间传递只读数据。Windows在通过WM_COPYDATA消息传递期间,不提供继承同步方式。SDK文档推荐用户使用SendMessage函数,接受方在数据拷贝完成前不返回,这样发送方就不可能删除和修改数据。注意,接受方在DefWndProc事件中,来处理这条消息。由于中文编码是两个字节,所以传递中文时候字节长度要搞清楚。

用WM_COPYDATA的前提:
1,知道接收消息进程的句柄。
2,接收消息进程重载了WM_COPYDATA消息映射,能对其做出反应(否则不是发送端自作多情了?)

前几天写程序用到WM_COPYDATA进行进程间通信,但是接收方怎么也收不到消息。调试发现找到的窗口句柄是没有问题的,查看MSDN也没有什么提示,百思不得其解。后来看了一些示例代码,发现不同之处是我的SendMessage调用中wParam和lParam参数都是0,因为我只是需要通过WM_COPYDATA消息通知一下接收程序即可,不用传递任何数据。试着将这两个参数改为非空,接收方就可以收到消息了。总结结论为:wParam参数是否为0没有影响,但是lParam参数必须为非空,即必须指向一个有效的COPYDATASTRUCT结构体。原因是什么呢?查了一些资料发现,SendMessage(WM_COPYDATA)底层是通过文件映射(File Mapping)完成的,大概流程是发送方线程根据COPYDATASTRUCT结构体中的传递数据信息,在共享内存中进行数据复制,接收方线程则会到共享内存中读取数据进行处理。因此如果指向COPYDATASTRUCT结构的指针为空的话,流程是无法进行的,所以接收方也理所当然收不到消息。

 

procedure TForm1.Button2Click(Sender: TObject);
var
  Receiver: THandle;
  buffer: array[0..1023] of char;
  Data: TCopyDataStruct;
begin
  Receiver := FindWindow('TReceiverForm', nil);
  if Receiver > 0 then
  begin
    StrPLCopy(@buffer, Edit1.Text, 1024); // Assumes message in Editbox
    Data.dwData := 0;
    Data.cbData := 1024;
    Data.lpData := @buffer;
    SendMessage(Receiver, WM_COPYDATA, 0, LongInt(@Data));
  end;
end;

type
  TForm1 = class(TForm)
    { ... }
  private
    { ... }
  protected
    procedure WmCopyData(var Msg: TMessage); message WM_COPYDATA;
  public
    { ... }
  end;

procedure TForm1.WmCopyData(var Msg: TMessage);
begin
  ShowMessage(
    'This message sent:' + #13 +
    string(PChar(PCopyDataStruct(Msg.LParam)^.lpData))
  );
end;

参考:http://www.xuebuyuan.com/976757.html

http://blog.csdn.net/iseekcode/article/details/4821082

posted @ 2014-12-21 14:15  findumars  Views(3517)  Comments(0Edit  收藏  举报