BITMAPINFOHEADER : заполнение данных с помощью copymemory
Я использую COM-интерфейс, где я получаю байтовые данные, представляющие DIP (Device Independent Bitmap). Я хочу взять этот байт[] и скопировать его данные в переменную BITMAPINFOHEADER.
У меня есть длинный кусок кода, и это только его часть, однако он написан на VBA и работает:
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSrc As Any, ByVal ByteLen As Long) Dim l() As Byte: l = v Dim bim As BITMAPINFOHEADER Debug.Print ("Length: " & (UBound(l) - LBound(l) + 1)) Debug.Print "Size of BitMapInfoHeader: " & Len(bim) Debug.Print "---------------" Debug.Print "l(0) : " & l(0) Debug.Print "biSize before: " & bim.biSize CopyMemory bim, l(0), Len(bim) Debug.Print "biSize after: " & bim.biSize Debug.Print "---------------"
Выход:
Length: 897832 Size of BitMapInfoHeader: 40 --------------- l(0): 40 biSize before: 0 biSize after: 40 ---------------
Приведенный выше код показывает, что переменная b имеет biSize 0 до и 40 после вызова метода CopyMemory.
Я попытался скопировать код на C#, но он не работает.
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)] public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count); byte[] l; BITMAPINFOHEADER bim = new BITMAPINFOHEADER(); BinaryFormatter bf = new BinaryFormatter(); using (MemoryStream ms = new MemoryStream()) { bf.Serialize(ms, v); l = ms.ToArray(); } int size = System.Runtime.InteropServices.Marshal.SizeOf(typeof(BITMAPINFOHEADER)); Debug.Print("Size of BitMapInfoHeader: " + size + ""); Debug.Print("---------------"); IntPtr bimPtr = Marshal.AllocHGlobal(Marshal.SizeOf(bim)); GCHandle pinned = GCHandle.Alloc(l, GCHandleType.Pinned); IntPtr lPtr = pinned.AddrOfPinnedObject(); Debug.Print("Byte Array Pointer: " + lPtr + ""); Debug.Print("BITMAPINFOHEADER Pointer: " + bimPtr + ""); Debug.Print("---------------"); Debug.Print("Byte Array Lenght: " + l.Length + ""); Debug.Print("---------------"); Debug.Print("biSize before: " + bim.biSize + ""); CopyMemory(bimPtr, lPtr, Convert.ToUInt32(size)); Debug.Print("biSize after: " + bim.biSize + "");
Что я уже пробовал:
Приведенная ниже строка кода работала в соответствии с принятым ниже ответом.
BITMAPINFOHEADER bim = (BITMAPINFOHEADER) Marshal.PtrToStructure(lPtr, typeof(BITMAPINFOHEADER));
последняя попытка
байт[] l;
BinaryFormatter bf = new BinaryFormatter(); using (MemoryStream ms = new MemoryStream()) { bf.Serialize(ms, v); l = ms.ToArray(); } int size = System.Runtime.InteropServices.Marshal.SizeOf(typeof(BITMAPINFOHEADER)); Debug.Print("Size of BitMapInfoHeader: " + size + ""); Debug.Print("---------------"); GCHandle pinned = GCHandle.Alloc(l, GCHandleType.Pinned); IntPtr lPtr = pinned.AddrOfPinnedObject(); Debug.Print("Byte Array Pointer: " + lPtr + ""); Debug.Print("---------------"); Debug.Print("Byte Array Lenght: " + l.Length + ""); Debug.Print("---------------"); BITMAPINFOHEADER bim = (BITMAPINFOHEADER)Marshal.PtrToStructure(lPtr, typeof(BITMAPINFOHEADER)); Debug.Print("biWidth after: " + bim.biWidth + ""); Debug.Print("biHeight after: " + bim.biHeight + ""); Debug.Print("biSize after: " + bim.biSize + ""); Debug.Print("biSizeImage after: " + bim.biSizeImage + ""); Debug.Print("biBitCount after: " + bim.biBitCount + "");
Выход:
Byte Array Pointer: 56182800 --------------- Byte Array Lenght: 897860 --------------- biWidth after: -256 biHeight after: 511 biSize after: 256 biSizeImage after: 3005743104
Приведенные выше значения кажутся неправильными по сравнению с тем, что я получаю из кода VBA.
Значения VBA
Byte Array Length: 897832 bim.biSize: 0 bim.biSize: 40 bim.biWidth: 501 bim.biHeight: 448
окончательное решение
Поэтому я сохранил массив байтов, который я получал, в текстовый файл, открыл этот текстовый файл в notepad++, а затем с помощью плагина HEX Editor увидел фактические данные.
Я заметил, что заголовок DIB начинается с байта 28, поэтому я увеличил свой указатель на 27, а затем получил правильные значения.
https://stackoverflow.com/questions/45696075/byte-array-to-image-parameter-is-not-valid
lPtr = new IntPtr(lPtr.ToInt64() + 27); BITMAPINFOHEADER bim = (BITMAPINFOHEADER)Marshal.PtrToStructure(lPtr, typeof(BITMAPINFOHEADER));