Когда мне следует вызывать DeleteObject () на растровом изображении - PullRequest
5 голосов
/ 14 декабря 2011

Я изучаю какой-то старый проект Win32 / MFC.

Я нашел следующее (псевдокод):

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?

Спасибо.

Ответы [ 2 ]

8 голосов
/ 14 декабря 2011

Нет, это не правильно.Код вызывает 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);
}

Суть в том, что код, который вы опубликовали, появляетсяработать, но зависит от недокументированного поведения.Я бы предпочел не рисковать и устранить эту зависимость.

6 голосов
/ 02 апреля 2013

В «Старом новом» от Рэймонда Чена есть соответствующая запись, объясняющая это поведение:

Люди из GDI обнаружили, что многие люди путаются и пытаются уничтожить объекты, пока они еще выбраны.в ДК.Отказ вызова вызвал две категории проблем: некоторые приложения просто пропускали ресурсы (так как они думали, что уничтожают объект, но не были).Другие приложения проверили возвращаемое значение и испугались, если увидели, что DeleteObject на самом деле не удалял объект.

Чтобы оба этих типа приложений были довольны, GDI иногда (не всегда) врет и говорит:Конечно, я удалил твой объект. "Он фактически не удалял его, потому что он все еще выделен в DC, но он также связывает строку вокруг пальца, и когда объект окончательно отменен, GDI скажет: «О, подождите, я должен был удалить этот объект"и выполните удаление.Таким образом, ложь, которую сделал GDI, была не столько ложью, сколько «оптимистическим предсказанием будущего».

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

...