Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should I call DeleteObject() on bitmap

I'm examining some legacy Win32/MFC project.

I've found the following (pseudo-code):

HDC hDC = ::CreateCompatibleDC(hDCWnd);
HANDLE hFileMap = ::CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, dwSize, FileMapName);
HBITMAP hBmp = ::CreateDIBSection(hDCWnd, &zBI, DIB_RGB_COLORS, &pvNull, hFileMap, 0);

::SelectObject(hDC, hBmp);
::DeleteObject(hBmp);
::CloseHandle(hFileMap);

// .. do something with hDC ..

::DeleteDC(hDC);

It looks strange for me. Could anyone please explain is it correct to delete the bitmap and/or close the file handle before I do something with the DC?

Thanks.

like image 569
Rom098 Avatar asked Dec 14 '11 06:12

Rom098


2 Answers

No, it's not correct. The code calls SelectObject() to select the bitmap into the device context, then calls DeleteObject() in an attempt to delete the bitmap while it's still selected in the device context. In this case, DeleteObject() will fail, so the bitmap is leaked.

http://msdn.microsoft.com/en-us/library/dd183539(v=vs.85).aspx

"Do not delete a drawing object (pen or brush) while it is still selected into a device context."

EDIT:

Well, that's interesting. I tried calling DeleteObject() while a bitmap is selected in the device context, and it returns 1 for me too. Interestingly, the bitmap is not actually deleted at this point; calling GetObject() on the "deleted" bitmap succeeds! However, as soon as the deleted bitmap is selected out of the device context, then it is actually deleted; calling GetObject() fails at that point. I also verified by watching the GDI handle count in Task Manager. So, apparently DeleteObject() will defer the deletion if the bitmap is currently selected into a device context, though I don't believe that's documented anywhere.

HDC hdc = CreateCompatibleDC(NULL);
if (hdc != NULL) {
    HBITMAP hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_SAMPLE));

    BITMAP bm = { 0 };
    int numBytes;

    // this succeeds as expected
    numBytes = GetObject(hBitmap, sizeof(BITMAP), &bm);

    HBITMAP hOldBitmap = SelectBitmap(hdc, hBitmap);

    DeleteObject(hBitmap);

    // this succeeds -- NOT expected!
    numBytes = GetObject(hBitmap, sizeof(BITMAP), &bm);

    SelectBitmap(hdc, hOldBitmap);

    // this fails as expected
    numBytes = GetObject(hBitmap, sizeof(BITMAP), &bm);

    DeleteDC(hdc);
}

The bottom line is that the code you posted appears to work, but is dependent on undocumented behavior. My preference would be to play it safe and eliminate that dependency.

like image 142
cbranch Avatar answered Nov 07 '22 13:11

cbranch


There is a related post in The Old New Thing from Raymond Chen explaining this behavior:

The GDI folks found that a lot of people mess up and try to destroy objects while they are still selected into DCs. Failing the call caused two categories of problems: Some applications simply leaked resources (since they thought they were destroying the object, but weren't). Other applications checked the return value and freaked out if they saw that Delete­Object didn't actually delete the object.

To keep both of these types of applications happy, GDI will sometimes (not always) lie and say, "Sure, I deleted your object." It didn't actually delete it, because it's still selected into a DC, but it also ties a string around its finger, and when the object is finally deselected, GDI will say, "Oh, wait, I was supposed to delete this object," and perform the deletion. So the lie that GDI made wasn't so much a lie as it was an "optimistic prediction of the future."

http://blogs.msdn.com/b/oldnewthing/archive/2013/03/06/10399678.aspx

like image 42
RED SOFT ADAIR Avatar answered Nov 07 '22 13:11

RED SOFT ADAIR