Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't "SaveDC" and "RestoreDC" function be used in different message processing code?

Tags:

c

winapi

gdi

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) ;
}
like image 988
user7028 Avatar asked Jun 27 '26 20:06

user7028


1 Answers

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.

like image 94
user7860670 Avatar answered Jun 29 '26 11:06

user7860670



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!