Message cycle in MFC

xiaoxiao2021-03-06  20

One,

News cycle of traditional SDK programs

In the traditional SDK program, the message loop is very simple. Maybe you don't believe, then let's take a look at the code below:

#include

Lresult Callback WndProc (HWND, UINT, WPARAM, LPARAM);

Int WinApi Winmain (Hinstance Hinstance, Hinstance Hprevinstance,

PSTR SZCMDLINE, INT ICMDSHOW)

{

Static tchar szappname [] = text ("hellowin");

WNDCLAS WNDCLASS;

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 links the created window and window class (see "window class (see" window class, so that all messages of the window will be sent to the window function WNDPROC, and then WndProc is dependent. The message gives different actions.

two,

Message cycle expected by MFC

The message loop in the traditional SDK program is very simple and binds the window and window functions. There is a problem in the MFC, such as the cdocument class, not a window, so there is no window class, but I also want it to respond to the message, what should I do? The problem is not only the case, let's take a look at the MFC's news, you will find more problems.

The MFC divides the message into three categories: 1. Standard message, that is, any WM_Command, any WM_ started, any class from CWND can accept the message, and accept according to the inheritance relationship (such as from CScrollView to CVIEW) Go to CWND). 2. Command message, ie WM_COMMAND, any class from ccmdTarget, and accept this message, accept the order as shown below, where the label is marked with the order of accepting the message, the arrow represents the call sequence:

Figure 1 turning flow of the message

3.Control Notification, notification class message, also appears in WM_COMMAND, generated by the control, to notify the parent window.

three,

Secret behind the news

Know how the MFC message flow is required, how does the MFC implement it? When a message appears, how do Application Framework know which object is sent to the message? In fact, all CCMDTARGET classes are engageable, all classes that can accept messages must be inherited in the CCMDTarget class, because these classes are common: containing declare_message_map, begin_MESSAGE_MAP, END_MESSAGE_MAP three macros. what! For these three macros, a huge news map, maybe you don't believe, then let's see how these three macros define:

#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 :: _ Messagentries [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;

}

It can be seen that the declare_MESSAGE_MAP macro applies for a global structure and the function of the structure, and fill in the global structure between Begin_Message_Map and End_Message_map, links the message and the corresponding process function, and passed the PBASEMAP in AFX_MSGMAP. Pointer, connect all kinds in inheritance sequence, providing information flowing roads (ie, messages, DC to meet standard message flow requirements).

Let's take an example:

CMYWND: PUBLIC CWND

{

......

Declare_message_map ()

}

Begin_MESSAGE_MAP (CMYWND, CWND)

ON_WM_CREATE ()

ON_WM_PAINT ()

END_MESSAGE_MAP ()

After being started, 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 :: _ Messagentries [0]};

Const AFX_MSGMAP_ENTRY CMYWND :: _ MessageEntries [] =

{

{WM_CREATE, 0, 0, 0, AFXSIG_IS,

(AFX_PMSG) (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}

}

Thus, WM_CREATE, WM_PAINT flows in the message network, when flowing to the MessageMap structure of the CMYWND class, discovers the record of the message, call the oncreate and the onpaint function recorded in the record, and perform the response message, thereby completing the Windows message driver mechanism.

four,

The starting point of the MFC message

We have established a message mobile network, but how the message received the message from the generated response function, and the standard message requires DC, and the command message has many turns (can be seen in the title II). Don't be nervous, we just need to see how the MFC is implemented.

Regardless of how it is said, it is the same for the Windows system, which is constantly removed from the message queue from the message queue, then sends the message to the window function with DispatchMessage. It knows in the "Birth of Window Class", MFC registers all the window handles functions into DEFWndProc, is that MFC will send all the messages to DefWndProc? Sorry, not, but all sent to the AfxWndProc function. You may want to ask why, this is what I want to know, then let's take a look at the MFC code:

BOOL CWND :: Createex (...)

{

......

PrecreateWindow (CS);

AfxhookWindowCreate (this);

HWND HWND = :: CREATEWINDOWEX (...);

......

}

Void AFXAPI AFXHOKWINDOWCREATE (CWND * PWND)

{

......

PthreadState-> m_hookoldcbtfilter =

:: 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;

}

I saw the code above, I don't know if you have a feeling of chest ", it turns out!" In fact, MFC called an AFXWINDOWCREATE function after the PRECREATEWINDOW registration window class, which sets the hook ( The hook is set with setwinowshook or setwindowshookex, which is a message that satisfies the settings, the system sends the function you set, this is the _afxcbtfilterhook function), so that each time you create a window, the function modifies the window function to AFXWNDPROC. As for why do you do this? That is to incorporate new 3D controls and compatible with MFC2.5.

Fives,

MFC message flow

The starting point of the message is the AFXWndProc function. All messages are sent to the AFXWndProc, but also from the AFXWndProc to their respective message response functions, how to stream? That 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 (...) // The function is too huge, and I have changed it, only reflecting the meaning, can't be executed.

{

......

IF (Message == WM_COMMAND)

Oncommand (WPARAM, LPARAM);

IF (Message == WM_NOTIFY)

ONNOTIFY (WPARAM, LPARAM, & LRESULT);

PMessage = getMessageMap ();

For (; pMessagemap! = null; pMessageMap = pimentagemap-> pbasemap)

{

IF ((LPENTRY = AFXFindMessagentry (pMessageMap-> LpenTries,

Message, 0, 0))! = null)

Break;

}

(this -> * (lpenTry-> PNF)) (...); // call message response function

}

AFX_MSGMAP_ENTRY AFXFINDMESSAGEENTRY (...)

{

......

While (LpenTry-> nsign! = AFXSIG_END)

{

IF (LpenTry-> NMESSAGE == NMSG && LpenTry-> ncode == ncode && nid> = lpendry-> NID

&& nid <= lpendry-> nlastid)

{

Return LpenTry;

}

LpenTry ;

......

}

After the message is sent to the onWndMSG of the corresponding window, then take the corresponding action according to the type of message: if it is a standard message, check the processed function in the forefront class (implemented by the AFXFindMessageEntry), if not, it is found in his father class (Implemented by PMessageMap-> PBaseMap), so on the order search message network, the search end can also not find the handler, then return to the WindowProc function to call the default defWindowProc function; if it is a command message or notification message to the oncommand or ONNOTIFY function Treatment in the process, to achieve the turn of the message:

Bool CWnd :: OnCommand (WParam WPARAM, LPARAM LPARAM)

{

......

Return Oncmdmsg (NID, NCODE, NULL, NULL);

}

Bool cframewnd :: oncmdmsg (...)

{

CView * pView = getActiveView ();

IF (pView! = null && pView-> oncmdmsg (...)) // is equivalent to the arrow pointing to the view in Figure 1

Return True;

IF (cwnd :: oncmdmsg (...)) // Figure 1 Frame itself

Return True;

CWINAPP * PAPP = AFXGetApp ();

IF (PAPP! = Null && PAP-> oncmdmsg (...)) // CWINAPP object in Figure 1

Return True;

Return False;

}

Bool cview :: ONCMDMSG (...)

{

IF (cwnd :: oncmdmsg (...)) // Figure 1 View itself

Return True;

IF (m_pdocument! = null) m_pdocument-> oncmdmsg (...); // Figure 1 View to DOC arrow

......

}

Bool cdocument :: ONCMDMSG (...)

{

IF (ccmdtarget :: oncmdmsg (...)) // Figure 1 DOC itself

Return True;

IF (m_pdoctemplate! = null && m_pdockemplate-> oncmdmsg (...)) // DOC Template in Figure 1

Return True;

Return False;

}

Bool ccmdtarget :: ONCMDMSG (...) // Note: CWND does not overload CCMDTARGET oncmdmsg

{

......

PMessageMap (); pimentagemap! = null;

PMessageMap = PMessageMap-> PBaseMAP)

{

LpenTry = AFXFindMessagentry (pMessagemap-> lpentries, ...);

IF (LpenTry! = NULL)

Return dispatchcmdmsg (... lpenTry-> PFN, ...);

}

Return False;

}

As can be seen from the code, the order in which the oncmdmsg each call is just the order required in Figure 1, which also implements the turning flow of the message, and finally the dispatchcmdmsg function is a call to find the message processing function processing message. To thismay, the message has been completed from the appearance of the process function!

转载请注明原文地址:https://www.9cbs.com/read-43335.html

New Post(0)