Occasionally, there is need to illustrate a point with a full program. To avoid reproducing the boring parts of the program, let’s agree on using the following template for our sample programs.
For expository purposes, I won’t use a C++ class. I’ll just keep all my variables global. In a real program, of course, instance data would be attached to the window instead of floating globally.
#define STRICT #include <windows.h> #include <windowsx.h> #include <ole2.h> #include <commctrl.h> #include <shlwapi.h> HINSTANCE g_hinst; /* This application's HINSTANCE */ HWND g_hwndChild; /* Optional child window */ /* * OnSize * If we have an inner child, resize it to fit. */ void OnSize(HWND hwnd, UINT state, int cx, int cy) { if (g_hwndChild) { MoveWindow(g_hwndChild, 0, 0, cx, cy, TRUE); } } /* * OnCreate * Applications will typically override this and maybe even * create a child window. */ BOOL OnCreate(HWND hwnd, LPCREATESTRUCT lpcs) { return TRUE; } /* * OnDestroy * Post a quit message because our application is over when the * user closes this window. */ void OnDestroy(HWND hwnd) { PostQuitMessage(0); } /* * PaintContent * Interesting things will be painted here eventually. */ void PaintContent(HWND hwnd, PAINTSTRUCT *pps) { } /* * OnPaint * Paint the content as part of the paint cycle. */ void OnPaint(HWND hwnd) { PAINTSTRUCT ps; BeginPaint(hwnd, &ps); PaintContent(hwnd, &ps); EndPaint(hwnd, &ps); } /* * OnPrintClient * Paint the content as requested by USER. */ void OnPrintClient(HWND hwnd, HDC hdc) { PAINTSTRUCT ps; ps.hdc = hdc; GetClientRect(hwnd, &ps.rcPaint); PaintContent(hwnd, &ps); } /* * Window procedure */ LRESULT CALLBACK WndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) { switch (uiMsg) { HANDLE_MSG(hwnd, WM_CREATE, OnCreate); HANDLE_MSG(hwnd, WM_SIZE, OnSize); HANDLE_MSG(hwnd, WM_DESTROY, OnDestroy); HANDLE_MSG(hwnd, WM_PAINT, OnPaint); case WM_PRINTCLIENT: OnPrintClient(hwnd, (HDC)wParam); return 0; } return DefWindowProc(hwnd, uiMsg, wParam, lParam); } BOOL InitApp(void) { WNDCLASS wc; wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = g_hinst; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = TEXT("Scratch"); if (!RegisterClass(&wc)) return FALSE; InitCommonControls(); /* In case we use a common control */ return TRUE; } int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpCmdLine, int nShowCmd) { MSG msg; HWND hwnd; g_hinst = hinst; if (!InitApp()) return 0; if (SUCCEEDED(CoInitialize(NULL))) {/* In case we use COM */ hwnd = CreateWindow( TEXT("Scratch"), /* Class Name */ TEXT("Scratch"), /* Title */ WS_OVERLAPPEDWINDOW, /* Style */ CW_USEDEFAULT, CW_USEDEFAULT, /* Position */ CW_USEDEFAULT, CW_USEDEFAULT, /* Size */ NULL, /* Parent */ NULL, /* No menu */ hinst, /* Instance */ 0); /* No special parameters */ ShowWindow(hwnd, nShowCmd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } CoUninitialize(); } return 0; }
Notice that all painting gets funneled through
the PaintContent
function.
This allows us to route
the WM_PRINTCLIENT
message
through the same paint function,
which has as an immediate consequence
the ability to animate the window with AnimateWindow
.
This will also prove useful for printing high-resolution screenshots.
Other than the trickiness with painting, there really isn’t anything here that you shouldn’t already know. The point of this program is to be a template for future programs.
My first mission will be an eight-part series on scrollbars.
That’s right. Scrollbars.
I can’t believe I have an eight-part series on scrollbars. And you probably can’t believe you’re reading about it.
0 comments