编程语言
首页 > 编程语言> > PInvoke用于复杂的方法调用C#

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

作者:互联网

我正在使用3. party SDK,它由.dll,.lib和.h文件组成.
我正在使用.dll进行PInvoke.和.h文件以查看函数名称和参数. (因此,我没有使用.lib文件).

SDK非常复杂,因此事实证明,制作PInvoke包装器是一个挑战.所有功能/结构/枚举均在.h文件中定义.

我尝试包装的函数称为InitBaseComponent,可以调用它,但是它返回一个“ Error In Argument”枚举.所以我的猜测是,编组会产生此问题.
因此,问题是:我正在这样做吗?

功能: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...
 }

结构:Method_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;
}

代表: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对象.

其他一些观察:

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

标签:c,pinvoke
来源: https://codeday.me/bug/20191122/2059952.html