Windows NT Systems
Programming
[ Home
| Syllabus |Course Notes]
Graphical User Interfacing
Console Window User Interfaces
SINGLE FOCUS OF USER INPUT
<=> SINGLE POINT OF PROGRAM CONTROL
- Text (ASCII) based information
- Keyboard based input
- Non-graphical
- User Interaction closely
controlled by the program.
Graphical User Interfaces
Pioneering work of XEROX PARC (Palo
Alto Research Center) 1970's
- Screen is "Painted"
- Even text is considered a
graphical object with font, size and other properties
- Any bitmapped image can be
display
- User interacts with this bit
mapped image by keyboard, mouse and possibly other
devices
Some Implications
- Separation of an object from
its graphical "view"
- Device Independent graphics
(including printers)
- Development of font libraries
- Increased use of pictures
(icons, etc).
- Frees user to interact more
independently
- Last implies multiple input
sources
Multiple Locus of Control
Route input request to proper
program segment
- All input events go to a
central locus of control which "switches"
to proper control code
e.g. Select statement
- Register code to handle event
= event calls this code
e.g. callback, interrupt handler
- Turn all events into messages
and use message routing scheme
- Default message
handlers
- Overriding message
handlers
- Multiple handlers per
message
- Messages can be
non-user event oriented
i.e. can turn "raw" input into
"nice" input
Last fits nicely with an object
oriented approach using inheritance.
Complex windows "objects"
can be built and reused easily.
Windows Programming Model (p.4-)
- External (and internal) events
are put in "messages"
- WinMain, creates main window
then spends life routing messages
- Window Procedure contains a
set of message handlers.
big Switch on message types
- Unprocessed messages or those
needing additional processing go to DefWindowProc,
the default window procedure
There are about 200 Windows 95
messages.
Each message starts with
"WM_"
- WM_CHAR: character from keyboard
- WM_COMMAND: menu selection, or from child
- WM_LBUTTONUP: mouse left button released
- WM_MOUSEMOVE: mouse moved
- WM_PAINT: window needs repainting
- WM_QUIT: need to terminate
- WM_SIZE: window is resized.
Message Parameters
- HANDLE of windows to which
message is directed
- Message ID: e.g. WM_PAINT,
WM_LBUTTONDOWN
- wParam: 32 bit WORD parameter
- lParam: 32 bit long parameter
SDK style Windows Program
/*------------------------------------------------------------
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) ;
}
Programming Aids
- Resource Compilers
- Icons
- Cursors
- bitmaps
- stringtable
- menus
- dialog boxes
- keyboard accelerators
- user defined
- Predefined Objects
Microsoft Foundation Class (MFC)
MFC
Encapsulates the WINDOWS API in
about 200 C++ classes
- Rarely need to call windows
API directly (if you don't want)
- Many are base classes from
which you derive your own customized classes
(inheritance)
- Many are thin wrappers around
WINDOWS API for efficiency.
- For example,
SetWindowPos is a WIN32 API for changing the
windows position
- SetWindowPos is also a
member function of the CWnd class
- Since all windows
objects are derived (directly or indirectly)
from this class, they inherit this function
- Application structure (which
runs the message loop - for instance)
- Document/View Architecture
- Powerful Objects
- CToolBar
- CFrameWnd
- COleDocument
- Controls which can
receive events
override OnChildNotify function
- Efficient (uses WINAPI
structures inside of classes
this allows WINAPI calls if you need them
- Source code is available for
examples
- Robust (assert and
assert_valid built in functions)
MFC Naming Conventions
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 |
CObject
Mother Object
- Serialization Support
- Run-time class information
- Diagnostic and debugging
support
- Overloads new and delete to
help protect against memory leaks
Serialize
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
AssertValid
#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
Dump
#ifdef _DEBUG
void CBirthDay:: Dump (CDumpContext& dc) const
{
CObject::Dump (dc);
dc << "Birthday =" << m_month << "-" << m_day << "-" << m_year <<endl;
}
#endif
Application Class Archtecture
CCmdTarget ->
CWinThread -> CWinApp -> User Application
- CCmdTarget: Makes a class
capable of receiving and processing messages
- CWinThread: represents a
thread of execution
- CWinApp:
- ProcessShellCommand
- OnFileOpen support
- Override InitInstance
to perform start up chores
CDocument
- IsModified
- UpdateAllViews
- OnFileSendMail: attaches
document to a mail message
Other Interesting Classes
- Window Classes: derived from CWnd -> CFrameWnd
- GDI Classes: Graphics Device
Interface for painting windows
- File Classes, CSocketFile,
plus Carchive
- Exception Classes
- OLE Classes
- Database Classes
- Threading Classes
- Collection Classes (lists and
stuff)
- Generally useful classes
(CString, CPoint, CRect, CTime)
Afx Functions
non-Class functions available to
all objects
Hello MFC: the header
(header file here)
//***********************************************************************
//
// 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
};
Hello MFC: the implementation
(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
}
Message Maps
Correlates messages with member
functions - set of MACROS
(could use "vtables" - virtual function tables - to
but would be more expensive in memory).
- Declare Message Map
- Create and Initialize
(identifies both base and derived classes)
- Override mssage member
functions
Macros in "afxmsg_.h" add the appropriate entries in the
message map.
Naming conventions:
MESSAGES: all caps start with
WM_
e.g. WM_PAINT
MemberFunctions: start with On
use lower case except capitalize beginning of words
e.g. OnPaint
MACROS: ALL CAPS starting with
ON_WM_
e.g. ON_WM_PAINT
- Message Handling prototypes:
- afx_msg void
OnLButtonDown(UINT nFlags, CPoint point)
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.
DECLARE_MESSAGE_MAP: under the hood
Adds three members to the class
declaration:
- private array of AFX_MSPMAP_ENTRY structures named _messageEntries:
contains info correlating message and their handlers
- static AFX_MSGMAP structure named messageMap:
contains pointer to base class's messageMap structure
- virtual function GetMessageMap that returns address of messageMap
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 }
};
Searching for a Message Handler
To Dispatch a Message:
- framework calls virtual
WindowProc function CMainWindow inherits from CWnd
- WindowProc calls OnWndMsg
- OnWndMsg uses
CMainWindow::messageMap to searches
CMainWindow::_messageEntries for entry whose message
ID matches
if found, the message handler is called
- If not found, gets pointer to
base class (CFrameWnd) messageMap and repeats the
search
- Eventually you should find a
handler or pass to default handling.
See figure 1.5 p. 40
Copyright chris wild 1997.
For problems or questions regarding this web contact [Dr. Wild].
Last updated: September 14, 1997.