尝试调用 Dll,但该方法具有复杂的结构类型,我无法在 .Net 中定义它

Posted

技术标签:

【中文标题】尝试调用 Dll,但该方法具有复杂的结构类型,我无法在 .Net 中定义它【英文标题】:Try Call Dll, But the method has a complicated struct type, I can't define it in .Net 【发布时间】:2015-11-02 10:47:08 【问题描述】:

C++ 中定义的结构是:

typedef struct _DEVICE_PATH_LIST_

    int NumDevice;  
    TCHAR *devicePath[DEVICE_PATH_LIST_SIZE];   
 DEVICE_PATH_LIST;

而C++函数的定义是:

 LandiWin_iGetDevicePathList( int iDeviceType, DEVICE_PATH_LIST *  devicePathList);

然后我想调用那个方法,所以我需要定义一个可以表示DEVICE_PATH_LIST的struct。这是我在 C# 中的定义:

[StructLayout(LayoutKind.Sequential)]
public unsafe struct DevicePathType

    public int NumDevice;
    [MarshalAs(UnmanagedType.ByValArray,SizeConst=32)]
    public char*[] devicePath;

但这不对,我也尝试了所有其他类型但都失败了。请帮我定义一个正确的结构。

【问题讨论】:

如果需要通过超过 32 台设备怎么办?数据是传递给函数还是由函数返回?认为函数签名完全定义了接口是一个非常常见的错误。您还必须详细说明语义。这样做的一种好方法是在 C++ 中显示示例调用代码。 你的 [MarshalAs] 不错,最好使用 public IntPtr[] devicePath。根据 C 代码的构建方式,使用 Marshal.PtrToStringAnsi() Marshal.PtrToStringUni() 恢复字符串。考虑到您在使用 char* 时遇到问题,可能是 Ansi。请注意,存在内存管理问题,如果调用者需要释放字符串,您可能会泄漏内存。通过调用该方法一百万次来测试它。并且您必须正确使用 CallingConvention,可能是 Cdecl。 @HansPassant,谢谢。当我使用 IntPtr[] 替换 char*[] 时它起作用了 【参考方案1】:

C++代码如下:

typedef struct _DEVICE_PATH_LIST_

 int NumDevice; 
 TCHAR *devicePath[DEVICE_PATH_LIST_SIZE];  
 DEVICE_PATH_LIST;

C#的代码应该是这样的:

[StructLayout(LayoutKind.Sequential)]
public struct DevicePathType

    public int NumDevice;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
    public IntPtr[] devicePath;

【讨论】:

以上是关于尝试调用 Dll,但该方法具有复杂的结构类型,我无法在 .Net 中定义它的主要内容,如果未能解决你的问题,请参考以下文章

将第三方 dll 链接到我的 dll

JNA 可以用于像 IMAPI 这样的复杂 Windows DLL

如何使用 GraalVM 从 C++ 调用具有非原始类型作为参数的 Java 入口点方法

从 C# 调用非托管 DLL,将结构作为参数传递

如何调用具有泛型类型的结构的关联函数?

PHP 源码学习 | 变量类型数据结构