Going into the MFC Forum (2) 2003-4-1 8:09:12 Yesky Mao Shou Hao Reading: 2420mfc Winmain Using MFC Programming Programmer Just started to make such a question: Where is my program starting? The answer is: starting from WinMain (). This problem is that the WinMain () function is not seen in the MFC application they have written. This function is hidden in the MFC framework, and the MFC designer works very well (this is mainly due to the programming mechanism for Window's message-driven programming mechanism so that it is easy to make a universal WinMain (), so in general No need to change the code of Winmain (), the MFC designer does not advocate the programmer to modify the code of WinMain (). In the MFC, the code that actually implements WinMain () is an AFXWINMAIN () function (you know this is a global MFC function based on its prefix AFX). A Win32 application (or process) is composed of one or more concurrent threads, where the first start-up thread is called the main thread, under Window, generally divide the thread into two major classes, interface threads, and working threads. The working thread is a general thread. It does not have a window, no message queue, etc., the interface thread has one or more windows, with a message queue and other elements that are exclusive to interface threads. Before discussing AFXWinMain (), first mention two important classes in the MFC, CWINTHREAD and CWINAPP, Cwinthread is class used to encapsulate interface threads, and CWINAPP is derived from CwinThread. In CwinThread, there are two important virtual functions initInstance () and ExitiniStance (), and the MFC programmers should be familiar with these two functions. In CWINAPP, another virtual function initApplication () is added to discuss the main purpose of AFXWinMain () is how these functions are called.
AfxWinMain () code is as follows: int AFXAPI AfxWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {ASSERT (hPrevInstance == NULL); file: // at win32, hPrevInstance always NULL int nReturnCode = -1; CWinThread * pThread = AfxGetThread (); CWinApp * pApp = AfxGetApp (); // AFX internal initialization if (AfxWinInit (hInstance, hPrevInstance, lpCmdLine, nCmdShow)!) goto InitFailure; // App global initializations (rare) if (pApp! = NULL && pApp-> InitApplication ()) goto InitFailure; // Perform specific initializations if) {if (pThread-> m_pMainWnd = NULL) {TRACE0 ( "Warning! (pThread-> InitInstance (!): Destroying non-NULL! m_pMainWnd / n "); pThread-> m_pMainWnd-> DestroyWindow ();} nReturnCode = pThread-> ExitInstance (); goto InitFailure;} nReturnCode = pThread-> Run (); InitFailure: AfxWinTerm (); return nReturnCode;} in In the above code, AFXGETTHREAD () returns the pointer of the current interface thread object, and AFXGetApp () returns the pointer of the application object, if the application (or process) is only one interface thread, then the two returns Both a global application pair Pointer, this global application object is the APP object by the MFC application framework (when using AppWizard to generate an SDI or MDI application, AppWizard will add this statement, and AFXGetApp () returned to this THEAPP address). Cwinapp :: initApplication (), cwinthread :: InitInstance (), cwinthread :: exitInstance () is called, I know from the code above, I don't have to repeat it. Below we put the focus on cwinthread :: run (). MFC's Control Center - Cwinthread :: Run () CWINTHREAD :: Run () is the control center of the MFC, and there is no exaggeration at all. In the MFC, all the assignments from the message queue are completed in the cwinthread :: run () function, like afxwinmain (), this function is also invisible to the programmer, its truth is AfxwinMain () The same. The first thing to mention is that the message taken from the message team, the MFC is distributed according to a particular mode according to the type of message, and this distribution mode is the MFC's own definition.
The fixed message distribution process and the virtual function of the active change in this process constitute the MFC message distribution mode. The application can locally customize these virtual functions to locally customize their messages distribution mode. It is through these virtual functions, and the MFC provides adequate flexibility for the application. All the code discussed below comes from the Threadcore.cpp file in the MFC source code, which are members of Cwinthread. CWINTHREAD :: Run () Cwinthread :: Run () code is as follows: int CWINTHREAD:: Run () {assert_valid (this); // for tracking the iDLE TIME State Bool Bidle = true; long lidlex = 0; / / acquire and dispatch messages until a WM_QUIT message is received for (;;) {// phase1:. check to see if we can do idle work while (bIdle && :: PeekMessage (& m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)! ) {// call onidle while in bidle state if (! Onidle (LidleCount )) BIDLE = false; // Assume "no idle" state} // Phase2: pump message while available do {// pump message, but quit on wm_quit If (! pumpMessage ()) Return EXITINSTANCE (); // reset "no idle" state after pumping "normal" message if (isidleMessage) {bidle = true; lidlecount = 0;}} while (: peekmessage) & m_msgcur, null, null, pm_noremove);} assert (false); // not reachable} CWINTHREAD:: Run () processing procedure is as follows: First, according to the idle logo and the message queue is empty, the current judgment is currently Whether the thread is in an idle state (this " The meaning of idle "is different from the meaning of the operating system. It is the so-called" idle "of the MFC. If so, call CwinThread :: OnIdle (), which is also a virtual function we are more familiar. If not, remove the message from the message queue, proceed until the message queue is empty. Here, we found that the MFC does not call GetMessage () to take a message from the thread message queue, but call PeekMessage ().
The reason is that getMessage () is a function with synchronous behavior. If there is no message in the message queue, getMessage () will always block, so that the thread is on the sleep state until there is one or more messages in the message queue, the operating system will Wake up this thread, getMessage () will return. If the thread is in sleep, it will not make the thread with the so-called "idle" state of the MFC; and PeekMessage () is a function with asynchronous behavior if the message queue is No message, it will return to 0 immediately, which will not cause the thread to sleep. In the above code, two functions are worth exploring, one is idle processing function onIdle (), and another is the message distribution processing function PumpMessage (). Don't ignore the CWINTHREAD's onder () function, which makes a lot of meaningful things. The following discusses PumpMessage (), onIdle () will be discussed in the following chapters. CWINTHREAD :: Run () core - Cwinthread :: PumpMessage () Title emphasizes the importance of pumpMessage (), Run () is the control center of the MFC, and pumpMessage () is the core of Run (), so from MFC The true control center is pumpMessage (). PumpMessage () code is extremely simple: BOOL CWinThread :: PumpMessage () {ASSERT_VALID (this); if (:: GetMessage (& m_msgCur, NULL, NULL, NULL)!) Return FALSE; // process this message if (m_msgCur.message ! = WM_KICKIDLE && PreTranslateMessage (& m_msgCur)) {:: TranslateMessage (& m_msgCur); :: DispatchMessage (& m_msgCur);}! return TRUE;} first, PumpMessage () call to the GetMessage () to take a message from the message queue, since PumpMessage ( ) Is called when there is a message in the message queue, so getMessage () will immediately return, determine that the currently removed message is not a WM_Quit message according to its return value (this message is generally put into POSTQUITMESSAGE () Thread message queue), if yes, return false, cwinthread :: run () This exits, cwinthread :: run () calls cwinthread :: exitInstance () exits the application. Behind getMessage () is the translateMessage () and DispatchMessage () functions we are familiar with. It can be seen that it is determined whether translateMessage () and DispatchMessage () are determined by a return value of a name as a PretranslateMessage () function. If the function returns True, the message will not be distributed to the window function processing. As far as my personal point of view, I have this preted (), so that the MFC can flexibly control the distribution mode of the message, it can be said that PretranslateMessage () is the MFC message distribution mode.