[ Home | Syllabus |Course Notes]
SINGLE FOCUS OF USER INPUT <=> SINGLE POINT OF PROGRAM CONTROL
Pioneering work of XEROX PARC (Palo Alto Research Center) 1970's
Route input request to proper program segment
Last fits nicely with an object oriented approach using inheritance.
Complex windows "objects" can be built and reused easily.
There are about 200 Windows 95 messages.
Each message starts with "WM_"
/*------------------------------------------------------------ HELLOWIN.C -- Displays "Hello, Windows 95!" in client area (c) Charles Petzold, 1996 ------------------------------------------------------------*/ #include <windows.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) // hinstance is HANDLE to this thread // hPrevInstance (obsolete) // szCmdLine - command line parameters // iCmdShow - initial window mode { static char szAppName[] = "HelloWin" ; HWND hwnd ; MSG msg ; WNDCLASSEX wndclass ; wndclass.cbSize = sizeof (wndclass) ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; // redraw on Hor and Ver size changes wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; // predefined icon wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; // paint background with this wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ; RegisterClassEx (&wndclass) ; hwnd = CreateWindow (szAppName, // window class name "The Hello Program", // window caption WS_OVERLAPPEDWINDOW, // window style // normal style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL) ; // creation parameters ShowWindow (hwnd, iCmdShow) ; // show window UpdateWindow (hwnd) ; // send WM_PAINT message while (GetMessage (&msg, NULL, 0, 0)) // msg is a structure with // hwmd // message ID // wParam,lParam // time // pt - mouse position // returns false if WM_QUIT { TranslateMessage (&msg) ; // have system perform keyboard translation on raw input DispatchMessage (&msg) ; //pass message back to windows which passes to appropriate window procedure } return msg.wParam ; // return code } LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hdc ; PAINTSTRUCT ps ; RECT rect ; switch (iMsg) { case WM_CREATE : PlaySound ("hellowin.wav", NULL, SND_FILENAME | SND_ASYNC) ; return 0 ; case WM_PAINT : hdc = BeginPaint (hwnd, &ps) ; GetClientRect (hwnd, &rect) ; DrawText (hdc, "Hello, Windows 95!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER) ; EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY : PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; }
Encapsulates the WINDOWS API in about 200 C++ classes
Hungarian notation: prefix denote data type
Prefix | DataType |
b | bool |
c | char |
cx,cy | distance hor/ver |
dw | DWORD |
h | HANDLE |
l | LONG |
n | int |
p | pointer |
pt | CPoint or POINT |
str | CString |
sz | zero-delimited string |
w | WORD |
wind | CWnd |
m_ | data member of class |
lp | long pointer |
Mother Object
void CBirthday::Serialize (CArchive& ar) { CObject::Serialize(ar); // serialize base class if(ar.IsStoring) ar << m_day << m_month << m_year; else ar >> m_day >> m_month >> m_year; }
// CDocument provide the CArchive for you
#ifdef _DEBUG void CBirthDay::AssertValid() const { CObject::AssertValid(); ASSERT (m_day > 0); ASSERT (m_month > 0); ASSERT (m_year > 0); ASSERT (m_day <= 31); ASSERT (m_month <= 12); } #endif
#ifdef _DEBUG void CBirthDay:: Dump (CDumpContext& dc) const { CObject::Dump (dc); dc << "Birthday =" << m_month << "-" << m_day << "-" << m_year <<endl; } #endif
CCmdTarget -> CWinThread -> CWinApp -> User Application
CDocument
non-Class functions available to all objects
//*********************************************************************** // // Hello.h // //*********************************************************************** class CMyApp : public CWinApp // derive our application { public: virtual BOOL InitInstance (); // Override this function }; class CMainWindow : public CFrameWnd // derive our window { public: CMainWindow (); // override this too protected: // access these protected functions afx_msg void OnPaint (); // allows us to paint our own window DECLARE_MESSAGE_MAP () // macro to set up Message Mapping };
(source file here) and (compilation directions here)
//*********************************************************************** // // Hello.cpp // //*********************************************************************** #include <afxwin.h> #include "Hello.h" CMyApp myApp; // instantiate my application ///////////////////////////////////////////////////////////////////////// // CMyApp member functions BOOL CMyApp::InitInstance () { m_pMainWnd = new CMainWindow; // create a new window and point to it m_pMainWnd->ShowWindow (m_nCmdShow); m_pMainWnd->UpdateWindow (); return TRUE; // FALSE would shut down the program } ///////////////////////////////////////////////////////////////////////// // CMainWindow message map and member functions BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd) // macros for defining the map ON_WM_PAINT () // only message we need to process END_MESSAGE_MAP () CMainWindow::CMainWindow () { Create (NULL, "The Hello Application"); // use defaults for the other parameters } void CMainWindow::OnPaint () { CPaintDC dc (this); // get a device context for "this" window CRect rect; GetClientRect (&rect); // find out how big the window is dc.DrawText ("Hello, MFC", // Draw this Text -1, // which is terminated by the null character &rect, // in this rectangle DT_SINGLELINE | DT_CENTER | DT_VCENTER); // on a single line in the center }
Correlates messages with member
functions - set of MACROS
(could use "vtables" - virtual function tables - to but
would be more expensive in memory).
Macros in "afxmsg_.h" add the appropriate entries in the message map.
Naming conventions:
MESSAGES: all caps start with WM_
e.g. WM_PAINTMemberFunctions: start with On use lower case except capitalize beginning of words
e.g. OnPaintMACROS: ALL CAPS starting with ON_WM_
e.g. ON_WM_PAINT
These arguments are derived from the wParam and lParam in the message
Can add User defined Messages:
ON_MESSAGE(WM_SETTEXT, OnSetText)
ON_COMMAND: for menu selections
ON_UPDATE_COMMAND: to keep UI objects in sync
"afx_msg" is really commentary - implies virtual function override but outside vtable mechanism.
DECLARE_MESSAGE_MAP: usually last entity in class definition.
Adds three members to the class declaration:
BEGIN_MESSAGE_MAP macro implements GetMessageMap function and initializes messageMap.
macros in between fill in the _messageEntries array
END_MESSAGE_MAP: adds NULL entry terminator
Thus:
// in the class declaration
DECLARE_MESSAGE_MAP( )
// in the class declaration private: static const AFX_MSGMAP_ENTRY _messageEntries[ ] ; protected: static const AFX_MSGMAP messageMap; virtual const AFX_MSGMAP* GetMessageMap( ) const;
// in the class implementation
BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)
// in the class implementation const AFX_MSGMAP* CMainWindow::GetMessageMap( ) const { return &CMainWindow::messageMap;}
const AFX_MSGMAP CMainWindow::messageMap = { &CFrameWnd::messageMap, &CMainWindow::_messageEntries[0] }
ON_WM_PAINT ( )
END_MESSAGE_MAP
const AFX_MSGMAP_ENTRY CMainWindow::_messageEntries[ ] = { { WM_PAINT, 0, 0, 0, AfxSig_vv, (AFX_PMSG)(AFX_PMSGW)(void (CWnd::*)(void)) OnPaint }, {0, 0, 0, 0, AfxSig_end, (AFX_PMSG) 0 } };
To Dispatch a Message:
See figure 1.5 p. 40