(转)深入解析SendMessage、PostMessage终上所述,我们得到如下结论:
1、
2、
3、
4、
5、
6、 本文将使用C++语言,在MFC框架的配合下给出PostMessage、SendMessage等的使用方式与使用不当造成的后果(讨论均针对自定义的消息进行)。如有什么错误,欢迎指正。
写过Windows程序的同学都知道PostMessage、SendMessage的区别,PostMessage函数调用发送之后,立即返回,不等待消息处理完成。而SendMessage则让调用的线程处于阻塞(BLOCk)状态,直到消息处理完成。
1) 代码:code_1
#define
void {
}
LRESULT {
}
code_1将运行的结果: Param1 = 0 Param2 = 0 RealTimes = 1 Param1 = 0 Param2 = 0 RealTimes = 2 Param1 = 0 Param2 = 0 RealTimes = 3 … Param1 = 0 Param2 = 0 RealTimes = 1000 结果远不如我们所料,表现为PostMessage多次发送时,2~1000的消息参数全被冲掉了。用pParam1、pParam2来处理进度条的话,后果可想而知(进度条根本没动)。如果将上面的PostMessage改为SendMessage,结果如下: Param1 = 1 Param2 = 1 RealTimes = 1 Param1 = 2 Param2 = 2 RealTimes = 2 Param1 = 3 Param2 = 3 RealTimes = 3 … Param1 = 1000 Param2 = 1000 RealTimes = 1000 可见,稳定的输出了需要的内容,可以很好的控制。 在此情况下(主线程中Post消息时),不仅没有改善用户体验,反而更差了。 不可以频繁使用PostMessage发送同一个消息,除非保证上一次发送的消息被处理完成(这如何保证???),这还不如直接用SendMessage。
当然OnMyTest函数可能是这样的:
LRESULT {
} 在这种情况下,如果用SendMessage的话,用户体验将会大大下降,甚至导致程序无法响应。于是有人提出了使用PostMessage,这样程序不会无法响应,最多显示不正确罢了。乍一看,提议似乎还不错,至少程序正常运行了。但是,这些网络访问、磁盘读写等操作为什么要放到界面的代码中呢?界面、代码分离才是合理的,因此可以认定,访问网络、磁盘读写等操作不应该放到这里来处理。
2) 代码:code_2
DWORD {
}
void {
}
LRESULT {
}
code_2的运行结果: (程序直接崩溃了) 线程函数不等待WM_MY_TEST的返回,循环1000次之后直接退出了,这导致栈上的变量nParam1、nParam2被释放,然后OnMyTest处理的时候,nParam1、nParam2的地址已经无效了,导致崩溃。SendMessage则不会出现此类情况。
修改程序 代码:code_2(2)
DWORD {
} 由于堆内存没有被释放,所以程序没有崩溃,在我的机器上运行结果为: Param1 = 27 Param2 = 27 RealTimes = 1 Param1 = 117 Param2 = 117 RealTimes = 2 Param1 = 162 Param2 = 162 RealTimes = 3 Param1 = 218 Param2 = 218 RealTimes = 4 Param1 = 272 Param2 = 272 RealTimes = 5 Param1 = 312 Param2 = 312 RealTimes = 6 Param1 = 353 Param2 = 353 RealTimes = 7 Param1 = 391 Param2 = 391 RealTimes = 8 Param1 = 431 Param2 = 431 RealTimes = 9 程序执行非常不稳定,每次结构都不同,当然也不能用这些数据了。当把两个new int放到for循环中,执行结果是稳定的,但这样的代码晦涩难懂。在这里用PostMessage没有任何好处,所以建议使用SendMessage。
代码:code_3
DWORD {
}
LRESULT {
} 我们可以多加个消息,WM_MUST_DO_THING_B,然后用PostMessage发送,哦,不能这样,B一定要在A完成之后,现在唯一的处理方式只有对B的处理加入到A的消息处理函数中,这将导致费解的代码。如果在原来的线程函数中PostMessage为SendMessage,则不会如此。
2)
LRESULT {
} 在这种情况下,建议使用SendMessageTimeout,当等待一段时间后,消息仍然没有处理完成,则程序放弃操作继续运行。
终上所述,我们得到如下结论:
1、
2、
3、
4、
5、
6、 |
|