Если у меня есть .Net Bitmap
, я могу создать из него растровое изображение GDI, вызвав GetHbitmap()
метод Bitmap
.
Bitmap bmp = new Bitmap(100, 100);
IntPtr gdiBmp = bmp.GetHbitmap();
Это работает нормально, но каждый раз, когда вы вызываете GetHbitmap
, Windows должна выделять новую память, на которую ссылается возвращаемое IntPtr
.
Что я хотел бы сделать - если это возможно - написать функцию (я знаю, что здесь потребуется PInvoke), которая также генерирует растровую копию GDI Bitmap
, но она перезаписывает существующий фрагмент памяти, на который уже ссылались IntPtr
возвращается из GetHbitmap
вместо выделения новой памяти. Так это будет выглядеть примерно так (если бы это был метод расширения Bitmap
):
// desired method signature:
void OverwriteHbitmap(IntPtr gdi)
{
}
// ex:
Bitmap bmp1 = new Bitmap(100, 100);
IntPtr gdi1 = bmp1.GetHbitmap();
Bitmap bmp2 = new Bitmap(100, 100);
bmp2.OverwriteHbitmap(gdi1); // gdi1 is still pointing to the same block
// of memory, which now contains the pixel data from bmp2
Как я могу это сделать? Я предполагаю, что мне нужно будет знать структуру растрового изображения GDI, и, вероятно, я могу использовать LockBits
и BitmapData
для этого, но я не совсем уверен, как именно.
Подсказки для охотников за головами:
Bitmap
имеет метод LockBits
, который блокирует растровое изображение в памяти и возвращает объект BitmapData
. Объект BitmapData
имеет свойство Scan0
, которое является IntPtr
, указывающим на начало пиксельных данных заблокированного растрового изображения (т. Е. Оно не указывает на заголовок растрового изображения, то есть на начало растрового изображения сам по себе).
Я почти уверен, что решение выглядит примерно так:
Bitmap bmp1 = new Bitmap(100, 100);
IntPtr gdi1 = bmp1.GetHbitmap(); // now we have a pointer to a
// 100x100 GDI bitmap
Bitmap bmp2 = new Bitmap(100, 100);
BitmapData data = bmp2.LockBits();
IntPtr gdi1Data = gdi1 + 68; // magic number = whatever the size
// of a GDI bitmap header is
CopyMemory(data.Scan0, gdi1Data, 40000);
Решение не должно быть универсальным - оно должно работать только для растровых изображений с форматом пикселей Format32bppArgb
(формат GDI + по умолчанию).