c dll 的 C# .net 包装器,特别是 lglcd (g19 sdk)

发布于 2024-10-10 16:35:05 字数 5596 浏览 3 评论 0原文

好吧,伙计们,这让我发疯了。 我正在 C# 中为 C lib 创建一个端口,但在使用位图(用 gdi 生成)和字节数组(从 c lib 中需要)时遇到问题,

这是代码(pastie)分为文件:

  1. Lglcd.dll: http://pastie.org/1424596 (编译)
  2. G19dotNet.dll: http://pastie.org/1424600(已编译, 这是 c# 的互操作库)
  3. TestProject: http://pastie.org/1424603 (编译, 但引发异常)

问题出在最后一个文件中(其他两个文件非常简单),第 116 行

res = LgLcd.NativeMethods.lgLcdUpdateBitmap(openContext.device, ref bmp.hdr, LgLcd.NativeConstants.LGLCD_SYNC_UPDATE(LgLcd.NativeConstants.LGLCD_PRIORITY_NORMAL));

这会引发对托管内存的无效内存访问的异常。

该函数的签名是这样的:

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

正如您所看到的,第二个参数是指向 lgLcdBitmapHeader 的指针,但我想(因为我看过旧版本的库)该指针被转换为 lgLcdBitmapQVGAx32 指针(即不同大小的结构)

我认为问题就在那里,但是我无法解决这个问题,实际上

这是结构的签名:

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

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

    [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; } }
    }

希望有人可以帮助我,我正在整个网络上观看,我已经找到了这个库的 .net 端口,但它很旧,并且没有我遇到的问题,因为不使用彩色位图(每种颜色 4 个字节)并且不使用 lgLcdBitmapHeader 结构(它使用一个更简单的)。而且它的源代码与我的非常相似。

任何帮助将不胜感激

有用的链接:

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

更新1:

我根据理论取得了一些进展。

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

这个签名在 c 中具有“意义”,因为指向结构体第一个元素的指针也是指向该结构体的指针。 事实上 lgLcdBitmapQVGAx32 有一个 lgLcdBitmapHeader 类型的第一个元素。 也就是说,他们正在利用 C 将所有内容转换为所有内容的可能性来创建“通用方法”,因为 lgLcdBitmapHeader 可以是 lgLcdBitmap160x43x1(第一个 elem 是 lgLcdBitmapHeader)或 lgLcdBitmapQVGAx32。

这是一个问题,因为在 C# 中我无法模拟这种能力,所以我创建了一些“辅助”函数,它们接受 lgLcdBitmap160x43x1 和 lgLcdBitmapQVGAx32 ,它们在内部用作指向 lgLcdBitmapHeader 的指针。

然而,这样做给了我另一个错误:

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 未处理 Message=Impossible do marshalling of 'parameter #2': 内部限制:结构太大或太复杂

它有一个 307200 字节的数组,我该怎么办?

更新2:

我设法在屏幕上显示图像,这意味着我的理论是正确的,我必须使用这种类型的“东西”才能使其工作:http://bytes.com/topic/c-sharp/答案/272048-内部限制-结构-太复杂-太大 然而,显示的图像是“损坏的”,我的意思是它具有原始图像的形状,但有点混乱和无色,也许是因为我传递位图的方式?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

过潦 2024-10-17 16:35:05

正如问题中直接解释的那样,需要使用非托管分配。

代码示例:

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

我还需要更改外部方法签名:

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

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);
杀手六號 2024-10-17 16:35:05

由于您拥有 c dll 的源代码,因此您应该考虑使用 Visual C++ CLR 项目编写包装器。
公共语言运行时允许您一起编写托管和非托管代码。那么你就不需要传递变量而是直接使用它们。

当您想从 C# 使用它时,只需从您的 C# 应用程序引用 C++ Clr 库。我以前用过这种方法,效果非常好。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文