MFC Under the Hood

Environment: Visual C++

Most of the time when you are creating a new MFC application, you'll start with the MFC App Wizard. The App Wizard generates a basic skeleton application which you will flesh out into a full-fledged, useful program.

Even the skeleton application you get from the App Wizard contains a lot of very arcane looking code, and there's a great deal of hidden code as well. The purpose of this article is to demystify some of that code. I'll show you how to build a simple MFC application without the App Wizard. By the time you are done, the mysterious looking code that comes from the App Wizard will no longer be so mysterious, and you'll be better prepared to modify it to suit your own purposes.

The hidden code first

Every 32 bit Windows application has two essential program elements: WinMain and WndProc. Your program will have one WinMain for the entire program, and one WndProc for each window in the program. Although MFC creates these for you, you still need to know a little about them.

WinMain is the function that starts your application. Once your application is running, the Windows operating system will start placing your application's messages in a message queue. WinMain makes three Windows API calls to get these messages from the operating system and to process them. First it calls GetMessage to retrieve a message. Then it calls TranslateMessage to perform any necessary conversion of the message. Finally, WinMain calls DispatchMessage, which tells the operating system to send the message to the appropriate WndProc for handling.

Once WndProc receives a message, it looks through its message handlers for instructions on what should be done with the message. Your job as a Windows application programmer, it to write the handlers.

A Simple MFC Application: Less Than 20 Lines of Code

Next we'll look at a simple, bare-bones MFC application. MFC provides the WinMain and WndProc. We must provide an MFC-derived application class and window management class.

Our application class will be derived from the MFC class CWinApp. CWinApp provides all the member variables and functions to initialize, start, run and close an application. CWinApp contains a pointer called m_pMainWnd which will point to an object of our derived window management class. Each MFC application has one and only one object of derived directly from CWinApp. In the example below, that class is called "CMyApp."

Our window management class will be derived from CFrameWnd. CFrameWnd has all the member variables and functions to create and manage windows. Note that when you create an object of our derived windows class, you have not created an actual window. The new object uses its Create() function to create windows.

Here's what happens when we start our program. You can follow along in the code:

  1. WinMain runs this code: CMyApp app; This creates an object of type CMyApp named "app." App will have all the member variables and functions of CWinApp which are needed to start, run and close our application.
  2. Then WinMain calls app's InitInstance( ) function. InitInstance() creates a new CMyWnd object with m_pMainWnd = new CMyWnd;
  3. The CMyWnd constructor calls its Create( ) function, which creates an instance of the window, but does not display it.
  4. The app's InitInstance() function then displays the window with m_pMainWnd-> ShowWindow(m_nCmdShow);
  5. WinMain calls the app's Run( ) function, which dispatches messages to the rest of the application.

Here is the code. Try it - it works!

     #include <afxwin.h>

     //derive my own window class from CFrameWnd
     class CMyWin:  public CFrameWnd
     {
          public:
          CMyWin( );
          DECLARE_MESSAGE_MAP( )
     };

     //define my window class' constructor:
     CMyWin::CMyWin( )
     {
          Create(0, "This Text Will Appear in the Title Bar");
     }

     //derive my own application class from CWinApp
     class CMyApp:  public CWinApp
     {
          public:
          virtual BOOL InitInstance( );
     };

     //define my application class' InitInstance( )
     BOOL CMyApp::InitInstance( )
     {
          m_pMainWnd = new CMyWin( );
          m_pMainWnd->ShowWindow(m_nCmdShow);
          m_pMainWnd->UpdateWindow();
          return TRUE;
     }

     //here is my application's message map
     BEGIN_MESSAGE_MAP(CMyWin, CFrameWnd)
         // any messages to be processed by 
         // CMyWin get listed here.
     END_MESSAGE_MAP( )

     //declare an instance of application 
     //class for WinMain to use.
     CMyApp app;

Here's what you get when you compile and run:

Your actual window will be bigger.

Single Document Interface Applications

The code above creates a simple, bare bones application. The code you will find in a single document interface application is more complicated, but still works along the same lines. You still have an application class derived from CWinApp. You still have a window management class derived from CFrameWnd. In this case, however, the derived window management class is called CMainFrame.

Your derived application class still has an InitInstance() function, but the function looks a lot more complicated. Among other things, it contains something like this:

     CSingleDocTemplate* pDocTemplate;
     pDocTemplate = new CSingleDocTemplate(
          IDR_MAINFRAME,
          RUNTIME_CLASS(CMyDoc),
          RUNTIME_CLASS(CMainFrame),  // main SDI frame window
          RUNTIME_CLASS(CMyView));
     AddDocTemplate(pDocTemplate);

Here, the application object creates a single document template pointer and points it to a new single document template object. There are four parameters passed to the CSingleDocTemplate constructor. The first is an integer, the resource ID for the IDR_MAINFRAME resource. The next three parameters pass class information for my document class, frame class and view class. Then the pointer to this new CSingleDocTemplate is added to the list of document templates maintained by the application object. (In an SDI application, there's only one template.)

IDR_MAINFRAME is a resource containing:

  1. The application icon.
  2. The application's menu.
  3. The accelerator table that goes with the menu.
  4. A document string.

The document string contains up to seven pieces of information in substrings separated by '\n' characters:

  1. The title that appears in the frame window's title bar.
  2. The title assigned to new documents. If omitted, the default is "Untitled."
  3. A description of the document type in an MDI application. This substring isn't used in an SDI application.
  4. A description of the document type followed by its default file name extension, e.g., "My Big Program(*.mbp)."
  5. The three letter extension for the document type, e.g., ".mbp"
  6. A name with no spaces that identifies the document type in the registry.
  7. A descriptive name of the document type, e.g., "My Big Program Document."

Here's a sample string:
"My Big Program\n\n\nMy Big Program(*.mbp)\n.mbp\nBigProgram\nMBP Document."

Conclusion

So there you have it. Now that you know a little more about what your wizard-generated code is doing, you can go in and start modifying it. For example, if you want to change the size and positioning of your application's main window, you can modify the Create( ) function. Try substituting the following code for the Create( ) function listed above. You'll get a much smaller window positioned in the upper left corner of the screen.

    RECT x;
    x.top = 30;
    x.left = 30;
    x.bottom = 300;
    x.right = 300;
    Create(NULL, "My New Window", WS_OVERLAPPEDWINDOW, x);

There are a lot of settings and functions you can play with. You might be the type who never changes the default code. Even so, the more you know about what's going on, the better your programs will be.



Comments

  • Calling from a Console Application

    Posted by dms489 on 03/22/2006 09:28am

    I appreciate a really simple piece of code that exposes the entrails of MFC startup. However, what I really want is to do the same thing from a console application - can this code be adapted to run from an int main() { ... }?

    Reply
  • Thanks

    Posted by Legacy on 06/12/2003 12:00am

    Originally posted by: Gustavo Figueiredo

    Very interesting Andrew, thanks a lot.

    Reply
  • document string

    Posted by Legacy on 10/09/2002 12:00am

    Originally posted by: RCL Software

    That was very useful, thank you.

    Reply
  • Do it needed deleting the m_pMainWnd pointer in the end of the application 1?

    Posted by Legacy on 07/25/2002 12:00am

    Originally posted by: Tang Jiangjun

    First I thank you for your instruction, I really learn much from you article.
    And I think it is needed that adding a delete operation in ExitInstance function for the m_pMainWnd pointer.
    Is it correct? Or maybe the framework can automanually delete that pointer.
    I'm waiting your instruction.

    Reply
  • A slight error

    Posted by Legacy on 07/11/2002 12:00am

    Originally posted by: Josh

    The article said: "CWinApp contains a pointer called m_pMainWnd which will point to an object of our derived window management class.". Actually, CWinApp doesn't contain the pointer, it is a member of CWinThread, the base
    class of CWinApp. Sorry for being picky. Otherwise, great article.

    Reply
  • MFC under the hood

    Posted by Legacy on 06/07/2002 12:00am

    Originally posted by: Ray Macchiarola

    still don't understand where:
    m_pMainWnd = new CMainFrame( ); //don't see it in
    // generated classes
    m_pMainWnd = new CMyWin( ); //this is understandable

    IN the code generated in AppWizard

    Reply
  • Multiple Documents?

    Posted by Legacy on 12/19/2001 12:00am

    Originally posted by: Cacho

    Your explanation is very helpful to someone at my level. Could you please expand for one Template/ multiple documents/ one view per document. I would be much obliged.
    

    Reply
  • Real Beginner

    Posted by Legacy on 08/08/2001 12:00am

    Originally posted by: TomThumb

    Hey, I'm a real beginner, and I've spent the past few hours wondering where to put in this source code to allow me to compile it. I'm running Microsoft Visual C++ 5.0.

    Anyone with hints/ideas.. please help.

    Tom

    • Getting Started

      Posted by dms489 on 03/22/2006 09:36am

      Create a new Project of type MFC Application. Delete all files except the main file you named, and paste this code into it. It will compile and run fine.

      Reply
    Reply
  • Great ! A nice way to explain Flow of MFC Program

    Posted by Legacy on 07/24/2001 12:00am

    Originally posted by: Shashikanth Pisse


    I liked the way Flow of MFC Application is
    described.

    Reply
  • Superb!

    Posted by Legacy on 07/17/2001 12:00am

    Originally posted by: olaimat

    Article provides a better exposition than my $50 book does.

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • IBM Worklight is a mobile application development platform that lets you extend your business to mobile devices. It is designed to provide an open, comprehensive platform to build, run and manage HTML5, hybrid and native mobile apps.

  • Recently, Forrester Consulting conducted a Total Economic Impact™ (TEI) study to better understand the impact of incorporating Polycom voice solutions with Microsoft Lync. Forrester interviewed a company that had already deployed the Lync/Polycom combination to determine its potential return on investment (ROI). Microsoft Lync provides presence information and promotes voice and video collaboration. Polycom extends the benefits of Lync with voice endpoints and further enables collaboration in multiple …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds