You are on page 1of 28

Microsoft Foundation Classes

MFC is an application framework providing an Object


Oriented (OO) encapsulation of the Win32 API
Win32 API too cumbersome for todays complicated apps
Many (most?) of todays native Windows apps are written
in MFC
Written in C++
MFC is to Win32 as C++ is to C
Knowledge of OO principles is a must-have to understand
MFC, but not necessarily to use it for routine Windows
apps
Heavily dependent upon abstraction, inheritance,
polymorphism, etc.
Hides much of the mundane Win32 API for example, no
more WndProc(), WinMain() (theyre there, somewhere,
but they are mostly hidden)

MFC Overview
Well over 200 classes exist, ranging from GUI to data
manipulation to OLE support to Internet support
Typical MFC naming convention (follows
Hungarian)C<class name> example CPen
Most MFC classes are subclasses of class CObject
CObject

(pardon the PowerPoint UML)

CWnd

CWnd, after a fashion, is derived from (is-a) Cobject


Inheritance and Abstraction are essential concepts of MFC
Some classes are not CObject derived (CString for
example) yet still provide very useful features

MFC Fundamentals
Several classes are fundamental encapsulations of Win32
functionality (well cover some of these much more)
CWinApp encapsulates the concept of a Win32 application
CCmdTarget encapsulates message pump functionality
CWnd encapsulates a generic window
CDialog encapsulates a generic dialog window
CString encapsulates C-style string manipulation (similar
to std::string) (not derived from CObject)
Many, many more CEditBox, CListBox, CMenu, CDC,
CBitmap, etc.
Some functionality has been abstracted without the use of
classes generally Afx<function name>()
Generally stick to available Afx-equivalent functions in
MFC apps if possible

MFC Fundamentals (cont.)


Developers generally inherit from MFC classes that
provide some functionality theyre interested in
Just as important as this free functionality, however, is that
this inheritance approach provides a consistent footprint
for your application classes
This is where polymorphism comes into play and is a
major component of MFC messaging
When you derive your window class from CWnd, MFC
knows your class has an OnPaint() method, for example
The framework, upon receiving a WM_PAINT for that
window, simply calls OnPaint() directly
If you have unique drawing requirements for that window,
you can implement your own OnPaint() functionality by
overriding CWnd::OnPaint()
NO MORE PEDANTIC MESSAGE PARSING!

MFC Messaging
So, how is WinMain, WndProc, Messaging, etc. handled in
an MFC app?
MFC applications instantiate a CWinApp-derived class
(derived by you)
CWinApp is typically global and only instantiated once at
program startup (global vars allocated at program start)
CWinApp constructor, called implicitly, kicks things off
CWinApp handles the message pump Peek, Get, Idle,
Pump, etc see CWinApp::Run
It also provides two methods, InitInstance, ExitInstance, to
allow you to initialize at app startup, or cleanup at exit
CWinApp delivers windows messages to windows
belonging to it
Those windows (CWnd derivatives) invoke various virtual
functions based on messages received

MFC Messaging (cont.)


Basic WM_PAINT message flow:
App

CWinApp::Run()
WM_PAINT
(hwnd, rect)

CWinApp::PumpMessage()

AfxWndProc()

(PeekMessage)

(Get/Translate/Dispatch)

(uses hwnd to CWnd map)

CWnd::WindowProc()
Message Map Magic
CWnd::OnPaint()

(uses msg to virtual map)

CYourWnd::OnPaint()
(voila)

MFC Messaging (cont.)


Wait what happened to HPARAM / LPARAM?
MFC usually parses the message args into meaningful
parameters sometimes complex
WM_LBUTTONDOWN example,
CYourWnd::OnLButtonDown(UINT, CPoint)
Sometimes, the info is available in different ways
WM_PAINT example:
void CYourWnd::OnPaint()
{
// get update rect, device context, etc
CPaintDC lcDC(this);
// ctor does many things for us
// gets DC, upd rect, etc
// lcDC.m_ps PAINTSTRUCT structure, filled in with tidbits
lcDC.TextOut(0,0,Testing.);
// lcDC dtor is called when function ends (out of scope)
// which cleans up (ReleaseDC(), etc.)
}

Simple MFC App


Result of all this encapsulation and abstraction?
Win32 apps are much easier to
create/debug/maintain/etc.
M$ provides some template applications via the
MFC AppWizard
Well look at a simple hello world MFC app
created for us by the AppWizard
3 classes: CMyApp, CMainFrame, CChildView
In Visual
New MFC Project
Single Document Interface (SDI)
Uncheck Document/View architecture support
MFC Standard, Use MFC in a shared DLL
No Status Bar, no Docking
No ActiveX
Name app class CMyApp (just for fun)

Simple MFC App


CMyApp
Main application class, handles initialization
(InitInstance), creates frame, other CWinApp
things

CMainFrame
Frame window class container for your main
window in an SDI app, handles most messages,
accelerators, menus, resizing, etc.
Frame windows are somewhat special (more
special in MDI apps)

CChildView
Your window!

Simple MFC App: CMyApp


// HelloWorldMFC.h : main header file for the app
//
#pragma once
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file
for PCH
#endif
#include "resource.h"

// main symbols

// CMyApp:
// See HelloWorldMFC.cpp for the implementation
class CMyApp : public CWinApp
{
public:
CMyApp();

// Overrides
public:
virtual BOOL InitInstance();
// Implementation
public:
afx_msg void OnAppAbout();
DECLARE_MESSAGE_MAP()
};

// HelloWorldMFC.cpp : Defines the class behaviors for app


#include "stdafx.h"
#include "HelloWorldMFC.h"
#include "MainFrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CMyApp
BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
END_MESSAGE_MAP()
// CMyApp construction
CMyApp::CMyApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
// The one and only CMyApp object
CMyApp theApp;
// CMyApp initialization
BOOL CMyApp::InitInstance()
{
InitCommonControls();
CWinApp::InitInstance();
// TODO: You should modify this string
// such as the name of your company or organization
SetRegistryKey(_T(SomeRegKey"));

extern CMyApp theApp;

Simple MFC App: CMyApp


// To create the main window, this code creates a new
// frame window object and then sets it as the
// application's main window object
CMainFrame* pFrame = new CMainFrame;
if (!pFrame)
return FALSE;
m_pMainWnd = pFrame;
// create and load the frame with its resources
pFrame->LoadFrame(IDR_MAINFRAME,
WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL,
NULL);

// App command to run the dialog


void CMyApp::OnAppAbout()
{
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
// CMyApp message handlers

}
// CMyApp message handlers
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
enum { IDD = IDD_ABOUTBOX };

// Implementation
protected:
DECLARE_MESSAGE_MAP()
};

void CAboutDlg::DoDataExchange(CDataExchange* pDX)


{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()

// The one and only window has been initialized,


// so show and update it
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;

protected:
virtual void DoDataExchange(CDataExchange* pDX);
DDX/DDV support

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

//

Simple MFC App: CMainFrame


// MainFrm.h : interface of the CMainFrame class
//
#pragma once

// MainFrm.cpp : implementation of the CMainFrame class


#include "stdafx.h"
#include "HelloWorldMFC.h"
#include "MainFrm.h"

#include "ChildView.h"
class CMainFrame : public CFrameWnd
{
public:
CMainFrame();
protected:
DECLARE_DYNAMIC(CMainFrame)
// Attributes
public:
// Operations
public:
// Overrides
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo);
// Implementation
public:
virtual ~CMainFrame();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
CChildView
m_wndView;

#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CMainFrame
IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_CREATE()
ON_WM_SETFOCUS()
END_MESSAGE_MAP()
// CMainFrame construction/destruction

CMainFrame::CMainFrame()
{
// TODO: add member initialization code here
}
CMainFrame::~CMainFrame()
{
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;

// Generated message map functions


protected:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSetFocus(CWnd *pOldWnd);
DECLARE_MESSAGE_MAP()
};

// create a view to occupy the client area of the frame


if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
{
TRACE0("Failed to create view window\n");
return -1;
}
return 0;
}

Simple MFC App: CMainFrame


BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by
// modifying the CREATESTRUCT cs

cs.dwExStyle &= ~WS_EX_CLIENTEDGE;


cs.lpszClass = AfxRegisterWndClass(0);
return TRUE;
}
// CMainFrame diagnostics
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
CFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
CFrameWnd::Dump(dc);
}
#endif //_DEBUG
// CMainFrame message handlers
void CMainFrame::OnSetFocus(CWnd* /*pOldWnd*/)
{
// forward focus to the view window
m_wndView.SetFocus();
}

BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra,


AFX_CMDHANDLERINFO* pHandlerInfo)
{
// let the view have first crack at the command
if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// otherwise, do default handling
return CFrameWnd::OnCmdMsg(nID, nCode,
pExtra, pHandlerInfo);
}

Simple MFC App: CChildView


// ChildView.h : interface of the CChildView class
//
#pragma once

// ChildView.cpp : implementation of the CChildView class


//

// CChildView window

#include "stdafx.h"
#include "HelloWorldMFC.h"
#include "ChildView.h"

class CChildView : public CWnd


{
// Construction
public:
CChildView();

#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CChildView

// Attributes
public:
// Operations
public:
// Overrides
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
// Implementation
public:
virtual ~CChildView();
// Generated message map functions
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
};

CChildView::CChildView()
{
}
CChildView::~CChildView()
{
}
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
END_MESSAGE_MAP()
// CChildView message handlers
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CWnd::PreCreateWindow(cs))
return FALSE;
cs.dwExStyle |= WS_EX_CLIENTEDGE;
cs.style &= ~WS_BORDER;
cs.lpszClass =
AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW),
reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), NULL);
return TRUE;

Simple MFC App: CChildView


void CChildView::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
dc.TextOut(10,10,"Hello world!");
// Do not call CWnd::OnPaint() for painting messages

The Message Map Macros


Message map macros provide convenient way to direct
specific messages to specific functions
Assumes, of course, classes are MFC derived
(header file)

// Generated message map functions


protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
};
(src file)

BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
END_MESSAGE_MAP()

void CChildView::OnPaint()
{
CPaintDC dc(this);
dc.TextOut(10,10,"Hello world!");
}

One of Many IDE Shortcuts


Visual Studio has many convenient shortcuts for MFC app
developers
Instead of manually adding message handlers, we can use
the IDE to insert the appropriate message map macros and
function footprints into our class
For example: To add WM_LBUTTONDOWN support to
CChildView, do the following:
In ClassView
Right-click on CChildView, properties
Press the Messages button
Scroll down to WM_LBUTTONDOWN
Click in right column, drop-down window, pick default name
Voila check your CChildView source code and notice what was added

In-Class Project
Create your own MFC application just like the example
Non-dialog based, SDI
Draw the random shapes (Joe not sure which homework
this was or if it was even a homework at all)

Hints:
You will need to handle WM_PAINT
and perhaps WM_TIMER? F1 help on SetTimer

Homework
MFC-ize homework

MFC Continues
Well continue to MFCize various previously
assigned programs
Same concepts apply MFC provides class
encapsulations of the majority of Win32
functionality
Well review the MFCizing of HW5 which
covers:
Additional WM_**** handlers (WM_VSCROLL, etc.)
Child controls (/windows) (CButton, etc.)
Handling control commands
(ON_COMMAND[_RANGE])
Menus
Accelerators

This should prepare you for MFCizing the chat


program

Some new MFC wrappers


CButton - Encapsulates a button control
window
CScrollBar Encapsulates a scroll bar
control window
CPen / CBrush encapsulates GDI objects
CMenu encapsulates a menu control
window (associated with IDR_*** menu
resource)

WM_DRAWITEM
As you know, this message allows us to
draw our own controls
This is a basic MFC message conversion
added message handler (via IDE)
CChildView::OnDrawItem()
MFC passes us a pointer to the relevant
DRAWITEMSTRUCT as a param
Not a lot new here
Note: CWnd::OnDrawItem() may cause
trouble, recommend not calling it

WM_VSCROLL - OnVScroll
CScrollBar encapsulates child scroll control
Called on parent window (our CChildView) when a child
scroll control (SB_VERT) has been affected
We assigned child-parent relationship when we called
maScrolls[X].Create(,this,) in
CChildView::OnCreate()
Most windows have only one vertical scroll bar (and
perhaps one horizontal bar)
Thus, MFC does not send the control ID in the
OnVScroll() param list
No problem, MFC does supply the actual pointer to the
CScrollBar object that was affected
We can compare HWNDs to determine which control was
affected
The rest of the function is nearly identical to the
WM_VSCROLL handler (with typical MFC changes)

ON_COMMAND_RANGE
Instructs MFC to invoke a particular method on a
window when any of the commands in the given
range are received (for example, child controls)
Part of the message map macro example:
ON_COMMAND_RANGE(1, 10, OnCommands)

We have to add this manually


I have it calling CChildView::OnCommands()
MFC sends the actual command ID in
OnCommands(), we switch off that to
determine what to do (which child control fired)
The controls were interested in are IDs 1-10 (ID
of 0 is illegal in MFC this is a change from
original HW5)

ON_COMMAND - Menus
MFC, by default, gives us a default menu
Each menu selection corresponds to a specific ID
(event)
We can use the IDE to edit the menu and correlate
specific menu events with specific functions on
our window(s)
Its quite similar to the WM_**** - message
handler correlation technique
As we add menu event handlers, Visual adds
ON_COMMAND entries into our windows
message map
Lets take a look
& in front of a character represents a menu
shortcut (&Edit->&Copy becomes Edit->Copy)

Accelerators
An accelerator is an even shorter cut
Control-C for copy, for example
Visual lets you edit the accelerator table
directly
You can also hook accelerators to functions
similarly to hooking menu events
Typically accelerators are hooked to menu
events, so thats what well look at
Lets take a look

Popup menu - CMenu


On right button down, the example uses
CMenu to load a menu resource, assign a
submenu to a popup style menu, and pop up
the menu at specific coordinates
It then uses the apps main window
(CMainFrame in this case) to track the
menu
// simple popup menu, using existing menu resource
void CChildView::OnRButtonDown(UINT nFlags, CPoint point)
{
ClientToScreen(&point);
CMenu menu;
menu.LoadMenu(IDR_MAINFRAME);
CMenu* popup = menu.GetSubMenu(1);
popup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
point.x, point.y, AfxGetApp()->m_pMainWnd);
}

Chat MFC style


Most MFC concepts have been covered
enough to enable you to MFCize the chat
program
A note about threads in MFC:
AfxBeginThread() usage
{

AfxBeginThread(SomeThreadFunc, (LPVOID)this);

}
UINT CChildView::SomeThreadFunc( LPVOID pParam )
{

!!! Do NOT call GUI methods from worker


threads !!! (Try PostMessage() instead)