c# - 用于复杂方法调用的 PInvoke C#

标签 c# pinvoke

我使用的是 3.party SDK,它由 .dll、.lib 和 .h 文件组成。 我正在使用 .dll 来反对 PInvoke。以及用于查看函数名称和参数的 .h 文件。 (所以我没有使用 .lib 文件)。

SDK 相当复杂,因此制作 PInvoke 包装器已被证明是一项挑战。所有函数/结构/枚举都在 .h 文件中定义。

我试图包装的函数称为 InitBaseComponent,我可以调用它,但它返回一个“参数错误”枚举。所以我猜是编码造成了这个问题。 所以问题是:我这样做对吗?

函数:InitBaseComponent(...)

//C Function: InitBaseComponent(...)
ERROR InitBaseComponent(
    Method_Interface* methodInterface, //[in]
    void* methodInst, //[in]
    ErrorCallBackFunction errorCallbackFunc, //[in]
    void* ErrorCallbackInst, //[in]
    Component* BaseComponent //[in, out]
);

//C# Function: InitBaseComponent(...)
[DllImport("externalSDK.dll", EntryPoint = "InitBaseComponent", CallingConvention = CallingConvention.Cdecl)]
public static extern ERROR InitBaseComponent(
    Method_Interface methodInterface, 
    IntPtr methodInst, 
    ErrorCallBackFunction errorCallbackFunc, 
    IntPtr ErrorCallbackInst, 
    out Component BaseComponent 
);

枚举:错误

//C Enum: ERROR 
typedef enum ERROR_E {
    OK = 0, //Everything is ok
    E_ARG = 1, //Error in the Arguments 
    E_DATA = 2 //Data error
    //And more...
 } ERROR;

 //C# Enum: ERROR
 public enum ERROR
 {
    OK = 0, //Everything is ok
    E_ARG = 1, //Error in the Arguments 
    E_DATA = 2 //Data error
    //And more...
 }

结构:方法接口(interface)

//C struct: Method_Interface
typedef struct Method_Interface_S 
{
    void* (*Method1)(void* Inst, size_t size);
    void* (*Method2)(void* Inst, size_t nelements, size_t bytes);
    void* (*Method3)(void* Inst, void *pointer, size_t size);
    void (*Method4)(void* Inst, void* pointer);
}Method_Interface;

//C# class: Method_Interface
[StructLayout(LayoutKind.Sequential)]
public class Method_Interface
{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void Method1_delegate(IntPtr Inst, uint size);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void Method2_delegate(IntPtr Inst, uint nelements, uint bytes);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void Method3_delegate(IntPtr Inst, IntPtr pointer, uint size);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void Method4_delegate(IntPtr Inst, IntPtr pointer);

    public Method1_delegate Method1;
    public Method2_delegate Method2;
    public Method3_delegate Method3;
    public Method4_delegate Method4;
}

委托(delegate):ErrorCallBackFunction

//C ErrorCallBackFunction
typedef void (*ErrorCallBackFunction)(void* errorCallBackInst, ERROR errorCode, const char* szMessage, const char* szDetail);

//C# delegate: ErrorCallBackFunction
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ErrorCallBackFunction(IntPtr errorCallBackInst, ERROR errorCode, string szMessage, string szDetail);

结构:组件

//C struct: Component
typedef struct Component_S
{
    void* ObjPointer;    
    unsigned long number; 
} Component;

//C# class: Component
[StructLayout(LayoutKind.Sequential)]
public class Component
{
    public IntPtr ObjPointer;
    public ulong number;
}

谁知道我做错了什么?

最佳答案

您已在 C# 中将 Component 声明为一个类。这意味着它已经是一个引用。但是随后您将它作为 out 参数传递,这增加了一个额外的间接层,太多了。因此,您需要删除 out,就像您对 methodInterface 所做的那样。

[DllImport(...)]
public static extern ERROR InitBaseComponent(
    Method_Interface methodInterface, 
    IntPtr methodInst, 
    ErrorCallBackFunction errorCallbackFunc, 
    IntPtr ErrorCallbackInst, 
    Component BaseComponent 
);

显然,在调用 InitBaseComponent 之前,您需要在 C# 中实例化 Component 对象。

一些其他观察:

  1. size_t 是指针大小的,因此您转换为 uint 将在 64 位平台上失败。
  2. C# long 是 64 位,但 C++ long 在 Windows 上是 32 位。因此,您对 C++ Component 结构的翻译是错误的。 number 字段必须用 uint 类型声明。

关于c# - 用于复杂方法调用的 PInvoke C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20117360/

相关文章:

c# - 使用 C# 和 Aster.NET 可靠地识别和跟踪 Asterisk 调用

c# - 快速文本阅读(替代 File.ReadAllText() 和/或 StreamReader.ReadToEnd())

c# - 为什么 C# 队列或列表只有计数而数组有长度?

c# - 无法连接到vb.net中的数据库

c# - ASP.NET 用户控件设计器支持

c# - DLL 导入中的 SafeFileHandle

c# - 将断言输出从 dll 重定向到文件

c# - 从 Dapper 存储过程返回列表

c# - 在没有 WMI 的情况下检测 HDD 是否通过 USB 或其他方式连接

c# - 调用 C dll 函数来更改 C# 中传递的参数