MFC C++ Source Projects                                 

   Contact
   C
   C++
   Visual Basic
   Java
   JavaScript
   DHTML
   Style Sheets
   About
   Normalization
   Active X
   TDC Binding
   PHP
   Perl and CGI
   Flash
   XML
   SQL
   Chat
   MCSE
   Linux
   Cabling   
 

   
 
    
    
C++ Win 32 Project 1:   MFC Menu Binary Executable:  MFCmenu1.exe

Objective:  To become familiar with some components of a basic MFC application.  This project is part of our second MFC tutorial. 
                  It introduces menus, resource files, message maps, message identifiers, message handlers, and many commands,
                  methods and objects that have to do with Windows messaging applications.

Introduction: Messaging is necessary with Windows applications, since Windows is a multi-tasking environment and multiple
                     programs will be running simultaneously.  These programs communicate with each other and the operating
                     system through messages.

Getting Started:

1. Launch your Visual C++ compiler.
2. Select  File->New  and then select "Win 32 Application" from the list of available options.
3. In the Project Name box, type "Menus".
4. Click "OK".  On the next screen, make sure "Create an Empty Project" is selected and click "Finish".
5. The compiler will tell you it is creating a new skeleton project.  Select "OK" to continue.
6. Add files to the project.  Click File->New and select "C/C++ Header File" for the files below with the ".h" extension.  Select "C++
    Source File" for the files with the ".cpp" extension, and "Text File" for files with the ".rc" extension.  Do not forget to reformat
    text that wraps around multiple lines in the HTML.  This will create errors in your C++ programs unless this text is placed on the
    same line.
7. Then paste the code in the HTML tables below into the appropriate C++ project files.
8. Click Project->Settings and select "Use MFC in a Shared DLL" from the combobox.  Click "OK".
9. Rebuild, compile and link.

 File 1: CGermMFCMenu.h

// ©2004 C. Germany
// File 1 of 4 -  MFC Menu - Header File - CGermMFCMenu.h

const int TEXT_SIZE = 16;
class CGermMFCMenu : public CFrameWnd {

      public:
      CGermMFCMenu();
      ~CGermMFCMenu() 
      {
         delete m_pWindowText1; 
         delete m_pWindowText2;
      } 
       //Function and Message Handler Prototype Declarations 
      void tally( int & nCount, double dAmount );
      afx_msg void OnExit(); 
      afx_msg void OnDoCalculate(UINT nCalculate); 
      afx_msg void OnShowTotal();
      afx_msg void OnClearTotal();
      afx_msg void LaunchAdventure();
      afx_msg void LaunchHangMan();
      private:
      int m_nJava;
      int m_nVisualBasic;           //count items ordered
      int m_nCPlusPlus;
      int m_nPHP;   
      double m_dTotal;                   //tally cost of the order
      char m_szText[ TEXT_SIZE ];                     //output string
      ostrstream MFCOutputString;                  //output string stream
      //Declare 2 pointers to CStatic Window objects
      CStatic * m_pWindowText1;  
      CStatic * m_pWindowText2;
      DECLARE_MESSAGE_MAP()
};
In the file above, the class "CGermMFCMenu" derives from our mandatory CFrameWnd class.    We set up two pointers to CStatic textbox objects so that when we later create new ones on the heap we can point to them.   In this example, we are using Windows messages, so we have to declare our message handler prototypes.  These "message handlers" are functions that we will define to do various things when their appropriate messages are received.  Notice that at the bottom we must also include the "DECLARE_MESSAGE_MAP()" function.  We create two pointers to CStatic textboxes, as in our first MFC program.  The only other truly new item here is that we have created an instance of the ostrstream class.  

The string stream class (ostrstream) works with MFC programs in much the same way as cout << and cin >> work with console programs.   We instantiate an object of this class and call it "MFCOutputString".  This object will later receive two arguments - the first is the address of a character array, and the second is a variable indicating the size of the character array. 


 File 2: menu_ids.h

//File 2 of 4 - header file - menu_ids.h 
//Define messages used by menus.cpp and menus.rc
//IDs for windows messaging are arbitrarily assigned here - that is to say
//it doesn't matter what you assign for an ID as long as it is unique.

#define  IDM_EXIT        2000
#define  IDM_Java     2021
#define  IDM_VisualBasic        2022
#define  IDM_CPlusPlus   2041
#define  IDM_PHP    2042
#define  IDM_SHOW_TOTAL  2051
#define  IDM_CLEAR_TOTAL 2052
#define  IDM_ADVENTURE_GAME  2061
#define  IDM_HANG_MAN 2062
 
In the second file above, we are simply defining the message IDs for use with our menu resource file objects.  It does not matter what numerical value we assign to these messages - they simply MUST be unique identifiers so that they will not be confused with any other messages.  The syntax is to use:   #define  +  the resource file object name  +  the unique numerical identifier


 File 3: menus.cpp

//File 3 of 4 - WinMain() file - menus.cpp 

#include <afxwin.h>    // MFC application framework
#include <strstream>   // string stream
#include <iomanip>     // I/O manipulators
#include "menu_ids.h"  // application message ID symbols

using namespace std;   //need for 2003. NET

#include "CGermMFCMenu.h" //CMenu class
//----------------------------------------------------------------------------------------------------------------------------

// Scope resolves to CGermMFCMenu Declared in First File
//Define CGermMFCMenu constructor
CGermMFCMenu::CGermMFCMenu()                   // construct window
   : MFCOutputString( m_szText, TEXT_SIZE )    // initialize ostrstream object
{
   // Window Caption and Label. Note: "Calculate" is the name of the menu object from the .rc file
   Create( NULL, "C. Germany 2004 - MFC Menu Example", WS_OVERLAPPEDWINDOW,
      CRect( 0, 0, 300, 200 ), NULL, "Calculate" );


// Use the pointers to CStatic declared previously to create 2 static text
// boxes on the heap (free store) and write to their labels and captions.

m_pWindowText1 = new CStatic;   // create a static text control box

m_pWindowText1->Create("Subcontract programming fees and hourly rates.\nC. Germany 2004", //text to display
                        WS_CHILD | WS_VISIBLE | WS_BORDER | SS_CENTER,  //window styles
                        CRect( 70, 60, 210, 130  ),  // window coordinates
                        this ); //window to draw text in 

m_pWindowText2 = new CStatic;   // create a static text control box

m_pWindowText2->Create("Programming, rated by hour per programmer. Pick a language!", //text to display
             WS_CHILD | WS_VISIBLE | SS_CENTER,  //window styles
             CRect(22,10,270,50),  // window coordinates
             this ); //window to draw text in 

    //Initialize all variables to null
   m_nJava = m_nVisualBasic = 0;
   m_nCPlusPlus = m_nPHP = 0;
   m_dTotal = 0.0;

} // close CGermMFCMenu constructor defnition

//----------------------------------------------------------------------------------------------------------------------------
// count each type of item ordered, compute total bill
void CGermMFCMenu::tally( int & nCount, double dAmount )
{
   nCount++;
   m_dTotal += dAmount;
}

//----------------------------------------------------------------------------------------------------------------------------
//afx_msg precedes each message handler function.  We are setting up
//functions that, after they are called, will "listen" for messages.

afx_msg void CGermMFCMenu::OnExit() 
{
   SendMessage( WM_CLOSE ); 
}

//----------------------------------------------------------------------------------------------------------------------------
afx_msg void CGermMFCMenu::OnDoCalculate(UINT nCalculate) 
{
   switch (nCalculate)
   {
   case IDM_Java:
        tally( m_nJava, 50.75 );
        break;
   case IDM_VisualBasic:     
        tally( m_nVisualBasic, 45.25 );
        break;
   case IDM_CPlusPlus:
        tally( m_nCPlusPlus, 50.95 );
        break;
   case IDM_PHP:
        tally( m_nPHP, 45.10 );
        break;     
   }
}

//----------------------------------------------------------------------------------------------------------------------------
afx_msg void CGermMFCMenu::OnShowTotal()
{
   MFCOutputString.seekp( 0 );              // reset output string
   MFCOutputString << setprecision( 2 ) 
       << setiosflags( ios::fixed | ios::showpoint )
       << "        $" << m_dTotal << ends;  // stopper
   // display new dialog box with output string
   MessageBox( m_szText, "Your total project cost per hour by number and type of programmers is:" );
   m_dTotal = 0.0;
}

//----------------------------------------------------------------------------------------------------------------------------
afx_msg void CGermMFCMenu::OnClearTotal()
{
        m_dTotal = 0.0;
        MessageBox( "          $0.00", "Cleared Order" );
}

//----------------------------------------------------------------------------------------------------------------------------
afx_msg void CGermMFCMenu::LaunchAdventure()
{
        system("AdventureGame9.exe");
}

//----------------------------------------------------------------------------------------------------------------------------
afx_msg void CGermMFCMenu::LaunchHangMan()
{
        system("HangMan.exe");
}

//----------------------------------------------------------------------------------------------------------------------------

// Begin MessageMap is sort of like adding an itemListener() in Java... 
// Open Message Map Tags, tells compiler which function to call when a message is received.

BEGIN_MESSAGE_MAP( CGermMFCMenu, CFrameWnd )

   ON_COMMAND( IDM_EXIT, OnExit )
   ON_COMMAND_RANGE(IDM_Java, IDM_PHP, OnDoCalculate)
   ON_COMMAND( IDM_SHOW_TOTAL, OnShowTotal )
   ON_COMMAND( IDM_CLEAR_TOTAL, OnClearTotal )
   ON_COMMAND( IDM_ADVENTURE_GAME, LaunchAdventure )
   ON_COMMAND( IDM_HANG_MAN, LaunchHangMan )
END_MESSAGE_MAP()

//----------------------------------------------------------------------------------------------------------------------------

// Below, CMenusApp, deriving from the mandatory CWinApp, acts like main() in a 
// console program. It creates a new CGermMFCMenu on the heap, which itself derives from
// the mandatory CFrameWnd.  Remember that CGermMFCMenu was declared in the 1st file. 
class MakeCGermMFCMenu : public CWinApp {

      public:

      BOOL InitInstance()        // called by CWinApp::CWinApp
      {
           m_pMainWnd = new CGermMFCMenu;            // create window
           m_pMainWnd->ShowWindow( m_nCmdShow );  // make it visible
           m_pMainWnd->UpdateWindow();            // force refresh
           return true;                           // report success
      }
} // Notice there's no semicolon here at end of class specification


MakeCGermMFCMenu;                   // calls CWinApp::CWinApp constructor

//----------------------------------------------------------------------------------------------------------------------------

In the third file above, the first new thing we do is to include "strstrea.h" and "iomanip.h".    We then define the CGermMFCMenu constructor, which in turn creates an instance of ostrstream using our MFCOutputString declared in the class specification of the first file.  We pass to it the two arguments mentioned earlier, an address of a char array, and the size of that char array. 

The next thing we do is call Create() to create the main window, passing in its attributes as arguments.  Notice the last highlighted argument in the parameters that get passed to Create(), the one in quotes called "Calculate".  This is where we pass in the name of the Menu object created in the "menus.rc" file.   The name of this object in the .rc file is "Calculate".  Passing this object's name to the Create() function adds that menu object to the window.  The "WS_OVERLAPPEDWINDOW" argument  specifies that is is a typical window with a title bar, minimize, maximize and close buttons.

The CRect() function nested inside the Create() method specifies window location and size.  The arguments passed to this function specify that the coordinates of the top left corner will be 0, 0 (top left corner of the screen) and that the window will be 200 wide by 200 high. 

Next, our pointer, m_pWindowText1, creates a new CStatic textbox on the heap and then calls that object's Create() method.  The text to be displayed, the textbox's position and size, and its attributes are all passed in as parameters.  The data member pointer m_pWindowText2 does the same thing as the first data member pointer.

Next, some variables are initialized and a function is defined.  We must use the ostrstream object  to display information when using this function.  Now it begins to get interesting.

Next, we declare our message handler functions.  Notice that they are always prefixed with afx_msg.  After this prefix, specifying that the function is a message handler, the function is declared with a return type and arguments, just as any other function would be.  The command "SendMessage()", explicitly transmits a message, passing it the pre-defined "WM_CLOSE" message ID as an argument.  The message handler, "OnClose()", inherited from CWnd, will receive the message and close the window and terminate the program. 

The message handler function "OnDoCalculate" simply tallies up the resulting total of each item selected based upon the unique identifier of each message received.  Then, in the next two functions, message boxes are created to display the results, using MessageBox(), and passing in char arrays and literal strings as arguments.   

In the "OnShowtotal" function, a few new interesting items are introduced.  First, "seekp()" is used to to position the "put pointer" to the beginning of the string.  The fucntion seekp() is passed a 0 to move the pointer to the beginning of the string.  The "put pointer" is used to keep track of the subscript value of the characters in the array in order to determine where the next write will occur.  The "ends" passed to the MFCOutputString ostrstream object functions as "endl" would function with cout << in console programming.  the "setprecision(2)" is used to format the output of the float to two decimal places. 

Next, we use our message map tags to define our message map.  The message map is where we associate our message handlers with our message identifiers.  This tells our application which message handler function to call based on which message is received.  These are all placed between our "BEGIN_MESSAGE_MAP" and "END_MESSAGE_MAP" tags.   We use the macro "ON_COMMAND" to map a single message identifier to a single message handler.  We use the macro "ON_COMMAND_RANGE" to map multiple message identifiers to message handlers.  By convention, though not mandatory, the prefix "IDM" is used with message identifiers and the prefix "On" is used with message handlers. 

Finally, the class "MakeCGermMFCMenu" is used to create an instance of "CGermMFCMenu" on the heap and thus construct the window and run the program.  As in the previous example, we must again provide an InitInstance() method and supply it with the three items:

  • Create an instance on the heap of our CGermMFCMenu class that derives from CFrameWnd

  • Call the ShowWindow() method to make the window visible

  • Call UpdateWindow() to refresh/repaint the screen so it will display the window

Notice that in the MFC, "BOOL" is used as a return type.  Remember that C++ is case sensitive, and the MFC's "BOOL" is different from the standard "bool" we find in C++.  This holds true as well with the MFC's "TRUE" and "FALSE" - they are different from C++'s standard "true" and "false". 

Finally, we create an instance of MakeCGermMFCMenu, and this creates the window and launches the application. 


 File 4: menus.rc

// File 4 of 4 - resource script for menu - menus.rc 
// Note: Create this files as a new plain text file and save it as "menus.rc".

#include <afxres.h>
#include "menu_ids.h"

// Sets up menus, sub-menus and which message to broadcast when they are clicked
Calculate MENU
{
   POPUP "File"
   {
      MENUITEM "Exit", IDM_EXIT
   }
   POPUP "Games"
   {
      MENUITEM "Adventure Game", IDM_ADVENTURE_GAME
      MENUITEM "Hang Man", IDM_HANG_MAN
   }
   POPUP "Level 1"
   {
      MENUITEM "PHP Programming", IDM_PHP 
      MENUITEM "VisualBasic Programming", IDM_VisualBasic  
   }
   POPUP "Level 2"
   {
      MENUITEM "C++ Programming", IDM_CPlusPlus 
      MENUITEM "Java Programming", IDM_Java 
   }
   POPUP "Order"
   {
      MENUITEM "Total Hourly Charges", IDM_SHOW_TOTAL
      MENUITEM "Clear Total", IDM_CLEAR_TOTAL
   }
}
This last file is a resource file.  Resource files have their own language and terminology.  They have the ".rc" extension.  you can create them manually in a text file if you know the terminology, or you may create them visually using Microsoft's resource editor.  To add message identifiers and handlers to resource file objects, you can create them using the editor and then later import the .rc file into a text editor.

Whew!  This second MFC lesson was a woozie!  We have covered a LOT of new material concerning the MFC.
The subsequent lessons will focus on MFC objects and their attributes, one at a time.

©2004 C. Germany