MFC command message routing process (view, framework, and Application)

Source: Internet
Author: User

I. Environment

IDE: vc6.0

OS: Windows XP

2. Compile the test code and environment Configuration

Create a Win32 application and select "A simple Win32 application"

Open the stdafx. h header file

#include <windows.h>

Changed:

#include <afxwin.h>

Modify the Project Settings and use the MFC static library to view the MFC source code provided by Microsoft.

Project-> Settings-> microsoftfoundation classes: use MFC in a static library

Return to the project CPP file and write the following test code:

#include "stdafx.h"#include "resource.h"class CMyView : public CView{DECLARE_MESSAGE_MAP ()public:virtual void OnDraw (CDC* pDC);afx_msg void OnFileNew ();};BEGIN_MESSAGE_MAP (CMyView, CView)   //ON_COMMAND (ID_NEW, OnFileNew)END_MESSAGE_MAP ()void CMyView::OnDraw (CDC* pDC){pDC->Ellipse (100, 100, 400, 400);}void CMyView::OnFileNew (){AfxMessageBox ("CMyView::OnFileNew");}class CMyFrameWnd : public CFrameWnd{DECLARE_MESSAGE_MAP ()public:afx_msg int OnCreate (LPCREATESTRUCT lpCreateStruct);afx_msg void OnFileNew ();};BEGIN_MESSAGE_MAP (CMyFrameWnd, CFrameWnd)   ON_WM_CREATE ()   //ON_COMMAND (ID_NEW, OnFileNew)END_MESSAGE_MAP ()int CMyFrameWnd::OnCreate (LPCREATESTRUCT lpCreateStruct){CMyView *pView = new CMyView;pView->Create (NULL, "", WS_CHILD | WS_VISIBLE | WS_BORDER, CRect (0,0,100,100), this, /*1001*/AFX_IDW_PANE_FIRST);m_pViewActive = pView;return CFrameWnd::OnCreate (lpCreateStruct);}void CMyFrameWnd::OnFileNew (){AfxMessageBox ("CMyFrameWnd::OnFileNew");}class CMyWinApp : public CWinApp{DECLARE_MESSAGE_MAP ()public:virtual BOOL InitInstance ();afx_msg void OnNewFile ();};BEGIN_MESSAGE_MAP (CMyWinApp, CWinApp)    ON_COMMAND (ID_NEW, OnNewFile)END_MESSAGE_MAP ()void CMyWinApp::OnNewFile (){AfxMessageBox ("CMyWinApp::OnNewFile");}CMyWinApp theApp;BOOL CMyWinApp::InitInstance (){CMyFrameWnd *pFrame = new CMyFrameWnd;pFrame->Create (NULL, "MFCSplit", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL, MAKEINTRESOURCE(IDR_MENU1));m_pMainWnd = pFrame;pFrame->ShowWindow (SW_SHOW);pFrame->UpdateWindow ();return TRUE;}

Note: you also need to add a menu resource in the project. Only one menu item is needed for the menu, and the ID is changed to id_new. The name is filenew.

The above code is worth noting that creating a view object and a window should be completed in the oncreate virtual function of the Framework Window, assign the created view object to m_pviewactive of the framework window so that the View window has been started and is active (and the contact between the View window and the Framework Window is established ).

In addition, when creating a View window, the parent window is specified as the frame window (this). In this way, the following object structure diagram can be summarized by combining values assigned to the initinstance function (m_pmainwnd = pframe) of the application.

Object structure diagram:

M_pmainwnd = pfarame

M_pviewactive = pview

Cmywinapptheapp; // global object, which can be used as needed

In addition, both afxgetapp () and afxgetthread () can return theapp object address.

Theapp

| -----> M_pmainwnd

| -----------> M_pviewactice

Iii. breakpoint tracking and analysis

In the code above: View class, framework class, and window class, I have added a message ing macro for the response menu, if you want to simply verify the conclusion, comment out any of the tests to obtain the routing sequence of the following commands:

View class-à framework class -- à application class

Of course, here I want to find out from the source code provided by Microsoft: Comment the Command Message response macro in the View class and window class.

Break down at the entrance of cmyview:; onfilenew, F5 debug the Startup Program, and click our filenew menu to trigger the message. Then we came to the breakpoint.

On the VC toolbar: View --> debugwindows --> callstack, you can see the call stack of cmyfileview: onfilenew. Double-click afxwndproc to enter the function entry and set the breakpoint.



Stop the current debugging, re-F5 debug the Startup Program, and go to the breakpoint at the afxwndproc entry.

Afxwndproc (hwnd, uint nmsg, wparam, lparam) {// The hwnd parameter stores the window handle generated by the message ............................ .......... // find the associated Class Object cwnd * pwnd = cwnd: Through hwnd :: fromhandlepermanent (hwnd );................................... .... return afxcallwndproc (pwnd, hwnd, nmsg, wparam, lparam );}

And

AfxWndProc->AfxCallWndProc

Into

Lresult afxapi afxcallwndproc (cwnd * pwnd, hwnd, uint nmsg, wparam = 0, lparam = 0) {// pwnd is the object pframe .............................. ..... // use pframe to call winddowproc. If windowproc is a virtual function, you can rewrite it // and call the window processing function we have defined. lresult = pwnd-> windowproc (nmsg, wparam, lparam );}

And

AfxWndProc--> AfxCallWndProc-->WindowProc


Into

LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam){// this==pFrame..................................................if (!OnWndMsg(message, wParam, lParam, &lResult))lResult = DefWindowProc(message, wParam, lParam);return lResult;}


And

AfxWndProc-->AfxCallWndProc--> WindowProc-->OnWndMsg

Into

Bool cwnd: onwndmsg (uint message, wparam, lparam, lresult * presult) {// This = pfarme ................................ ........... // special case for commands, if (Message = wm_command) {If (oncommand (wparam, lparam) {lresult = 1; goto lreturntrue ;} return false;} // special case for notifies. If (Message = wm_notify) {nmhdr * pnmhdr = (nmhdr *) lparam; if (pnmhdr-> hwndfrom! = NULL & onnotify (wparam, lparam, & lresult) goto lreturntrue; return false ;}// special case for activation, activate if (Message = wm_activate) _ afxhandleactivate (this, wparam, cwnd: fromhandle (hwnd) lparam); // special case for set cursor implements Ror, cursor if (Message = wm_setcursor & _ afxhandlesetcursor (this, (short) loword (lparam), hiword (lparam) {lresult = 1; goto lreturntrue ;}.................................... ......................}

Set the breakpoint to press F5 in the IF (Message = wm_command) command of onwndmsg to run and trigger the message to the breakpoint.

And

AfxWndProc-->AfxCallWndProc-->WindowProc-->OnWndMsg-->OnCommand

Into

BOOL CFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam){// this===pFrame    ....................................// route as normal commandreturn CWnd::OnCommand(wParam, lParam);}

And

AfxWndProc-->AfxCallWndProc-->WindowProc-->OnWndMsg-->OnCommand-->OnCommand

Into

BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam){// this===pFrame    ........................................return OnCmdMsg(nID, nCode, NULL, NULL);}


And

AfxWndProc-->AfxCallWndProc-->WindowProc--> OnWndMsg-->OnCommand-->OnCommand-->OnCmdMsg

Into

BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,AFX_CMDHANDLERINFO* pHandlerInfo){// this==pFrame    ....................................// pump through current view FIRSTCView* pView = GetActiveView();if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))return TRUE;// then pump through frameif (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))return TRUE;// last but not least, pump through appCWinApp* pApp = AfxGetApp();if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))return TRUE;return FALSE;}

In this function, you can clearly see the routing process of command messages, cview --> cframewnd --> theapp

The previous blog post on the message search process has been analyzed and will not be repeated here. The following message ing lookup linked list is drawn:

 

 

Here we only analyze the message processing process of theapp.

And

AfxWndProc--> AfxCallWndProc--> WindowProc--> OnWndMsg-->OnCommand-->OnCmdMsg

Into

Bool c0000target: on0000msg (uint NID, int ncode, void * pextra, afx_cmdhandlerinfo * phandlerinfo) {// This = pviewfor (pmessagemap = getmessagemap (); pmessagemap! = NULL; pmessagemap = pmessagemap-> pbasemap) {// pmessagemap = getmessagemap () get the header node of the message ing linked list, that is, the address of the static member messagemap in theapp object // find the elements that contain the corresponding processing function of the message in the _ messageentries array, if lpentry is found, it points to this element. Otherwise, it is null and continues searching for const afx_msgmap_entry * lpentry = afxfindmessageentry (pmessagemap-> lpentries, nmsg, ncode, NID );..................................... .. // if the return _ afxdispatch1_msg (this, NID, ncode, lpentry-> PFN, pextra, lpentry-> nsig, phandlerinfo );}.................................... .....................}

Now, the message routing process has been analyzed.

Pview --> pfarme --> theapp


MFC command message routing process (view, framework, and Application)

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.