0xAA55 发表于 2015-11-23 17:31:20

【GDI】讨论一下SelectObject与DeleteObject

我在stackoverflow上面看到的内容:http://stackoverflow.com/questions/8500137/when-should-i-call-deleteobject-on-bitmap
以前我都是采取在DeleteDC后再逐个将自己用SelectObject选入的对象进行DeleteObject销毁处理。然而我发现很多人都不是我这样写的。

原文中给的伪代码: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);

//用这个hDC绘图什么的

::DeleteDC(hDC);提问者说:“这让我感到哪里不对。。有没有谁能出来帮我解释一下这哪里错了?”
解答的人一开始说“任何时候你都不能用DeleteObject将一个已经选入hDC的对象销毁,在这个对象正在被使用的时候,你调用DeleteObject会失败,然后这个hBmp就泄露了。”而且还提供了MSDN的DeleteObject的函数说明:
https://msdn.microsoft.com/en-us/library/dd183539(v=vs.85).aspx

结果这个人做了几次测试后发现,“经过我的测试,在我将hBitmap选入hDC后调用DeleteObject,它给我返回了个1,表示执行成功。有意思的是,这个位图其实并没有被销毁。调用GetObject来取得这个位图是能够成功的!然而,在我把这个已经删除了的位图选出hDC后,它就真的被销毁了,调用GetObject也会失败。对此我也在任务管理器的GDI句柄监视里面看到了这个现象。这样我认为DeleteObject会根据情况来帮你删除对象,即使我觉得这完全没有被任何文档所记载。”HDC hdc = CreateCompatibleDC(NULL);
if (hdc != NULL) {
    HBITMAP hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_SAMPLE));

    BITMAP bm = { 0 };
    int numBytes;

    //这句肯定能执行成功。
    numBytes = GetObject(hBitmap, sizeof(BITMAP), &bm);

    HBITMAP hOldBitmap = SelectBitmap(hdc, hBitmap);

    DeleteObject(hBitmap);

    //这句出乎意料地能执行成功。
    numBytes = GetObject(hBitmap, sizeof(BITMAP), &bm);

    SelectBitmap(hdc, hOldBitmap);

    //这句肯定不能执行成功。
    numBytes = GetObject(hBitmap, sizeof(BITMAP), &bm);

    DeleteDC(hdc);
}最后得出的结论是:
当你用DeleteObject删除一个GDI对象的时候,其实只是减少了这个GDI对象的引用而已。它实际上如果还在被使用的话,它其实还是存在的。
用SelectObject将其选出后,如果它没有任何引用了,它就会被销毁。
估计DeleteDC也会做相同的处理呢。

FFFFFFFE 发表于 2015-11-24 08:50:42

页: [1]
查看完整版本: 【GDI】讨论一下SelectObject与DeleteObject