При создании растрового изображения с помощью Image.FromHbitmap (), как скоро можно будет удалить исходный дескриптор растрового изображения? - PullRequest
5 голосов
/ 17 июня 2010

Из документации Image.FromHbitmap() в http://msdn.microsoft.com/en-us/library/k061we7x%28VS.80%29.aspx:

Метод FromHbitmap создает копию растрового изображения GDI; так что вы можете освободить входящее растровое изображение GDI, используя метод GDIDeleteObject, сразу после создания нового образа.

Это довольно явно говорит о том, что дескриптор растрового изображения может быть немедленно удален с помощью DeleteObject, как только будет создан экземпляр растрового изображения.

Однако, глядя на реализацию Image.FromHbitmap() с Reflector, видно, что это довольно тонкая оболочка для функции GDI +, GdipCreateBitmapFromHBITMAP().

Существует довольно скудная документация по функциям плоского API GDI +, но http://msdn.microsoft.com/en-us/library/ms533971%28VS.85%29.aspx говорит, что GdipCreateBitmapFromHBITMAP() соответствует конструктору Bitmap::Bitmap(), который принимает HBITMAP и HPALETTE в качестве параметров.

Документация для этой версии Bitmap::Bitmap() конструктора в http://msdn.microsoft.com/en-us/library/ms536314%28VS.85%29.aspx содержит следующее:

Вы несете ответственность за удаление растрового изображения GDI и палитры GDI. Однако не следует удалять растровое изображение GDI или палитру GDI до тех пор, пока объект GDI + Bitmap :: Bitmap не будет удален или выйдет из области видимости.

Не передавайте в конструктор GDI + Bitmap :: Bitmap растровое изображение GDI или палитру GDI, которые в настоящее время (или ранее) были выбраны в контексте устройства.

Кроме того, в исходном коде для C ++ части GDI + в GdiPlusBitmap.h можно увидеть, что рассматриваемый конструктор Bitmap::Bitmap() сам является оболочкой для функции GdipCreateBitmapFromHBITMAP() из плоского API:

inline 
Bitmap::Bitmap(
    IN HBITMAP hbm, 
    IN HPALETTE hpal
    )
{
    GpBitmap *bitmap = NULL;

    lastResult = DllExports::GdipCreateBitmapFromHBITMAP(hbm, hpal, &bitmap);

    SetNativeImage(bitmap);
}

Что я не могу легко увидеть, так это реализацию GdipCreateBitmapFromHBITMAP(), которая является ядром этой функциональности, но два замечания в документации кажутся противоречивыми. В документации .Net говорится, что я могу немедленно удалить дескриптор растрового изображения, а в документации GDI + говорится, что дескриптор растрового изображения должен храниться до тех пор, пока объект обертки не будет удален, но оба они основаны на одной и той же функции GDI +.

Кроме того, документация GDI + предостерегает от использования исходного HBITMAP, который в настоящее время или ранее выбран в контексте устройства. Хотя я могу понять, почему растровое изображение не следует выбирать в контексте устройства в настоящее время, я не понимаю, почему существует предупреждение против использования растрового изображения, которое ранее было выбрано в контексте устройства. Это могло бы предотвратить использование растровых изображений GDI +, созданных в памяти с использованием стандартного GDI.

Итак, в итоге:

  1. Нужно ли сохранять исходный дескриптор растрового изображения до тех пор, пока объект .Net Bitmap не будет удален?
  2. Делает ли функция GDI +, GdipCreateBitmapFromHBITMAP(), копию исходного растрового изображения или просто удерживает маркер на оригинале?
  3. Почему я не должен использовать HBITMAP, который был ранее выбран в контексте устройства?

1 Ответ

2 голосов
/ 21 июня 2010

Эмпирически кажется, что документация .Net верна.Действительно, можно немедленно вызвать DeleteObject() на HBITMAP, переданном на Image.FromHbitmap(), и, похоже, от этого не будет никаких негативных последствий.

Исходя из того, что я узнал путем обратного проектирования кода, то же самое будетпримените к конструктору GDI + Bitmap::Bitmap() и функции GDI + GdipCreateBitmapFromHBITMAP(), хотя это противоречит опубликованной документации.

Возможно, документация GDI + является чрезмерно консервативной, оставляя за собой право в будущей версиидержитесь за предоставленный дескриптор HBITMAP.Если такое изменение когда-либо произойдет в GDI +, инфраструктура .Net должна будет измениться, чтобы сохранить опубликованный контракт, сделав копию растрового изображения перед передачей его в GDI +.

...