关于VC++中两种自定义消息的发送与接收的方法实现进行说明.docx
《关于VC++中两种自定义消息的发送与接收的方法实现进行说明.docx》由会员分享,可在线阅读,更多相关《关于VC++中两种自定义消息的发送与接收的方法实现进行说明.docx(38页珍藏版)》请在冰豆网上搜索。
关于VC++中两种自定义消息的发送与接收的方法实现进行说明
在MFC中添加用户自定义消息
首先弄清楚两点:
(1)谁要发送这个消息
(2)谁要接受这个消息。
用一个简单的例子来说明。
对象A向B(也可以就是A到A)发送消息。
1发送消息
首先在A的头文件中定义这个消息:
#defineWM_USERMESSAGEWM_USER+30
所有自定义消息都是以WM_USER消息为基础加上一个任意的自然数来表示的。
A是向外发送消息的对象,因此在A的某个方法(函数)里就会调用用来发消息的函数B:
:
SendMessage()/B:
:
PostMessage(),因为是B接受消息,因此是如上的形式。
2接受消息
对象接受一个消息,应该有三部分:
在头文件中有该消息的处理函数的原型;在实现文件中有接受消息映射的宏;以及该消息的处理函数的具体实现。
2.1头文件中加上自定义消息的处理函数原型
在DECLARE_MESSAGE_MAP()语句之前,一对AFX_MSG之间加上如下形式的函数原型:
afx_msgLRESULTOnProcName(WPARAMwParam,LPARAMlParam);
对Win32来说,wParam,lParam是传递消息最常用的手段。
2.2在实现文件中加上接受消息映射的宏
在cpp文件里,BEGIN_MESSAGE_MAP语句之后,在一对AFX_MSG_MAP之间,增加如下形式的代码:
ON_MESSAGE(WM_USERMESSAGE,OnProcName)
上面是不用分号结尾的。
2.3在实现文件中给出消息处理函数的具体实现。
发信人:
Amia(小羊·橘子·和中南海有缘),信区:
VisualC
标题:
MFC中自由使用自定义消息
发信站:
哈工大紫丁香(2003年11月26日07:
45:
34星期三),站内信件
消息映射、循环机制是Windows程序运行的基本方式。
VC++MFC中有许多现成的消息句柄,可当我们需要完成其它的任务,需要自定义消息,就遇到了一些困难。
在MFC ClassWizard中不允许添加用户自定义消息,所以我们必须在程序中添加相应代码,以便可
以象处理其它消息一样处理自定义消息。
通常的做法是采取以下步骤:
第一步:
定义消息。
推荐用户自定义消息至少是WM_USER+100,因为很多新控件也要使用WM_USER消息。
#defineWM_MY_MESSAGE(WM_USER+100)
第二步:
实现消息处理函数。
该函数使用WPRAM和LPARAM参数并返回LPESULT。
LPESULTCMainFrame:
:
OnMyMessage(WPARAMwParam,LPARAMlParam)
{
//TODO:
处理用户自定义消息
...
return0;
}
第三步:
在类头文件的AFX_MSG块中说明消息处理函数:
classCMainFrame:
publicCMDIFrameWnd
{
...
//一般消息映射函数
protected:
//{{AFX_MSG(CMainFrame)
afx_msgintOnCreate(LPCREATESTRUCTlpCreateStruct);
afx_msgvoidOnTimer(UINTnIDEvent);
afx_msgLRESULTOnMyMessage(WPARAMwParam,LPARAMlParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
}
第四步:
在用户类的消息块中,使用ON_MESSAGE宏指令将消息映射到消息处理函数中。
BEGIN_MESSAGE_MAP(CMainFrame,CMDIFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_WM_TIMER()
ON_MESSAGE(WM_MY_MESSAGE,OnMyMessage)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
如果用户需要一个定义整个系统唯一的消息,可以调用SDK函数RegisterWindowMessage定义
消息:
staticUINTWM_MY_MESSAGE=RegisterWindowMessage("User");
并使用ON_REGISTERED_MESSAGE宏指令取代ON_MESSAGE宏指令,其余步骤同上。
当需要使用自定义消息时,可以在相应类中的函数中调用函数PostMessage或SendMessa
ge发送消息PoseMessage(WM_MY_MESSAGE,O,O);如果向其他进程发送消息可通过如下方法
发送消息:
DWORDresult;
SendMessageTimeout(wnd->m_hWnd,//目标窗口
WM_MY_MESSAGE,//消息
0,//WPARAM
0,//LPARAM
SMTO_ABORTIFHUNG|
SMTO_NORMAL,
TIMEOUT_INTERVAL,
&result);
以避免其它进程如果被阻塞而造成系统死等状态。
可是如果需要向其它类(如主框架、子窗口、视类、对话框、状态条、工具条或其他控
件等)发送消息时,上述方法显得无能为力,而在编程过程中往往需要获取其它类中的某个
识别信号,MFC框架给我们造成了种种限制,但是可以通过获取某个类的指针而向这个类发送消息,而自定义消息的各种动作则在这个类中定义,这样就可以自由自在的向其它类发送消息了。
下面举的例子叙述了向视类和框架类发送消息的方法:
在主框架类中向视类发送消息:
视类中定义消息:
ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage)//定义消息映射
视类定义消息处理函数:
//消息处理函数
LRESULTCMessageView:
:
OnMyMessage(WPARAMwParam,LPARAMlParam)
{
//TODO:
处理用户自定义消息
...
return0;
}
//发送消息的测试函数
voidCMainFrame:
:
OnTest()
{
CView*active=GetActiveView();//获取当前视类指针
if(active!
=NULL)
active->PostMessage(WM_MY_MESSAGE,0,0);
}
在其它类中向视类发送消息:
//发送消息的测试函数
voidCMainFrame:
:
OnTest()
{
CMDIFrameWnd*pFrame;
CMDIChildWnd*pChild;
CView*pView;
//获取主窗口指针
pFrame=(CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
//获取子窗口指针
pChild=(CMDIChildWnd*)pFrame->GetActiveFrame();
//获取视类指针
pView=pChild->GetActiveView();
if(pView!
=NULL)
pView->PostMessage(WM_MY_MESSAGE,0,0);//发送消息
}
其余步骤同上。
在视类中向主框架发送消息:
首先在主框架中定义相关的消息,方法同上,然后在发送消息的函数中添加代码如下
//发送消息的测试函数
voidCMessageView:
:
OnTest()
{
CFrameWnd*active=GetActiveFrame();//获取当前主窗口框架指针
if(active!
=this)
active->PostMessage(WM_MY_MESSAGE,0,0);
return0;
}
在其它类中向不同的类发送消息可依次方法类推,这样我们的程序就可以的不受限制
向其它类和进程发送消息,而避免了种种意想不到的风险。
下面一个例子程序为多文档程序里在一对话框中向视类发送消息,详述了发送自定义消
息的具体过程。
实现步骤:
第一步:
在VC++中新建工程Message,所有ClassWizard步骤选项均为缺省,完成。
第二步:
在主菜单中添加测试菜单为调出对话框,在框架类中建立相应函数OnTest()
第三步:
在资源中建立对话框,通过ClassWizard添加新类TestDialog,添加测试按钮,
在对话框类中建立相应函数OnDialogTest()
//通过对话框按钮发送消息的函数
voidTestDialog:
:
OnDialogTest()
{
CMDIFrameWnd*pFrame;
CMDIChildWnd*pChild;
CView*pView;
//获取主窗口指针
pFrame=(CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
//获取子窗口指针
pChild=(CMDIChildWnd*)pFrame->GetActiveFrame();
//获取视类指针
pView=pChild->GetActiveView();
if(active!
=NULL)
active->PostMessage(WM_MY_MESSAGE,0,0);//发送消息
}
在Message.h头文件中添加如下语句:
staticUINTWM_MY_MESSAGE=RegisterWindowMessage("Message");
第四步:
在视类中添加自定义消息:
在头文件MessageView.h中添加消息映射
protected:
//{{AFX_MSG(CMessageView)
//}}AFX_MSG
afx_msgLRESULTOnMyMessage(WPARAMwParam,LPARAMlParam);//此行为添加代码
DECLARE_MESSAGE_MAP()
在视类文件MessageView.cpp中的消息映射中添加自定义消息映射
BEGIN_MESSAGE_MAP(CMessageView,CView)
//{{AFX_MSG_MAP(CMessageView)
//}}AFX_MSG_MAP
//Standardprintingcommands
ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage)//此行添加代码定义唯一消息
END_MESSAGE_MAP()
添加相应的0消息处理函数
LRESULTCMessageView:
:
OnMyMessage(WPARAMwParam,LPARAMlParam)
{
CRectrect;
GetClientRect(&rect);
InvalidateRect(&rect);
test=!
test;
return0;
}
在MessageView.h中添加布尔变量public:
BOOLtest;
在视类构造函数中初始化test变量:
test=FALSE;
修改CMessageView:
:
OnDraw()函数
voidCMessageView:
:
OnDraw(CDC*pDC)
{
CMessageDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
//以下程序显示消息响应效果
if(test)
pDC->TextOut(0,0,"消息响应!
");
}
第五步:
显示测试对话框
在MainFrame类中包含对话框头文件:
#include"TestDialog.h";
OnTest()函数中添加代码
voidCMainFrame:
:
OnTest()
{
TestDialogdialog;
dialog.DoModal();
}
运行程序,在测试菜单打开对话框,点击测试按钮即可看到结果。
关于VC++中两种自定义消息的发送与接收的方法实现进行说明
说明:
以下用一个自创的对话框类(MyMessageDlg)向视图类(MessageTestView)
发送自定义消息为例,说明这两种不同方法的自定义消息的
总结:
消息传递的方法一:
使用ON_MESSAGE
使用ON_MESSAGE响应消息,必须配合定义消息#defineWM_MY_MESSAGE(WM_USER+100)
对于发送消息者-MyMessageDlg,
在其MyMessageDlg.h中,定义#defineWM_MY_MESSAGE(WM_USER+100)
在其MyMessageDlg.cpp中要先添加:
#include"MainFrm.h"
因为使用了CMainFrame*定义对象。
并且要有测试消息的函数:
voidMyMessageDlg:
:
OnButtonMsg()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
CMainFrame*pMF=(CMainFrame*)AfxGetApp()->m_pMainWnd; //先通过获取当前框架指针
CView*active=pMF->GetActiveView();//才能获取当前视类指针
if(active!
=NULL) //获取了当前视类指针才能发送消息
active->PostMessage(WM_MY_MESSAGE,0,0); //使用PostMessage发送消息
}
对于消息的接受者-MessageTestView,
在其MessageTestView.h中,也要定义#defineWM_MY_MESSAGE(WM_USER+100)
并定义消息映射函数-OnMyMessage()
protected:
//{{AFX_MSG(CMessageTestView)
afx_msgLRESULTOnMyMessage(WPARAMwParam,LPARAMlParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
在其MessageTestView.cpp中,
先要声明响应消息:
BEGIN_MESSAGE_MAP(CMessageTestView,CEditView)
//{{AFX_MSG_MAP(CMessageTestView)
ON_MESSAGE(WM_MY_MESSAGE,OnMyMessage)
//}}AFX_MSG_MAP
再添加消息响应的函数实现:
LRESULTCMessageTestView:
:
OnMyMessage(WPARAMwParam,LPARAMlParam)
{
MessageBox("OnMyMessage!
");
return0;
}
消息传递的方法二:
使用ON_REGISTERED_MESSAGE
使用ON_REGISTERED_MESSAGE注册消息,必须配合
staticUINTWM_MY_MESSAGE=RegisterWindowMessage("Message");
对于消息的发送者-MyMessageDlg,
在其MyMessageDlg.h中,只要
定义staticUINTWM_MY_MESSAGE=RegisterWindowMessage("Message");
就可以了。
在其MyMessageDlg.cpp中要先添加:
#include"MainFrm.h"
因为使用了CMainFrame*定义对象。
并且要有测试消息的函数:
voidMyMessageDlg:
:
OnButtonMsg()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
CMainFrame*pMF=(CMainFrame*)AfxGetApp()->m_pMainWnd; //先通过获取当前框架指针
CView*active=pMF->GetActiveView();//才能获取当前视类指针
if(active!
=NULL) //获取了当前视类指针才能发送消息
active->PostMessage(WM_MY_MESSAGE,0,0); //使用PostMessage发送消息
}
对于消息的接收者-MessageTestView,
在其MessageTestView.h中不要定义
staticUINTWM_MY_MESSAGE=RegisterWindowMessage("Message");
应该把这个定义放到MessageTestView.cpp中,要不会出现:
redefinition
在其MessageTestView.h中只要定义消息映射函数
protected:
//{{AFX_MSG(CMessageTestView)
afx_msgLRESULTOnMyMessage(WPARAMwParam,LPARAMlParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
在其MessageTestView.cpp中,先定义
staticUINTWM_MY_MESSAGE=RegisterWindowMessage("Message");
接着注册消息:
BEGIN_MESSAGE_MAP(CMessageTestView,CEditView)
//{{AFX_MSG_MAP(CMessageTestView)
ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage)
//}}AFX_MSG_MAP
最后添加消息响应的函数实现:
LRESULTCMessageTestView:
:
OnMyMessage(WPARAMwParam,LPARAMlParam)
{
MessageBox("OnMyMessage!
");
return0;
}
----------------------------------------------------------------
比较两种方法,只是略有不同。
但也要小心谨慎,以免出现接收不到消息的情况。
-------------------------------------------------------------------
其他注意事项:
发送消息的-MyMessageDlg.cpp前也要定义
staticUINTWM_MY_MESSAGE=RegisterWindowMessage("Message");
接受消息的-MessageTestView.cpp前也要定义
staticUINTWM_MY_MESSAGE=RegisterWindowMessage("Message");
RegisterWindowMessage("Message")中""的内容是什么不重要,写什么都可以,单必须
发送者与接受者是一样的内容,例如:
"Message"
MFC消息类型
1、命令消息(WM_COMMAND)所有派生自 CCmdTarget 的类都有资格接受WM_COMMAND。
2、Window消息(WM_xxx)所有派生自 CWnd 的类都有资格接受 WM_xxx。
3、控件消息(WM_NOTIFY)控件向其父窗口通知消息。
消息处理
1、WM_xxx 消息处理
窗口类(自身)处理→基类处理→CWnd∷DefWindowProc()处理;
其所对应的宏一般为在消息 WM_ 前面加上 ON_。
2、命令消息处理
命令消息来自命令用户接口对象(菜单、加速键或工具栏按钮)发出的WM_COMMAND消息;
㈠、WM_COMMAND消息
其所包含的类型和对应的宏如下:
①、ON_COMMAND(ID,pfn)标准的命令消息;
②、ON_COMMAND_EX(ID,pfn)多个对象对同一个命令 ID 的处理;
其函数的原型如下:
afx_msg BOOL pfn(UINT nID)
说明:
当返回 TRUE 时表示已经处理,不用在消息处理链中继续处理该命令;为 FALSE 时表示继续在消息处理链中处理该命令。
注意:
其一:
在多对象处理中一定要使用该宏;
其二:
pfn(UINT nID)(消息处理函数)返回值将其类型void改成BOOL,而且必须为FALSE;
其三:
多个对象的处理是由高层向低层的过程:
即视图类→主框架窗口类→应用程序类;
③、ON_COMMAND_RANGE(nID,nLastID,pfn)多个命令 ID 提供相同的处理;
注意:
其一:
确保nID、nLastID的值在 Resource.h 中是连续的。
其二:
一般在函数 pfn(UINT nID) 中加入参数,用来确定那一个按钮点击。
㈡、CN_UPDATE_COMMAND_UI消息
当菜单项、工具栏按钮等[命令用户接口对象]要更新其状态时所对应的消息,它所包含的类型和对应的宏如下:
①、ON_UPDATE_COMMAND_UI(ID,pfn)
其中函数的原型如下:
afx_msg void pfn(CCmdUI* pCmdUI)
②、ON_UPDATE_COMMAND_UI_RANGE(nID,nLastID,pfn)该函数可以处理一组[命令用户接口对象]的外观;
其中函数的原型如下:
afx_msg void pfn(CCmdUI* pCmdUI)
重要:
CCmdUI 中的 m_nID 成员表示不同的 ID,因此可以利用它来进行区别处理。
3、控件的通知消息
从控件和子窗口发送到父窗口的WM_COMMAND通知消息(即在发送命令消息中加入控件的通知码)。
注意:
在 Window9x 新控件中不再传送WM_COMMAND通知消息,而是发送 WM_NOTIFY 消息,但为了兼容,旧有的控件还是传送WM_COMMAND消息。
例如:
CEdit控件向父窗口发送 EN_CHANGE 通知代码的WM_COMMAND消息。