The Structure of a
Windows Application
A standard Windows application consists of
several well-known elements:
-
The entry point, _tWinMain, which
provides the HINSTANCE of the application, the
command-line arguments and the flag indicating how to show the main
window
-
A call to RegisterClass to register the
main window class
-
A call to CreateWindow(Ex) to create
the main window
-
A call to ShowWindow and
UpdateWindow to show the main window
-
A message loop to dispatch messages
-
A procedure to handle the main window's
messages
-
A set of message handlers for messages that the
main window is interested in handling
-
A call to DefWindowProc to let Windows
handle messages that the main window is not interested in
-
A call to PostQuitMessage after the
main window has been destroyed
A bare-bones example follows:
#include "stdafx.h" // Includes windows.h and tchar.h
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
// Entry point
int APIENTRY _tWinMain(HINSTANCE hinst,
HINSTANCE /*hinstPrev*/,
LPTSTR pszCmdLine,
int nCmdShow) {
// Register the main window class
LPCTSTR pszMainWndClass = __T("WindowsApp");
WNDCLASSEX wc = { sizeof(WNDCLASSEX) };
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.hInstance = hinst;
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszClassName = pszMainWndClass;
wc.lpfnWndProc = WndProc;
if( !RegisterClassEx(&wc) ) return -1;
// Create the main window
HWND hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
pszMainWndClass,
__T("Windows Application"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0,
CW_USEDEFAULT, 0,
0, 0, hinst, 0);
if( !hwnd ) return -1;
// Show the main window
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Main message loop
MSG msg;
while( GetMessage(&msg, 0, 0, 0) ) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
// Windows procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT nMsg, WPARAM wparam,
LPARAM lparam) {
switch( nMsg ) {
// Message handlers for messages we're interested in
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rect; GetClientRect(hwnd, &rect);
DrawText(hdc, __T("Hello, Windows"), -1, &rect,
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
EndPaint(hwnd, &ps);
}
break;
// Post the quit message when main window is destroyed
case WM_DESTROY:
PostQuitMessage(0);
break;
// Let Windows handle messages we don't want
default:
return DefWindowProc(hwnd, nMsg, wparam, lparam);
break;
}
return 0;
}
All Windows applications
have similar requirements. These requirements can be expressed in
procedural Win32 calls, as the example just showed. However, when
procedural calls model an underlying object model, C++ programmers
feel compelled to wrap those calls behind member functions. The
Windowing part of the Win32 API (often called User32) is clearly
implementing an underlying object model consisting of Window
classes (represented by the WNDCLASSEX structure), Window
objects (represented by the HWND), and member function
invocation (represented by calls to the WndProc). For the
C++ programmer adverse to the schism between a preferred object
model and that of User32, ATL provides a small set of windowing
classes, as shown in Figure
10.1.
The classes in bold, CWindow,
CWindowImpl, CWinTraits, CWinTraitsOR,
CDialogImpl, CSimpleDialog and,
CContainedWindowT, are the most important. The others,
CWindowImplRoot, CWindowImplBaseT, and
CDialogImplBaseT, are helper classes to separate
parameterized code from invariant code. This separation helps to
reduce template-related code bloat, but these classes are not a
fundamental part of the ATL windowing classes. The former classes
form the discussion for the bulk of the rest of this chapter.
|