Windows Programming/Introduction to MFC
From Wikibooks, the open-content textbooks collection
Contents |
[edit] Microsoft Foundation Classes (MFC)
In essence, MFC is a SDK interface (wrapper) only, consisting in a set of classes that act as wrappers around the Win32 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). One should learn the Win32 API or at least have some ideas since some of the SDK functions are absent form the MFC and remember would help you better to understand the MFC.
Some tools, such as 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. 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 also 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 some of its implementations aren't the best, you should also try to use the STL when ever you can, it's part of the C++ standard now and multi-platform so you will save some time if you later decide to port the code.
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 (http://msdn2.microsoft.com/en-us/visualc/aa442855.aspx), on the release of Visual Studio 2008 Service Pack 1, Microsoft seems to once again be actively supporting the MFC.
Today the common users find acceptable for a low complexity program having a memory footprint of 30-80Mb (common in Java or .Net applications), low response times or "outside of you control" applications like the WEB now provides, so it is debatable if the impact of required for the use of MFC in small applications outbalanced any of 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:
- 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). - Use other libraries that depend on the MFC.
- Have a complex install for your application.
To distribute MFC-Based project you must build it with static MFC libraries or distribute project with the needed MFC dlls. There is no any warranty that your customer has dlls for your program. Old MFC-Based programs must work with new MFC versions. They must but don't do it always. Your customer will be very glad if after installing your project some his old software products will begin hang up.
[edit] MFC Conventions
The MFC uses the Hungarian notation. It uses prefixes, like "m_" to indicates it is a member variable, the "p" indicates that a pointer and the rest of the name is normally written out with caps on the first letter.
[edit] Using MFC
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
[edit] stdafx.h
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.
[edit] theApp
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);
[edit] Getting Started
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.
[edit] Basic MFC Program
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.
[edit] Global Variables
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.
[edit] Cleanly closing an MFC application
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.