Visual C++ Workshop
Session 8
R. Eckert

MFC WINDOWS PROGRAMMING (APP/WINDOW APPROACH)

The Microsoft Foundation Class (MFC) Library--

A Hierarchy of C++ classes designed to facilitate Windows programming
An alternative to using Win32 API functions
A Visual C++ Windows app can use either Win32 API MFC or both:


About 200 MFC classes (versus 2000+ API functions)
Provide a framework upon which to build Windows applications
Encapsulate most of Win32 API in a set of logically organized classes

Some characteristics of MFC:

1. Offer convenience of REUSABLE CODE:
     Many tasks common to all Windows apps are provided by MFC
     Our programs can inherit and modify this functionality as needed
     We don't need to recreate these tasks
     MFC handles many clerical details in Windows programs

2. Produce smaller executables:
     Typically 1/3 the size of their API counterparts

3. Can lead to faster program development:
     But there's a steep learning curve--
          Especially for newcomers to object-oriented programming

4. MFC Programs must be written in C++ and require the use of classes:
     Programmer must have good grasp of:
          How classes are declared, instantiated, and used
          Encapsulation
          Inheritance
          Polymorphism--virtual functions

MFC Class Hierarchy (See online help on "Hierarchy Chart")--

CObject: At top of hierarchy ("Mother of all classes")
     Provides features like serialization (disk reading/writing)
     All its functionality is inherited by any classes derived from it

Important Derived Classes--

     CFile: Support for file operations

     CDC: Encapsulates the device context (Graphical Drawing)

     CGdiObject: Base class for various drawing objects (bitmaps, pens, etc.)

     CMenu: Encapsulates menu management

     CCmdTarget: Encapsulates message passing process & is parent of:

          CWnd: Base class all windows are derived from; most common:

               CFrameWindow: Can contain other windows
                    ("normal" kind of window we've been using)

               CView: Encapsulates process of displaying data

               CDialog: Encapsulates dialog boxes

          CWinThread: Defines a thread of execution & is parent of:

               CWinApp: Most important class dealt with in MFC apps:
                    Encapsulates an MFC application
                    Controls following aspects of Windows programs:
                         Startup, initialization, execution, shutdown
                    An application should have one CWinApp object
                    When instantiated, application begins to run

          CDocument:
               Encapsulates the data associated with a program

Primary task in writing MFC program--to create classes
     Most will be derived from MFC library classes


MFC Class Member Functions--

Most functions called by an app will be members of an MFC class

Examples: 
     ShowWindow()--a member of CWnd class
     TextOut()--a member of CDC
     LoadBitmap()--a member of CBitmap

Applications can also call API functions directly
     More convenient to use MFC member functions

MFC Global Functions--

Not members of any MFC class
Always begin with Afx prefix (Application FrameworKS)
Independent of or span MFC class hierarchy

Example: 
     AfxMessageBox()--
          Message boxes are predefined windows
          Can be activated independently from rest an application


A Minimal MFC Program (App/Window Approach)
 
Simplest MFC programs must contain two classes derived from hierarchy:

     An application class derived from CWinApp--
          Defines the application

     A window class usually derived from CFrameWnd--
          Defines the application's main window

     Every MFC program must have these two classes


Message Processing under MFC--

Like API programs, MFC programs must handle messages from Windows

     API mechanism: huge switch/case statement

     MFC mechanism: "message maps" (lookup tables):

     Table entries:
          Message number 
          Pointer to a derived class member message-processing function

     Programs must:
          Declare message-processing functions
          Map them to messages app is going to respond 
               Mapping by "message-mapping macros" 

     Most MFC app windows use a window procedure supplied by library

     Message maps enable the library window procedure to find the function    
     corresponding to the current message



SPECIFIC STEPS IN WRITING A SIMPLE MFC PROGRAM (App/Window Approach)--

A. DECLARATIONS (.h)

1. Declare a window class derived from CFrameWnd (e.g., CMainWin)--
Class Members:
     The constructor
     Message-processing ftn declarations [e.g., afx_msg void OnChar()]
     DECLARE_MESSAGE_MAP() macro:
          Allows windows based on this class to respond to messages
          Declares that a msg map will be used to map messages to functions
          Should be last class member declared

2. Declare an application class derived from CWinApp (e.g., CApp)--
     Must override CWinApp's InitInstance() virtual function:
          Called each time a new instance of application is started
               (i.e., when an object of this class is instantiated)

B. IMPLEMENTATION (.CPP)

1. Define constructor for class derived from CFrameWnd (CMainWin)--
     Should call member function Create() to create the window
          Does what CreateWindow() does in API programming

2. Define message map for class derived from CFrameWnd CMainWin)--
     BEGIN_MESSAGE_MAP(owner, base)
            List of "message macros" [e.g., ON_WM_CHAR()]
     END_MESSAGE_MAP()

3. Define (implement) message-processing functions declared in 1 above--

4. Define (implement) InitInstance() overriding function--
   Done in class derived from CWinApp (CApp):
     Should have initialization code for each new instance of the app:
          Create a CMainWin object  pointer to program's main window
              (Used to refer to the window, like hWnd in API programs)
          Invoke object's ShowWindow() member function
          Invoke object's UpdateWindow() member function
          Must return non-zero to indicate success
     [MFC's implementation of WinMain() calls this function]

Nature & form of simple window & application have been defined      
     But neither exists--
     Must instantiate an application object derived from CWinApp (CApp)

5. Create an instance of the application class (CApp)
   Causes WinMain() to execute--it's now part of MFC [WINMAIN.CPP]
   WinMain() does the following:
        Calls AfxWinInit()--
             which calls AfxRegisterClass() to register window class
        Calls CApp::InitInstance() [virtual function overridden in 4 above]--
             which creates, shows, and updates the window
        Calls CWinApp::Run()--
             which calls CWinThread::PumpMessage()--
                  which contains the GetMessage() loop
        After this returns (i.e., when the WM_QUIT message is received)--
        AfxWinTerm() is called--
             which cleans up and exits


PROG1 Example MFC Application: Just creates a skeleton frame window--



Specific Steps in Creating and Building an MFC Application like PROG1 
"Manually" using Microsoft Developer Studio--
 
1. "File | New", "Win32 Application" as always
   Enter a Project Name and Location as usual

2. Enter header file text (e.g., PROG1.H)--see DECLARATIONS above
   Enter source text (e.g., PROG1.CPP)--see IMPLEMENTATION above
   [If already entered, copy into project's directory and:
          "Project | Add To Project | Files", entering name of .CPP file.]

2. "Project | Settings", "General" Tab
   From "Microsoft Foundation Classes:" combo box, choose:
          "Use MFC in a Shared DLL"

3. Build the project as usual

<See PROG1.H and PROG1.CPP Listings>


MSG1 Example MFC Application: Mouse/Character Message Processing--



User presses mouse button
     Left/Right Button down==>string displayed at current mouse cursor position
Keyboard key pressed==>
Character displayed at upper lefthand corner of client area

<See MSG1.H and MSG1.CPP Listings>


DEVELOPING AND USING RESOURCES WITH MFC:

Menus in App/Window Programs--

Create .rc file manually with text editor

Or visually with Developer Studio resource editorsresource.h & .rc files
     Both should be edited to get rid of extra "garbage"
          (Used by AppWizard) 

resource.h file:
     Should only contain #defines for menu item IDs
 
program's .rc file:
     Should only have menu section and two #includes at the top--
          #include <afxres.h>
          #include "resource.h"

All other stuff should be edited out 

Add .cpp source file and .rc file to project and build (as usual)


MENU1 Example Program--



Has menu with items "One", "Two", and "Help"
     "One" a popup with items "Alpha" and "Beta" 
     "Two" a popup with item "Gamma" 
Selection of any menu item==>appropriate message box is displayed

Left mouse button pressed==>"Abort/Retry/Ignore" message box
     Appropriate message box depending on which button user selects from

MENU1.RC Resource Script File--

Created with Developer Studio's menu editor --> RESOURCE.H
Both edited to get rid of AppWizard "garbage"


USING MODAL DIALOG BOXES IN MFC--

Dialog Box--child window containing one or more child window controls
Dialog template given in resource (.rc) file

Under Win32 API:
     Created with DialogBox() or DialogBoxParam()
     Messages from controls handled by Msg-processing function--
          Uses switch/case statement to handle msgs from

Under MFC:
     Dialog boxes encapsulated by the CDialog class (derived from CWnd)     
     App should derive its own dialog box class from CDialog
     Dialog box message handling done with message maps
          Dialog box class declarations (.h file):
               Message handling functions
               Message map
          Dialog box class implementation (.cpp file) defines:
               Dialog box message map
               Message handler functions

Creating a dialog box under MFC:
     Constructor of CDialog-derived class should call CDialog constructor
          Arguments: ID of dialog box (as specified in .rc file), owner window
          Creates the dialog box (not activated yet)
     Init code should be placed in CDialog's OnInitDialog() handler function     
          (Invoked in response to the WM_INITDIALOG message)

Activating dialog box under MFC:
     Use CDialog's DoModal() member function
          Displays dialog box
          Msgs from dialog box controls go to dialog box handler functions
          Until dialog box has been closed with CDialog's EndDialog()
               DoModal() returns & main message processing continues

DIALOG1 Example Program--



User clicks "Dialog" main menu item:
     Modal dialog box containing "Red", "Green", "Cancel", "OK" buttons     
     User chooses "Red" or "Green" buttons:
          Message box with appropriate text appears
     User chooses "Cancel" or "OK" buttons:
          Dialog box closes
User clicks "Exit" main menu item:
     window is closed and program terminates

DIALOG1.RC and RESOURCE.H files--

Created with Developer Studio's menu and dialog box editors
"Garbage" edited out
Dialog box ID name: "SAMPLEDIALOG"
Default ID's for dialog box "OK" and "Cancel" buttons: IDOK, IDCANCEL
     CDialog contains default handlers for their WM_COMMAND messages

DIALOG1.H and DIALOG.CPP <See Listings>


DIALOG BOXES CONTAINING LIST BOXES--

List boxes: controls that both generate and receive messages

Under Win32 API:
     App uses SendDlgItemMessage() to send messages like:
          LB_ADDSTRING, LB_GETCURSEL, LB_GETTEXT, etc. 
List box sends messages in response to user selecting items

Under MFC:
     App uses CListBox-derived class member functions to send messages
          e.g., AddString(), GetCurSel(), GetText(), etc. (See online help)
     To identify control message is for, use CWnd's GetDlgItem() function
          Returns a pointer to the control--which should be typecast:
     CListBox *plistbox = (CListBox *)GetDlgItem(CONTROL_ID);
          Pointer used to access member functions to send messages control    
              Example:
                   plistbox->AddString("some string");
                   Causes "some string" to be added to list box

List box initialization--

     Override WM_INITDIALOG message handler, OnInitDialog()--
          Adds strings to the list with calls to AddString()
     Declare OnInitDialog() in section of .h file that declares CDialog class. 
     OnInitDialog() definition (in .cpp file):
          Call base class OnInitDialog() 
          Make calls to AddString() to fill the dialog box


DIALOG2 Example Program--



User clicks "Dialog" main menu item:
     Dialog box with fruit selection list box appears
     User double clicks fruit or selects fruit & presses "Select Fruit" button    
          Message box appears with fruit selection and position in list box

Dialog box messages of interest:
     IDD_SELFRUIT 
          (the button)
     LBN_DBLCLK of ID_LB1 list box
          (notification code generated when user double clicks item in list box) 
     Dialog's Message Map defines OnSelect() to be handler for both
          Calls GetDlgItem()-->Pointer to the list box
          Invokes GetCurSel() and GetText() to retrieve item selected