第一步:定义消息。
推荐用户自定义消息至少是WM_USER+100,因为很多新控件也要使用WM_USER消息。
#define WM_MY_MESSAGE (WM_USER+100)
第二步:实现消息处理函数。该函数使用WPRAM和LPARAM参数并返回LPESULT。
LPESULT CMainFrame::OnMyMessage(WPARAMwParam, LPARAM lParam)
{
// TODO: 处理用户自定义消息
...
return 0;
}
第三步:在类头文件的AFX_MSG块中说明消息处理函数:
class CMainFrame:public CMDIFrameWnd
{
...
// 一般消息映射函数
protected:
// {{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCTlpCreateStruct);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg LRESULT OnMyMessage(WPARAM wParam,LPARAM lParam);
//}}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定义
消息:
static UINTWM_MY_MESSAGE=RegisterWindowMessage("User");
并使用ON_REGISTERED_MESSAGE宏指令取代ON_MESSAGE宏指令,其余步骤同上。
当需要使用自定义消息时,可以在相应类中的函数中调用函数PostMessage或SendMessa
ge发送消息PoseMessage(WM_MY_MESSAGE,O,O); 如果向其他进程发送消息可通过如下方法
发送消息:
DWORD result;
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)//定义消息映射
视类定义消息处理函数:
// 消息处理函数
LRESULT CMessageView::OnMyMessage(WPARAMwParam, LPARAM lParam)
{
// TODO: 处理用户自定义消息
...
return 0;
}
//发送消息的测试函数
void CMainFrame::OnTest()
{
CView * active = GetActiveView();//获取当前视类指针
if(active != NULL)
active->PostMessage(WM_MY_MESSAGE,0,0);
}
在其它类中向视类发送消息:
//发送消息的测试函数
void CMainFrame::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);//发送消息
}
其余步骤同上。
在视类中向主框架发送消息:
首先在主框架中定义相关的消息,方法同上,然后在发送消息的函数中添加代码如下
//发送消息的测试函数
void CMessageView::OnTest()
{
CFrameWnd * active = GetActiveFrame();//获取当前主窗口框架指针
if(active != this)
active->PostMessage(WM_MY_MESSAGE,0,0);
return 0;
}
在其它类中向不同的类发送消息可依次方法类推,这样我们的程序就可以的不受限制
向其它类和进程发送消息,而避免了种种意想不到的风险。
下面一个例子程序为多文档程序里在一对话框中向视类发送消息,详述了发送自定义消
息的具体过程。
实现步骤:
第一步:在VC++中新建工程Message,所有ClassWizard步骤选项均为缺省,完成。
第二步:在主菜单中添加测试菜单为调出对话框,在框架类中建立相应函数OnTest()
第三步:在资源中建立对话框,通过ClassWizard添加新类TestDialog,添加测试按钮,
在对话框类中建立相应函数OnDialogTest()
//通过对话框按钮发送消息的函数
void TestDialog::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头文件中添加如下语句:
static UINTWM_MY_MESSAGE=RegisterWindowMessage("Message");
第四步:在视类中添加自定义消息:
在头文件MessageView.h中添加消息映射
protected:
//{{AFX_MSG(CMessageView)
//}}AFX_MSG
afx_msg LRESULT OnMyMessage(WPARAM wParam,LPARAM lParam); //此行为添加代码
DECLARE_MESSAGE_MAP()
在视类文件MessageView.cpp中的消息映射中添加自定义消息映射
BEGIN_MESSAGE_MAP(CMessageView, CView)
//{{AFX_MSG_MAP(CMessageView)
//}}AFX_MSG_MAP
// Standard printing commands
ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage)//此行添加代码定义唯一消息
END_MESSAGE_MAP()
添加相应的0消息处理函数
LRESULT CMessageView::OnMyMessage(WPARAMwParam, LPARAM lParam)
{
CRect rect;
GetClientRect(&rect);
InvalidateRect(&rect);
test=!test;
return 0;
}
在MessageView.h中添加布尔变量 public:BOOL test;
在视类构造函数中初始化test变量:test=FALSE;
修改CMessageView::OnDraw()函数
void CMessageView::OnDraw(CDC* pDC)
{
CMessageDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// 以下程序显示消息响应效果
if(test)
pDC->TextOut(0,0,"消息响应!");
}
第五步:显示测试对话框
在MainFrame类中包含对话框头文件:
#include "TestDialog.h";
OnTest()函数中添加代码
void CMainFrame::OnTest()
{
TestDialog dialog;
dialog.DoModal();
}
运行程序,在测试菜单打开对话框,点击测试按钮即可看到结果。
SendMessage 参数详解
Windows是一个消息驱动式系统,SendMessage是应用程序和应用程序之间进行消息传递的主要手段之一,这里我搜集整理了SendMessage函数的详细参数介绍,以备自用。
VFP声明:
DECLARE INTEGER SendMessage IN user32;
INTEGER hWnd,;
INTEGER wMsg,;
INTEGER wParam,;
INTEGER lParam
参数1:hWnd-窗口句柄。窗口可以是任何类型的屏幕对象。
参数2:wMsg-用于区别其他消息的常量值.
参数3:wParam-通常是一个与消息有关的常量值,也可能是窗口或控件的句柄.
参数4: lParam-通常是一个指向内存中数据的指针。
wMsg参数常量值:
#DeFine WM_CREATE0x01
创建一个窗口
#DeFine WM_DESTROY0x02
当一个窗口被破坏时发送
#DeFine WM_MOVE0x03
移动一个窗口
#DeFineWM_SIZE 0x05
改变一个窗口的大小
#DeFineWM_ACTIVATE 0x06
一个窗口被激活或失去激活状态
#DeFineWM_SETFOCUS 0x07
一个窗口获得焦点
#DeFineWM_KILLFOCUS 0x08
一个窗口失去焦点
#DeFineWM_ENABLE 0x0A
一个窗口改变成Enable状态
#DeFineWM_SETREDRAW 0x0B
设置窗口是否能重画
#DeFineWM_SETTEXT 0x0C
应用程序发送此消息来设置一个窗口的文本
#DeFineWM_GETTEXT 0x0D
应用程序发送此消息来复制对应窗口的文本到缓冲区
#DeFineWM_GETTEXTLENGTH 0x0E
得到与一个窗口有关的文本的长度(不包含空字符)
#DeFineWM_PAINT 0x0F
要求一个窗口重画自己
#DeFineWM_CLOSE 0x10
当一个窗口或应用程序要关闭时发送一个信号
#DeFineWM_QUERYENDSESSION 0x11
当用户选择结束对话框或程序自己调用ExitWindows函数
#DeFineWM_QUIT 0x12
用来结束程序运行
#DeFineWM_QUERYOPEN 0x13
当用户窗口恢复以前的大小位置时,把此消息发送给某个图标
#DeFineWM_ERASEBKGND 0x14
当窗口背景必须被擦除时(例在窗口改变大小时)
#DeFineWM_SYSCOLORCHANGE 0x15
当系统颜色改变时,发送此消息给所有顶级窗口
#DeFineWM_ENDSESSION 0x16
当系统进程发出WM_QUERYENDSESSION消息后,此消息发送给应用程序,通知它对话是否结束
#DeFineWM_SHOWWINDOW 0x18
当隐藏或显示窗口是发送此消息给这个窗口
#DeFineWM_ACTIVATEAPP 0x1C
发此消息给应用程序哪个窗口是激活的,哪个是非激活的
#DeFineWM_FONTCHANGE 0x1D
当系统的字体资源库变化时发送此消息给所有顶级窗口
#DeFineWM_TIMECHANGE 0x1E
当系统的时间变化时发送此消息给所有顶级窗口
#DeFineWM_CANCELMODE 0x1F
发送此消息来取消某种正在进行的摸态(操作)
#DeFineWM_SETCURSOR 0x20
如果鼠标引起光标在某个窗口中移动且鼠标输入没有被捕获时,就发消息给某个窗口
#DeFineWM_MOUSEACTIVATE 0x21
当光标在某个非激活的窗口中而用户正按着鼠标的某个键发送此消息给当前窗口
#DeFineWM_CHILDACTIVATE 0x22
发送此消息给MDI子窗口当用户点击此窗口的标题栏,或当窗口被激活,移动,改变大小
#DeFineWM_QUEUESYNC 0x23
此消息由基于计算机的训练程序发送,通过WH_JOURNALPALYBACK的hook程序分离出用户输入消息
#DeFineWM_GETMINMAXINFO 0x24
此消息发送给窗口当它将要改变大小或位置
#DeFineWM_PAINTICON 0x26
发送给最小化窗口当它图标将要被重画
#DeFineWM_ICONERASEBKGND 0x27
此消息发送给某个最小化窗口,仅当它在画图标前它的背景必须被重画
#DeFineWM_NEXTDLGCTL 0x28
发送此消息给一个对话框程序去更改焦点位置
#DeFineWM_SPOOLERSTATUS 0x2A
每当打印管理列队增加或减少一条作业时发出此消息
#DeFineWM_DRAWITEM 0x2B
当button,combobox,listbox,menu的可视外观改变时发送
#DeFine WM_MEASUREITEM 0x2C
当button, combo box, listbox, list view control, or menu item被创建时
#DeFineWM_VKEYTOITEM 0x2E
此消息有一个LBS_WANTKEYBOARDINPUT风格的发出给它的所有者来响应WM_KEYDOWN消息
#DeFineWM_CHARTOITEM 0x2F
此消息由一个LBS_WANTKEYBOARDINPUT风格的列表框发送给他的所有者来响应WM_CHAR消息
#DeFineWM_SETFONT 0x30
当绘制文本时程序发送此消息得到控件要用的颜色
#DeFineWM_GETFONT 0x31
应用程序发送此消息得到当前控件绘制文本的字体
#DeFineWM_SETHOTKEY 0x32
应用程序发送此消息让一个窗口与一个热键相关连
#DeFineWM_GETHOTKEY 0x33
应用程序发送此消息来判断热键与某个窗口是否有关联
#DeFineWM_QUERYDRAGICON 0x37
此消息发送给最小化窗口,当此窗口将要被拖放而它的类中没有定义图标,应用程序能返回一个图标或光标的句柄,当用户拖放图标时系统显示这个图标或光标
#DeFineWM_COMPAREITEM 0x39
发送此消息来判定combobox或listbox新增加的项的相对位置
#DeFineWM_COMPACTING 0x41
显示内存已经很少了
#DeFineWM_WINDOWPOSCHANGING 0x46
发送此消息给那个窗口的大小和位置将要被改变时,来调用setwindowpos函数或其它窗口管理函数
#DeFineWM_WINDOWPOSCHANGED 0x47
发送此消息给那个窗口的大小和位置已经被改变时,来调用setwindowpos函数或其它窗口管理函数
#DeFineWM_POWER 0x48
当系统将要进入暂停状态时发送此消息
#DeFineWM_COPYDATA 0x4A
当一个应用程序传递数据给另一个应用程序时发送此消息
#DeFineWM_CANCELJOURNA 0x4B
当某个用户取消程序日志激活状态,提交此消息给程序
#DeFineWM_NOTIFY 0x4E
当某个控件的某个事件已经发生或这个控件需要得到一些信息时,发送此消息给它的父窗口
#DeFineWM_INPUTLANGCHANGEREQUEST 0x50
当用户选择某种输入语言,或输入语言的热键改变
#DeFineWM_INPUTLANGCHANGE 0x51
当平台现场已经被改变后发送此消息给受影响的最顶级窗口
#DeFineWM_TCARD 0x52
当程序已经初始化windows帮助例程时发送此消息给应用程序
#DeFineWM_HELP 0x53
此消息显示用户按下了F1,如果某个菜单是激活的,就发送此消息个此窗口关联的菜单,否则就发送给有焦点的窗口,如果当前都没有焦点,就把此消息发送给当前激活的窗口
#DeFineWM_USERCHANGED 0x54
当用户已经登入或退出后发送此消息给所有的窗口,当用户登入或退出时系统更新用户的具体设置信息,在用户更新设置时系统马上发送此消息
#DeFineWM_NOTIFYFORMAT 0x55
公用控件,自定义控件和他们的父窗口通过此消息来判断控件是使用ANSI还是UNICODE结构
#DeFineWM_CONTEXTMENU ??
当用户某个窗口中点击了一下右键就发送此消息给这个窗口
#DeFine WM_STYLECHANGING 0x7C
当调用SETWINDOWLONG函数将要改变一个或多个窗口的风格时发送此消息给那个窗口
#DeFineWM_STYLECHANGED 0x7D
当调用SETWINDOWLONG函数一个或多个窗口的风格后发送此消息给那个窗口
#DeFineWM_DISPLAYCHANGE 0x7E
当显示器的分辨率改变后发送此消息给所有的窗口
#DeFineWM_GETICON 0x7F
此消息发送给某个窗口来返回与某个窗口有关连的大图标或小图标的句柄
#DeFineWM_SETICON 0x80
程序发送此消息让一个新的大图标或小图标与某个窗口关联
#DeFineWM_NCCREATE 0x81
当某个窗口第一次被创建时,此消息在WM_CREATE消息发送前发送
#DeFineWM_NCDESTROY 0x82
此消息通知某个窗口,非客户区正在销毁
#DeFineWM_NCCALCSIZE 0x83
当某个窗口的客户区域必须被核算时发送此消息
#DeFineWM_NCHITTEST 0x84
移动鼠标,按住或释放鼠标时发生
#DeFineWM_NCPAINT 0x85
程序发送此消息给某个窗口当它(窗口)的框架必须被绘制时
#DeFineWM_NCACTIVATE 0x86
此消息发送给某个窗口仅当它的非客户区需要被改变来显示是激活还是非激活状态
#DeFineWM_GETDLGCODE 0x87
发送此消息给某个与对话框程序关联的控件,widdows控制方位键和TAB键使输入进入此控件通过应
#DeFineWM_NCMOUSEMOVE 0xA0
当光标在一个窗口的非客户区内移动时发送此消息给这个窗口 非客户区为:窗体的标题栏及窗 的边框体
#DeFine WM_NCLBUTTONDOWN 0xA1
当光标在一个窗口的非客户区同时按下鼠标左键时提交此消息
#DeFineWM_NCLBUTTONUP 0xA2
当用户释放鼠标左键同时光标某个窗口在非客户区十发送此消息
#DeFineWM_NCLBUTTONDBLCLK 0xA3
当用户双击鼠标左键同时光标某个窗口在非客户区十发送此消息
#DeFineWM_NCRBUTTONDOWN 0xA4
当用户按下鼠标右键同时光标又在窗口的非客户区时发送此消息
#DeFineWM_NCRBUTTONUP 0xA5
当用户释放鼠标右键同时光标又在窗口的非客户区时发送此消息
#DeFineWM_NCRBUTTONDBLCLK 0xA6
当用户双击鼠标右键同时光标某个窗口在非客户区十发送此消息
#DeFineWM_NCMBUTTONDOWN 0xA7
当用户按下鼠标中键同时光标又在窗口的非客户区时发送此消息
#DeFineWM_NCMBUTTONUP 0xA8
当用户释放鼠标中键同时光标又在窗口的非客户区时发送此消息
#DeFineWM_NCMBUTTONDBLCLK 0xA9
当用户双击鼠标中键同时光标又在窗口的非客户区时发送此消息
SendMessage与PostMessage的区别
PostMessage将消息放入消息队列后马上返回,而SendMessage直到窗口过程处理完消息后才返回,SDK文档推荐用户使用SendMessage()函数,接收方在数据复制完成前不返回,这样发送方就不可能删除和修改数据。
SendMessage函數是阻塞的。PostMessage函數是非阻塞的。
SendMessage:
函数功能:该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。而函数PostMessage不同,将一个消息寄送到一个线程的消息队列后立即返回。
函数原型:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);
参数:
hWnd:其窗口程序将接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。
Msg:指定被发送的消息。
wParam:指定附加的消息指定信息。
IParam:指定附加的消息指定信息。
返回值:返回值指定消息处理的结果,依赖于所发送的消息。
备注:需要用HWND_BROADCAST通信的应用程序应当使用函数RegisterWindowMessage来为应用程序间的通信取得一个唯一的消息。
如果指定的窗口是由调用线程创建的,则窗口程序立即作为子程序调用。如果指定的窗口是由不同线程创建的,则系统切换到该线程并调用恰当的窗口程序。线程间的消息只有在线程执行消息检索代码时才被处理。发送线程被阻塞直到接收线程处理完消息为止。
Windows CE:Windows CE不支持Windows桌面平台支持的所有消息。使用SendMesssge之前,要检查发送的消息是否被支持。
速查:Windows NT:3.1及以上版本:Windows:95及以上版本;Windows CE:1.0及以上版本;头文件:winuser.h;输入库:user32.lib;Unicode:在Windows NT环境下以Unicode和ANSI方式实现。
PostMessage:
函数功能:该函数将一个消息放入(寄送)到与指定窗口创建的线程相联系消息队列里,不等待线程处理消息就返回。消息队列里的消息通过调用GetMessage和PeekMessage取得。
函数原型:B00L PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
参数
hWnd:其窗口程序接收消息的窗口的句柄。可取有特定含义的两个值:
HWND.BROADCAST:消息被寄送到系统的所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口。消息不被寄送到子窗口。
NULL:此函数的操作和调用参数dwThread设置为当前线程的标识符PostThreadMessage函数一样。
Msg:指定被寄送的消息。
wParam:指定附加的消息特定的信息。
IParam:指定附加的消息特定的信息。
返回值:如果函数调用成功,返回非零值:如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。
备注:需要以 HWND_BROADCAST方式通信的应用程序应当用函数 RegisterwindwosMessage来获得应用程序间通信的独特的消息。
如果发送一个低于WM_USER范围的消息给异步消息函数(PostMessage.SendNotifyMessage,SendMesssgeCallback),消息参数不能包含指针。否则,操作将会失败。函数将再接收线程处理消息之前返回,发送者将在内存被使用之前释放