Ok guys, this makes me crazy. I am creating a port for C lib in C #, but I have a problem using a bitmap (generated using gdi) with a byte array (required from c lib)
Here is the code, (graze), divided into files:
The problem is in the last file (the other two are quite simple), line 116
res = LgLcd.NativeMethods.lgLcdUpdateBitmap(openContext.device, ref bmp.hdr, LgLcd.NativeConstants.LGLCD_SYNC_UPDATE(LgLcd.NativeConstants.LGLCD_PRIORITY_NORMAL));
This throws an exception for invalid access to memory in managed memory.
The signature of the function is as follows:
/// Return Type: DWORD->unsigned int ///device: int ///bitmap: lgLcdBitmapHeader* ///priority: DWORD->unsigned int [System.Runtime.InteropServices.DllImportAttribute("LgLcd", EntryPoint = "lgLcdUpdateBitmap")] public static extern uint lgLcdUpdateBitmap([System.Runtime.InteropServices.In] int device, [System.Runtime.InteropServices.In] ref lgLcdBitmapHeader bitmap, [System.Runtime.InteropServices.In] uint priority);
As you can see, the second parameter is a pointer to lgLcdBitmapHeader, but I suppose (because I saw an older version of lib) that this pointer is passed to the pointer lgLcdBitmapQVGAx32 (which is a structure of different sizes)
I think there is a problem, however I can not solve this problem, really
here is the signature of the structure:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] public struct lgLcdBitmapHeader {
and
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] public struct lgLcdBitmap160x43x1 {
I hope someone can help me, I look all over the network and I found the .net port of this library, but it is very old and I have no problem because I do not use (with 4 bytes for each color ) and does not use lgLcdBitmapHeader struct (it uses a simpler one). Also, the source code is very similar to mine.
Any help would be appreciated
Useful links:
http://lglcdnet.codeplex.com/SourceControl/changeset/changes/5538
Update 1:
I have made some progress based on theory.
DWORD WINAPI lgLcdUpdateBitmap(IN int device, IN const lgLcdBitmapHeader *bitmap, IN DWORD priority);
This signature has a "value" in c because the pointer to the first element of the structure is also a pointer to this structure. Actually, lgLcdBitmapQVGAx32 has the first element of type lgLcdBitmapHeader. However, they use C's ability to drop everything to create a “generic method”, since lgLcdBitmapHeader can be either lgLcdBitmap160x43x1 (the first element is lgLcdBitmapHeader) or lgLcdBitmapQVGAx32.
This is a problem because in C # I cannot emulate this capacity, so I created some "helper" functions that accept lgLcdBitmap160x43x1 and lgLcdBitmapQVGAx32, which are internally used as pointers to lgLcdBitmapHeader.
This made, however, another mistake:
System.Runtime.InteropServices.MarshalDirectiveException non è stata gestita Message=Impossibile effettuare il marshalling di 'parameter #2': Limitazione interna: la struttura è troppo complessa o troppo grande. Source=G19dotNet StackTrace: in G19dotNet.LgLcd.NativeMethods.lgLcdUpdateBitmapQVGAx32(Int32 device, lgLcdBitmapQVGAx32& bitmap, UInt32 priority) in ConsoleTest2.Program.Main(String[] args) in C:\Documents and Settings\Administrator\documenti\visual studio 2010\Projects\G19dotNet\ConsoleTest2\Program.cs:riga 116 in System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) in System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) in Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() in System.Threading.ThreadHelper.ThreadStart_Context(Object state) in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) in System.Threading.ThreadHelper.ThreadStart() InnerException:
English version of System.Runtime.InteropServices.MarshalDirectiveException non è stata gestita Message = Impossibile effettuare il marshalling di 'parameter # 2': Internship restriction: la struttura è troppo complessa o troppo grande .:
System.Runtime.InteropServices.MarshalDirectiveException is not handled Message = Impossible make marshalling 'parameter # 2': Internal constraint: structure is too big or too complicated
It has an array of 307200 bytes, what should I do?
Update 2:
I managed to show the image on my screen, this means that my theory is correct, I had to use this type of “thing” to make it work: http://bytes.com/topic/c-sharp/answers/272048-internal-limitation -structure-too-complex-too-large However, the image shown is “broken”, I mean that it has the shape of the original image, but a little confused and unpainted, perhaps because the way to transmit the bitmap?
Update 3 and solution:
I solved the problem myself, the code is really ugly, and I will post it here in the paste, I hope someone finds this useful. The most important part of the code is:
/// <summary> /// LONG GetBitmapBits( /// __in HBITMAP hbmp, /// __in LONG cbBuffer, /// __out LPVOID lpvBits /// ); /// </summary> /// <param name="hbmp"></param> /// <param name="cbBuffer"></param> /// <param name="lpvBits"></param> /// <returns></returns> [DllImport("Gdi32", EntryPoint = "GetBitmapBits")] public extern static long GetBitmapBits([In] IntPtr hbmp,[In] int cbBuffer,[Out] byte[] lpvBits); [DllImport("Gdi32", EntryPoint = "GdiFlush")] public extern static void GdiFlush(); public static void FillPixelArray3(Bitmap bmp, ref byte[] array) { IntPtr hbmp = bmp.GetHbitmap(); GdiFlush(); //Marshal SizeOf is to "ensure" that other people will notice that array.Length //must be multiplied GetBitmapBits(hbmp, array.Length * Marshal.SizeOf(typeof(byte)), array); }
and this:
IntPtr unhandledPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LgLcd.lgLcdBitmapQVGAx32))); Marshal.StructureToPtr(bmp, unhandledPtr, true); res = LgLcd.NativeMethods.lgLcdUpdateBitmap(openContext.device, unhandledPtr, LgLcd.NativeConstants.LGLCD_SYNC_UPDATE(LgLcd.NativeConstants.LGLCD_PRIORITY_NORMAL)); Marshal.FreeHGlobal(unhandledPtr);