I am using a COM Interface where I am receiving byte data representing a DIP (Device Independent Bitmap). I want take this byte[] and copy its data into a BITMAPINFOHEADER variable.
I have a long piece of code and this is only part of it, however it is written in VBA and it works:
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 "---------------"
Output:
Length: 897832
Size of BitMapInfoHeader: 40
---------------
l(0): 40
biSize before: 0
biSize after: 40
---------------
Above code shows the variable b has a biSize of 0 before and 40 after the CopyMemory Method is called upon.
I tried to replicate the code in C# however it doesn't work.
[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 + "");
What I have tried:
The below line of code worked as per accepted answer below.
BITMAPINFOHEADER bim = (BITMAPINFOHEADER) Marshal.PtrToStructure(lPtr, typeof(BITMAPINFOHEADER));
Latest Attempt
byte[] 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 + "");
Output:
Byte Array Pointer: 56182800
---------------
Byte Array Lenght: 897860
---------------
biWidth after: -256
biHeight after: 511
biSize after: 256
biSizeImage after: 3005743104
Above values don't seem right as compared to what I am getting from the VBA Code.
VBA Values
Byte Array Length: 897832
bim.biSize: 0
bim.biSize: 40
bim.biWidth: 501
bim.biHeight: 448
Final Solution
So I saved the byte array I was getting into a text file, open this text file in notepad++ and then using the HEX Editor plugin saw the actual data.
I notice the DIB Header what starting at byte 28, so I incremented my pointer by 27 and then I got the correct values.
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));