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

时间:2014-12-12 07:56:01

标签: c# c++ pointers dll struct

我需要使用C#来控制带有C ++ DLL的测试模块,下面是最初在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 ++函数的参数已损坏或其他什么,任何人都可以帮助我吗?提前致谢。

1 个答案:

答案 0 :(得分:0)

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

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