I try to set my preferred device context properties in WM_CREATE message and then use it in WM_PAINT message. My method is to use SaveDC and RestoreDC function in WM_CREATE and WM_PAINT message respectively. But the result doesn't meet my need. What I really need is to show a circle in the center of the client area.
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("HelloWin") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, // window class name
TEXT ("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window 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) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect;
static int nSavedDC;
switch (message)
{
case WM_CREATE:
hdc = GetDC(hwnd);
SetMapMode(hdc, MM_LOMETRIC);
GetClientRect(hwnd, &rect);
SetViewportOrgEx(hdc, rect.right/2, rect.bottom/2, NULL);
nSavedDC = SaveDC(hdc); //I want to save the current state of device context to be used in WM_PAINT message.
ReleaseDC(hwnd, hdc);
return 0;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
RestoreDC(hdc, nSavedDC); //Restore the the state of device context which is saved in WM_CREATE message.
Ellipse(hdc, -100, 100, 100, -100);
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
Your code lacks error handling. You need to inspect all the values returned by each GDI function call.
As described on MSDN page the purpose of SaveDC / RestoreDC is mostly to restore state to original after you finish drawing. And this is exactly what you aren't doing in both WM_CREATE and WM_PAINT message handlers. You always leave DC in modified state.
As for using SaveDC / RestoreDC to set up DC state once and then quickly restore it at every paint operation instead of setting up from scratch every time I think of at least one obstacle: If some other function calls RestoreDC in between handlers DC restoring item that wasn't on top of the DC states stack then your saved state that was on top of the stack will get destroyed as described here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With