为什么只能用SendMessage发送消息WM

 我来答
EvenHHZ
2016-10-25 · 知道合伙人软件行家
EvenHHZ
知道合伙人软件行家
采纳数:13691 获赞数:18845
个人出版图书:《玩转Python网络爬虫》、《玩转Django2.0》

向TA提问 私信TA
展开全部
资料1:WM_COPYDATA是用内存映射机制实现的。
简单思路如下:
发送进程为A,目标进程为B。
当A进程用SendMessage(WM_COPYDATA,wParam,lParam)进行发送的时候,它先调用
HANDLE hMap = CreateFileMapping(0xFFFFFFFF,NULL,PAGE_READWRITE,NULL,dwSize,"MSName")
其中dwSize为lParam信息得到的长度(也就是COPYDATASTRUCT结构得到的信息)
MSName可以是MS自己定义的名字,这样就把内容复制到共享内存中。然后等待B进程处理;
当B进程处理WM_COPYDATA消息时,它先用OpenFileMapping()和MapViewOfFile()得到共享内存地址,
然后再把地址值保存到lParam里面使B进程处理消息过程能处理这些数据,处理好后进行A与B再
用CloseHandle()等API进行清除操作就OK了。

SkyJacker注:按照这种说法,那么进程B,如何知道映射文件名是"MSName"呢?
还是lParam本身就表示映射文件名了?
资料2:
SendMessage是同步函数,会等到窗口处理完才返回
PostMessage是异步函数,只是将消息挂到消息队列中就立即返回,由于无法同步可能导致无法响应,
一般情况下窗口消息是不会被丢弃的。
这是因为系统必须管理用以传递数据的缓冲区的生命期,如果你使用PostMessage,数据缓冲区会在接受端有机会处理该数据之前被系统摧毁掉!
看看候杰翻译的"多线程程序设计" 里面有详细解释,总而言之 只能用SendMessage。

SkyJacker注:话虽然是这么说,但是异步也可以接收数据吧。socket函数connect,recv,send等也运行正常啊。
因此,只能是SendMessage函数的设计使然,而不是因为同步或异步的原因。

资料3:请问如何在2个进程间(一个是多线程数据采集程序,一个是画面显示程序)传递大量数据?
采集程序中存在数量不定的线程,其中每一个线程都可以采集数据,并将数据发送到显示程序进行显示。
显示程序就是一个简单的UI程序,将接收到的采集数据显示出来。
在一定时间段中采集的数据量比较大:每秒几条数据。每条数据大概2-3K(来自不同线程)

原来我使用SendMessage(WM_COPYDATA,…) 在2个进程间传递数据。但最近发现一个BUG:
有时在显示数据过程中切换UI的窗口,会引起系统deadlock! 后来查阅资料,发现用SendMessage传递数据时,
在某些情况下的确可以引起deadlock,所以按照书中的建议用SendMessageTimeout(WM_COPYDATA,…) 进行自我保护方式数据传输。
deadlock问题倒是解决了,但又出现数据丢失问题,原因是SendMessageTimeout经常返回timout错误 !

我的问题是除了SendMessage(WM_COPYDATA,…) 方法,还有没有别的方法实现本文中所说的采集程序和画面显示程序间大量数据的传递?
PostMessage不支持 WM_COPYDATA.
SendMessageCallback, SendNotifyMessage也不支持WM_COPYDATA.

我查过国外的很多网站,大概的结论是:

1)WM_COPYDATA是在两个进程间传递大量数据最方便,最好使的方法.
2)但只有SendMessage,SendMessageTimeout支持WM_COPYDATA
3)SendMessage(WM_COPYDATA,…)内部实现是通过File mapping实现的, 系统自动完成同步工作.
4)SendMessage是阻塞的(block), 在某些情况下会引起deadlock. 所以更安全的方法是使用SendMessageTimeout

SkyJacker注:还是没有点明本质。

二、通过反汇编试图熟悉SendMessage过程
1、发送过程:
procudure SendAlmData(const SendText: string);
var
DS: TCopyDataStruct;
begin
DS.dwData := 0;
DS.cbData := Length(SendText); //SendText表示要发送的数据
DS.lpData := @SendText[1];
SendMessage(FaceHandle, WM_COPYDATA, 0, LongWord(@DS)); //FaceHandle表示接收数据的主界面
//PostMessage(FaceHandle, WM_COPYDATA, 0, LongWord(@DS));
//此处必须用SendMessage,用PostMessage主界面接收不到消息
end;
2、SendMessage声明
SendMessage(FaceHandle, WM_COPYDATA, 0, LongWord(@DS)); //WM_COPYDATA = $004A;
LRESULT SendMessage(
HWND hWnd, // handle of destination window
UINT Msg, // message to send
WPARAM wParam, // first message parameter 短参数
LPARAM lParam // second message parameter 长参数
);

3、通过WM_CopyData传输数据
通过TCopyDataStruct结构存储要传输的数据.
只有DS: TCopyDataStruct一个局部变量的情况。
TCopyDataStruct结构:
tagCOPYDATASTRUCT = packed record
dwData: DWORD;
cbData: DWORD;
lpData: Pointer;
end;
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式