[Original] the ins and outs of MFC programming

Source: Internet
Author: User

MFC Program Design
The ins and outs
Question: I have been thinking about writing this thing some days ago. I started my blog with a name (but it is called <winmain Function Analysis of the MFC framework program>), so I didn't care about it anymore, in fact, it is just the tip of the iceberg. I still have no clear explanation about how the MFC runs. Although my blog is seldom visited, I will continue to finish this article based on the mentality of doing things.
Note: 1. The author of this article traces the code in vs2003. This code is copied in vs2003 and mfc7 is used.
2. the MFC programs of different frameworks are different. This document takes a single document as an example.
3. The reader of this article needs to have a certain SDK Foundation, and does not need much. At least know its basic framework and background!
4. The article only serves as a description, so the code will be deleted.
I still don't know where the main function of MFC is? How to run it? It's really not brilliant.
I have been familiar with jjhou's in-depth introduction to MFC. Haha, this article is intended for friends who have never read that book but want to learn about MFC programming. (Friends who haven't read the book are not buying it now ?) In fact, this article is mainly a summary and supplement to Chapter 6 of "getting down to MFC! (This article has some opinions on the different parts of this book !)
Let's get down to the truth.
If you use Appwizard to step by step next and then look for the winmain function in classview, you will be disappointed. What are the biggest characteristics of MFC? Encapsulation! The MFC package is so good that many people who want to learn it are discouraged. Let's talk less about it. Let's continue with our topic today, the main function! To tell you the truth, even if you search for all the files generated by MFC, you cannot find the word winmain. So where is it nearby?
I believe you have come up with the idea that the main function should be in the main application file. Is it the file "Your defined program name. cpp? That's it. Crtl + F again. Can you see the winmain function we are looking? You may be disappointed again, but note the following:
//////////////////////////////////////// /////////////////////////////////////
// The one and only cmyapp object

Cmyapp theapp; // The project name I created is my.
Isn't it special? Pay attention to the comment "the one and only cmyapp object". Each application has only one cmyapp object. I think you should have thought that each program of the winmain function can only have one. Is there a great relationship between this global object and the winmain function? That's right. Trust your intuition.
Note: those who know the details of C ++ must know that the global object takes precedence over the execution of the main function. If you do not know, it doesn't matter. I will tell you here: "global objects take precedence over Mian function execution and are built on stacks. Remember, remember !"
Now, we should go deep into the winmain operating mechanism. Specifically, it should be the MFC mechanism!
First, let's take a look at the library file of MFC, which can bring us many surprises. (The corresponding directory of vc6 is/Microsoft Visual Studio/vc98/mfc/src; the corresponding directory of vc7 is/Microsoft Visual Studio. NET 2003/vc7/atlmfc/src/mfc)
Now let's start from this global journey.
Cmyapp theapp;
In this case, the system executes the cwinapp constructor of the cmyapp parent class, and then executes the constructor of the cmyapp. (You have a father and a son first !), The cwinapp constructor is called.
Cwinapp Constructor (in the MFC Code provided by VC, query keywords in the form of a word or phrase in the text, and open appcore. CPP. The following uses the same search method and does not repeat it .) Find the following content:
Cwinapp: cwinapp (lpctstr lpszappname)
If (lpszappname! = NULL)
M_pszappname = _ tcsdup (lpszappname );
M_pszappname = NULL;
// Initialize cwinthread state
Afx_module_state * pmodulestate = _ afx_cmdtarget_getstate ();
Afx_module_thread_state * pthreadstate = pmodulestate-> m_thread;
Assert (afxgetthread () = NULL );
Pthreadstate-> m_pcurrentwinthread = this;
Assert (afxgetthread () = This );
M_hthread =: getcurrentthread ();
M_nthreadid =: getcurrentthreadid ();
// Initialize cwinapp state
Assert (afxcurrentwinapp = NULL); // only one cwinapp object please
Pmodulestate-> m_pcurrentwinapp = this;
Assert (afxgetapp () = This );
OK, you can do it here. Take a closer look at the code above. It has completed the startup of the thread amount of the application, and it has given the life of our program. Note:
Pthreadstate-> m_pcurrentwinthread = this;
Pmodulestate-> m_pcurrentwinapp = this;
These two lines of code are actually one thing to do.
This Code indicates that this pointer is obtained for the Global Object of cmyapp. (Why is it the pointer of cmyapp? This is currently in cwinapp? My answer is, but you are the cwinapp construction caused by the cmyapp object !!) This pointer is not an ordinary character. We will rely on it to do a lot of work later.
The member variables in cwinapp get the configuration and initial values because theapp is a global object.
After the parent class is constructed, the Child class is constructed. But we can see that Appwizard does not do anything in our subclass? Yes, it's all yours!
Cmyapp: cmyapp ()
// Todo: Add construction code here,
// Place all significant initialization in initinstance
Next is the main role of today. Search for the keyword "winmain" and many files will appear. Don't worry, because now we should first look at the winmain statement. Open appmodul. cpp:

_ Twinmain (hinstance, hinstance hprevinstance,
Lptstr lpcmdline, int ncmdshow)
// Call shared/exported winmain
Return afxwinmain (hinstance, hprevinstance, lpcmdline, ncmdshow );
Here _ twinmain is a macro named to support Unicode. What really works is afxwinmain. Check whether its parameters are the same as the winmain function of the SDK?
Search for afxwinmain again, which is actually in winmain. cpp:
Int afxapi afxwinmain (hinstance, hinstance hprevinstance,
Lptstr lpcmdline, int ncmdshow)
Assert (hprevinstance = 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 (! Pthread-> initinstance ())
If (pthread-> m_pmainwnd! = NULL)
Trace (traceappmsg, 0, "Warning: destroying non-null m_pmainwnd/N ");
Pthread-> m_pmainwnd-> destroywindow ();
Nreturncode = pthread-> exitinstance ();
Goto initfailure;
Nreturncode = pthread-> Run ();
Pay attention to five details for this code segment:
Cwinapp * PAPP = afxgetapp ();
This is the object pointer. Don't remember? The one pointing to the cmyapp! It is worth noting that afx is global and can be called at any time. (Afx is the development code of the MFC Development Team. It means that application framework legend X is only for good looks, doesn't it really mean ?!)
If (! Afxwininit (hinstance, hprevinstance, lpcmdline, ncmdshow ))
Afxwininit completes thread initialization and window class registration. For more information, see the definition in appinit. cpp.
If (PAPP! = NULL &&! PAPP-> initapplication ())
In fact, Papp and pthread are the same pointer and both are pointers to cmyapp. Here, because initapplication is not defined in cmyapp, cwinapp: initapplication () is actually called (), completed Content Management of MFC.
If (! Pthread-> initinstance ())
Because it is rewritten in cmyapp, calling it in cmyapp is actually initialization. The definition of the default window class is also completed. If you are familiar with SDK programming, you will not forget the steps for designing, registering, creating, implementing, and updating window classes. At this time, MFC thinks that you have designed the default window class.
Now you can't help wondering, what is the difference between initapplication () and initinstance?
The answer is: If you execute a program, both functions will be called. If you do not close the previous program, execute another program, then only the last function is executed.
Nreturncode = pthread-> Run ();
This step has become the active source of the program in "getting down to MFC". In my opinion, it is the step for you to drive on the accelerator. We will elaborate on it later!
After the design window class, it should be the registration. MFC automatically calls (jumps to) afxenddeferregisterclass (wincore. CPP). Five window classes are registered for you: afxwnd, afxcreatebar, afxmdiframe, afxframeorview, and afxolecontrol. The above window class MFC will be automatically converted into independent class names without two, for calling.
After the window is registered, it should be the creation of the window. At this time, cframewnd: Create () will be called. The code is located in winfrm. cpp.
Bool cframewnd: Create (lpctstr lpszclassname,
Lpctstr lpszwindowname,
DWORD dwstyle,
Const rect & rect,
Cwnd * pparentwnd,
Lpctstr lpszmenuname,
DWORD dwexstyle,
Ccreatecontext * pcontext)
Hmenu = NULL;
If (lpszmenuname! = NULL)
// Load in a menu that will get destroyed when window gets destroyed
Hinstance hinst = afxfindresourcehandle (lpszmenuname, rt_menu );
If (hmenu =: loadmenu (hinst, lpszmenuname) = NULL)
Trace (traceappmsg, 0, "Warning: failed to load menu for cframewnd./N ");
Postncdestroy (); // perhaps Delete the C ++ object
Return false;

M_strtitle = lpszwindowname; // save title for later

If (! Createex (dwexstyle, lpszclassname, lpszwindowname, dwstyle,
Rect. Left, rect. Top, rect. Right-rect. Left, rect. Bottom-rect. Top,
Pparentwnd-> getsafehwnd (), hmenu, (lpvoid) pcontext ))
Trace (traceappmsg, 0, "Warning: failed to create cframewnd./N ");
If (hmenu! = NULL)
Destroymenu (hmenu );
Return false;

Return true;
The window creation is completed, and the extended calling createex is also involved. For details, see msdn.
At this point, you can't help but ask, are we all finished with MFC? The windows for industrial production are all the same. I want to have my own style!
Don't worry, MFC provides users with an opportunity to modify the window design, that is, precreatewindow (createstruct & Cs). You can query the createstruct struct in msdn, you will find that it is almost the same as our createwindow. This is an opportunity for MFC to change the window. During precreatewindow, it will jump to cwnd: precreatewindow, which contains a macro: afxdeferregisterclass. Its function is: if the window class is not registered, it will be registered; if it is registered, no matter what it is!
The design, registration, and creation of window classes have been completed, and only updates and displays are available. These tasks are completed by cmyapp: initinstance:
M_pmainwnd-> showwindow (sw_show );
M_pmainwnd-> updatewindow ();
Now if (! Pthread-> initinstance () has been completed. According to the content of the main function, next this: nreturncode = pthread-> Run ()
In this case, the run () function of cmyapp should be called, but in the cmyapp class, such a function is not declared or defined at all. According to the original polymorphism, the pointer is promoted to cwinapp :: run (), whose code is located in appcore. CPP:
Int cwinapp: Run ()
If (m_pmainwnd = NULL & afxolegetuserctrl ())
// Not launched/embedding or/automation, but has no main window!
Trace (traceappmsg, 0, "Warning: m_pmainwnd is null in cwinapp: Run-quitting application./N ");
Afxpostquitmessage (0 );
Return cwinthread: Run ();
Finally, you will find that it calls a cwinthread: Run (), and you will not be able to see the cwinthread: Run () Code (at least I did not find it, because Microsoft only provides part of the MFC code .) However, you can find the cwinthread: Run () Description in msdn:
The run function that controls the thread. Contains the message pump. Generally, this parameter is not rewritten.
The specific points are:
Run acquires and dispatches Windows messages until the Application Generated es a wm_quit message. if the thread's Message Queue currently contains no messages, run callonidle to perform idle-time processing. incoming messages go to The pretranslatemessage member function for special processing and then to the Windows function translatemessage for standard keyboard translation. finally, the dispatchmessage WINDOWS function is called.
Run is rarely overridden, but you can override it to implement special behavior.
This member function is used only in user-interface threads.
It originally wrapped the message loop and called message map in MFC! I will write an article to explain the details of message ing!
OK, the MFC is no longer mysterious. I have mastered the ins and outs of it. When I look at other MFC books, I will know how to do it? Why am I doing this? This is the technical realm that I pursue.

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.