Many do software development people have a kind of the spirit of the matter, such as the MFC we have been using, very convenient, do not learn too much of the original rational knowledge can make a variety of window procedures, but like to delve into the friend certainly want to know, exactly what Microsoft helped us to do something, let us in its framework can be simple to write programs. This article began to share with you a colleague written by the MFC core mechanism analysis (a little finishing), the language is simple and understandable, after reading this analysis of the series, I believe left to you is the MFC operating mechanism of deep understanding.
an overview of the six core mechanisms of MFC
We chose C + +, mainly because it is artistic enough, free enough, we can implement various ideas, and MFC encapsulates a variety of functions that are flexible to use, how can we tolerate this "black box" operation? So the research and analysis of the core mechanism of MFC becomes inevitable.
First, list the six core mechanisms of MFC to speak:
1, the initialization of MFC program.
2, run-time type identification (RTTI).
3, dynamic creation.
4, permanent preservation.
5, message map.
6, Message delivery.
This article is about the first part, the MFC program initialization process.
Simple MFC Window Program
Design a simple complete MFC program that produces a window. Of course this does not allow AppWizard to generate for us automatically. We can write under the WIN32 application project as follows:
#include <afxwin.h>classMYAPP: PublicCWinApp { Public: BOOL InitInstance ()//② Program in point {CFrameWnd*frame=NewCFrameWnd ();//Structural FrameworkM_pmainwnd=frame;//set the m_pMainWnd to frame; Frame->create (NULL,"The simplest window");//Building a frameworkFrame->showwindow (Sw_show);//Show Framereturn true;//return } }; MYAPP Theapp; //① Build the application.
Set the link MFC library, run, you can see a window.
From above, you can see that building an MFC window is easy and only two steps: One is to derive an application class from CWinApp (here is MyApp) and then build the Application object (Theapp), You can create a window that you need (that is, what you need to do in InitInstance ().)
The whole program, just rewrite a InitInstance () function, create an object (Theapp), is a complete window program. This is the magic of "black box" Operation!
When we were trying to applaud Microsoft, we suddenly felt empty, and we wanted to know what Microsoft did for us, and what we needed to do when we wanted to make our own programs, even in the few lines of the program, where we didn't know, for example, why there's a m_pmainwnd pointer variable , where does it come from and where to go again? Think about how wonderful it is to program in DOS. Uh, what variables do we need, what variables to declare, what functions to use, what functions to write, or reference libraries ... But what do we do now?
We can reverse the thinking, MFC to achieve this effect, it is how to do it? First we must understand, VC + + is not a language, it is like we learn C language when a similar Notepad editor (please forgive my inappropriate analogy), so, in VC we use C + + language programming, C + + is the fundamental (beginners always think VC is a what new language, A complex language that is much more advanced than C + +, Khan). Speaking so much, I would like to use a simple word to summarize the "MFC black Box", is to add some cured "C + + code" for our program.
Since the MFC black box has helped us to add code, let's think about what kind of code it will help us to add. Will he help us with the code that solves the unary two-time equation? Of course not, so it's actually a common code that is required to write a window program every time.
And what is GM like? Every time we write the WinMain () function, we have to register the window, generate the window, the message loop, the callback function ... That is, every time you want something, let them disappear from our eyes, let MFC help Write!
Manual Mode the proposed MFC program Initialize
To know the MFC initialization process, you can certainly track the execution of the program. But this kind of tracking is very troublesome, I believe everybody will follow the dizzy. I think even if you understand the MFC code, it is easy to let people find the north, we do not understand when, in the thousands of lines of the maze of procedures to find out how to export?
We want to change a method, instead of rewriting an MFC library, WOW! Do not laugh, be careful of your teeth, I am not crazy (although the Madman also said that he is not crazy). What we want to write is the simplest MFC class library, that is, the MFC macro, the theoretical things to write out. We're going to use the most streamlined code to be simple enough to just run.
1. MFC libraries that need to be "rewritten"
Since we are writing this section of the MFC program initialization process, above we also have an executable MFC program. The program only uses two MFC classes, one is CWinApp and the other is CFrameWnd. Of course, there are many equally important MFC classes such as view classes, document classes, and so on. But in the above program can not be used, so temporarily omitted it (in short, for the sake of simplicity).
OK, now start writing the MFC class Library ... Alas, there is a big problem before, is to let everyone recite the MFC hierarchy chart. God, that fish net how to remember live, but since we want to understand him, must know it is derived from there.
Considering that everyone is working hard, let's look at the parent-child relationship of the above two classes (the arrow stands for derivation):
Cobject->ccmdtarget->cwinthread->cwinapp-> its own rewrite of the InitInstance () application class.
CObject (IBID.)->ccmdtarget (IBID.)->cwnd->cframewnd
After you see the hierarchy diagram, you can finally start writing the MFC class library. According to the above hierarchy, we can write the following six classes (for the sake of intuition, eliminating the constructors and destructors).
///////////////////////////////////////////////////////// classcobiect{};//the base class for the MFC class. classCCmdTarget: Publiccobject{}; ------------------------------------------------classCWinThread: Publicccmdtarget{}; classCWINAPP: Publiccwinthread{}; ------------------------------------------------classCWnd: Publicccmdtarget{}; classCFrameWnd: Publiccwnd{}; /////////////////////////////////////////////////////////
Let's think about it, what should there be in the class above? It is immediately conceivable that the CWinApp class or its base class CCmdTarget inside should have a virtual function virtual BOOL InitInstance (), yes, because there is the entry point of the program, the place of the initialization program, that is naturally unavoidable. Maybe some friends will say, anyway InitInstance () must be overloaded in a derived class, I do not define in the CCmdTarget or CWinApp class, left to CWinApp derived classes to increase the function can be. This problem may be a bit more and more distant, but I believe that C + + friends of the virtual function should be not too many problems. In general, it is much easier to define a virtual function as a programmer if it is clear that a function of a base class is to be used by a derived class.
Also a lot of friends ask, why C + + does not automatically define all the functions of the base class as virtual functions, so it can save a lot of trouble, so that all functions in accordance with the derived class has a defined function to invoke the derived class, not defined on the call base class, do not write the trouble of the virtual good! In fact, many object-oriented languages have done so. But define a virtual function to generate a virtual function table, to occupy the system space, the more virtual function, the larger the table, sometimes outweigh the gains! It's a bit of a shiver here, because in the message map that we're going to explain later, we'll all be more likely to experience this.
Above we have solved a problem, is to write a virtual BOOL InitInstance () in Ccmdtarge.
2. WinMain () function and CWinApp class
We want to think about it, we also want us MFC "Hide" more things: WinMain () function, Design window class, window registration, message loop, callback function ... We immediately thought the encapsulation wanted to encapsulate them. Everyone seems vaguely aware of the encapsulation WinMain () is not easy, think WinMain () is a special function, many times it represents the beginning and the end of a program. So in the past when we wrote the program, we wrote the program habits from WinMain () to the left of the large, to the right brace to return, end the program.
We change an angle to think, there is something can get WinMain () outside to do, many beginners, always feel WinMain () function is a big function, what function seems to be in it to really run. In fact, this understanding is very one-sided, even wrong. We can write a C + + program like this:
#include <iostream.h> class test{ public: Test () {cout< <" Please change your view of the main () function!" "<<Endl;} }; Test test1; /* ************************ */ void main () {} ///////////////////////////////////////////////////
In the above program, the main () function of the portal does nothing on the surface, but the program executes (note: The actual entry function did something we could not understand) and output a sentence (note: The global object runs first than main ()). Now you can know our WinMain () function can do nothing, the program can still run, but no this entry function program will error.
So which class does the WinMain () function put on, see the following procedure:
#include <afxwin.h> class public CWinApp { public: BOOL InitInstance () //② Program in point { AfxMessageBox (" The program can still run! "); return true ; } }; MYAPP Theapp; // ① Build the application.
As you can see, I don't have a framework, and the program can run--a dialog box pops up (if no WinMain () function program will get an error). Above I write this or for the sake of intuition, in fact, we just write two lines of the program:
#include <afxwin.h>
CWINAPP Theapp; The entire program constructs only one CWinApp class object, the program can run!
So, as long as we construct the CWinApp object, we can execute the WinMain () function. We immediately believe that the WinMain () function is in the CWinApp class or its base class, not in other classes. In fact, this view is wrong, we know that when writing a C + + program, it is not possible for you to include the entry function in a class, WinMain () is called by the system, and our normal program itself calls the function has an essential difference. We can briefly imagine that when the CWinApp object is constructed, WinMain () executes.
Now it's clear that most of the "Common code (we want to encapsulate the hidden stuff)" can be put into the CWinApp class, so how does it work? Why do you construct a CWinApp class object to "Automatically" execute so many things.
Let's think about it, after the CWinApp class object is constructed, it "automatically" executes its own constructor. Then we can put the code that we want to execute "automatically" in the constructor of the CWinApp class.
Then the CWinApp class may be designed to do so (whichever is more correct):
classCWINAPP: Publiccwinthead{ Public:VirtualBOOL InitInstance ();//The in point of an interpreted programCWINAPP:: CWinApp () {//constructor Function ////////////////////////WinMain ();//This is a mistake everyone sees.Create ();//design, create, update display WindowsRun ();//message Loops ////////////////////// } };
After writing, we immediately feel that it seems wrong, WinMain () function here as if there is really no use, and can be called this way (please allow me to put my hand on the Bible to declare: WinMain () is not a normal function, it is to assume the initialization of the application, including the initialization of the global variables, is called by the system rather than by the program itself, and WinMain () returns, the program ends, and the process is undone). Then look at the Create () function, which determines what window to design and what window to create? If it can be determined in the CWinApp constructor, we later design MFC program window is a kind of, this does not seem reasonable.
Looking back, can we make the WinMain () function A statement that does not contain it? No, let's take a look at the four parameters of the WinMain () function:
WinMain (HInstance, HINSTANCE, LPSTR, int)
Where the first parameter points to an instance handle, we must specify the instance handle when designing the WNDCLASS. Our window programming, certainly to design the window class. So, WinMain () to write the following simple:
int WinMain (hinstance hinst, hinstance hprevinstance, LPSTR lpcmdline, int ncmdshow)
{Hinstance=hinst}
Now that the instance handle is not known until the program starts executing, the Create () function that we use for creating the window must also be inside WinMain () (because if you wait until WinMain () finishes executing, the program ends, the process is undone, and of course the Create () window is not created).
And look at the run () (message loop) function, can it run outside of the WinMain () function? As we all know, the message loop is the same few lines of code, but let's not try to put it out of the WinMain () function.
So our WinMain () function can be written like this:
WinMain (...)
{
...... The window class object executes the Create Window function ...
...... The program class object executes the message loop function ...
}
For the WinMain () problem, we have to summarize, we encapsulate the time is not to encapsulate it into the CWinApp class, but because of WinMain () invariance (or have rules to follow), MFC is fully capable of constructing CWinApp class object, we Help us finish those lines of code.
Turning a big circle, we seem to be back to the beginning of the SDK programming. But now we can clearly know that the surface of MFC and SDK programming is very different, but in essence, MFC just encapsulates the SDK function in the form of a class, after encapsulation, we can only need a few lines of code in the WinMain () function to complete a window program. We also know how to encapsulate the Application class (CWINAPP) and the main frame window class (CFRAMEWND). Let's start by designing these two classes.
3, "Rewrite" of MFC library
For the sake of simplicity, we ignore the writing of the base and derived classes of these two classes, which may be regarded as irresponsible, but I feel that this will relieve the burden and avoid a better understanding of the various types of wear and clothing that we are able to understand (we specify in the key areas). Also, I write all the code in the same file, so that everyone does not look so hard, but this is the least advocating code-writing method, we do not learn Oh!
#include <windows.h>hinstance hinstance; classCFrameWnd {HWND hwnd; Public: CFrameWnd (); //You can also call Create () hereVirtual~CFrameWnd (); intCreate ();//class just keep an eye on this function! BOOL Showwnd (); }; classCWinApp1 { Public: CFrameWnd* M_PMAINWND;//inside the real MFC//It is a CWnd pointer, but here because does not write CWnd class//just write it as the CFrameWnd pointerCwinapp1* M_pcurrentwinapp;//point to the Application object itselfCWinApp1 (); Virtual~CWinApp1 (); VirtualBOOL InitInstance ();//MFC was originally a function that must be overloaded, the most important function!!!! VirtualBOOL Run ();//message Loops}; Cframewnd::cframewnd () {} CFrameWnd::~CFrameWnd () {}intCFrameWnd::Create ()//Encapsulation Create window code{wndclass wndcls; Wndcls.style=0; Wndcls.cbclsextra=0; Wndcls.cbwndextra=0; Wndcls.hbrbackground=(Hbrush) getstockobject (White_brush); Wndcls.hcursor=loadcursor (Null,idc_cross); Wndcls.hicon=LoadIcon (Null,idc_arrow); Wndcls.hinstance=hinstance; Wndcls.lpfnwndproc=defwindowproc;//The Default window procedure function. //You can imagine MFC as a common window process. Wndcls.lpszclassname="window class name"; Wndcls.lpszmenuname=NULL; RegisterClass (&wndcls); HWND=createwindow ("window class name","Window Instance header name", Ws_overlappedwindow,0,0, -, -, Null,null,hinstance,null); return 0; } BOOL Cframewnd::showwnd ()//Show Update Window{ShowWindow (hwnd,sw_shownormal); UpdateWindow (HWND); return 0; } ///////////// Cwinapp1::cwinapp1 () {M_pcurrentwinapp= This; } CWINAPP1::~CWinApp1 () {}//The following is the InitInstance () function, which is rewritten for the derived class of CWinApp in MFC .//here for the convenience of understanding, put it in the CWinApp class inside complete! //you just have to remember that the real MFC overrides this function in the derived class. BOOL cwinapp1::initinstance () {m_pMainWnd=NewCFrameWnd; m_pMainWnd-Create (); m_pMainWnd-Showwnd (); return 0; } BOOL Cwinapp1::run ()//////////////////////Encapsulating message Loops{msg msg; while(GetMessage (&msg,null,0,0) {translatemessage (&msg); DispatchMessage (&msg); } return 0; } //////////////////////////////////////////////////////Encapsulating message LoopsCWinApp1 Theapp; //application Objects (global) intWINAPI WinMain (hinstance hinst, hinstance hprevinstance, LPSTR lpCmdLine,intncmdshow) {hinstance=hinst; CWinApp1* papp=Theapp.m_pcurrentwinapp; //the real MFC is going to write a global function AfxGetApp to get the CWinApp pointer. Papp->InitInstance (); Papp-Run (); return 0; }
The code is so long that it actually only writes three functions, one is the Create () of the CFrameWnd class, and the second is the InitInstance () and run () of the CWinApp class. In this particular note is InitInstance (), the real MFC, that is we have to build the window of our own needs, we rewrite this function.
As you can see, after encapsulating the above two classes, you can create a window program by writing a few lines of code in the entry function WinMain. In MFC, because the WinMain function is a fixed number of lines of code, so MFC can definitely help us do it automatically (MFC's specialty is to help us to complete the regular code), so we create an MFC application, we do not see the WinMain function.
One of the six core mechanisms of MFC: Initialization of MFC programs