MFC之Message

/*
消息类型:
1.标准消息:除WM_COMMAND之外,所有以WM_开头的消息。从CWnd派生的类,都可以
接受到这类消息。
2.命令消息:来自菜单、加速键或工具栏按钮,消息中包含命令标识符ID,以WM_COMMAND形式呈现。
从CCmdTarget派生的类,都可以接受到这类消息。
3.通知消息:由控件产生的消息,目的是向父窗口(通常是对话框)通知事件的发生。
从CCmdTarget派生的类,都可以接受到这类消息。

CWnd派生于CCmdTarget类,所以凡是从CWnd派生的类,既可以接受标准消息,
也可以接受命令消息和通告消息。而从CCmdTarget派生的类,则只能接受命令
消息和通告消息,不能接收标准消息。

文档类(CMenuDoc)和应用程序类(CWinApp)类都派生于CCmdTarget类,所以他们不能接收
标准消息。
添加一个菜单后,在四个类中都添加其响应函数,则执行顺序为:
视图类->文档类->框架类->应用程序类
*/
<think>我们正在讨论MFC中的PostMessage函数使用。根据引用内容,MFC在处理消息时,对于预定义的消息(如WM_SIZE)会提供更易用的参数映射(如OnSize中的CPoint),但对于用户自定义消息,需要自己处理参数。PostMessage用于将消息放入窗口的消息队列中并立即返回,不等待窗口处理消息。它的用法与SendMessage(发送消息并等待处理)不同。在MFC中,PostMessage的常用形式是:BOOLPostMessage(UINTmessage,WPARAMwParam=0,LPARAMlParam=0);其中,message可以是Windows预定义的消息(如WM_QUIT,WM_KEYDOWN等),也可以是用户自定义的消息(通过WM_USER+一个整数来定义)。用户自定义消息的步骤:1.定义消息:通常在头文件中使用#define定义,例如:#defineWM_MY_MESSAGE(WM_USER+100)2.声明消息处理函数:在类的声明中(通常在头文件)使用afx_msg声明函数,例如:afx_msgLRESULTOnMyMessage(WPARAMwParam,LPARAMlParam);3.在消息映射表中添加映射:在源文件中使用ON_MESSAGE宏,例如:BEGIN_MESSAGE_MAP(CMyWnd,CWnd)ON_MESSAGE(WM_MY_MESSAGE,OnMyMessage)END_MESSAGE_MAP()4.实现消息处理函数:在源文件中实现,例如:LRESULTCMyWnd::OnMyMessage(WPARAMwParam,LPARAMlParam){//处理消息return0;}5.发送消息:在需要发送消息的地方,调用PostMessage,例如:PostMessage(WM_MY_MESSAGE,(WPARAM)someValue,(LPARAM)someOtherValue);注意:PostMessage是CWnd类的成员函数,因此只能在CWnd派生类中调用。如果要向其他窗口发送,需要获得目标窗口的指针,然后调用其PostMessage。示例代码:假设我们有一个对话框类CMyDialog,我们想自定义一个消息WM_MY_MESSAGE,并在对话框中处理它。在MyDialog.h中:#defineWM_MY_MESSAGE(WM_USER+100)classCMyDialog:publicCDialog{//...其他代码protected:afx_msgLRESULTOnMyMessage(WPARAMwParam,LPARAMlParam);//...其他代码};在MyDialog.cpp中:BEGIN_MESSAGE_MAP(CMyDialog,CDialog)ON_MESSAGE(WM_MY_MESSAGE,OnMyMessage)//...其他消息映射END_MESSAGE_MAP()LRESULTCMyDialog::OnMyMessage(WPARAMwParam,LPARAMlParam){//这里可以处理消息//例如,wParam和lParam可以传递整数或指针,根据需求设计intnValue=(int)wParam;CString*pStr=(CString*)lParam;//注意:如果传递指针,要确保指针有效(比如不要传递局部变量的地址,因为消息是异步的,可能发送后局部变量已经销毁)//使用pStr...注意:如果传递了动态分配的内存,记得在适当的地方释放return0;//返回值通常取决于消息,但自定义消息可以根据需要返回}在需要发送消息的地方(比如对话框中的一个按钮处理函数中):voidCMyDialog::OnButtonClick(){//假设我们想传递一个整数和一个字符串intnValue=100;CString*pStr=newCString(_T("Hello"));//动态分配,注意要在处理函数中释放//发送消息PostMessage(WM_MY_MESSAGE,(WPARAM)nValue,(LPARAM)pStr);}在消息处理函数中释放内存:LRESULTCMyDialog::OnMyMessage(WPARAMwParam,LPARAMlParam){intnValue=(int)wParam;CString*pStr=(CString*)lParam;//使用字符串CStringstrMsg;strMsg.Format(_T("Received:%d,%s"),nValue,(LPCTSTR)(*pStr));AfxMessageBox(strMsg);//释放内存deletepStr;return0;}注意:使用指针传递数据时,要确保内存管理正确。如果消息发送后,在接收前对象被销毁,可能导致访问无效内存。因此,也可以考虑使用全局变量或其他同步机制。另外,如果传递的数据很小,也可以不使用指针,而将数据拆分成两个参数(wParam和lParam)传递,比如两个整数。安全提示:由于PostMessage是异步的,如果传递指针,要确保指针所指向的内存在接收消息时仍然有效。通常,我们建议使用动态分配(如new)并在接收消息后释放,但要注意避免内存泄漏。另外,如果消息传递过程中程序退出,可能会导致消息丢失,从而内存泄漏,因此需要谨慎。另一种方式:使用SendMessage(同步)可以避免内存管理问题(因为发送后立即处理,可以使用局部变量),但会阻塞调用线程。根据引用[1],对于自定义消息,MFC不会自动映射参数,所以我们需要自己定义处理函数并解析wParam和lParam。引用[2]展示了OnSize处理函数,这是MFC已经映射好的,参数是nType,cx,cy。而自定义消息则需要我们按照上述步骤处理。引用[3]提到了获取应用程序实例句柄的函数AfxGetInstanceHandle,在PostMessage中通常不需要,但如果有需要获取实例句柄的情况可以使用。因此,使用PostMessage进行自定义消息传递的关键在于定义消息、映射处理函数以及正确使用参数传递数据。相关问题:1.在MFC中,PostMessage和SendMessage有什么区别?2.如何安全地在PostMessage中传递数据?3.MFC中自定义消息的步骤是什么?4.在MFC中,如何发送消息给其他应用程序的窗口?</think>### MFC中PostMessage函数使用详解 在MFC中使用`PostMessage`进行消息传递时,需理解其异步特性和参数处理机制。该函数将消息放入目标窗口的消息队列后立即返回,不等待消息处理完成,适用于非阻塞式通信。 #### 基本语法 ```cpp BOOL PostMessage( UINT Msg, // 消息ID WPARAM wParam = 0, // 消息参数1 LPARAM lParam = 0 // 消息参数2 ); ``` #### 使用步骤 1. **定义自定义消息**(在头文件中) ```cpp #define WM_USER_MYMSG (WM_USER + 100) // WM_USER是自定义消息起点 ``` 2. **声明消息处理函数**(在类声明中) ```cpp afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam); ``` 3. **添加消息映射**(在实现文件中) ```cpp BEGIN_MESSAGE_MAP(CMyWnd, CWnd) ON_MESSAGE(WM_USER_MYMSG, &CMyWnd::OnMyMessage) // 关键映射宏 END_MESSAGE_MAP() ``` 4. **实现消息处理函数** ```cpp LRESULT CMyWnd::OnMyMessage(WPARAM wParam, LPARAM lParam) { CString str = (LPCTSTR)lParam; // 解析LPARAM参数 MessageBox(str); return 0; } ``` 5. **发送消息** ```cpp // 在需要发送的位置 CString data = _T("Hello from PostMessage!"); PostMessage(WM_USER_MYMSG, 0, (LPARAM)(LPCTSTR)data); ``` #### 关键注意事项 1. **参数传递安全**: - 若传递指针(如字符串地址),需确保目标窗口处理时指针仍有效 - 推荐传递简单类型或使用`SendMessage`同步传递 ```cpp // 安全示例:传递整型值 PostMessage(WM_USER_MYMSG, (WPARAM)value, 0); ``` 2. **跨线程通信**: - 需获取目标窗口的有效指针 - 使用`::PostMessage`全局函数并指定窗口句柄 ```cpp CWnd* pTarget = AfxGetMainWnd(); // 获取主窗口 if(pTarget) pTarget->PostMessage(WM_USER_MYMSG, 0, 0); ``` 3. **与SendMessage区别**: - `PostMessage`异步执行,立即返回 - `SendMessage`阻塞调用线程直到消息处理完成[^1] 4. **资源释放**: - 若传递动态分配内存,需在接收方释放 - 或使用`WM_COPYDATA`消息自动管理内存 #### 完整示例场景 假设需要在工作线程中通知主窗口更新UI: ```cpp // 工作线程中 void CWorkerThread::Run() { while(!bStop) { // ...处理任务... ::PostMessage(AfxGetMainWnd()->m_hWnd, WM_USER_UPDATE_PROGRESS, (WPARAM)progress, 0); } } // 主窗口消息映射 ON_MESSAGE(WM_USER_UPDATE_PROGRESS, &CMainFrame::OnUpdateProgress) // 处理函数 LRESULT CMainFrame::OnUpdateProgress(WPARAM wParam, LPARAM) { int progress = (int)wParam; m_progressCtrl.SetPos(progress); // 更新进度条 return 0; } ``` #### 常见问题解决 - **消息未接收**:检查窗口句柄有效性,确保消息映射正确 - **参数解析错误**:在64位系统中注意`WPARAM`/`LPARAM`为64位类型 - **消息队列满**:连续发送大量消息可能导致队列溢出
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值