Jump to content

Windows Programming/Microsoft Foundation Classes

From Wikibooks, open books for an open world

Microsoft Foundation Classes (MFC)

[edit | edit source]

In essence, MFC is a SDK interface, a library consisting in a set of classes that act as wrappers around portions of the Windows API, so that C++ programmers may program Windows using some concepts of the object-oriented programming (OOP) paradigm and the C++ language (the Win32 API is based on C, as seen in C and Win32 API Section of the book). One should learn the Win32 API or at least have some ideas since some functions are absent from the MFC and would help you to better understand the SDK.

Some tools, such as Microsoft Visual Studio, are capable of automatically generating large amounts of MFC skeleton code for use in a project. Because of this, most MFC tutorials or reference materials will teach the subject using the automated Visual Studio tools, and leave out some of the gritty details. In this book where possible we try to be neutral.

MFC was first oriented mostly for enterprise-level programming projects, created in an age most code was done in C and Object Oriented Programming was only in the realm of Smalltalk.

Since the release of Visual Studio 6.0 and the MFC 6.0 little was known of the future support to the MFC since the company was favoring the .NET Framework. Version 7.0, 7.1 and 8.0 were mostly extensions to support the new OSs and to aid developers in migrating to the new framework. Since then information on the future of the MFC could be only extracted from Steve Teixeira, Microsoft Corporation, June 2005 paper - MFC: Visual Studio 2005 and Beyond, on the release of Visual Studio 2008 Service Pack 1, Microsoft seems to once again be actively supporting the MFC.

Many users today find it acceptable for a low complexity program to have a memory footprint of 30-80Mb (this is common in Java or .Net applications), low response times or "outside of your control" applications like the internet now provides. It is therefore debatable if the impact of use of MFC in small applications outweighs the benefits the libraries provides. Most of the software made specifically for Windows today uses MFC.

You should prefer the Win32 API SDK, or an alternative wrapper for it, if you do not intend to:

  1. Make use of a complex GUI, use the document/view architecture or complex controls.
    This will increase the use of system resources (memory use, exe and install size).
  2. Use other libraries that depend on the MFC.
  3. Have a complex install for your application.
    To distribute MFC-Based project you must build it with static MFC libraries or distribute your project with the needed MFC dlls. There is no guarantee that your customer has the required dlls for your program. Old MFC-Based programs must work with new MFC versions. They should but don't do it always. Your customer will not be very happy if after installing your project some of his old software products begin hanging.

MFC and C++

[edit | edit source]

The MFC design principle is an attempt for simplification. The wrapper classes were designed so to simplify some tasks and automates others. Because of those facts, however, a certain amount of fine-tunable control was lost from the raw Win32 API or excessive automation was archived. The MFC has been recognized as having serious design flaws and inconsistencies and has not been actively maintained. The C++ language and best practices have evolved and today this constitutes a barrier for the utilization of the framework.

As MFC predates the STL standardization in to the C++ language, it implements its own versions of the STL containers, not as complete and even inconsistent, this simplistic solutions the MFC implementations tend to be faster, however you should prefers to use the STL when ever you can, it will make the code more C++ standard and permit easier portability in converting the code to multi-platform.

Multiple Inheritance

The MFC class library does not use Multiple Inheritance and was not designed with full support for Multiple Inheritance.

Since most MFC classes derive from CObject using Multiple Inheritance will be cause problems of ambiguity (any reference to CObject member functions will have to be disambiguated). Static member functions, including operator new and operator delete must also be disambiguated.

The best option is to avoid the use of Multiple Inheritance with MFC but take a look at Using C++ Multiple Inheritance with MFC (msdn.microsoft.com) for the needed information on how to bypass the limitations.

MFC Conventions

[edit | edit source]

The MFC uses the Hungarian notation. It uses prefixes, like "m_" to indicate a member variable or "p" to indicate a pointer, and the rest of the name is normally written out in CamelCase (the first letter of each word is capitalized).

CObject as the Root for most MFC Classes

All the significant classes in MFC derive from the CObject class. The CObject does not have any member data, but does have some default functionality.

Using MFC

[edit | edit source]

MFC requires header files that are separate from the standard <windows.h> header file. The core of the MFC system requires the inclusion of <afxwin.h>. Other header files that are of some use are <afxext.h> (for MFC extensions), and <afxcmn.h> (for the MFC common dialog boxes).

Simply changing the header files, unfortunately, is still not enough. The MFC DLL libraries must be linked to by the project, because the DLL files contain the class definitions that will be used throughout every program. To use MFC, you must link to the MFC libraries

stdafx.h

[edit | edit source]

stdafx.h is the standard include for MFC projects - that is, if you create a new MFC project, a stdafx.h will automatically be created for you. It will include all the rest of the necessary MFC header files.

theApp

[edit | edit source]
extern CYourAppClass theApp;

Use in the header file of your application class and then include it wherever you need to use theApp.

You could try the AfxGetApp function to get a pointer to theApp, an efficient method of accessing members of your application is to make a pointer to theApp a member variable of the class which needs it -- for example:

class CMyDialog : public CDialog 
{ 

  // other class stuff here... 
  
  // Attributes 
  public: 
    CMdiApp* m_pApp; 
};

and make sure you initialize m_pApp in the constructor or else will be accessing a NULL pointer.

CMyDialog::CMyDialog(CWnd* pParent /*=NULL*/): CDialog(CMyDialog::IDD, pParent) 
{ 
           //{{AFX_DATA_INIT(CMyDialog) 
           //}} AFX_DATA_INIT 
           // Outside the special-format comments above... 
           m_pApp = (CMdiApp*)AfxGetApp( ); 
}

and voila! Now any time you need access to your application, you got it!

m_pApp->m_nMemberVar; 
m_pApp->MemberFunction(nParam1, strParam2);

Getting Started

[edit | edit source]

First and foremost, it must be mentioned, that MFC is not the brand of C++ programming that "looks like C". MFC makes heavy use of the object-oriented features of C++, which can seem "dense" or even unreadable to a new C++ programmer. It is highly recommended that the reader become very familiar with C++ concepts such as classes and hierarchies now, if they are not familiar concepts yet.

The root class for MFC is the CObject class. CObject itself does not support multiple inheritance, but derivative classes do. Each application begins in a class derived from CWinApp. Every program must have a CWinApp class, and each application may only have one. CWinApp contains a number of functions for initializing an application, and controlling the instance handle (similar to the HINSTANCE member of the WinMain function). Programs that want to display a window must utilize a derivative of the CWnd class.

Basic MFC Program

[edit | edit source]

We will outline here a basic MFC program that will create a simple window, but won't handle any user input. From this basic outline, we will be able to tackle more difficult subjects.

#include <afxwin.h>  //basic MFC include
 
//class derived from CFrameWnd, which is derived from CWnd
class Basic_Window:public CFrameWnd
{
   public:
       Basic_Window()
       {
            Create(NULL, "Basic MFC Window");
            // In some cases you might want to use
            // Create(NULL, _T(":Basic MFC Window"));
       }
};
 
//class derived from CWinApp, which is the main instance of our application
class MyProgram:public CWinApp
{
      //a pointer to our window class object
      Basic_Window *bwnd; 
   public:
 
      //this is essentially our "entry point"
      BOOL InitInstance()
      {
           bwnd = new Basic_Window();
           m_pMainWnd = bwnd;
           m_pMainWnd->ShowWindow(1);
           return 1;
      }
};
  
//the program class instance pointer
MyProgram theApp;

As we see here, we are immediately relying on class definitions and inheritance, so it is a good idea for readers who are not completely familiar with these topics to brush up on them before continuing.

Global Variables

[edit | edit source]

MFC provides a number of global variables, that are instantiated and then utilized in the underlying MFC framework to compile your program. We can see this in our basic example code when we use the variable m_pMainWnd.

Cleanly closing an MFC application

[edit | edit source]

The generic solution is PostQuitMessage([exit code]);, but take care to cleanup any lingering resources (closing documents, deallocating memory and resources, destroying any additional windows created etc), on the other hand using AfxGetMainWnd()->PostMessage( WM_CLOSE ); can be a better method in some situations, since it triggers the correct shutdown sequence. This is especially important on MDI/SDI applications because it gives a chance for documents to prompt for save before exit or for the user to cancel the exit.

Wait mouse cursor

[edit | edit source]

To display a busy/wait mouse cursor the MFC as added a simple helper class. Instantiate a CWaitCursor class inside a function and a wait cursor is then displayed for the duration of that function, auto destruction of the class will restore the cursor state.

CWaitCursor aWaitCursor;

Threads

[edit | edit source]

As it should be expected the MFC also wraps the Win32 thread primitives in special classes and functions of its own. For generic information of threads and C++ see the C++ Programming Wikibook section on Multitasking. The MFC devised threads in worker threads and GUI threads.

Worker threads

[edit | edit source]

Worker threads are especially useful to perform background tasks, or any asynchronous work that doesn't require user intervention, a print job, calculations, waiting for an event, etc. To create a worker thread, the simplest way is to implement a function that will perform the desisted work, and then create the thread with AfxBeginThread() that will use that specific function.

Communication

[edit | edit source]
Clipboard

To do:
Complete


Exit strategy

[edit | edit source]

Never use TerminateThread() unless you have no other choice to guarantee a thread termination. It is poor practice and dangerous.

A proper thread exit can be archived by a normal return from the thread (completion) or by signaling it to return prematurely. Since we are working on Windows and on a 32 bit bound CPUs (making 32 bits accesses atomic), it is considered safe (but not portable) to use a shared bool variable to indicate to a thread to exit, any other synchronization methods can be used if available.

Since the only issue regarding thread termination is on aborting a job or exiting the program without having threads running, when dealing with worker threads, in the class that created the thread on the destructor you should signal the thread to abort and then use WaitForSingleObject() to wait for the thread to terminate.