2011-12-14 49 views
4

我正在檢查一些傳統的Win32/MFC項目。什麼時候應該在位圖上調用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); 

// .. do something with hDC .. 

::DeleteDC(hDC); 

它看起來很奇怪我。任何人都可以請解釋是否刪除位圖和/或關閉文件句柄是否正確,然後再對DC執行某些操作?

謝謝。

回答

6

不,這是不正確的。該代碼調用SelectObject()來選擇位圖到設備上下文中,然後調用DeleteObject()試圖在設備上下文中仍然選中時刪除該位圖。在這種情況下,DeleteObject()將會失敗,所以位圖被泄漏。

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

「同時它仍然選擇到設備上下文不要刪除圖形對象(筆或刷子)。」

編輯:

嗯,這很有意思。我嘗試在設備上下文中選擇位圖時調用DeleteObject(),並且它也返回1。有趣的是,在這一點上位圖實際上並沒有被刪除;在「已刪除」位圖上調用GetObject()成功!但是,只要從設備上下文中選擇刪除的位圖,它就會被刪除;呼叫GetObject()在這一點上失敗。我也通過觀察任務管理器中的GDI句柄數來驗證。所以,顯然DeleteObject()將延遲刪除,如果位圖當前選擇到設備上下文,但我不相信這是記錄在任何地方。

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); 
} 

底線是您發佈的代碼似乎有效,但依賴於無證行爲。我的選擇是玩它安全並消除依賴。

+0

我從:: DeleteObject的(人BMP)檢查返回值和:: CloseHandle的(hFileMap),兩者相加返回TRUE,所以看起來該DeleteObject的調用不會在這件事上失敗或者我錯了嗎? – Rom098

+0

對編輯的評論:是的,我也觀察過這種行爲,在DC上選中時,DeleteObject調用時不會刪除位圖,然後在DeleteDC調用中刪除位圖。它看起來像SelectObject/DeleteObject有一些引用計數器,但沒有關於它在MSDN中的信息。 – Rom098

+1

@羅曼:我同意,有一些無證魔術發生。但如果我是你,我不希望我的代碼因爲這依靠那魔術我們無法保證它將來會繼續工作。 – cbranch

5

有一個在舊的新內容相關的職位從雷蒙德陳解釋這一行爲:

GDI的人發現,很多人陷入困境,並試圖摧毀 對象,而他們仍然入選區議會。電話 未能成功導致兩類問題:一些應用程序只是泄露了資源(因爲他們認爲他們正在銷燬該對象,但不是 )。其他應用程序檢查了返回值,並且如果他們看到DeleteObject實際上沒有刪除該對象,則會嚇壞了 。

爲了保持這兩種應用程序的快樂,GDI有時候會(不總是)說謊,並說:「當然,我刪除了你的對象。」它並沒有 實際上將其刪除,因爲它仍然被選中爲一個DC,但它也會在其手指周圍綁上一個字符串,並且當對象最終取消選中 時,GDI會說:「哦,等等,我應該刪除這個 對象「,並執行刪除操作。所以GDI所做的謊言並非如此,因爲它是對未來的樂觀預測。「

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

相關問題