MFC添加自定义消息及重写消息过程

2023-10-26

由于MFC中无法通过类向导来自定义消息,所以需要手动添加,主要过程如下:

本文基于vs2008下通过线程实现数据实时更新的对话框运用程序

1. 定义消息(Resource.h文件中):

由于很多新控件也会用到WM_USER消息,所以定义WM_USER+100或更高,避免冲突

#define   WM_UPDATEDATA    (WM_USER + 100)

 

2015-3-18 更新

1. 定义消息( stdafx.h文件中):

由于很多新控件也会用到WM_USER消息,所以定义WM_USER+100或更高,避免冲突,消息定义到stdafx.h文件中,Resource.h文件由系统维护,经常出现自定义的消息丢失。

#define   WM_UPDATEDATA    (WM_USER + 100)

2. 声明消息响应函数:

放在消息映射部分,即DECLARE_MESSAGE_MAP()之前

复制代码

// 实现
protected:
    HICON m_hIcon;

    // 生成的消息映射函数
    virtual BOOL OnInitDialog();
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    afx_msg LRESULT OnUpdateData(WPARAM wParam, LPARAM lParam);
    DECLARE_MESSAGE_MAP()

复制代码

3. 实现消息响应函数:

由于在vs2008中未定义ON_MESSAGE_VOID,所以定义的消息响应函数必须有返回值,即LRESULT;而消息参数是WPARAM wParam和LPARAM lParam

LRESULT CEditTestDlg::OnUpdateData(WPARAM wParam, LPARAM lParam)
{
    UpdateData(wParam);
    return 0;
}

4. 将消息映射到消息处理函数:

放在AFX_MSG_MAP之前,把WM_UPDATEDATA消息映射到消息响应函数OnUpdateData

复制代码

BEGIN_MESSAGE_MAP(CEditTestDlg, CDialog)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_MESSAGE(WM_UPDATEDATA, OnUpdateData)
    //}}AFX_MSG_MAP
    ON_BN_CLICKED(IDC_BUTTON1, &CEditTestDlg::OnBnClickedButton1)
END_MESSAGE_MAP()

复制代码

5. 发送自定义消息:

以下函数是在一个新的线程中调用的,PostMessage,SendMessage,SendMessageTimeout均可用,推荐使用SendMessageTimeout函数

复制代码

static UINT SendMsgThread(LPVOID lpParam)
{
    CEditTestDlg *dlg = (CEditTestDlg*) lpParam;
    int i = 0;
    while (i < 100)
    {
        Sleep(20);
        i += 1;
        dlg->m_value2.Format(_T("%d"), i);
        //PostMessage(dlg->m_hWnd,WM_UPDATEDATA,FALSE,NULL);
        //SendMessage(dlg->m_hWnd,WM_UPDATEDATA,FALSE,NULL);
        SendMessageTimeout(dlg->m_hWnd, WM_UPDATEDATA, FALSE,NULL, SMTO_BLOCK, 1000, NULL);
    }
    return 0;
}

复制代码

 

 

如果用户需要一个定义整个系统唯一的消息,可以调用SDK函数RegisterWindowMessage定义消息:
在Resource.h中将代码

#define   WM_UPDATEDATA    (WM_USER + 100)

修改为

static UINT WM_UPDATEDATA=RegisterWindowMessage(_T("User"));

并使用ON_REGISTERED_MESSAGE宏指令取代ON_MESSAGE宏指令,其余步骤同上。
注:如果仍然使用ON_MESSAGE宏指令,compile可以通过,但是无法响应消息。

//*************重写消息

c++消息机制是遇到两个参数不是很明白 查了下资料 记录下(以下都是我个人理解,错误请帮忙指正):

 

LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam, LPARAM lParam);

这是一个向指定的窗口发送指定消息的函数

HWND hWnd 这个参数是窗口的句柄,相当于id的玩意 不难理解

UINT Msg 这个是要发送的消息 如:WM_CLOSE,WM_SETTEXT。。。。。。。好多

WPARAM wParam和LPARAM lParam这两个参数不是很陌生 下面也是我看其他的资料得到的理解

 

Windows的消息必须参考帮助文件才能知道具体的含义。如果是你定义的消息,愿意怎么使这两个参数都行。但是习惯上,我们愿意使用LPARAM传 递地址,而WPARAM传递其他参数。”

接下来谈谈什么是消息机制:系统将会维护一个或多个消息队列,所有产生的消息都回被放入或是插入队列中。系统会在队列中取出每一条消息,根据消息的接收句柄而将该消息发送给拥有该窗口的程序的消息循环。每一个运行的程序都有自己的消息循环,在循环中得到属于自己的消息并根据接收窗口的句柄调用相应的窗口过程。而在没有消息时消息循环就将控制权交给系统所以Windows可以同时进行多个任务。下面的伪代码演示了消息循环的用法:

 

 

例如:主程序MyDlg.cpp

1.自定义消息:#define WM_TRAY WM_USER 100

2.函数原形:afx_msg LRESULT OnTrayNotify(WPARAM wParam,LPARAM lParam);

3.消息映射:ON_MESSAGE(WM_TRAY,OnTrayNotify)

4.原函数:

LRESULT CMyDlg::OnTrayNotify(WPARAM wParam,LPARAM lParam)

{

return m_tray.OnTrayNotify(wParam,lParam);

}

 

上面程序呢 主要过程是这样 自定义了一个消息WM_TRAY 

再创建一个函数OnTrayNotify 

然后将消息和函数绑定在一起ON_MESSAGE(WM_TRAY,OnTrayNotify)

每当接受这个消息时就运行函数

而WPARAM wParam,LPARAM lParam这两个参数就是消息附带的参数跟着消息一起传递过来

 

在Win32 SDK中消息本身是作为一个结构体记录传递给应用程序的,这个记录中包含了消息的类型以及其他信息。这个记录类型叫做MSG,它在window中是这样声明的:
typedef struct tagMSG { // msg
HWND hwnd; //窗口句柄
UINT message; //消息常量标识符
WPARAM wParam; //32位消息的特定附加信息,具体表示什么处决于message
LPARAM lParam; //32位消息的特定附加信息,具体表示什么处决于message
DWORD time; //消息创建时的时间
POINT pt; //消息创建时的鼠标位置
} MSG;

hwnd 接收消息的32位窗口句柄。窗口可以是任何类型的屏幕对象,因为Win32能够维护大多数可视对象的句柄(窗口、对话框、按钮、编辑框等)。


message 用于区别其他消息的常量值,这些常量可以是Windows单元中预定义的常量,也可以是自定义的常量。


wParam 通常是一个与消息有关的常量值,也可能是窗口或控件的句柄。 lParam 通常是一个指向内存中数据的指针。由于wParam,lParam和指针都是32位的,需要时可以强制类型转换。具体表示什么,与message相关,他们是事先定义好的。


如果自定义消息:#define WM_MYMESSAGE WM_USER+100,需确定wParam,lParam的意义 (假设wParam=0时发送数据,wParam=1时接收数据,lParam为CMyClass* 指针,指向一个CMyClass对象,准备要发送的数据或接收数据 发送WM_MYMESSAGE时 SendMessage(hwnd,WM_MYMESSAGE,0,pMyClassObject) 接收消息的窗口,接收WM_MYMESSAGE中(CMyClass*)lParam参数即pMyClassObject传过来的数据

 

//**********

1. 怎样使用MFC发送一个消息用MFC发送一个消息的方法是,

首先,应获取接收消息的CWnd类对象的指针;

然后,调用CWnd的成员函数SendMessage( )。

LRESULT Res=pWnd->SendMessage(UINT Msg, WPARAM wParam, LPARAM lParam);

pWnd指针指向目标CWnd类对象。变量Msg是消息,wParam和lParam变量包含消息的参数,如鼠标单击哪里或选择了什么菜单项。目标窗口返回的消息结果放在变量Res中。

发送消息到一个没有CWnd类对象的窗口,可以用下列目标窗口的句柄直接调用Windows API:

LRESULT Res=::SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

这里的hWnd是目标窗口的句柄。

2. 怎样用MFC寄送一个消息

用MFC寄送一个消息与发送一个消息几乎相同,但寄送时用PostMessage( ) ,而不是用SendMessage( );返回值Res也不一样,Res不是一个由目标窗口返回的值,而是一个布尔值,用来表示消息是否成功地放到消息队列中。

3. 检索一个寄送消息

正常情况下,一旦消息被寄送后,应用程序在后台发送它。但是在特殊情况下,需要你自己去删除一个消息,例如想在应用程序接收到某种消息之前停止应用程序。有两种方法可以从应用程序消息队列中删除一个消息,但这两种方法都没有涉及MFC。

■ 第一种方法:在不干扰任何事情之下窥视消息队列,看看一个消息是否在那里。

BOOL res=::PeekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg ) ;

■ 第二种方法:实际上是等待,一直等到一个新的消息到达队列为止,然后删除并返回该消息。

BOOL res=::GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);

在这两种方法中,变量hWnd指定要截获消息的窗口,如果该变量设为NULL,所有窗口消息将被截获。wMsgFilterMin和wMsgFilterMax变量与SendMessage( )中的变量Msg相对应,指定查看消息的范围。如果用"0,0",则所有的消息都将被截获。如果用WM_KEYFIRST,WM_KEYLAST或WM_MOUSEFIRST,WM_MOUSELAST,则所有键盘或鼠标的消息将被截获。wRemoveMsg变量指定PeekMessage( )是否应该真正地从队列中删除该消息。(GetMessage( )总是删除消息)。该变量可以取两个值:

■ PM_REMOVE,PeekMessage( )将删除消息。

■ PM_NOREMOVE,PeekMessage( )将把消息留在队列里,并返回它的一个拷贝。

当然,如果把消息留在消息队列中,然后再次调用PeekMessage( )查看相同类型的消息,则将返回完全相同的消息。

lpMsg变量是一个指向MSG结构的指针,MSG包含检索到的消息。

typedef struct tagMSG {

HWND hwnd; // window handle message is intended for

UINT message;

WPARAM wParam;

LPARAM lParam;

DWORD time; // the time the message was put in the queue

POINT pt; // the location of the mouse cursor when the

// message was put in the queue

} MSG;

4. MFC怎样接收一个寄送的消息

MFC处理一个寄送和发送消息的唯一明显不同是寄送的消息要在应用程序的消息队列中花费一些时间。在消息泵(message pump)弹出它之前,它要一直在队列中。

消息泵

MFC应用程序中的消息泵在CWinApp的成员函数Run()中。应用程序开始运行时,Run()就被调用,Run()把时间分割成两部分。一部分用来执行后台处理,如取消临时CWnd对象;另一部分用来检查消息队列。当一个新的消息进来时,Run()抽取它—即用GetMessage( )从队列中取出该消息,运行两个消息翻译函数,然后用DispatchMessage( )函数调用该消息预期的目标窗口进程。

消息泵调用的两个翻译函数是PreTranslateMessage( )和::TranslateMessage( )。目标窗口的MFC类可调用reTranslateMessage在发送消息给它之前进行消息翻译,例如,CFrameWnd用PreTranslateMessage( )将加速键(如,Ctrl+S存储文件)转换为命令消息。翻译前的消息通常被处理掉,而翻译后的消息(如果有的话)将被重新寄送到队列里。::TranslateMessage是一个窗口函数,将原始键码转换为键字符。消息一旦被DispatchMessage()发送,MFC处理它就像处理SendMessage()发送的消息一样。

5. MFC怎样处理一个接收到的消息

处理接收到的消息的目的非常简单:将消息指向一个函数,该函数通过消息中的消息标识符处理它。非MFC窗口用简单的case语句来实现该目标,每个case语句执行一些函数,或调用其他一些函数。

MainWndProc(HWND hWnd, UINT message, W PARAM wParam,LPARAM lParam)

{

switch(message)

{

case WM_CREATE:

: : :

break;

case WM_PAINT:

: : :

break;

default:

return(DefWindowProc(hWnd,message,wParam,lParam));

}

return(NULL);

}

任何遗漏的消息将被传输到一个默认的消息处理函数,但是,case语句不能很好地适应C++和封装技术。在C++环境中,要求消息被一个专门处理该类型消息的类的成员函数处理。因此,MFC不采用case语句,而采用更加复杂和回旋的方法。但它允许用私有类处理消息,而只需做下面三件事情:

■ 从将要接收消息的CWnd类对象派生类(对于命令消息是CCmdTarget)。

■ 在派生类中写一个处理消息的成员函数。

■ 在类中定义一个查找表(叫做消息映像),该表具有成员函数的条目和它要处理的消息的标识符。

然后,MFC依次调用下面的函数,指引输入消息到处理函数。

1) AfxWndProc( )接收消息,寻找消息所属的CWnd对象,然后调用AfxCallWndProc( )。

2) AfxCallWndProc( )存储消息(消息标识符和参数)供未来参考,然后调用WindowProc( )。

3) WindowProc( ) 发送消息给OnWndMsg( ) ,然后,如果消息未被处理,则发送给DefWindowproc( )。

4) OnWndMsg( )要么为WM_COMMAND消息调用OnCommand( ),要么为WM_NOTIFY消息调用OnNotify( )。任何被遗漏的消息都将是一个窗口消息。OnWndMsg( )搜索类的消息映像,以找到一个能处理任何窗口消息的处理函数。如果OnWndMsg( )不能找到这样的处理函数,则把消息返回到WindowProc( ),由它将消息发送给DefWindowProc( )。

5) OnCommand()查看这是不是一个控件通知(lParam不是NULL);如果它是,OnCommand( )就试图将消息映射到制造通知的控件;如果它不是一个控件通知,或者控件拒绝映射的消息,OnCommand( )就调用OnCmdMsg( )。

6) OnNotify( )也试图将消息映射到制造通知的控件;如果映射不成功, OnNotify( )就调用相同的OnCmdMsg( )函数。

7) 根据接收消息的类,OnCmdMsg( )将在一个称为命令传递(Command Routing)的过程中潜在地传递命令消息和控件通知。例如,如果拥有该窗口的类是一个框架类,则命令和通知消息也被传递到视图和文档类,并为该类寻找一个消息处理函数。

为什么要消息映像?

这毕竟是C++语言;为什么OnWndMsg( )不为每个窗口消息调用一个预定义的虚拟函数?因为它太占CPU。若是那样,当扫描一个消息映像以加速该过程时,OnWndMsg( )可能会做出意想不到的事情,并陷入汇编器。注意通过重载WindowProc( )、OnWndMsg( )、OnCommand( )、OnNotify( ) 或OnCmdMsg( )可以修改这一过程。重载OnWndMsg( )可以在窗口消息被排序之前插入该过程。重载OnCommand( )或OnNotify( )可以在消息被反射之前插入该过程。

 

//***********

windows消息机制(MFC)

消息分类与消息队列

Windows中,消息使用统一的结构体(MSG)来存放信息,其中message表明消息的具体的类型,

而wParam,lParam是其最灵活的两个变量,为不同的消息类型时,存放数据的含义也不一样。

time表示产生消息的时间,pt表示产生消息时鼠标的位置。

按照类型,Windows将消息分为:

(0) 消息ID范围

系统定义消息ID范围:[0x0000, 0x03ff]
用户自定义的消息ID范围: 
WM_USER: 0x0400-0x7FFF (例:WM_USER+10) 
WM_APP(winver> 4.0):0x8000-0xBFFF (例:WM_APP+4) 
RegisterWindowMessage:0xC000-0xFFFF【用来和其他应用程序通信,为了ID的唯一性,使用::RegisterWindowMessage来得到该范围的消息ID 】

(1) 窗口消息:即与窗口的内部运作有关的消息,如创建窗口,绘制窗口,销毁窗口等。

     可以是一般的窗口,也可以是MainFrame,Dialog,控件等。 

     如:WM_CREATE, WM_PAINT, WM_MOUSEMOVE, WM_CTLCOLOR, WM_HSCROLL等

(2) 当用户从菜单选中一个命令项目、按下一个快捷键或者点击工具栏上的一个按钮,都将发送WM_COMMAND命令消息。

     LOWORD(wParam)表示菜单项,工具栏按钮或控件的ID;如果是控件, HIWORD(wParam)表示控件消息类型。

     #define LOWORD(l) ((WORD)(l))

     #define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))

(3) 随着控件的种类越来越多,越来越复杂(如列表控件、树控件等),仅仅将wParam,lParam将视为一个32位无符号整数,已经装不下太多信息了。

    为了给父窗口发送更多的信息,微软定义了一个新的WM_NOTIFY消息来扩展WM_COMMAND消息。

    WM_NOTIFY消息仍然使用MSG消息结构,只是此时wParam为控件ID,lParam为一个NMHDR指针,

    不同的控件可以按照规则对NMHDR进行扩充,因此WM_NOTIFY消息传送的信息量可以相当的大。

注:Window 9x 版及以后的新控件通告消息不再通过WM_COMMAND 传送,而是通过WM_NOTIFY 传送,
      但是老控件的通告消息, 比如CBN_SELCHANGE 还是通过WM_COMMAND 消息发送。

(4) windwos也允许程序员定义自己的消息,使用SendMessage或PostMessage来发送消息。

windows消息还可以分为:

(1) 队列消息(Queued Messages) 
消息会先保存在消息队列中,消息循环会从此队列中取出消息并分发到各窗口处理 
如:WM_PAINT,WM_TIMER,WM_CREATE,WM_QUIT,以及鼠标,键盘消息等。
其中,WM_PAINT,WM_TIMER只有在队列中没有其他消息的时候才会被处理,
WM_PAINT消息还会被合并以提高效率。其他所有消息以先进先出(FIFO)的方式被处理。

(2) 非队列消息(NonQueued Messages) 
消息会绕过系统消息队列和线程消息队列,直接发送到窗口过程进行处理 
如:WM_ACTIVATE, WM_SETFOCUS, WM_SETCURSOR,WM_WINDOWPOSCHANGED

Windows系统的整个消息系统分为3个层级:

    ① Windows内核的系统消息队列

    ② App的UI线程消息队列

    ③ 处理消息的窗体对象

Windows内核维护着一个全局的系统消息队列;按照线程的不同,系统消息队列中的消息会分发到应用程序的UI线程的消息队列中;

应用程序的每一个UI线程都有自己的消息循环,会不停地从自己的消息队列取出消息,并发送给Windows窗体对象;

每一个窗体对象都使用窗体过程函数(WindowProc)来处理接收到的各种消息。

复制代码

复制代码

 1 LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 2 {
 3     PAINTSTRUCT ps;
 4     HDC hdc;
 5 
 6     switch (message)
 7     {
 8     case WM_COMMAND:
 9         break;
10     case WM_PAINT:
11         hdc = BeginPaint(hWnd, &ps);
12         // TODO: 在此添加任意绘图代码...
13         EndPaint(hWnd, &ps);
14         break;
15     case WM_DESTROY:
16         PostQuitMessage(0);
17         break;
18     default:
19         return DefWindowProc(hWnd, message, wParam, lParam);
20     }
21     return 0;
22 }

复制代码

复制代码

需要的话,在WindowProc中,可以用::GetMessageTime获取当前消息产生的时间,
用::GetMessagePos获取当前消息产生时鼠标光标所在的位置。

(1) 各个窗口消息由各个窗体(或控件)自身的WindowProc(虚函数)接收并处理。

(2) WM_COMMAND命令消息统一由当前活动主窗口的WindowProc接收,经过绕行后,可被其他的CCmdTarget对象处理。

(3) WM_COMMAND控件通知统一由子窗口(控件)的父窗口的WindowProc接收并处理,也可以进行绕行被其他的CCmdTarget对象处理。

     (例如:CFormView具备接受WM_COMMAND控件通知的条件,又具备把WM_COMMAND消息派发给关联文档对象处理的能力,

         所以给CFormView的WM_COMMAND控件通知是可以让文档对象处理的。)

     另外,WM_COMMAND控制通知会先调用ReflectLastMsg反射通知子窗口(控件),如果子窗口(控件)处理了该消息并返回TRUE,则消息会停止分发;

     否则,会继续调用OnCmdMsg进行命令发送(如同WM_COMMAND命令消息一样)。

注:WM_COMMAND命令消息与WM_COMMAND控件通知的相似之处:
WM_COMMAND命令消息和WM_COMMAND控制通知都是由WindowProc给OnCommand处理,
OnCommand通过wParam和lParam参数区分是命令消息或通知消息,然后送给OnCmdMsg处理。
事实上,BN_CLICKED控件通知消息的处理和WM_COMMAND命令消息的处理完全一样。
因为该消息的通知代码是0,ON_BN_CLICKED(id,memberfunction)和ON_COMMAND(id,memberfunction)是等同的。

(4)WM_NOTIFY消息只是对WM_COMMAND控件通知进行了扩展,与WM_COMMAND控件通知具有相同的特点。

SendMessage与PostMessage

PostMessage 把消息投递到消息队列后,立即返回; 
SendMessage把消息直接送到窗口过程处理,处理完才返回。

GetMessage与PeekMessage

GetMessage 有消息且该消息不为WM_QUIT,返回TRUE。
              有消息且该消息为WM_QUIT,返回FALSE。
                  没有消息时,挂起该UI线程,控制权交还给系统。
PeekMessage 有消息返回TRUE,如果没有消息返回FALSE;不会阻塞。
                   是否从消息队列中删除此消息(PM_REMOVE),由函数参数来指定。

要想在没有消息时做一些工作,就必须使用PeekMessage来抓取消息,以便在没有消息时,能在OnIdle中执行空闲操作(如下):

复制代码

复制代码

 1 while (TRUE) 
 2 {
 3     if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) 
 4     {
 5         if (msg.message == WM_QUIT)
 6             break;
 7         TranslateMessage(&msg);
 8         DispatchMessage(&msg);
 9     }
10     else 
11     {
12         OnIdle();
13     }
14 }

复制代码

复制代码

例如:MFC使用OnIdle函数来清理一些临时对象及未使用的动态链接库。

只有在OnIdle返回之后程序才能继续处理用户的输入,因此不应在OnIdle进行较长的任务。

MFC消息处理

在CWnd中,MFC使用OnWndMsg来分别处理各类消息:

如果是WM_COMMAND消息,交给OnCommand处理;然后返回。

如果是WM_NOTIFY消息,交给OnNotify处理;然后返回。

如果是WM_ACTIVATE消息,先交给_AfxHandleActivate处理,再继续下面的处理。

如果是WM_SETCURSOR消息,先交给_AfxHandleSetCursor处理,然后返回。

如果是其他的窗口消息(包括WM_ACTIVATE消息),则

  首先在消息缓冲池(一个hash表,用于加快消息处理函数的查找)进行消息匹配,
    若匹配成功,则调用相应的消息处理函数;
    若不成功,则在消息目标的消息映射数组中进行查找匹配,看它是否能处理当前消息。
  如果消息目标处理了该消息,则会匹配到消息处理函数,调用它进行处理;

否则,该消息没有被应用程序处理,OnWndMsg返回FALSE。

MFC消息映射

消息映射实际是MFC内建的一个消息分派机制。

把MFC中的宏进行展开(如下),可以得到消息映射表整个全貌。

注:GetMessageMap为虚函数。
     {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0}:对象消息映射表的结束标识

窗口消息只能由CWnd对象来处理,采用向基类直线上朔的方式,来查找对应的消息响应函数进行处理。

一旦找到消息响应函数(若有返回值且为TRUE),就停止上朔。因此,我们经常会看到这样的代码:

增加一个消息处理函数来写我们的逻辑时,MFC ClassWizard会在该函数之前或之后显示调用其基类对应的函数,保证基类中逻辑被执行。

命令消息可由CCmdTarget对象接收并处理(OnCmdMsg为虚函数),除了向基类直线上朔方式外,还有命令绕行机制(要防止形成圈,死循环)。

在某种程度上,控制通知消息由窗口对象处理是一种习惯和约定。然而,控件通知消息也是可以有CCmdTarget对象接收并处理,并进行命令绕行的。

下图为MFC经典单文档视图框架的命令消息绕行路线:

函数调用过程如下(如果没有任何对象处理该条WM_COMMAND消息,最后会被::DefWindowProc处理)。

非模态对话框的消息处理

1 static CAboutDlg aboutDlg;
2 aboutDlg.Create(IDD_ABOUTBOX, this);
3 aboutDlg.ShowWindow(SW_SHOW);

应用程序只有一个消息循环。

对于窗口消息,非模态对话框(及其子控件)与父窗口(及其子控件)都是用自身的WindowProc函数接收并处理,互不干扰。

对于命令消息,由当前活动主窗口的WindowProc接收(例如:当前活动主窗口为非模态对话框,则命令消息会被非模态对话框接收)。

可以在当前活动主窗口的OnCmdMsg中做命令绕行,使得其他的CCmdTarget对象也可以处理命令消息。

对于控件通知,由其父窗口的WindowProc接收并处理,一般不进行命令绕行被其他的CCmdTarget对象处理。

模态对话框的消息处理

1 CAboutDlg aboutDlg;
2 aboutDlg.DoModal();

(1) 模态对话框弹出来后,首先会让父窗口失效,使其不能接受用户的输入(键盘鼠标消息)。

1 EnableWindow(hwndParent, FALSE) ;

(2) 父窗口消息循环被阻塞(会卡在DoModal处,等待返回),由模态对话框的消息循环来接管(因此整个程序不会卡住)。

    接管后,模态对话框的消息循环仍然会将属于父窗口及其子控件的窗口消息(不包括键盘鼠标相关的窗口消息)发送给它们各自的WindowProc窗口函数,进行响应处理。

(3) 模态对话框销毁时(点击IDOK或IDCANCEL),父窗口消息循环重新激活,继续DoModal后的逻辑。

    激活后,父窗口有可以重新接受用户的输入(键盘鼠标消息)。

1 EnableWindow(hwndParent, TRUE) ;

从上面的过程中,我们可以得到如下结论:

对于窗口消息,模态对话框主窗口(及其子控件)与父窗口(及其子控件)都是用自身的WindowProc函数接收并处理,互不干扰。

只是父窗口(及其子控件)无法接受到键盘鼠标消息相关的窗口消息。

对于命令消息,由模态对话框主窗口的WindowProc接收。可以在模态对话框主窗口的OnCmdMsg中做命令绕行,使得其他的CCmdTarget对象也可以处理命令消息。

对于控件通知,由其父窗口的WindowProc接收并处理,一般不进行命令绕行被其他的CCmdTarget对象处理。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MFC添加自定义消息及重写消息过程 的相关文章

  • 支持 IAccesible 接口以在文本编辑器中移动插入符号的正确解决方案是什么?

    我想从头开始实现一个支持 IAccessible 接口的文本编辑器 我正在使用 MFC 和 Win32 API 当记事本等标准文本编辑器中的插入符号位置发生变化时 讲述人 JAWS 等客户端工具将发音与插入符号移动相对应的字母 单词或行 我
  • 如何禁用 MFC 中的最大化按钮?

    如何禁用 SDI 应用程序中的最大化按钮 功能 为了完整性 int CMainFrame OnCreate LPCREATESTRUCT lpCreateStruct ModifyStyle WS MAXIMIZEBOX 0
  • 在 Visual Studio 2013 中显示带有偏移量的控件

    最近 我将源代码从 Visual Studio 2010 迁移到 Visual Studio 2013 在 Visual Studio 2013 中构建后 控件将显示有偏移 单击下面的链接查看图像 链接到图像 https i stack i
  • Visual Studio 无法识别我的网络摄像头激光测距仪代码的 MFC 库

    我尝试直接从互联网复制源代码 但由于下面发现的错误 我无法构建 调试整个文件 请帮忙 Error occurred while restoring NuGet packages System ArgumentException The pa
  • 如何正确捕获 Aero/DWM 上的特定窗口

    背景资料 我编写了这个 MFC 应用程序并使用了很长时间 当用户按下 Print Screen Alt Print Screen 键时 它几乎会自动将屏幕截图保存到硬盘 我一直推迟使用任何与 Aero 相关的东西 直到现在我已经使用 Win
  • MFC winMain 如何最终进入可执行文件?

    In MFC wWinMain定义于appmodul cpp 据我所知 该文件内置于 mfc90ud dll 中 但是 当我运行我的应用程序时 调用堆栈显示MyApplication exe wWinMain 它是如何采取的wWinMain
  • C++ Builder vs Delphi vs MFC

    我正在学习MFC 发现它不太好用 我听说过很多关于 Delphi 的事 对 Delphi 的研究让我接触到了 C Builder C Builder 是否提供了 C MFC 的严肃且良好的替代方案 C Builder 比 MFC 更好吗 C
  • dll 中的 MFC LoadString 失败

    我在 dll 中有一个静态函数 它使用 LoadString 从资源加载字符串 当我从该 dll 调用此函数时 一切正常 但是 当我从其他模块 activeX 控件 调用此函数时 LoadString 失败并出现错误 ERROR RESOU
  • Boost::序列化和 MFC Doc/View 架构

    我正在移植现有的 MFC C 应用程序以对 XML 文件使用 Boost Serialization 我的 CDocument 对象包含应用程序的所有数据 我已将序列化函数实现为 template
  • 如何将 unicode 字符变成小写字母

    我在 VC MFC 中将 unicode 字符转换为小写字母时遇到问题 我在 CString 变量中有 unicode 字符 所以 使用英语 MakeLower 工作正常 我得到小写字母 但它无法将 unicode 字符转换为小写 我确实尝
  • MFC:如何捕获Web浏览器控件中的链接单击事件?

    我有一个带有 Web 控件的 MFC 应用程序 单击可单击链接时 它将使用 IE 打开 而不是默认浏览器 问题 有没有办法强制使用默认浏览器打开它 如果没有 我如何捕获链接单击事件 以便稍后可以操纵单击事件 谢谢 不 据我所知还没有 查看有
  • 当窗口未最大化时缺少 WM_NCLBUTTONUP 消息的奇怪问题

    我有一个处理 WM NCLBUTTONUP 消息的窗口 以便处理标题栏中自定义按钮的点击 当窗口最大化时 这非常有效 但当窗口未最大化时 WM NCLBUTTONUP 消息永远不会到达 不过我确实收到了 WM NCLBUTTONDOWN 消
  • 如何通过单击 MainFrame 内的按钮来更改 MFC 视图

    我想通过单击窗口内的按钮来更改呈现的视图像这样 https i stack imgur com 3IA2o png 我的项目设置 我制作了一个没有文档 视图支持的 MFC 项目 SDI 我在设计器中又创建了两个视图并向它们添加了类 新的视图
  • MFC CMenu 工具提示未显示

    我尝试使用类似的东西来设置 CMenu 项的工具提示 如所述here https stackoverflow com questions 2400180 mfc how to add tooltip in cmenu items 但它只是显
  • MinGW支持MFC吗?

    我已经使用 MinGW 开发了 WinAPI 应用程序 没有出现任何问题 现在 我可以用 MFC 做同样的事情吗 我只是在这里猜测 但我认为您需要购买 Visual Studio 的副本才能获得使用 MFC 的许可证 MFC 也不因其对 C
  • 捕获由纯 C++ dll 中的 MFC 应用程序生成的 Windows 消息

    首先 这可能吗 我有一个与某些硬件接口的第三方 dll 它是用MFC编写的 我 从 dll 供应商处 收到了一个示例 Visual Studio 2010 解决方案 该解决方案只有一个项目 调用相关第三方 dll 的 MFC 应用程序 ex
  • C++ 检查 unicode 字符是否为全角

    如何检查unicode字符是否是全角 我使用Win32 MFC 例如 中是全宽 A不是全角 是全宽 F不是全宽 你需要的是检索东亚宽度 http www unicode org reports tr11 的角色 您可以通过解析来做到这一点东
  • 如何在 MFC 中创建带圆角的进度控件?

    我需要在 MFC 应用程序中创建一个带圆角的进度条 我尝试过使用 CreateRoundRectRgn 和 SetWindowRgn 的组合 它具有使控件完全消失的效果 我还尝试使用透明的 GIF 覆盖层 该覆盖层将绘制在进度栏的顶部 但我
  • 如何在 MFC 中调整对话框大小时移动控件?

    我已经在 MFC 中创建了对话框视图 从下图中可以清楚地看到 如滑块控件和编辑框等 当我调整对话框大小时 这些控件不会移动 在此输入图像描述 https i stack imgur com 7OxAK jpg 我想移动控件以适应对话框 但不
  • 为什么#pragma optimize("", off)

    我正在审查一个 C MFC 项目 在某些文件的开头有这样一行 pragma optimize off 我知道这会关闭所有以下功能的优化 但这样做的动机通常是什么 我专门使用它来在一组特定代码中获得更好的调试信息 并在优化的情况下编译应用程序

随机推荐

  • java中的输入输出

    java与C语言和C 不同 java的输入输出比较复杂 下面我将来介绍一下java的输入输出 输出 java中有三种方法进行输出 class Main public static void main String args System o
  • iview table使用自定义按钮取消某个选中的单项

    实现效果 选中选项后然后弹出选中的选项框 点击删除按钮删除某一个选项 table中的选中状态也随之变化 ivew坑 给data设置 checked其实对table上的checkBox并没有作用 用js给data数据设置该属性并没有作用 具体
  • 标准的遗传算法求函数最大值

    最近看了下遗传算法 刚看了一点 就觉得手痒 非要把程序编制出来看看效果 我现在总认为那些理论再高深 无法用计算机实现就是空话 呵呵 下面是我调试了好久的代码 无赖没有学过数据结构 算法 程序写的很差 单效果还是出来了 高兴 和大家共同分享下
  • ipmitool工具的安装遇到的问题

    1 从https gitee com mirrors ipmitool git下载ipmitool源码 https gitee com mirrors ipmitool git 因为官网的下载速度比较慢 推荐使用gitee下载 2 进行编译
  • python练习题之

    本文来源于公众号 csdn2299 喜欢可以关注公众号 程序员学府 安装Tornado 省事点可以直接用grequests库 下面用的是tornado的异步client 异步用到了tornado 根据官方文档的例子修改得到一个简单的异步爬虫
  • android 打砖块教程,少儿编程教程:设计打砖块游戏。

    凤县微课堂 你我共成长 愿以此小小的平台 助你成就更好的自己 第二百零七期 少儿编程教程 第5讲 设计打砖块游戏 创建一个小球的角色 在运动选项中选择 碰到边缘就反弹 当角色运动到窗口的边缘 就会反弹运动 在控制选项中选择重复执行 并在运动
  • 五线谱音名和组别对照表_五线谱简谱对照表

    五线谱与钢琴对照表 五线谱与钢琴对照表 一 以下图示五条线 就是五线谱 分一 二 三 四 五条线 二 五条线中间的空白处为间 共有四间 三 放在五线谱开头 分别为高音谱号和低音谱号 四 五线谱 简谱音阶对照示意图 五 简谱唱法与五线谱的音名
  • 网页搜索指定网站内容site

    查询资料时指定查询某一个网站使用 site 参数site空格 指定网站域名 搜索内容 例如 site csdn php
  • 华为OD机试 - 两数之和绝对值最小(Java)

    题目描述 给定一个从小到大的有序整数序列 存在正整数和负整数 数组 nums 请你在该数组中找出两个数 其和的绝对值 nums x nums y 为最小值 并返回这个绝对值 每种输入只会对应一个答案 但是 数组中同一个元素不能使用两遍 输入
  • Dropout层到底在干些什么(Pytorch实现)

    Dropout 一 基本概念 二 Dropout工作原理 1 Dropout工作流程 2 Dropout如何缓解过拟合 3 Dropout实际实现 三 Pytorch实现 1 实际实现方式 训练模式下 2 调用方式 3 参数解析 4 实例
  • 使用单片机的串口蓝牙通信写的接收SBUF里的数据,并进行发送执行命令,显示在数码管上,波特率9600

    include
  • 目标跟踪2020

    cvpr2022 23 TCTrack Temporal Contexts for Aerial Tracking 空中跟踪的时间上下文 paper code 模型87M cvpr2020大盘点 CVPR 2020 论文大盘点 目标跟踪篇
  • 计算机组成原理知识点梳理(一)

    注 所学教材为 计算机组成原理 第二版 唐朔飞 编著 本次梳理涵盖内容为 第一章 计算机系统概论 1 1 计算机系统简介 1 2 计算机的基本组成 参考内容以及图片来源为书本和csdn博文 第一章 计算机系统概论 1 1 计算机系统简介 计
  • fb直接渲染

    include
  • 黑马--LINUX学习笔记(五)

    makefile依赖过程 工作原理 Makefile的优化
  • oracle 递归查询 CONNECT BY、START WITH、CONNECT_BY_ROOT、CONNECT_BY_ISLEAF、SYS_CONNECT_BY_PATH

    创建表 初始化数据 CREATE TABLE TB COMPANY COMPANY ID INTEGER PRIMARY KEY COMPANY VARCHAR2 256 UP COMPANYID INTEGER INSERT INTO T
  • 【Python】读取excel数据

    python3读取excle数据 import xlrd workbook xlrd open workbook r test xls encoding override gbk print workbook sheet names she
  • C++中string的常用函数总结

    标准c 中string类函数介绍 注意不是CString 之所以抛弃char 的字符串而选用C 标准程序库中的string类 是因为他和前者比较起来 不必 担心内存是否足够 字符串长度等等 而且作为一个类出现 他集成的操作函数足以完成我们大
  • selenium还能这么玩:连接已经存在的浏览器

    测试和爬虫对selenium并不会陌生 现有的教程已经非常多 但是因为 selenium 封装的方法比较底层 所以灵活性非常高 我们可以基于这种灵活性来实现非常丰富的定制功能 这篇文章介绍一个操作 可以让 selenium 连接我们手动打开
  • MFC添加自定义消息及重写消息过程

    由于MFC中无法通过类向导来自定义消息 所以需要手动添加 主要过程如下 本文基于vs2008下通过线程实现数据实时更新的对话框运用程序 1 定义消息 Resource h文件中 由于很多新控件也会用到WM USER消息 所以定义WM USE