PostMessage和SendMessage的区别

本文对比了PostMessage和SendMessage两种Windows消息传递方式的区别。PostMessage为异步消息投放,无论消息是否被处理都会立即返回;而SendMessage为同步消息投放,在消息被处理完毕前会阻塞当前线程。此外,还介绍了这两种消息传递方式在同一线程和跨线程使用时的行为差异。

1, PostMessage只把消息放入队列,不管其他程序是否处理都返回,然后继续执行,这是个异步消息投放函数。而SendMessage必须等待其他程序处理消息完了之后才返回,继续执行,这是个同步消息投放函数。而且,PostMessage的返回值表示PostMessage函数执行是否正确;而SendMessage的返回值表示其他程序处理消息后的返回值。这点大家应该都明白。 2, 如果在同一个线程内,PostMessage发送消息时,消息要先放入线程的消息队列,然后通过消息循环Dispatch到目标窗口。SendMessage发送消息时,系统直接调用目标窗口的消息处理程序,并将结果返回。SendMessage在同一线程中发送消息并不入线程消息队列。 如果在不同线程内。最好用PostThreadMessage代替PostMessage,他工作的很好。SendMessage发送消息到目标窗口所属的线程的消息队列,然后发送消息的线程等待(事实上,他应该还在做一些监测工作,比如监视QS_SENDMESSAGE标志),直到目标窗口处理完并且结果返回,发送消息的线程才继续运行。这是SendMessage的一般情况,事实上,处理过程要复杂的多。比如,当发送消息的线程监测到有别的窗口SendMessage一个消息到来时,他直接调用窗口处理过程(重入),并将处理结果返回(这个过程不需要消息循环中GetMessage等的支持)。 3, msdn: If you send a message in the range below WM_USER to the asynchronous message functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its message parameters can not include pointers. Otherwise, the operation will fail. 如果发送的消息码在WM_USER之下(非自定义消息)且消息参数中带有指针,那么PostMessage,SendNotifyMessage,SendMessageCallback这些异步消息发送函数将会调用失败。 最好不要用PostMessage发送带有指针参数的消息。

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/Aoouch/archive/2007/03/09/1525457.aspx

<think>首先,用户的问题是关于MFC中的PostMessageSendMessage区别及使用方法。我需要根据系统指令来构建回答。 系统指令关键点: - 所有行内数学表达式用$...$格式。 - 独立公式用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,如[^1]。 - 回答结构清晰,帮助用户逐步解决问题。 - 参考站内引用:用户提供了两个引用,但说这些仅供参考,不是用户真正的需求。我需要基于用户的问题来回答。 用户问题:"我想了解MFC中PostMessageSendMessage区别及使用方法 请问MFC PostMessage SendMessage 区别 使用方法" 所以,核心是解释PostMessageSendMessage区别以及如何使用它们。 结构化回答: 1. **介绍**:简要说明这两个函数的作用。 2. **区别**:详细比较PostMessageSendMessage。 3. **使用方法**:解释如何在实际代码中使用它们。 4. **注意事项**:提到一些重要点,如窗口存在性等。 5. **生成相关问题**:在结束时添加相关问题。 参考提供的引用: - 引用[1]:提到目标窗口必须存在,消息处理函数必须能处理消息,参数要符合要求。 - 引用[2]:强调自定义函数要写在正确的类中,比如给父窗口发送消息时,函数要写在父窗口类中。 我需要确保回答真实可靠,基于我的知识: - PostMessage:异步发送消息,不等待处理完成,立即返回。 - SendMessage:同步发送消息,等待消息处理完成后再返回。 - 在MFC中,使用CWnd类的成员函数,如pWnd->PostMessage(), pWnd->SendMessage()。 - 参数:消息ID、wParam、lParam。 - 区别包括阻塞行为、返回值等。 使用中文回答。 添加引用标识:在回答中,如果提到引用中的点,就自然地添加[^1]或[^2]。例如,当提到窗口存在性时,可以引用[^1]。 生成相关问题:在回答结束时,添加类似示例的"相关问题"部分。 LaTeX:用户的问题中没有数学内容,但系统指令说所有行内数学表达式必须用$...$。如果回答中涉及数学,要用它。但这里可能不涉及数学,所以可能不需要。如果有变量或简单方程,可以应用。例如,在讨论消息参数时,如果有数学表达式,但这里不太可能。 最终回答结构: - 开头:介绍函数。 - 主体:分点解释区别使用方法。 - 结尾注意事项。 - 相关问题。 生成相关问题: - 类似于示例:"1. 如何优化消息传递性能?2. 如何处理自定义消息?3. 在什么场景下使用PostMessage vs SendMessage?" 确保回答清晰、逐步。</think>### MFC中PostMessageSendMessage区别及使用方法 在MFC(Microsoft Foundation Classes)框架中,`PostMessage` `SendMessage` 是用于窗口间通信的核心函数,它们允许发送消息到指定窗口的消息队列。这些消息可以是系统定义的(如WM_CLOSE)或自定义的(如WM_USER + 100)。以下我将逐步解释它们的区别、使用方法及注意事项,确保回答基于可靠知识(参考MFC文档常见开发实践)。 #### 一、PostMessage SendMessage区别 这两个函数的主要区别在于消息传递的 **同步性** **阻塞行为**,这直接影响程序的执行流程性能。以下是关键比较: 1. **SendMessage**: - **同步发送**:调用 `SendMessage` 时,当前线程会阻塞,直到目标窗口的消息处理函数(如 `OnMessage`)完成处理并返回结果后才继续执行。这类似于函数调用,确保消息被立即处理。 - **返回值**:函数返回消息处理的结果(如LRESULT类型),开发者可以直接使用这个值进行后续操作。 - **适用场景**:适用于需要即时响应或顺序执行的场景,例如修改窗口状态后立即获取确认。 - **潜在风险**:如果目标窗口的消息处理函数耗时较长,可能导致调用线程卡死(死锁),需谨慎使用。 2. **PostMessage**: - **异步发送**:调用 `PostMessage` 时,消息被放入目标窗口的消息队列,函数立即返回,不等待处理完成。消息会在目标窗口的消息泵(如 `GetMessage` 循环)中异步处理。 - **返回值**:函数返回一个BOOL值(TRUE表示消息成功入队,FALSE表示失败),但不提供消息处理的结果。 - **适用场景**:适用于非紧急或后台任务,例如发送通知而不阻塞当前线程,提高程序响应性。 - **潜在风险**:消息可能延迟处理,如果队列积压,可能导致消息丢失;需确保目标窗口及时处理消息。 **关键区别总结**: - **阻塞性**:SendMessage 是同步阻塞的,PostMessage 是异步非阻塞的。 - **性能影响**:在高并发场景下,PostMessage 更高效,因为它不阻塞调用线程;SendMessage 可能导致性能瓶颈。 - **错误处理**:如果目标窗口不存在或不可用,两者都可能失败,但 SendMessage 会立即返回错误,而 PostMessage 可能只返回FALSE[^1]。 #### 二、使用方法 在MFC中,这两个函数都是 `CWnd` 类的成员函数,通过窗口指针调用。使用前需确保目标窗口已创建且消息处理函数已定义。以下是基本步骤代码示例: 1. **基本语法**: - `SendMessage`:`LRESULT SendMessage(UINT Msg, WPARAM wParam = 0, LPARAM lParam = 0);` - `PostMessage`:`BOOL PostMessage(UINT Msg, WPARAM wParam = 0, LPARAM lParam = 0);` - 参数说明: - `Msg`:消息ID(例如WM_COMMAND或自定义消息如WM_USER + 100)。 - `wParam` `lParam`:附加参数,用于传递数据(如整数、指针),需与消息处理函数匹配。 2. **使用步骤**: - **步骤1: 获取目标窗口指针** 在发送消息的类中(如子窗口或主框架),使用 `GetParent()`、`FindWindow()` 或 `AfxGetMainWnd()` 获取目标窗口的 `CWnd*` 指针。 **注意**:消息的自定义处理函数必须定义在目标窗口的类中(如父窗口类)。例如,给父窗口发送消息时,自定义函数需写在父窗口的 `.h` `.cpp` 文件中[^2]。 - **步骤2: 定义消息处理函数** 在目标窗口类头文件中声明消息处理函数,并在实现文件中添加消息映射。例如: ```cpp // 在父窗口类头文件(如 MainFrm.h)中 class CMainFrame : public CFrameWnd { public: afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam); // 声明自定义消息处理函数 DECLARE_MESSAGE_MAP() }; // 在父窗口类实现文件(如 MainFrm.cpp)中 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage) // WM_MY_MESSAGE 是自定义消息ID END_MESSAGE_MAP() LRESULT CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam) { // 处理消息,例如更新UI CString str = (LPCTSTR)lParam; AfxMessageBox(str); return 0; // 返回结果 } ``` - **步骤3: 发送消息** 在发送方代码中调用函数。示例:从子窗口向父窗口发送消息。 ```cpp // 在子窗口类中 void CChildView::SendMessageExample() { CMainFrame* pMainFrame = (CMainFrame*)AfxGetMainWnd(); // 获取父窗口指针 if (pMainFrame != nullptr) { // 使用 SendMessage:同步发送,等待处理 LRESULT result = pMainFrame->SendMessage(WM_MY_MESSAGE, 0, (LPARAM)_T("Hello via SendMessage")); // 使用返回值(如检查result) // 使用 PostMessage:异步发送,不等待 BOOL success = pMainFrame->PostMessage(WM_MY_MESSAGE, 0, (LPARAM)_T("Hello via PostMessage")); if (!success) { AfxMessageBox(_T("PostMessage failed!")); } } } ``` 3. **常见错误及调试**: - **目标窗口不存在**:调用前检查窗口指针是否为 `nullptr`,否则可能导致崩溃[^1]。 - **参数不匹配**:确保 `wParam` `lParam` 类型与处理函数一致,例如传递字符串时用 `(LPARAM)(LPCTSTR)str`。 - **消息未处理**:如果消息ID未在目标窗口的消息映射中定义,消息会被忽略;使用调试器检查消息队列。 #### 三、注意事项 - **窗口存在性**:目标窗口必须已创建且消息泵正在运行,否则消息发送失败。在窗口销毁时避免发送消息[^1]。 - **线程安全**:PostMessage 是线程安全的,可用于跨线程通信;SendMessage 在跨线程调用时可能引发死锁,需使用 `SendMessageTimeout` 替代。 - **性能优化**:频繁发送消息时,优先使用 PostMessage 避免UI冻结;对实时性要求高的操作(如绘图)使用 SendMessage。 - **自定义消息**:定义消息ID时,从 `WM_USER`(如 `#define WM_MY_MESSAGE WM_USER + 100`)开始,以避免与系统消息冲突。 通过以上步骤,您可以安全地在MFC项目中使用这些函数。如果消息处理涉及复杂逻辑,建议添加错误日志或使用断言。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值