C# .net wrapper for c dll, specifically lglcd (g19 sdk)
Asked Answered
P

2

6

Ok guys, this is making me crazy. I'm creating a port for a C lib in C# but I've a problem in using a bitmap (generated with gdi) with a byte array (required from the c lib)

Here are is the code, (pastie) divided in files:

  1. Lglcd.dll: http://pastie.org/1424596 (compiled)
  2. G19dotNet.dll: http://pastie.org/1424600 (compiled, this is the interop lib for c#)
  3. TestProject: http://pastie.org/1424603 (compile, but throws an exception)

The problem is in the last file (the other two are pretty straightforward), 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 an invalid memory access to managed memory.

The signature of the function is this one:

/// 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 param is a pointer to lgLcdBitmapHeader, but I suppose (because I've seen an older version of the lib) that this pointer is casted to a lgLcdBitmapQVGAx32 pointer (which is a struct of different size)

I think the problem is there, however I can't manage to solve this, really

here is the signature of the struct:

    [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public struct lgLcdBitmapHeader
    {

        /// DWORD->unsigned int
        public uint Format;
    }

and

    [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public struct lgLcdBitmap160x43x1
    {

        /// lgLcdBitmapHeader->Anonymous_5fa96ca7_9cc3_4b33_b5aa_ccff9833813a
        public lgLcdBitmapHeader hdr;

        /// BYTE[]
        //public fixed byte pixels[NativeConstants.LGLCD_BMP_WIDTH * NativeConstants.LGLCD_BMP_HEIGHT * NativeConstants.LGLCD_BMP_BPP];
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = NativeConstants.LGLCD_BMP_WIDTH * NativeConstants.LGLCD_BMP_HEIGHT * NativeConstants.LGLCD_BMP_BPP)]
        public byte[] pixels;
        public static int SizeConst { get { return NativeConstants.LGLCD_BMP_WIDTH * NativeConstants.LGLCD_BMP_HEIGHT * NativeConstants.LGLCD_BMP_BPP; } }
    }

I hope someone can help me, I'm watching all over the web and I've found a .net port of this lib but it's very old, and doesn't have the problem that I have because doesn't use colored bitmaps (with 4 bytes for each color) and doesn't use lgLcdBitmapHeader struct (it uses a simpler one). Also it's source code is very similar to mine.

Any help will be appreciated

Useful Links:

http://lglcdnet.codeplex.com/SourceControl/changeset/changes/5538

Update 1:

I did some progress based on a teory.

DWORD WINAPI lgLcdUpdateBitmap(IN int device,
                           IN const lgLcdBitmapHeader *bitmap,
                           IN DWORD priority);

This signature has "a meaning" in c, because the pointer to the first element of a struct is also the pointer to that struct. In fact lgLcdBitmapQVGAx32 has a first element of type lgLcdBitmapHeader. That said, they are using the possibility of C to cast everything to everything to create a "generic method", because lgLcdBitmapHeader can be both lgLcdBitmap160x43x1 (first elem is lgLcdBitmapHeader) or lgLcdBitmapQVGAx32.

This is a problem because in C# I can't emulate this capacity, so I created some "helper" functions which accept lgLcdBitmap160x43x1 and lgLcdBitmapQVGAx32 which are internally used as pointers to lgLcdBitmapHeader.

This done, however, gave me another error:

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': Limitazione interna: la struttura è troppo complessa o troppo grande.:

System.Runtime.InteropServices.MarshalDirectiveException not handled Message=Impossible do marshalling of 'parameter #2': Internal limitation: the structure is too big or too complex

It has an array of 307200 bytes, what should I do?

Update 2:

I managed to show an image on my screen, means that my teory was correct, I had to use this type of "thing" to make it works: http://bytes.com/topic/c-sharp/answers/272048-internal-limitation-structure-too-complex-too-large However the image shown is "broken", I mean it has the shape of the original image but a bit confused and uncolored, maybe because the way on how I pass the bitmap?

Preponderance answered 3/1, 2011 at 1:43 Comment(3)
Maybe you have to marshal something up into an un-managed type before passing it?Heronry
That's for sure, however I don't know how to marshal in this way, I'm not good with Interop services, I'm going madPreponderance
Am not very sure, but can u take a look at msdn.microsoft.com/en-us/library/23acw07k.aspxLowestoft
P
1

Usage of unmanaged allocation is needed as explained directly in the question.

Code example:

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);

Also I needed to change the extern method signature:

    [DllImportAttribute("LgLcd", EntryPoint = "lgLcdUpdateBitmap")]
    public static extern uint lgLcdUpdateBitmap([In] int device, [In] IntPtr bitmap, [In] uint priority);
    //OLD ONE:
    public static extern uint lgLcdUpdateBitmap([In] int device, [In] ref lgLcdBitmapHeader bitmap, [In] uint priority);
Preponderance answered 3/1, 2011 at 16:47 Comment(0)
C
0

Since you have the source code for c dll, you should consider writing the wrapper with Visual C++ CLR project. Common Language Runtime allows you to write managed and unmanaged code together. Then you wont need to pass variables but use them directly.

And when you want to use it from c# just reference the C++ Clr library from your c# app. I used this way before and it works perfectly.

Catheterize answered 3/1, 2011 at 14:53 Comment(3)
I think it's better but never used c++ clr However I managed to show something, the problem now is showing the bitmap correctlyPreponderance
@Fire: Ok then i guess you should check out the pixel format. We have pf 32bppARGB, pf 32bppRGBA... is it possible you see the alpha value instead of green?Catheterize
Mh I managed to make it works in a different way, I PInvoked GetBitmapBits wich works well with an HBITMAP, I can easily get it from my bitmap... so everything is fine, I think it's ok in this way too. Btw the format is RGBAPreponderance

© 2022 - 2024 — McMap. All rights reserved.