Beginner VC Series II: Message Loop

Source: Internet
Author: User

 Intended audience: C ++ basics for beginners.

Http://www.vckbase.com/document/viewdoc? Id = 1048

One of the VC beginner's entry series: the birth of window classes

I,Message loop of traditional SDK programs 

In traditional SDK programs, the message loop is very simple. Maybe you don't believe it. Let's look at the following code:

#include <windows.h>LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,                    PSTR szCmdLine, int iCmdShow){static TCHAR szAppName[] = TEXT ("HelloWin") ;WNDCLASwndclass ; wndclass.style  = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc  = WndProc ;wndclass.lpszClassName= szAppName ;RegisterClass (&wndclass);hwnd = CreateWindow( szAppName,……,NULL);     ShowWindow (hwnd, iCmdShow) ;UpdateWindow (hwnd) ;     while (GetMessage (&msg, NULL, 0, 0))       {TranslateMessage (&msg) ;  DispatchMessage (&msg) ;          }return msg.wParam ;}LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){    switch (message)          {case WM_CREATE:                     ………case WM_PAINT:                     ………case WM_DESTROY:PostQuitMessage (0) ;return 0 ;          }   return DefWindowProc (hwnd, message, wParam, lParam) ;}

In winmain, createwindow uses a parameter to associate the created window with the window class (see "The Birth of the window class, in this way, all messages in the window will be sent to the window function wndproc of the window class, and then wndproc will give different actions based on different messages.

II,Message loop expected by MFC
In traditional SDK programs, message loops are very simple, and windows and window functions are bound together. In MFC, a problem occurs. For example, the cdocument class is not a window, so there is no window class. But I also want it to respond to messages. How can this problem be solved? The problem is not just that. Let's look at the message of MFC and we will find more problems.
MFC divides messages into three categories: 1. standard Message, that is, any message starting with WM _ Except wm_command. Any class derived from cwnd can accept the message, and accept it according to the inheritance relationship (for example, from cscrollview to cview and then to cwnd ). 2. The command message, namely wm_command, is any class derived from c1_target and can accept the message. The order of receipt is shown in. The label indicates the order of receipt of the message, and the arrow indicates the call order:


Figure 1 transition of a message

3. Control notification: the notification message also appears in the form of wm_command, which is generated by the Control and notifies its parent window.

III,Secrets behind message macros
Knowing the message flow requirements of MFC, how does MFC implement it? When a message appears, how does the application framework know the object to which the message is sent? In fact, all the classes that can receive messages must inherit from the csf-target class, because these classes share a common feature: Three macros including declare_message_map, begin_message_map, and end_message_map. Ah! These three macros have organized a large message ing Network. Maybe you don't believe it. Let's look at how these three macros are defined:

#define DECLARE_MESSAGE_MAP()/private:/     static const AFX_MSGMAP_ENTRY _messageEntries[];/protected:     static AFX_DATA const AFX_MSGMAP messageMap;/     virtual const AFX_MSGMAP* GetMessageMap() const;/#define BEGIN_MESSAGE_MAP(theClass, baseClass)/     const AFX_MSGMAP* theClass::GetMessageMap() const/{return &theClass::messageMap;}/AFX_DATADEF const AFX_MSGMAP theClass::messageMap = /{&baseClass::messageMap, &theClass::_messageEntries[0]};/const AFX_MSGMAP_ENTRY theClass::_messageEntries[]=/{/#define END_MESSAGE_MAP()/{0,0,0,0,AfxSig_end,(AFX_pMSG)0}/};/typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);struct AFX_MSGMAP_ENTRY{     UINT  nMessage;     UINT  nCode;     UINT  nID;     UINT  nLastID;     UINT  nSig;     AFX_PMSG pfn;};struct AFX_MSGMAP{    const AFX_MSGMAP* pBaseMap;    const AFX_MSGMAP_ENTRY* lpEntries;};

We can see that the declare_message_map macro applied for a global structure and function to obtain the structure in its class, and filled in the global structure just now between begin_message_map and end_message_map, connect a message with the corresponding processing function, and connect all types of messages in the inherited order through the pbasemap pointer in afx_msgmap, so as to provide the path of Message flow (that is, the direct current of the message, meets the requirements of standard message flow ).

The following is an example:

CMyWnd : public CWnd{   ……   DECLARE_MESSAGE_MAP()}BEGIN_MESSAGE_MAP(CMyWnd,CWnd)     ON_WM_CREATE()     ON_WM_PAINT()END_MESSAGE_MAP()

The Code is as follows:

CMyWnd:public CWnd{    ……private:    static const AFX_MSGMAP_ENTRY _messageEntries[];protected:    static AFX_DATA const AFX_MSGMAP messageMap;    virtual const AFX_MSGMAP* GetMessageMap() const;}const AFX_MSGMAP* CMyWnd::GetMessageMap() const{  return &CMyWnd::messageMap;}AFX_DATADEF const AFX_MSGMAP CMyWnd::messageMap={&CWnd::messageMap, &CMyWnd::_messageEntries[0]};const AFX_MSGMAP_ENTRY CMyWnd::_messageEntries[]={{WM_CREATE,0,0,0,AfxSig_is,(AFX_PMSG)(AFX_PMSGW)(int(AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT))OnCreate},{WM_PAINT,0,0,0,AfxSig_vv,(AFX_PMSG)(AFX_PMSGW)(void (AFX_MSG_CALL CWnd::*)(void))OnPaint},{0,0,0,0,AfxSig_end,(AFX_PMSG)0}};

In this way, wm_create and wm_paint flow in the message network. When the messagemap structure of the flow to the cmywnd class is found, the oncreate and onpaint functions recorded in the record are called to respond to the message, this completes the Windows message driver mechanism.

IV,Start Point of the MFC message 
We have established a message flow network, but how the message receives the message from the generation to the response function, and the standard message needs to be DC, there are also many turns in the command message (which can be seen in the second title ). Don't be nervous. We just need to see how MFC is implemented.
In any case, it is the same for Windows systems. It uses getmessage (or other) to retrieve messages from the message queue, and then uses dispatchmessage to send messages to the window function. In "The Birth of window classes", we know that MFC registers all window processing functions as defwndproc. Does it send all the messages to defwndproc? Sorry, no, but all sent to the afxwndproc function. You may want to ask why, which is what I want to know. Let's look at the MFC code:

BOOL CWnd::CreateEx(……){……PreCreateWindow(cs);AfxHookWindowCreate(this);HWND hWnd = ::CreateWindowEx(……);……}void AFXAPI AfxHookWindowCreate(CWnd *pWnd){……pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,_AfxCbtFilterHook,NULL,::GetCurrentThreadId());……}_AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam){……if(!afxData.bWin31){_AfxStandardSubclass((HWND)wParam);}……}void AFXAPI _AfxStandardSubclass(HWND hWnd){……oldWndProc = (WNDPROC)SetWindowLong(hWnd,GWL_WNDPROC,(DWORD)AfxGetAfxWndProc());}WNDPROC AFXAPI AfxGetAfxWndProc(){……return &AfxWndProc;}

After reading the above code, I wonder if you have any feeling of being confused. "Ah, it turned out to be like this! "In fact, after MFC registers the window class in precreatewindow, it calls the afxhookwindowcreate function before creating the window. This function sets the hook (the hook is set with setwinowshook or setwindowshookex, in this way, the system sends you the set function when the Set message is available. Here is the _ afxcbtfilterhook function), so that each time you create a window, this function modifies the window function to afxwndproc. Why? It is compatible with mfc2.5 to accommodate new 3D controls.

V,MFC message flow 
The starting point of a message is the afxwndproc function. All messages are sent to afxwndproc, and they are routed from afxwndproc to their respective message response functions again. How does one stream? Only MFC knows:

Lresult callback afxwndproc (.......) {...... Return afxcallwndproc (pwnd, hwnd, nmsg, wparam, lparam);} lresult afxapi afxcallwndproc (......) {...... Lresult = pwnd-> windowproc (nmsg, wparam, lparam );......} Lresult cwnd: windowproc (......) {...... If (! Onwndmsg (message, wparam, lparam, & lresult) lresult = defwindowproc (message, wparam, lparam );......} Bool cwnd: onwndmsg (......) // This function is too huge. I modified it to reflect the meaning and cannot execute {...... If (Message = wm_command) oncommand (wparam, lparam); If (Message = wm_notify) ony y (wparam, lparam, & lresult); pmessage = getmessagemap (); (; pmessagemap! = NULL; pmessagemap = pmessagemap-> pbasemap) {If (lpentry = afxfindmessageentry (pmessagemap-> lpentries, message, 0, 0 ))! = NULL) break;} (this-> * (lpentry-> PNF ))(......); // Call the message response function} afx_msgmap_entry afxfindmessageentry (......) {...... While (lpentry-> nsign! = Afxsig_end) {If (lpentry-> nmessage = nmsg & lpentry-> ncode = ncode & nid> = lpentry-> NID & nid <= lpentry-> nlastid) {return lpentry;} lpentry ++ ;}......}

After the message is sent to the onwndmsg of the corresponding window, take the corresponding action based on the Message Type: if the message is a standard message, check whether there is a processing function in the previous class (implemented by afxfindmessageentry ), if no, find the function in the parent class (implemented by pmessagemap-> pbasemap). In this way, you can search for the Message Network in sequence and cannot find the processing function after the search is complete, return to the windowproc function to call the default defwindowproc function. If it is a command message or notification message, it is sent to the oncommand or oncommand y function for processing to realize the flow of messages:

Bool cwnd: oncommand (wparam, lparam ){...... Return ondomainmsg (NID, ncode, null, null);} bool cframewnd: ondomainmsg (......) {Cview * pview = getactiveview (); If (pview! = NULL & pview-> on1_msg (......)) // Return true; If (cwnd: on1_msg (......)) // In Figure 1, frame itself returns true; cwinapp * PAPP = afxgetapp (); If (PAPP! = NULL & PAPP-> on1_msg (......)) // In Figure 1, the cwinapp object return true; return false;} bool cview: on1_msg (......) {If (cwnd: on1_msg (......)) // In Figure 1, the view itself returns true; If (m_pdocument! = NULL) m_pdocument-> on1_msg (......); // View the doc arrow in Figure 1 ......} Bool cdocument: on1_msg (......) {If (c1_target: on1_msg (......)) // In Figure 1, the doc itself returns true; If (m_pdoctemplate! = NULL & m_pdoctemplate-> on1_msg (......)) // Doc templatereturn true; return false;} bool c1_target: on1_msg (…) In Figure 1 (......) // Note: cwnd does not load the on1_msg {… of c1_target {...... For (pmessagemap = getmessagemap (); pmessagemap! = NULL; pmessagemap = pmessagemap-> pbasemap) {lpentry = afxfindmessageentry (pmessagemap-> lpentries ,......); If (lpentry! = NULL) return dispatch1_msg (...... Lpentry-> PFN ,......);} Return false ;}

From the code, we can see that the order in which onmsg is called is exactly the order required in figure 1, which enables the flow of messages, finally, the dispatchreceivmsg function calls the found message processing function to process messages. Now, the processing function has been found after the message appears!

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.