
Contact
Search
C
C++
Visual Basic
Java
JavaScript
DHTML
Style Sheets
About
Active X
TDC Binding
PHP
Perl and CGI
Flash
XML
SQL
Messages
Chat
MCSE
Linux
Cabling
ActionScript
Downloads
E-Cards
|
I. General Introduction - The Microsoft Foundation Classes
The Microsoft Foundation Classes, known as the "MFC", are used for creating Windows Applications. The MFC provides a common application
programming interface (API) for Windows programs. It provides all of the features we expect from a Windows program: menus, minimize and
maximize buttons, text boxes, checkboxes, list boxes, combo boxes, radio buttons, graphics and multimedia. The MFC in Visual C++ can be
compared to the Abstract Windows Toolkit (AWT) in Java.
In contrast to the basic 32-bit console applications we have compiled previously, we must compile Windows applications by selecting "Win32
application" so that they will incorporate MFC .dll support. We do this by clicking "Project", and then "Settings". Then, in the "General" tab,
select the "Use MFC in a shared DLL" option.
There are three primary classes we deal with when using the MFC. They are:
CDialog = for creating basic program Windows with all their functionality
CFrameWnd = for creating basic program Windows with all their functionality
CWinApp = for creating and executing instances of Windows applications
Windows is an event driven, multi-tasking environment. As such, it needs a way of distinguishing between input and processes for various
programs that may be open simultaneously, and multiple instances that may be running of the same program. To do this, Windows uses
messaging. Some basic components of Windows messaging are:
Messages -
Everything in a Windows GUI communicates using messages.
Programs listen for messages to be sent and when they are
received, corresponding functions are executed.
WindowProc() or WndProc() - Function for
handling Windows messages.
DECLARE_MESSAGE_MAP() - MFC programs that use
messages must declare their message map by using the macro
"DECLARE_MESSAGE_MAP()" within
the class declaration. Forgetting to include this
macro is a non-fatal logic error
- your program will compile, but it will fail to function
properly.
Message Map - The message map is declared in the
source file (.cpp) and ties message identifiers to message
handlers with message
macros. All of this must be sandwiched between
BEGIN_MESSAGE_MAP and
END_MESSAGE_MAP tags.
Message Macros - indicate the messages the program
will handle. MFC pre-defined message macros have the
same name as their
message identifiers, but they are prefixed with "ON_".
For customized, programmer-defined macros, the command "ON_COMMAND"
associate's custom message identifiers with custom message
handlers.
Message Identifier - unique number (can be
arbitrarily assigned as long as each is unique)
Message Handler - functions that execute in response
to messages |
Here's a syntax example:
BEGIN_MESSAGE_MAP(owner class name,
base class)
//Message Handlers, identifiers and
macros.
END_MESSAGE_MAP() |
Some predefined message identifiers and their predefined message handlers are:
Message Identifier
WM_PAINT
ON_COMMAND (programmer defined) |
Message Handler
ON_WM_PAINT()
ON_COMMAND (programmer defined)
|
Message Queue - Queued messages are those that WinMain() extracts from the queue in a cyclical fashion. Non-queued messages call
the WindowProc() function directly and override the messages in the queue being processed by WinMain().
Message Loop - A block of code for retrieving Windows messages from the queue. Its structure is like:
| MSG msg;
while( GetMessage(&msg, 0, 0, 0) == TRUE) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} |
This details a three part process:
1 - GetMessage() - retrieve message from queue
2- TranslateMessage() - perform necessary covnersions
3 - DispatchMessage() - call WindowProc() to deal with the message
The structure of a Windows message is as follows:
struct MSG
{
HWND hwnd;
//Handle for the particular window
UINT message;
//Message ID
WPARAM wParam;
//Message parameter (32-bit)
LPARAM lParam;
//Message parameter (32-bit)
DWORD time;
//Time message was queued
POINT pt;
//Mouse position
} |
Cooperative multitasking - prevalent in Windows 3.1, depends on each individual application periodically giving up control of the CPU.
Pre-emptive multi-tasking - prevalent with Win 95 and beyond, the operating system can interrupt an application and transfer control to
another application.
API - Application Programming Interface
II. MFC Basics
CWinApp - Every MFC program MUST have exactly one instance of a class derived from CWinApp. Some call it
"InitInstance()" or "WinMain()" or "WndProc()" or WindowProc()", and it is comparable to main() in a console
application. It is "boiler plate code", used for an instantiation of a class derived from CWinApp. Example:
// A typical WinMain() function and its 4 basic arguments:
*
1
2
3
4
int WINAPI WinMain(HINSTANCE
hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow)
{
// function code goes here
} |
Analysis of WinMain()'s 4 arguments:
* = WINAPI is placed in front of functions called by Windows
1 = hInstance - 32bit int handle to a running instance of program, distinguishes between multiple instances
2 = hPrevInstance - old 16bit relic used with old Windows 3.1 programs, to prevent multiple instances
3 = lpCmdLine - pointer to string for accepting command line arguments when launched from command prompt
4 = nCmdShow - how window is to look when created
The code that would be placed into the WinMain() function would typically include:
BOOL StartTheWindow() {
m_pMainWnd = new WelcomeWindow();
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return
TRUE; } |
There are two basic objects we must derive from that we will deal with repetitively in Windows:
CStatic - A static MFC text box. Displays text but does not send messages, so it can not be used for input.
CDialog - A dynamic dialog box. They can send messages, therefore they can accept input and pass it to the program.
CEdit -
editable textbox that can receive user input.
GetDlgItem() - grabs address of CEdit, CStatic, checkbox
or other user object. Can then assign it to a pointer.
GetWindowText() - returns as string whatever text
is in an object.
SetWindowText() - sets text
of object pointed to with what is passed in.
SetFocus() - switches focus/cursor to window
calling this function.
DoModal() - makes
window called upon modal (modality).
atoi() -
converts string to integer (input from CEdit boxes comes in
as string data, must be converted).
itoa() -
converts integer to string.
DS_MODALFRAME -
resource file specifies that other windows can not be
accessed until this one closed
DEFPUSHBUTTON
- resource file button.
PUSHBUTTON - resource
file button.
WS_CAPTION - resource file title
bar.
WS_POPUP - resource setting indicates a
stand alone window, not a child.
WS_SYSMENU -
resource setting indicating system menu with close and move
menu items.
IDC_STATIC - static control
LTEXT - left text control
RTEXT -
right text control
CTEXT - center text control |
Resource
file - A plain ASCII text file with a ".rc" extension.
You can create and edit a resource file as a text file, then
add to project manually. Or you can use the graphical
editor and tool box to design a resource form manually.
The language used for this is a scripting language, separate
from C++, and is explicitly for user interface design.
It is compiled with the final project. Some resource
file keywords are: |
MENU -
resource keyword in resource script to create a menu
POPUP - resource keyword to create menu label
MENUITEM - resource keyword selectable menu item
afx_msg - denotes message ID ON_COMMAND -
prefixes message handlers between message map tags |
MFC components will be examined in detail, each one at a time in subsequent tutorials. You may begin these tutorials and your study
of MFC objects here:
Hungarian Notation - a case sensitive method of prefixing variables in most MFC programs according to their data types.
A table of prefixes follows:
Prefix
ar
b
c
c
d
l
lp
m_
n
i
p
s
sz
s_
|
Meaning
array
bool
char
class
double
long
long pointer
class member variable
integer
integer
pointer
string
string with null termination
static class member variable |
| Let's start off our
MFC studies with the traditional "Hello World" application.
In this example, we will only use 2 files, a header and a
source, and we will not be using a resource file. This
will give us an introduction to a basic MFC file:
Source File:
HelloMFC.exe
. |
// File 1 of 2. "Welcome.h" - First Program in C++ with MFC
//-----------------------------------------------------------------------------------------------------------------------------
class HelloWorldWindow : public CFrameWnd {
public:
HelloWorldWindow(); // constructor initializes window
~HelloWorldWindow(); // destructor releases resources
private:
CStatic * TextMessage; // Will hold the message
};
//-----------------------------------------------------------------------------------------------------------------------------
//CStatic is a static text box. Static meaning it does not send messages.
//Therefore it can not be used for user input.
|
|
In the header file above, we must derive from
"CFRameWnd", so we create a class called "HellowWorldWindow" to serve that
purpose. As a private data member, we create a pointer to a CStatic text
box that will later be used to create a new Static textbox on the heap.
|
// File 2 of 2. "Welcome.cpp" - First Program in C++ with MFC
// Include application framework windows class definitions:
#include <afxwin.h> // application frameworks header
#include "Welcome.h" // class definition for application
//---------------------------------------------------------------------------------------------------------------------------
// constructor initializes the window
HelloWorldWindow::HelloWorldWindow()
{
// Create Window with Title Bar
Create( NULL, // default CFrameWnd class
"Adventure Game 10.1", // window title
WS_OVERLAPPEDWINDOW, // full-featured window
CRect( 100, 100, 350, 300 ) ); // screen coordinates
TextMessage = new CStatic; // create a static control on heap. Point to it.
TextMessage->Create( // create Windows control
"Introduction to My Game", // text
WS_CHILD | WS_VISIBLE | WS_BORDER // window styles
| SS_CENTER, // static object styles
CRect( 60, 50, 185, 100 ), // window coordinates
this ); // context that owns child window
}
//---------------------------------------------------------------------------------------------------------------------------
HelloWorldWindow::~HelloWorldWindow()
{
delete TextMessage;
}
//---------------------------------------------------------------------------------------------------------------------------
// declare our application class based on CWinApp
class HelloMFC : public CWinApp {
public:
BOOL InitInstance() // override default function
{
m_pMainWnd = new HelloWorldWindow(); // create window on heap
m_pMainWnd->ShowWindow( m_nCmdShow ); // make visible
m_pMainWnd->UpdateWindow(); // force refresh
return TRUE; // report success
}
};
HelloMFC TEST; // creating an instance of the class will display the window.
//--------------------------------------------------------------------------------------------------------------------------- |
|
In the second file, notice
that we first include "afxwin.h",
which we need for MFC and windows objects. Next, we define
the constructor of
our "HelloWorldWindow" class which derived from our mandatory
CFrameWnd. Notice that inside the constructor, we call the
function "Create" and pass it several parameters. This
creates the main application window, set is size, position,
label and properties.
Next, we take our pointer to a CStatic textbox object and use it
to point to a new CStatic textbox we create on the heap.
We then call the
text box's Create() method and use its arguments to assign text,
properties, position and size attributes to the CStatic textbox.
We code
our constructor to take care of the pointer and heap object we
set up as a private data member in our class.
Finally, we create a class, "HelloMFC", which derives from our
mandatory "CWinApp" class. This defines a special
method that will be called
when this class is instantiated - "InitInstance()".
InitInstance() needs to do three things:
-
Create an
instance on the heap of our HelloWorldWindow 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
Yes, there is
a lot of data hiding going on here. The authors of the MFC
intended programmers to be able to use their objects without
having
to fathom all of their bits and pieces. At this point, we
will begin to deviate from standard C++ and focus solely upon
the MFC, Microsoft's
unique and specific toolkit for writing Windows C++
applications. We don't need to learn how to create
check boxes, radio buttons and text
boxes on our own - we simply need to learn how to use the ones
that have already been provided for us by Microsoft.
Let's look at
a basic Windows program form scratch.
Note: If you choose to
compile this example, you must NOT select the "Use MFC in a
shared .DLL" option.
// A native Windows program from scratch to display text in a window
#include <windows.h>
long WINAPI WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASS WindowClass; // Structure to hold our window's attributes
static char szAppName[] = "OFWin"; // Define window class name
HWND hWnd; // Window handle
MSG msg; // Windows message structure
// Redraw the window if the size changes
WindowClass.style = CS_HREDRAW | CS_VREDRAW;
// Define our procedure for message handling
WindowClass.lpfnWndProc = WindowProc;
WindowClass.cbClsExtra = 0; // No extra bytes after the window class
WindowClass.cbWndExtra = 0; // structure or the window instance
WindowClass.hInstance = hInstance; // Application instance handle
// Set default application icon
WindowClass.hIcon = LoadIcon(0, IDI_APPLICATION);
// Set window cursor to be the standard arrow
WindowClass.hCursor = LoadCursor(0, IDC_ARROW);
// Set gray brush for background color
WindowClass.hbrBackground = static_cast<HBRUSH>(GetStockObject(GRAY_BRUSH));
WindowClass.lpszMenuName = 0; // No menu, so no menu resource name
WindowClass.lpszClassName = szAppName; // Set class name
// Now register our window class
RegisterClass(&WindowClass);
// Now we can create the window
hWnd = CreateWindow(
szAppName, // the window class name
"A Basic Window the Hard Way", // The window title
WS_OVERLAPPEDWINDOW, // Window style as overlapped
CW_USEDEFAULT, // Default screen position of upper left
CW_USEDEFAULT, // corner of our window as x,y...
CW_USEDEFAULT, // Default window size
CW_USEDEFAULT, // ....
0, // No parent window
0, // No menu
hInstance, // Program Instance handle
0 // No window creation data
);
ShowWindow(hWnd, nCmdShow); // Display the window
UpdateWindow(hWnd); // Cause window client area to be drawn
// The message loop
while(GetMessage(&msg, 0, 0, 0) == TRUE) // Get any messages
{
TranslateMessage(&msg); // Translate the message
DispatchMessage(&msg); // Dispatch the message
}
return msg.wParam; // End so return to Windows
}
// Listing OFWIN_2
long WINAPI WindowProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam)
{
HDC hDC; // Display context handle
PAINTSTRUCT PaintSt; // Structure defining area to be drawn
RECT aRect; // A working rectangle
switch(message) // Process selected messages
{
case WM_PAINT: // Message is to redraw the window
hDC = BeginPaint(hWnd, &PaintSt); // Prepare to draw the window
// Get upper left and lower right of client area
GetClientRect(hWnd, &aRect);
SetBkMode(hDC, TRANSPARENT); // Set text background mode
// Now draw the text in the window client area
DrawText(
hDC, // Device context handle
"Who am I, and why am I here? What thoughts these words betray ...",
-1, // Indicate null terminated string
&aRect, // Rectangle in which text is to be drawn
DT_SINGLELINE| // Text format - single line
DT_CENTER| // - centered in the line
DT_VCENTER); // - line centered in aRect
EndPaint(hWnd, &PaintSt); // Terminate window redraw operation
return 0;
case WM_DESTROY: // Window is being destroyed
PostQuitMessage(0);
return 0;
default: // Any other message - we don't want to know,
// so call default message processing
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
|
For the next
lesson, go on to the :
MFC Menu Application .
Supplementary:
| Using the Debugger
- Since using the MFC will add complexity to our C++
programs, let's become familiar with the debugger. You
use the C++
debugger by setting "breakpoints". You do this by
clicking "Insert/Remove Breakpoint" from the "Build"
toolbar. Selecting "Go" from the
Build -> Start Debug submenu will start the debugging
process. The program will stop between breakpoints and
when asking for input. You can
switch back and forth between the debug and run-time program
windows with Alt + TAB. You may use the "Watch" window
to view and change
the values of variables.
"Break Execution"
allows the programmer to stop the program in mid-execution.
"Apply Code Changes" allows changing
the code while the program is running and seeing its
effects. The "Show Next Statement" repositions the
cursor on the next line where execution will begin, and so
is useful for editing that line.
The "Step Into"
feature executes program statements, one per click, and the
"Step Out" exits them. "Run to Cursor" executes all
code up to the position of the cursor. "Quick Watch"
is useful for monitoring variable values. The "Call
Stack" button displays the program's function call stack - a
list of functions that were called in order for the flow of
the program to be where it currently is. |
|

|
|