Naughty MFC (2)

Source: Internet
Author: User
Tags getmessage goto

The last book says that the WinMain and window handlers are replaced by the corresponding class actions and macro operations, respectively. This time we'll take a look at how the MFC program works after the replacement.

First put the class inheritance map, you can review it at any time.


The first action statement in the main CPP file:

The one and only CMyWinApp Objectcmywinapp Theapp;

1. generating an object is a natural call to the constructor, but not only to call its own constructor, but also to call the parent class's constructor. Although an automatically generated class whose constructor is empty, the constructor of the parent class can still perform some initialization operations.

You can see the constructor definition of CWinApp by opening the APPCORE.CPP file in the MFC framework. Its close section operates as follows:

CWINAPP:: CWINAPP (LPCTSTR lpszappname) {if (lpszappname! = NULL) M_pszappname = _tcsdup (lpszappname); elsem_pszappname = NULL;// Initialize CWinThread Stateassert (afxgetthread () = = NULL);p Threadstate->m_pcurrentwinthread = this; ASSERT (afxgetthread () = = this); M_hthread =:: GetCurrentThread (); M_nthreadid =:: GetCurrentThreadID ();//Initialize CWinApp Stateassert (Afxcurrentwinapp = = NULL); Only one CWinApp object pleasepmodulestate->m_pcurrentwinapp = this; ASSERT (AfxGetApp () = = this);/non-running state until winmainm_hinstance = Null;m_pszhelpfilepath = Null;m_pszprofile Name = Null;m_pszexename = Null;m_lpcmdline = Null;m_pcmdinfo = NULL; ...} 

As seen above, member variables in CWINAPP areconfigured and initialized because of the presence of Theapp Global Objects . If no Theapp exists in the program, the compile link can pass smoothly, but a system error message will appear when executed.

2.After the Theapp configuration is complete, the WinMain is coming out. but we didn't write the code, and is prepared by MFC and added directly to the application code by the linker , whose code can be viewed in APPMODUL.CPP:

extern "C" int winapi//_t is a macro _tWinMain (HInstance hinstance, hinstance hprevinstance,lptstr lpcmdline to support Unicode preparation, int ncmdshow) {//Call shared/exported Winmainreturn afxwinmain (hinstance, hPrevInstance, lpCmdLine, nCmdShow);}

3. as seen above, the function body is called the Afxwinmain function (in WINMAIN.CPP), the main part of the function is as follows:

int AFXAPI Afxwinmain (hinstance hinstance, hinstance hprevinstance, LPTSTR lpcmdline, int ncmdshow) {int nreturncode =-1; cwinthread* pThread = Afxgetthread ();//Get pointer to current interface thread object cwinapp* PAPP = AfxGetApp ();//Get pointer to Application object//AFX Internal Initializationif (! AfxWinInit (HInstance, hPrevInstance, lpCmdLine, nCmdShow)//Assign a value to a partial member variable and initialize the thread goto initfailure;//APP Global initializations (rare) if (papp! = NULL &&!papp->initapplication ())//Perform MFC internal management goto initfailure;//Perform Specific Initializationsif (!pthread->initinstance ())//Perform window-related operations {if (Pthread->m_pmainwnd! = NULL) {TRACE0 (" warning:destroying non-null m_pmainwnd\n ");p Thread->m_pmainwnd->destroywindow (); Nreturncode = Pthread->exitinstance (); goto initfailure;} Nreturncode = Pthread->run ();//The opening of the message loop initfailure:afxwinterm (); return nreturncode;} 

4. in the above function body, AfxWinInit is called again, the function is defined in APPINIT.CPP, the main part is as follows:

BOOL AFXAPI afxwininit (hinstance hinstance, hinstance hprevinstance, LPTSTR lpcmdline, int ncmdshow) {//fill in the Initia L State for the applicationcwinapp* papp = AfxGetApp (); if (papp! = NULL) {//Windows specific initialization (not done if n o CWinApp)//Assign a value papp->m_hinstance = Hinstance;papp->m_hprevinstance = Hprevinstance;papp->m_ for the Application object's partial member lpCmdLine = Lpcmdline;papp->m_ncmdshow = Ncmdshow;papp->setcurrenthandles ();} Initialize thread specific data (for main thread) if (!afxcontextisdll) afxinitthread ();//Call = = = >return TRUE;}

5. Finally, the Afxinitthread function is called. The function is defined in THRDCORE.CPP and reads as follows:

void AFXAPI Afxinitthread () {if (!afxcontextisdll) {//Set message Filter proc_afx_thread_state* Pthreadstate = AfxGetThreadState (); ASSERT (Pthreadstate->m_hhookoldmsgfilter = = NULL);p Threadstate->m_hhookoldmsgfilter =:: SetWindowsHookEx (WH_ Msgfilter,_afxmsgfilterhook, NULL,:: GetCurrentThreadID ()); #ifndef _afx_no_ctl3d_support//intialize CTL3D for this thread_afx_ctl3d_state* pctl3dstate = _afxctl3dstate;if (pctl3dstate->m_pfnautosubclass! = NULL) (*pCtl3dState- >m_pfnautosubclass) (AfxGetInstanceHandle ());//Allocate thread local _afx_ctl3d_thread just for automatic termination_afx_ctl3d_thread* ptemp = _afxctl3dthread;ptemp;  Avoid unused Warning#endif}}

The function primarily initializes the related state of the thread and, by the way, sets a "hook". The declaration of the hook function is as follows:

Hhook WINAPI SetWindowsHookEx (__in int idhook,//hook type, i.e. it handles message type __in HOOKPROC LPFN,//callback function address __in hinstance Hmod,//Application instance Handle. If dwThreadID identifies a thread created by the current process, and the subroutine code is in the current process, hmod must be null. __in DWORD dwThreadID); The thread ID associated with the installed hook child threads

The Wh_msgfilter hooks set in the body of the function allow us to monitor messages that are passed to menus, scroll bars, message boxes, and messages that are passed to the dialog box that was established by the application that installed the hook thread.

6. OK, so far the call to the AfxWinInit function is completely over, and the next call is the InitApplication function.

Papp->initapplication ();

Where initapplication is a virtual function and is not rewritten in this class, it calls the corresponding initapplication function of the parent class, which is equivalent to: CWinApp:: InitApplication ();

The function is defined in APPCORE.CPP and reads as follows:

BOOL cwinapp::initapplication () {if (Cdocmanager::p Staticdocmanager! = null) {if (M_pdocmanager = = null) M_pdocmanager = Cdocmanager::p Staticdocmanager; Cdocmanager::p staticdocmanager = NULL;} if (M_pdocmanager! = null) m_pdocmanager->adddoctemplate (null); elsecdocmanager::bstaticinit = False;return TRUE;}

The operations are related to MFC internal management operations.

7. the next steps are: pthread->initinstance ();

Afxgetthread () Returns a pointer to the current interface thread object, AfxGetApp () returns a pointer to the Application object, and if the application (or process) has only one interface thread running, then both return a global Application object pointer. This global Application object is the default Theapp object of the MFC application framework.

When we call Afxgetthread, there is only one interface thread running. In other words, the above statement invocation is also equivalent to: Papp->initinstance (); Well, this is the first time you can actually see the code you want to analyze in our own project. Part of the code for the InitInstance function is automatically generated in the CPP file of the class that inherits Cwndapp, and the main content is as follows:

BOOL cmywinapp::initinstance () {cmyframewnd* Pmyframewnd = new cmyframewnd;//Register related window class Pmyframewnd->showwindow (m_ nCmdShow);p Myframewnd->updatewindow (); return TRUE;}

8. It is clear that the default constructor for Cmyframewnd should be called next. In this class, the automatically generated code does nothing, but the related operations of its parent class CFrameWnd are also called. The key step in the CFrameWnd constructor is to call the CFrameWnd::Create function. The main operations of the function are as follows:

BOOL cframewnd::create (LPCTSTR lpszclassname, LPCTSTR lpszwindowname, DWORD dwstyle, const rect& RECT, cwnd* PParentW nd, LPCTSTR lpszmenuname, DWORD dwExStyle, ccreatecontext* pContext)/* First parameter: Specifies the Wndclass window class, Placing null is to produce a standard frame window with the Windows class built into MFC. Second parameter: Specify the window caption The third parameter: Specify the window style, default is ws_overlappedwindow fourth parameter: Specify the position and size of the window fifth parameter: Specifies the parent window. For a top-level window, this value should be null, which means no (in fact, the parent window is desktop). Sixth parameter: Specify the menu seventh parameter: Specify the expansion style of the window eighth parameter: pointer to a CCREATECONTEXT structure, which is used by the framework to initialize the window in a program with Document/view structure. */{hmenu HMENU = null;if (lpszmenuname! = NULL) {//search for an instance that contains the menu resource (the current process or a mounted dll) hinstance HInst = Afxfindresourcehandl ( Lpszmenuname, Rt_menu);//Load Menu resource if ((HMenu =:: LoadMenu (HInst, lpszmenuname)) = = NULL) {TRACE0 ("warning:failed to load men U for cframewnd.\n "); PostNcDestroy (); Perhaps delete to C + + Objectreturn FALSE;}} M_strtitle = lpszWindowName; Store the window caption for later use (such as refresh display)//Call Cwnd::createex () if (! CreateEx (dwExStyle, lpszClassName, lpszWindowName, Dwstyle, Rect.left, Rect.top, Rect.right–rect.left, Rect,bottom–re Ct.top, PPARENTWND-&GT GetSafeHwnd (), HMenu, (LPVOID) pContext) {if (HMenu! = NULL) DestroyMenu (hMenu);//If creation fails, release the menu resource return FALSE;} return TRUE;}
9.In the upper function, the most important operation is to call the CreateEx function again. However, the function has not been redefined since CFrameWnd, so the CreateEx function defined in CWnd is called. The function is defined in WINCORE.CPP, and the main operations are as follows:
BOOL CWnd:: CreateEx (DWORD dwExStyle, LPCTSTR Lpszclassname,lpctstr lpszWindowName, DWORD dwstyle,int x, int y, int nwidth, int nheigh  T,hwnd hwndparent, HMENU nidorhmenu, lpvoid lpparam) {//Allow modification of several common create parameterscreatestruct Cs;cs.dwexstyle = Dwexstyle;cs.lpszclass = Lpszclassname;cs.lpszname = Lpszwindowname;cs.style = DwStyle;cs.x = X;cs.y = y;cs.cx = nwidth;cs.cy = Nheight;cs.hwndparent = Hwndparent;cs.hmenu = Nidorhmenu;cs.hinstance = AfxGetInstanceHandle (); Cs.lpcreateparams = Lpparam;if (! PreCreateWindow (CS)) {PostNcDestroy (); return FALSE;} Afxhookwindowcreate (this); HWND hwnd =:: CreateWindowEx (Cs.dwexstyle, Cs.lpszclass,cs.lpszname, Cs.style, Cs.x, Cs.y, cs.cx, Cs.cy,cs.hwndparent, Cs.hmenu, Cs.hinstance, Cs.lpcreateparams), ...} 

in the above function, the PreCreateWindow and:: CreateWindowEx two functions are called successively. The main operations of PreCreateWindow are defined in WINFRM.CPP, and the main contents are as follows:

BOOL CFrameWnd::P Recreatewindow (createstruct& cs) {if (Cs.lpszclass = = NULL) {VERIFY (Afxdeferregisterclass (afx_ Wndframeorview_reg)); cs.lpszclass = _afxwndframeorview;  Color_window Background} ...}

One . It also calls the Afxdeferregisterclass function (this is actually a macro). It is defined in AFXIMPL.H, as follows:

#define AFXDEFERREGISTERCLASS (Fclass) afxenddeferregisterclass (Fclass)

There is also a call to the Afxenddeferregisterclass function, which is defined in WINCORE.CPP, and the main operations are as follows:

BOOL AFXAPI Afxenddeferregisterclass (LONG ftoregister) {//Mask off all classes that is already registeredafx_module_stat e* pModuleState = afxgetmodulestate () ftoregister &= ~pmodulestate->m_fregisteredclasses;if (FToRegister = = 0) return TRUE;   LONG fregisteredclasses = 0;//common Initializationwndclass wndcls;memset (&wndcls, 0, sizeof (WNDCLASS)); Start with NULL Defaultswndcls.lpfnwndproc = Defwindowproc;wndcls.hinstance = AfxGetInstanceHandle (); wndcls.hCursor = Afxdata.hcurarrow;initcommoncontrolsex init;init.dwsize = sizeof (init);//work to register classes as specified by Ftore Gister, populate fregisteredclasses as we GOif (Ftoregister & Afx_wnd_reg) {//child windows-no Brush, no icon, safes T default class Styleswndcls.style = Cs_dblclks | Cs_hredraw | Cs_vredraw;wndcls.lpszclassname = _afxwnd;if (AfxRegisterClass (&wndcls)) fregisteredclasses |= AFX_WND_REG;} if (Ftoregister & Afx_wndolecontrol_reg) {//OLE Control windows-use parent DC for SPEEDWNDCLS.STyle |= CS_PARENTDC | cs_dblclks | Cs_hredraw | Cs_vredraw;wndcls.lpszclassname = _afxwndolecontrol;if (AfxRegisterClass (&wndcls)) fRegisteredClasses |= AFX_ Wndolecontrol_reg;}   if (Ftoregister & Afx_wndcontrolbar_reg) {//Control bar Windowswndcls.style = 0; Control bars don ' t handle double clickwndcls.lpszclassname = _afxwndcontrolbar;wndcls.hbrbackground = (hbrush) (color_ Btnface + 1); if (AfxRegisterClass (&WNDCLS)) fregisteredclasses |= Afx_wndcontrolbar_reg;} if (Ftoregister & Afx_wndmdiframe_reg) {//MDI Frame window (also used for splitter window) Wndcls.style = Cs_dblclks;wn Dcls.hbrbackground = Null;if (_afxregisterwithicon (&wndcls, _afxwndmdiframe, Afx_idi_std_mdiframe)) Fregisteredclasses |= Afx_wndmdiframe_reg;} if (Ftoregister & Afx_wndframeorview_reg) {//SDI Frame or MDI child windows or views-normal Colorswndcls.style = Cs_ dblclks | Cs_hredraw | Cs_vredraw;wndcls.hbrbackground = (hbrush) (Color_window + 1); if (_afxregisterwithicon (&wndcls, _afxWndFrAmeorview, Afx_idi_std_frame)) fregisteredclasses |= Afx_wndframeorview_reg;} if (Ftoregister & Afx_wndcommctls_reg) {//This flag was compatible with the old InitCommonControls () APIINIT.DWICC = IC C_win95_classes;fregisteredclasses |= _afxinitcommoncontrols (&init, afx_win95ctls_mask); FToRegister &= ~AFX _win95ctls_mask;} ......}

The above function registers some window classes before creating the window, depending on the function of the window. The main use of the two functions _afxregisterwithicon and AfxRegisterClass.

The AfxRegisterClass function is actually called inside the function _afxregisterwithicon. The function is defined as follows:

Afx_static BOOL AFXAPI _afxregisterwithicon (wndclass* pwndcls,lpctstr lpszclassname, UINT Nidicon) {pwndcls-> lpszClassName = lpszClassName; HInstance HInst = AfxFindResourceHandle (Makeintresource (Nidicon), Rt_group_icon); if (Pwndcls->hicon =:: LoadIcon ( HInst, Makeintresource (Nidicon))) = = NULL) {//Use default icon Specifies Iconpwndcls->hicon =:: LoadIcon (NULL, Idi_ application);} Return AfxRegisterClass (PWNDCLS);}

The code that makes sense in this article in AfxRegisterClass is as follows:

BOOL AFXAPI AfxRegisterClass (wndclass* lpwndclass) {wndclass wndcls;if (GetClassInfo, Lpwndclass-> lpszClassName, &wndcls)) {//class already Registeredreturn TRUE;} if (!::registerclass (Lpwndclass)) {TRACE1 ("Can ' t register window class named%s\n", Lpwndclass->lpszclassname); return FALSE;} ... return TRUE;}

function to create the corresponding window object by calling RegisterClass to register the window class so that it can be used later for the CreateWindowEx function. Now that the CREATE function is finished, the Cmyframewnd object is also constructed.

The following execution statements are:

Pmyframewnd->showwindow (m_ncmdshow);p Myframewnd->updatewindow ();

Call the ShowWindow function to display the window, and call the UpdateWindow function to send the WM_PAINT message to the program to drive the drawing of the window. To this InitInstance function finally completed, leaving the last operation:pthread->Run();

As with the Pthread->initinstance () above, the call is also papp-> run (); Because the run virtual function is not overridden in this class, the run function in the parent class CWinApp is called. The function is defined in APPCORE.CPP and reads as follows:

int CWinApp::Run () {if (m_pMainWnd = = NULL && Afxolegetuserctrl ()) {//not launched/embedding or/automation, but H As no main window! TRACE0 ("Warning:m_pmainwnd is NULL in cwinapp::run-quitting application.\n"); Afxpostquitmessage (0);} return Cwinthread::run ();}

In normal cases, the above function calls the Cwinthread::run function. The function is defined in THRDCORE.CPP, and the main contents are as follows:

int Cwinthread::run () {assert_valid (this);//For tracking the idle time statebool bidle = TRUE; LONG Lidlecount = 0;//Acquire and dispatch messages until a wm_quit message is received.for (;;) {//Phase1:check to see if we can do idle Workwhile (bidle &&!::P eekmessage (&m_msgcur, NULL, NULL, NULL, pm_n Oremove)) {//Call OnIdle while in Bidle Stateif (! OnIdle (lidlecount++)) Bidle = FALSE; Assume "no idle" state}//phase2:pump messages while availabledo{//pump message, but quit on wm_quitif (! PumpMessage ()) return ExitInstance ();//reset "no idle" state after pumping "normal" Messageif (Isidlemessage (&m_ Msgcur)) {bidle = True;lidlecount = 0;}} while (::P eekmessage (&m_msgcur, NULL, NULL, NULL, Pm_noremove));} ASSERT (FALSE);  Not reachable}

At last we saw the familiar figure of the peekmessage we dreamed of. Little Joe has appeared, so Big Joe? Don't worry, look at PumpMessage on the line, people are just a little shy.

the definition of pumpmessage in the same file, the main contents are as follows:

BOOL CWinThread::P umpmessage () {assert_valid (this); if (!::getmessage (&m_msgcur, NULL, NULL, NULL)) {return FALSE;} ... if (m_msgcur.message! = Wm_kickidle &&! PreTranslateMessage (&m_msgcur)) {:: TranslateMessage (&m_msgcur);::D ispatchmessage (&m_msgCur);} return TRUE;}

Yes, in addition to GetMessage, there are translatemessage and DispatchMessage sisters Flowers, the appearance of all appeared. Now the message loop has been opened, the program successfully ran, and work.

Have to say, write here feel body is hollowed out, I want to drink a glass of water, think about life.



Naughty MFC (2)

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.