1
votes

I have the following code in the WM_PAINT message handler of the main window :

void BossController::paint ( HWND hwnd, HBITMAP skin )
{


 PAINTSTRUCT ps;
 HDC hdc;



 hdc = BeginPaint ( hwnd, &ps );

     HDC dcSkin = CreateCompatibleDC ( hdc );                               // memory dc for skin

     HDC hMemDc = CreateCompatibleDC ( hdc );                               // memory dc for painting

     HBITMAP hmemBmp = CreateCompatibleBitmap ( hdc, width, height  );      // Create bitmap to draw on

     HBITMAP hOldMemBmp = (HBITMAP)SelectObject ( hMemDc, hmemBmp );        // select memory bitmap in memory dc

     HBITMAP hOldSkinBmp = (HBITMAP)SelectObject ( dcSkin, skin );  //select skin bitmap in skin memory dc


        BitBlt ( hMemDc, 0, 0, width, height, dcSkin, 0, 0, SRCCOPY );      // Paint Skin on Memory DC
        BitBlt ( hdc, 0, 0, width, height, hMemDc, 0, 0, SRCCOPY );         // Paint Skin on Window DC


     DeleteObject ( hOldSkinBmp );
     DeleteObject ( hOldMemBmp );
     DeleteObject(  hmemBmp );
     DeleteDC ( hMemDc );
     DeleteDC ( dcSkin );

 EndPaint ( hwnd, &ps );


};

I will be painting text on the skin aswell, that's why I am BitBlt ing on memory DC with a memory bitmap, I have tried with straight painting(directly to hdc) as well, but none worked, and I am not sure how to debug it. The only thing I could check was to check the skin against NULL in LoadBitmap function's return value and also in the void BossController::paint ( HWND hwnd, HBITMAP skin ). And BitBlt's return value.

It always shows a rectangle with the background color I chose while creating the window. (window is a custom skinned one so, no title bar etc is there.

Can someone point out the errors if any or the potential pitfalls or maybe how to debug it ?

1
Your delete code is wrong... don't delete the hOld* bitmaps. Instead, select them back into their DCs before deleting anything. I don't think that's your problem, though.rodrigo
@rodrigo do we really need to select them back, since we will be deleting the DCs ultimately before the function returns, and these are memory DCs ?StudentX
You must undo each SelectObject by selecting the hOld... object back into the DC. Deleting a DC that still contains one of your objects causes a handle leak, which will eventually cause bad painting.ScottMcP-MVP
What is skin - I guess HBITMAP. Is it compatible with dcSkin (bpp, etc)? Use OutputDebugString() to see intermediate values / error codes.i486

1 Answers

1
votes

It looks like nobody ever answered this.

First off, I don't know what framework you're using, but there are normally a few checks before one starts painting. A typical paint handler begins something like:

RECT r;
if (GetUpdateRect(&r) == 0)
{
    // Nothing to paint, exit function.
    return 0;
}

PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);

if (hdc == 0)
{
    // No display device context available, exit function.
    return 0;
}

Second, I don't know what 'skin' is (an HBITMAP, but I don't know anything about how it was created, where it come from, what its dimensions and bit depth are).

Third, your cleanup is incorrect. Always call SelectObject to restore the previous selected bitmap, pen, brush, etc. Then call DeleteObject on whatever you created.

As for how to debug, if something's broken in a paint handler, you should always strip it to the bare minimum, verify functionality, and start adding in things until it breaks. In this case, I would replace all of your existing code with a simple filled rectangle in a weird color and see if that works. Then I'd do a BitBlt directly from the 'skin' bitmap on top of the funky color, and see if that works.

The most common errors with GDI programming are caused by things like using the wrong coordinates (e.g. Window coordinates instead of Client coordinates, or giving the wrong offset into your source in a BitBlt call), failure to correctly create resources (e.g. CreateCompatibleDC, then calling CreateCompatibleBitmap using the new DC, which results in a monochrome bitmap), or failure to properly clean up (e.g. the way you didn't select the old resources before disposing of your newly-created ones). It's also common to not even initiate a repaint correctly, such that your WM_PAINT handler isn't even getting hit. The first step is always a breakpoint to make sure your code is even executing!