You are on page 1of 15

Chapter 2

MFC Hierarchy and Application Flow


Objectives
List the benefits provided to the majority of MFC classes by deriving them from CObject class. List the classification of MFC classes. Flow of a typical MFC Application. Customizing your application by overriding CWinApp functions. Explain the need for Message Maps. Use MFC macros to handle messages.

Introduction
The Microsoft foundation Class library (MFC) and Visual C++ provides an environment you can use to easily create a wide variety of applications. This Chapter discusses the various class types and primary architecture that is used in most applications. It introduces the MFC class hierarchy and explains the flow of a typical MFC application. It also explains grouping MFC classes according to specific functions and important features of CObject class. In this chapter we will see how to customize application by overriding CWinApp functions such as InitInstance, Run, ExitInstance and OnIdle. Finally this chapter discusses about message maps, the various macros involved and how it works.

The Windows Programming Model


Programs written for traditional operating environments use a procedural programming model in which programs execute from top to bottom in an orderly fashion. The path taken from start to finish may vary with each invocation of the program depending on the input it receives or the conditions under which it is run, but the path remains fairly predictable. In a C program, execution begins with the first line in the function named main( ) and ends when main returns. In between, main might call other functions and these functions might call several other functions but ultimately it is the program - not the operating system - that determines what gets called and when. Windows employs the event-driven programming model. Application responds to event by processing messages sent by the operating system. The entry point for a Windows program is a function named WinMain, but most of the action takes place in another function WndProc. The window procedure processes messages sent to the applications window. WinMain creates that window and then enters a loop, retrieving messages and dispatching them to the window procedure. Messages wait in a message queue until they are retrieved. The message loop inside WinMain spins in a continuous cycle, retrieving and dispatching messages. The loop ends when the special WM_QUIT message is retrieved from the message queue, signaling that its time for the application to end. When message loop ends, WinMain returns and the application terminates. This can be pictorially represented as follows:

Page 16

MFC Hierarchy and Application Flow

Incoming Messages

WM_PAINT WM_PAINT WM_KEYDOWN WM_KEYDOWN WM_COMMAND WM_COMMAND WM_SIZE WM_SIZE WM_LBUTTONDOWN WM_LBUTTONDOWN

System Message Queue

Appln1 MessageQueue Appln2 MessageQueue


Post Message

Appln3 MessageQueue

Application Message Queue Retrieved Messages WinMain Message Loop Dispatched Messages Message MessageHandler Handler Message MessageHandler Handler Message MessageHandler Handler

Application

Window Procedure
Send Message

Message MessageHandler Handler Message MessageHandler Handler Message MessageHandler Handler

Unprocessed Messages DefWindowProc DefWindowProc

Classification of MFC
Features of CObject Application Architecture classes

SEED Infotech Ltd.

MFC Hierarchy and Application Flow

Page 17

User Interface Classes Database Classes General Purpose classes Global Afx functions.

MFC contains nearly 250 classes. Some of these classes are used directly, while others serve as base classes for your own classes.

Features of CObject
By taking a look at the class hierarchy chart, it can be seen that majority of the classes are directly or indirectly derived from CObject. CObject provides following three features:

Serialization support Run-time class information support Diagnostic and debugging support

Serialization Support
Serialization is a process by which objects archive themselves to and from a storage object such as a file on the disk. CObject includes two member functions that play a role in serialization: IsSerializable and Serialize. The IsSerializable function tests whether object is eligible for serialization. It returns TRUE if an object supports serialization, and FALSE if it does not. Serialize serializes the objects data members to a storage medium represented by a CArchive object.

Run-time class information support


Another feature of CObject is, support for runtime class information, because it is derived from CRuntime class. Objects derived from CObject contain information about their origin that is accessible at run time. This run time type-checking feature gives functions the ability to react based on the type of object that is acted on. CObject provides two member functions to help out : IsKindOf and GetRuntimeClass. The latter returns a pointer to a CRuntimeClass structure. IsKindOf accepts a CRuntimeClass pointer and returns TRUE or FALSE indicating whether the object was created from that class or one of its derivatives. ASSERT( pObject->IsKindOf ( RUNTIME_CLASS (CWnd ) ) ); The above statement causes an assertion error if the object to which pObject refers is not a CWnd or its derivative. MFCs RUNTIME_CLASS macro returns a CRuntimeClass pointer for the class name in parenthesis. One use for IsKindOf is to validate the parameters passed to functions that accept pointers to classes.

Diagnostic and debugging support


A third feature that CObject provides to its derived classes is diagnostic support. The virtual member function AssertValid instructs an object to perform a validity check on itself using a series of assertions. The virtual member function Dump performs a diagnostic dump of the objects data members, which is helpful for debugging a program and the object it uses. CObject-derived classes often override these functions and provide classspecific code to perform meaningful validity checks and diagnostic dumps. It provides information about the execution of your program that is especially useful when program behavior is not as expected.

SEED Infotech Ltd.

Page 18

MFC Hierarchy and Application Flow

CObjects other benefits are : it overloads the new and delete operators to provide protection against memory leaks.

Application Architecture Classes

The application architecture classes represent the basic architectural elements of a program and include CWinApp, CDocument, CCmdTarget and CWinThread. These classes are first instantiated when application starts and they have significant responsibilities.

CWinApp
CWinApp represents the application itself. Virtually all MFC applications derive a class from CWinApp. An application object provides member functions for initializing your application and each instance of the application. It also provides member function for running the application. It encapsulates the WinMain() function of SDK. This application object used by MFC program provides a higher level of abstraction for the developer. This is done by encapsulating all the repetitive code like WinMain(), message loop etc. The application begins with the construction of application object and terminates when application object is destroyed.

CDocument
The CDocument class defines the basic characteristics of the document objects used to store data in document/view applications. CDocument provides some important member functions including IsModified for determining whether a document has been modified since it was last saved, and UpdateAllViews for updating the views of a document when the documents data changes. CDocument overriddables such as DeleteContents and OnNewDocument enable a derived document class to be customized to work in cooperation with the framework. Another of CDocuments new features is the OnFileSendMail function, which sends a mail message with the document attached to it.

CCmdTarget
Most of the application architecture classes are derived from CCmdTarget, which contributes function and data members that transform the class into a command target capable of receiving and processing messages. To use a message map, a class must be

SEED Infotech Ltd.

MFC Hierarchy and Application Flow

Page 19

derived from CCmdTarget.

CWinThread
Encapsulates threading capabilities of the operating system. Member functions enable MFC programs to create and manipulate threads.

User-Interface Classes

Window classes GDI Classes

The User-Interface classes encompass the elements of a Window-based application that are visible to the user. These include windows, dialog boxes, menus and controls. They also encapsulate the Windows device context and graphic device interface (GDI) drawing objects.

Window classes
MFCs CWnd class encapsulates the properties of a window. CFrameWnd and CMDIFrameWnd, which model the behavior of top-level windows containing menus, toolbars, and other objects; CView, which forms the foundation for views in the document/view applications; CDialog, which encapsulates dialog boxes, and the MFC control classes corresponding to push buttons, list boxes and other objects.

GDI Classes

GDI stands for Graphics Device Interface and is the component of Windows responsible for output to screens, printers and other devices. MFCs CDC class encapsulates the functionality of the Windows device context, which links an application to a screen, printer or the other output device and allows GDI output functions to be executed. CDC derivatives such as CPaintDC, CClientDC and CWindowDC are special cases of the more generic CDC class. CPaintDC automatically calls the BeginPaint and EndPaint API functions from its constructor and destructor. CMetaFileDC provides a wrapper for GDI metafiles - files in which drawing command are recorded and later played back to do the actual drawing. CGdiObject is the base class for MFCs representation of the GDI objects such as CPen, CBrush, etc. Other classes derived from CGdiObject include CBitmap, which represents bitmaps; CPalette, which represents color palettes and CRgn, which encapsulates GDI objects known as regions - areas on the screen defined by combining rectangles, polygons, ellipses, and other shapes.

SEED Infotech Ltd.

Page 20

MFC Hierarchy and Application Flow

Database Classes

MFC generalizes the interface to database management system fitted with Open Database Connectivity (ODBC) drivers through the CDatabase and CRecordSet classes. CDatabase represents an ODBC connection to a data source, and CRecordSet represents a set of records in that data source. The CRecordView class further simplifies database operations by connecting a recordset object to a dialog-like form view that displays the values of the fields in the current record. The helper class CLongBinary provides an abstract representation of large binary objects such as bitmaps. When it encounters a CLongBinary object implemented as a data member in a recordset object, MFCs record field exchange (RFX) mechanism allocates memory to store the object and loads it from the database. This prevents the programmer from having to supply special logic to read and write database fields that dont fit nearly into a predefined data type. Data Access Object (DAO) classes encapsulate the OLE interface to the Microsoft Jet database engine that serves Microsoft Access. CDaoDatabase represents an open DAO database, and CDaoWorkspace represents a workspace containing a collection of CDaoDatabase objects. Jet databases can also be accessed through MFCs ODBC classes, but the DAO classes offer richer interfaces than their ODBC counterparts and may deliver superior performance because DAO member functions travel through fewer layers before reaching the underlying database engine. In general, the DAO classes are ideal for accessing small, locally stored Microsoft Access Databases, while the ODBC classes are useful for accessing any database served by an ODBC driver.

General purpose classes


File Classes Exception Classes Collection Classes Miscellaneous Classes

A no. of general purpose classes in MFC do not encapsulates the Windows API.

SEED Infotech Ltd.

MFC Hierarchy and Application Flow

Page 21

File Classes

MFCs CFile class provides an object-oriented interface to files by taking standard file I/O functions such as Read and Write and implementing them in the context of file objects. CFile also serves as the base class for other classes including CMemFile, which represents files that are stored in memory rather than on disk. COleStreamFile, which maps CFile functions to functions in the OLE IStream interface. CSocketFile, which can be combined with a CArchive object to serialize objects over networks using Windows sockets; and CStdioFile, which supports buffered file I/O in text and binary modes.

Exception Classes

CException is an abstract base class from which an assortment of MFC exception classes designed for use with C++s try/ throw/ catch exception handling mechanism are derived. CFileException, describes exceptions generated by file operations. Other exception classes include CMemoryException for out-of-memory errors, CArchiveException for archive errors, COleException for OLE errors and CResourceException for errors loading and creating Windows resources. AfxThrowFileException and AfxThrowMemoryException aid applications in throwing exceptions.

SEED Infotech Ltd.

Page 22

MFC Hierarchy and Application Flow

Collection Classes and Templates

A group of classes known as the MFC collection classes provides class library support for common data structures such as arrays and linked lists. CByteArray, CPtrArray, CStringArray, and other array classes implement arrays that can be sized dynamically. Array classes are ideal for storing document data. List classes such as CStringList and CObList implement MFC versions of the doubly linked lists, whose members contain pointers to the next and previous elements in the list. Map classes support cables of datatypes keyed by other datatypes.

Miscellaneous Classes

MFC includes a number of general-purpose classes to represent simple data types such as points and rectangles and more complex datatypes such as strings. E.g. CPoint, CSize, CRect, CTime, CTimeSpan. CPoint and CRect classes are mostly used. CTime represents absolute times and dates and includes a useful static function named GetCurrentTime that returns a CTime object initialized with current date and time.

SEED Infotech Ltd.

MFC Hierarchy and Application Flow

Page 23

Global Afx Functions


AfxGetApp AfxGetMainWnd Returns a pointer to the application object. Returns a pointer to the applications mainframe window. Returns the pointer to a string containing the application name.

AfxGetInstanceHandle Returns the handle identifying the current application instance. AfxGetAppName

MFC Application Flow


InitInstance CWinApp Overidables WinMain() in MFC General flow of execution within MFC application Hidden Message Map

The InitInstance Function


The purpose of InitInstance is to provide the application with the opportunity to initialize itself. The value returned by InitInstance determines what the framework does. Returning FALSE from InitInstance shuts down the application. To call a regular Windows API function from an MFC program, preface the function name with the global scope resolution operator:: . This notation will ensure that the API function is called even if the object that makes the call has a member function with the same name.

CWinApp Overridables
The CWinApp class is the base class from which you derive a Windows application object. An application object provides member functions for initializing your application (and each instance of it) and for running the application. InitInstance is just one of several virtual CWinApp member functions you can override to customize the behavior of the application object. ExitInstance is useful for cleaning up before an application terminates. If you use InitInstance to allocate memory or other resources, ExitInstance is the perfect place to deallocate those resources. The default implementation of ExitInstance saves certain program settings in document/view applications and performs some routine cleanup chores required by the framework. The value returned by ExitInstance is the exit code returned by WinMain. Other CWinApp overridables include OnIdle, Run and PreTranslateMessage. OnIdle is used for performing background-processing chores such as spooling a document to a printer or performing garbage collection on in-memory data structures. Because OnIdle is called when an application is idle that is when there are no message waiting- it provides an excellent mechanism for performing low priority background tasks without spawning a separate thread of execution. Run can be overridden to customize the message loop by replacing it with a message loop of your own. If you want to perform some specialized preprocessing on certain messages before they are dispatched to the program, you can override PreTranslateMessage.

WinMain() in MFC
MFC provides several raw global functions along with a predefined WinMain() function for the

SEED Infotech Ltd.

Page 24

MFC Hierarchy and Application Flow

framework (as a global C++ function) The class library uses the function name AfxWinMain(). Initializations (including creating the main application thread and setting several window and object handles) are made in AfxWinInit() , a global C++ function found in APPINIT.CPP Next comes the main Application entry point - the point at which the global code activates the application object, just before it takes control of the process: CWinApp::InitInstance(). You can override and tap into this method for custom application intialization. After asserting the application object pointer is valid, the applications message pump is started with a call to the CWinApp:: Run() method . nReturnCode = pApp - > Run ( ); This is where MFC hides its comprehensive application message loop : the message pump.

General flow of execution within an MFC application


During application initialization, WinMain() calls the application objects InitApplication() and InitInstance() methods. The applications message pump is started when WinMain() calls the Run() method ; when the application terminates, WinMain() calls the application objects ExitInstance() method.

Program Entry Point

WinMain ( ) Initialize App Initialize Instance Pump message

CWinApp :: InitApplication ( ) Initialize App

CWinApp :: InitApplication ( ) Initialize Instance


Quit ?

CWinApp :: Run ( ) Pump Messages

CWinApp :: ExitInstance( )

SEED Infotech Ltd.

MFC Hierarchy and Application Flow

Page 25

The Hidden Message Loop


When the global AfxWinMain() function initializes an application object and calls its Run() method , the application starts its message pump and takes local control of the process. Within an application object, the Run() method kicks in the application message pump. It actually does this by calling its inherited CWinThread :: Run() method. The CWinApp is derived from CWinThread. The Run() method really just starts a message loop that performs several tasks. First, it starts an infinite loop (the actual message loop itself) by using ( ; ; ) statement . The code within the for ( ; ; ) block loops until told to stop by the receipt of a WM_QUIT message.

Phase 1 Idle processing


The code within the for ( ; ; ) block is composed of two nested loops . These nested loops control a two - phase messaging system, including idle processing and message handling. The idle processing is done by the first phase. // phase1 : check to see if we can do idle work while ( bIdle && ! :: PeekMessage ( & m_msgCur , NULL, NULL, NULL, PM_NOREMOVE)) { // call OnIdle while in bIdle state if ( ! OnIdle (lIdleCount ++)) bIdle = FALSE ; // assume no idle state }

The PeekMessage() Win32 API function is used to retrieve messages during the long process of an applications run . PeekMessage() is used for running operations in the background ; it uses the PM_NOREMOVE macro to specify that the messages are not to be removed from the queue after processing . The phase 1 loop then calls CWinApp : : OnIdle() to utilize any application idle time for other duties like Updating menu items and toolbar buttons and cleaning up internal data structures.

Phase 2 : Message Pumping


The second nested loop within the for ( ; ; ) block is used to pump messages from a threads queue and send it to the window procedure for processing by calling CWinApp::PumpMessage() ( which turns out to actually be inherited CWinThread::PumpMessage() method ) // pump message , but quit on WM_QUIT if(!PumpMessage ( )) return ExitInstance ( ) ; //The CWinThread :: PumpMessage ( ) method contains the actual MFC message loop, SDK style. BOOL CWinThread :: PumpMessage( ) { ASSERT_VALID (this); if(! ::GetMessage (&m_msgCur, NULL, NULL, NULL )) { return FALSE; } // process this message

SEED Infotech Ltd.

Page 26

MFC Hierarchy and Application Flow

if(m_msgCur.message != WM_KICKIDLE && ! PrevTranslateMessage ( m_msgCur)) { :: TranslateMessage ( &m_msgCur); :: DispatchMessage( &m_msgCur); } return TRUE ; }

The Message Map


Message map Macros How Message Map works A message map is a table that correlates messages with the member functions an application provides to handle those messages. The message map is MFCs way of avoiding the lengthy vtables that would be required if every class had a virtual function for every possible message it might receive. Any class derived from CCmdTarget can contain a message map.

Message map Macros


Message map contains one or more macros that specify which message will be handled by which function. The DECLARE_MESSAGE_MAP macro is used at the end of the declaration of the class. It indicates that there are Message map entries after the class for which handlers have been written as member functions of the class. The BEGIN_MESSAGE_MAP macro is used to begin the definition of Message Maps. The macro takes two parameter the class name of the derived class and the class name of the parent class. The macro entries for each message handler function should follow the BEGIN_MESSAGE_MAP entry. The END_MESSAGE_MAP macro marks the end of the definition of a message map. This indicates to MFC that there are no more message map entries for the particular class. Add member functions to handle the messages. BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd) ON_WM_PAINT ( ) END_MESSAGE_MAP ( )

BEGIN_MESSAGE_MAP begins the message map and identifies both the class to which the message map belongs and the base class. END_MESSAGE_MAP ends the message map. In between these two macros are macros identifying message map entries. ON_WM_PAINT is a macro defined in the MFC header file Afxmsg_.h, which adds an entry for WM_PAINT messages to the message map. MFC provides macros for more than 100 Windows messages ranging from WM_ACTIVATE to WM_WININICHANGE. To process a message for which MFC does not provide a message-map macro, create an entry for the message using the ON_MESSAGE macro, which accepts two parameters - the message ID and the address of the corresponding class member function. The following statement maps WM_SETTEXT messages to a member function named OnSetText ON_MESSAGE (WM_SETTEXT, OnSetText) Other special-purpose message-map macros provided by MFC include ON_COMMAND, which maps menu selections and other user-interface (UI) events to class member functions,

SEED Infotech Ltd.

MFC Hierarchy and Application Flow

Page 27

ON_UPDATE_COMMAND_UI, which correlates menu items and toolbar buttons with special update handlers that keep UI object in sync with other elements of the application. afx_msg void OnPaint ( ); DECLARE_MESSAGE_MAP ( ) afx_msg is a visual reminder that OnPaint is a message handler. You can omit it if youd like because it reduces to whitespace when its complied. The term afx_msg is meant to connote a function that behaves as a virtual function does but without requiring a VTable entry. DECLARE_MESSAGE_MAP is usually the final statement in the class declaration because it uses C++ access specifiers to specify the visibility of its members. You can follow DECLARE_MASSEGE_MAP with member declarations of your own, but if you do you should lead off with a public, protected or private keyword to ensure the visibility you want for those members.

How Message Map Works


MFCs DECLARE_MESSAGE_MAP macro adds three members to the class declaration : a private array of AFX_MSGMAP_ENTRY structures named _messageEntries that contains information correlating messages and message handlers; a static AFX_MSGMAP structure named messageMap that contains a pointer to the classs _messageEntries and a pointer to the base classs messageMap structure; and a virtual function named GetMessageMap that returns messageMaps address. BEGIN_MESSAGE_MAP contains the implementation for the GetMessageMap function and code to initialize the messageMap structure. The macros that appear between BEGIN_MESSAGE_MAP and END_MESSAGE_MAP fill in the _messageEntries array, and END_MESSAGE_MAP marks the end of the array with a NULL entry. // In the class declaration DECLARE_MESSAGE_MAP () // In the class implementation BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd) ON_WM_PAINT () END_MESSAGE_MAP ()

With this infrastructure the framework can call GetMessage() to get a pointer to CMainWindows messageMap structure. It can then scan the _messageEntries array to see if CMainWindow has a handler for the message, and if necessary it can grab a pointer to CFrameWnds messageMap structure and scan the base classs message map, too.

SEED Infotech Ltd.

Page 28

MFC Hierarchy and Application Flow

MessageMap structures CWnd &CCmdTarget:::messageMap &CWnd:_messageEntries [0] WM_DRAWITEM WM_MEASUREITEM CFrameWnd WM_CTLCOLOR WM_COMPAREITEM ............ ............ &CWnd::messageMap &CFrameWnd:_messageEntries [0] WM_INITMENUPOPUP WM_MENUSELECT WM_CREATE WM_DESTROY ...... .......
CFrameWnd::OnInitMenuPopup CFrameWnd::OnInitMenuPopup CFrameWnd::OnMenuSelect CFrameWnd::OnMenuSelect CFrameWnd::OnCreate CFrameWnd::OnCreate CFrameWnd::OnDestroy CFrameWnd::OnDestroy

CWnd::OnDrawItem CWnd::OnDrawItem CWnd::OnMeasureItem CWnd::OnMeasureItem CWnd::OnCtlItem CWnd::OnCtlItem CWnd::OnCompareItem CWnd::OnCompareItem

CMainWindow

&CframeWnd::messageMap CMainWindow::_messageEntries [0]

WM_PAINT WM_PAINT -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

CMainWindow::OnPaint CMainWindow::OnPaint

What MFCs message mapping mechanism amounts to is a very efficient way of connecting messages to message handlers without using virtual function. Virtual functions are not space efficient because they require VTables , and VTables consume memory even if the functions in them are not overridden. The amount of memory used by a message map in contrast is proportional to the number of message entries it contains. Since its extremely rare for programmer to implement a window class that includes handlers for all of the different message types, message mapping conserves a few hundred bytes of memory just about every time a CWnd is wrapped around an HWND.

SEED Infotech Ltd.

MFC Hierarchy and Application Flow

Page 29

Summary
Majority of the classes in MFC are derive from CObject. CWinApp is the base class from which your windows application object is derived. CWinApp class encapsulates WinMain function. CwinApp overridables are InitInstance Run ExitInstance OnIdle Any class derive from CCmdTarget has a message map. Message map is a table that correlates messages with member function an application provides to handle those messages. Message map macros include DECLARE_MESSAGE_MAP declaration. BEGIN_MESSAGE_MAP of your message map. END_MESSAGE_MAP used to end definition of used to begin definition used at the end of class

your message map.

Quiz
1) CObject provides following three features _______________, _____________ and _____________ . 2) What is Serialization ? 3) Which MFC class represents the application and encapsulates WinMain? 4) ________________ member function initializes the application. 5) What is a message map?

SEED Infotech Ltd.