【问题标题】:passing structure when calling C++ DLL function in C#在 C# 中调用 C++ DLL 函数时传递结构
【发布时间】:2015-02-10 21:37:01
【问题描述】:

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

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# 类型的 Marshal.SizeOf() 并比较您的 C++ 类型的 sizeof()
  • printf("size => %d",di) 这给了我 256 Marshal.SizeOf(di) 给了我 32 但不知道是什么造成了这种差异?即使将 bool_t 的 int 更改为 byte,我的 C# 结构仍然是错误的?
  • 没有区别,sizeof返回位和Marshal.SizeOf字节,所以是一样的。
  • 谢谢,有没有其他调试技巧可以用来找出导致我的 C# 结构与 C++ 不同的原因?

标签: c# c++ pointers dll struct


【解决方案1】:

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

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

【讨论】:

  • 谢谢,我把它们改成了下面的字节 public byte init_bus_only;公共字节use_pmu;但是现在我得到了 BUS_LOAD_LIBRARY_FAIL,仍然无法弄清楚还有什么问题?
  • 如果没有明显的错误,请在 DLL 的文档中检查导致 BUS_LOAD_LIBRARY_FAIL 的原因。
  • 对不起,我知道 init_bus_only,实际上我稍微更改了变量命名并忘记在发布时将其更改回来,我将初始化项目和值设置为与 C++ 示例完全相同,仍然试图找到什么导致 C# 结构失败。
  • 文档中只说加载总线DLL失败,好像没什么用。
  • NM,我缺少另一个DLL文件,谢谢大家的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-01
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多