A standard Windows application consists of several well-known elements:
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. Figure 10.1. UML diagram of ATL window classes
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. |