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)