0

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?

vfloyd
  • 17
  • 3
  • c++ tag is not correct. Change it to Win32. – i486 Dec 16 '14 at 10:29
  • You have not drawn anything in compatBitmap - what you expect to see after BitBlt? Suppose there must be "noise" i.e. random image. – i486 Dec 16 '14 at 10:32
  • I removed the c++ tag. I'm just seeing a white rectangle at the place of the overlapping window. – vfloyd Dec 16 '14 at 10:53
  • I think you will see the same white rectangle without BitBlt - it is the normal background erase (white). – i486 Dec 16 '14 at 10:59
  • But why my old g_hDC is not restored ? – vfloyd Dec 16 '14 at 11:01
  • Are you sure that `g_hDC` is valid and does have something in it? Try painting something (`Ellipse()` or `Rectangle()` will do) into `g_hDC` before you do the `BitBlt()`. And... surely you were closer to the mark when you started: you need to use `hdc` to draw on, not just to create a compatible DC from. – AAT Dec 16 '14 at 14:01
  • I don't think you need a compatible bitmap in this case either - `hdc` is the screen DC, ready to use. – AAT Dec 16 '14 at 14:09
  • 2
    At no point do you draw into the DC returned by `BeginPaint`. – Raymond Chen Dec 16 '14 at 15:00

2 Answers2

1

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.)

andlabs
  • 11,290
  • 1
  • 31
  • 52
  • Thank for your answer. I tried with the second BitBlt and I get the same result. A white rectangle. I also tried with the code example you provided. Same result. – vfloyd Dec 16 '14 at 13:44
  • I edited my first post with the code I'm testing at the moment. I have still the white rectangle. – vfloyd Dec 16 '14 at 15:53
0

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.

i486
  • 6,491
  • 4
  • 24
  • 41
  • Thank for your response. I edited the code in my first post. It still doesn't work. (note that I now BitBlt into compatDC instead of hdc). The problem is that I don't understand what I'm doing. It's not logical for me. Why should I create a compatibleDc so that BeginPaint already gave me a DC ?? – vfloyd Dec 16 '14 at 10:59
  • The idea with DC-s is very strange. I have used it for years and still cannot understand fully the idea - but this is the method for work. DC is the object where you draw - something like virtual display. It can be the real display, can be memory virtual display, can be printer surface. I am not sure whether your g_hDC contains valid bitmap and is compatible with hdc/compatDC. If you `BitBlt` from g_hDC to compatDC, you will need extra `BitBlt` to transfer image from compatDC to hdc (real display). Try this instead `BitBlt(hdc,0,0,rect.right,rect.bottom,compatDC,0,0,SRCCOPY);`. – i486 Dec 16 '14 at 11:03