Processing WM_PAINT

688 views Asked by At

I have read many examples on the internet but I'm still stuck. I'm trying to process the WM_PAINT message sent to my application.

In my application, I always draw in the same DC, named g_hDC. It works perfectly. When WM_PAINT is received, I just try to draw the content of my g_hDC into the DC returned by BeginPaint. I guess g_hDC contains the last bitmap that I drawn. So I just want to restore it.

case WM_PAINT:
 PAINTSTRUCT ps;

 int ret;
 HDC compatDC;
 HDC currentDC;
 HDC paintDC;
 HBITMAP compatBitmap;
 HGDIOBJ oldBitmap;

 paintDC   = BeginPaint(g_hWnd, &ps);

 currentDC = GetDC(g_hWnd);
 compatDC  = CreateCompatibleDC(paintDC);
 compatBitmap=CreateCompatibleBitmap(paintDC, CONFIG_WINDOW_WIDTH, CONFIG_WINDOW_HEIGHT);
 oldBitmap=SelectObject(compatDC, compatBitmap);

 ret = BitBlt(compatDC,
              ps.rcPaint.left,
              ps.rcPaint.top,
              ps.rcPaint.right - ps.rcPaint.left,
              ps.rcPaint.bottom - ps.rcPaint.top,
              currentDC,
              ps.rcPaint.left,
              ps.rcPaint.top,
              SRCCOPY);

 ret = BitBlt(paintDC,
              ps.rcPaint.left,
              ps.rcPaint.top,
              ps.rcPaint.right - ps.rcPaint.left,
              ps.rcPaint.bottom - ps.rcPaint.top,
              compatDC,
              ps.rcPaint.left,
              ps.rcPaint.top,
              SRCCOPY);

  DeleteObject(SelectObject(compatDC, oldBitmap));
  DeleteDC(compatDC);
 DeleteDC(currentDC);

 EndPaint(g_hWnd, &ps);

break;

But it just draws a white rectangle ... I tried many possibilities and nothing works. Can you please help me?

2

There are 2 answers

2
i486 On

Use this to delete bitmat: DeleteObject( SelectObject(compatDC,oldBitmap) ); - without DeleteBitmap on prev line. SelectObject returns current (old) selection as return value - and you delete it. In your case you are trying to delete still selected bitmap.

PS: I don't see CreateCompatibleDC - where you are creating compatDC? Add compatDC = CreateCompatibleDC( hdc ); before CreateCompatibleBitmap.

2
andlabs On

There are a number of things you are doing wrong.

First, your saving g_hDC is relying on an implementation detail: you notice that the pointers are the same, and thus save the pointer. This may work in the short term for a variety of reasons related to optimization on GDI's part (for instance, there is DC cache), but will stop working eventually, when it is least convenient. Or you may be tempted to use the DC pointer when you don't have the DC, and will scribble over something else (or fail to do so due to GDI object thread affinity).

The correct way to access the DC of a window outside its WM_PAINT is by calling GetDC(hwnd).

CreateCompatibleDC() creates an in-memory DC compatible with hdc. Drawing to compatDC is not enough to draw to hdc; you need to draw back to hdc after you draw to compatDC. For your case, you will need to have two BitBlt() calls; the second one will blit back from compatDC onto hdc. See this sample code for details.

You cannot DeleteObject() a bitmap while you have it selected into a DC. Your SelectObject(compatDC, oldBitmap) call needs to come before DeleteObject(compatBitmap). (This is what i486 was trying to get at in his answer.)

(I'm sure this answer is misleading or incomplete in some places; please let me know if it is.)