在 C# 中调用 DLL 函数时传递结构C++

passing structure when calling C++ DLL function in C#

本文关键字:结构 C++ 函数 调用 DLL      更新时间:2023-10-16

我需要使用 C# 来控制具有C++ DLL 的测试模块,下面是最初在头文件中定义的结构和 init 函数C++

typedef unsigned char       uint8_t;
typedef unsigned long       uint32_t;
typedef unsigned short      uint16_t;
typedef unsigned char       bool_t;
typedef signed short        int16_t;
typedef signed char         int8_t;
typedef signed long         int32_t;
#define ER      0x2
#define BS      0x4000
typedef enum {
    nI2C,
    nSPI,
    nUSB,
    nSDIO
} mBus;
typedef uint8_t cAddr; 
typedef enum {
    nCPHA0=0,
    nCPHA1
} mPhase;
typedef enum {
    nCPOL0=0,
    nCPOL1
} mSpiPol;
typedef struct {
    mPhase cPha;
    mSpiPol cPol;
} mSpiCfg;
typedef struct {
    uint8_t             xo; 
    bool_t              init_bus_only;                          
    uint32_t            zone; 
    mBus             bustype;  
    mBus             transporttype; 
    cAddr         i2cAddr;
    mSpiCfg          spiCfg;
    bool_t              use_pmu; 
} mInitCfg;
typedef enum {
    OK = 0,
    FAIL = -1,  
    BUS_ALREADY_LOADED = -2,
    BUS_TYPE_UNKNOWN = -3,
    BUS_LOAD_LIBRARY_FAIL = -4,
    BUS_GET_PROC_FAIL = -5,
    BUS_INIT_FAIL = -6,
    Err_CHIP_INIT = -7
} retCode;
typedef struct {
    mInitCfg cfg;
} mDrvIn;
__declspec(dllexport) retCode cp_init(mDrvIn * inp);

在C++中,它被称为如下

static void init(void)
{
mDrvIn di;
retCode rc;
memset(&di, 0, sizeof(mDrvIn));
di.cfg.bustype = nI2C; 
di.cfg.init_bus_only = 1;
di.cfg.transporttype = di.cfg.bustype;
di.cfg.zone = ER | BS;
    rc = cp_init(&di);
    if(rc < 0) {
    printf("Failed to initialize. Error code %d: %s", rc, to_string(rc));
    return;
}
}

我在调用 DLL 函数时使用以下 C# 结构

using cAddr = System.Byte;
public enum mBus
{
    nI2C,
    nSPI,
    nUSB,
    nSDIO
};
public enum mPhase
{
    nCPHA0 = 0,
    nCPHA1
};
public enum mSpiPol
{
    nCPOL0 = 0,
    nCPOL1
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct mSpiCfg
{
    public mPhase cPha;
    public mSpiPol cPol;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct mInitCfg
{
    public byte xo; 
    public byte init_bus_only; 
    public uint zone; 
    public mBus bustype; 
    public mBus transporttype; 
    public cAddr i2cAddr;
    public mSpiCfg spiCfg; 
    public byte use_pmu; 
};
public enum retCode
{
    OK = 0,
    FAIL = -1,  
    BUS_ALREADY_LOADED = -2,
    BUS_TYPE_UNKNOWN = -3,
    BUS_LOAD_LIBRARY_FAIL = -4,
    BUS_GET_PROC_FAIL = -5,
    BUS_INIT_FAIL = -6,
    Err_CHIP_INIT = -7
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct mDrvIn
{
    public mInitCfg cfg;
};
[DllImport("mdrv.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern retCode cp_init(ref mDrvIn inp);

我使用以下代码来初始化

public static void init()
{
    mDrvIn di = new mDrvIn();
    retCode rc = new retCode();
    di.cfg.bustype = mBus.nI2C;
    di.cfg.init_bus_only = 1;
    di.cfg.transporttype = di.cfg.bustype;
    di.cfg.zone = 0x2 | 0x4000;
    rc = cp_init(ref di);
    if (rc < 0)
    {
        Console.Write("Failed to initialize. Error code: " + rc);
        return;
    }
}

问题是使用 C++ 初始化模块可以正常工作,但 C# 不能,它总是会返回错误代码 -5(这意味着总线错误:无法枚举 DLL 内的总线函数),结构的指针似乎被成功传递给 DLL 没有错误,因此我想知道我在 C# 中转换的结构是否有问题, 因此,传递给C++函数的参数已损坏或其他原因,任何人都可以帮助我吗?提前谢谢。

在C++代码中,将bool_t定义为unsigned char(8 位),但在 C# 代码中,使用int(32 位),因此结构在init_bus_only后停止有效。

编辑:此外,在C++代码中,将init_bus_only设置为 1,而在 C# 代码中没有,但您应该在没有帮助的情况下找到它。在询问之前仔细检查您的代码。