繁体   English   中英

C#将指向struct(包含非blittable类型)的指针传递给非托管C ++ DLL

[英]C# pass pointer to struct (containing non-blittable types) to unmanaged C++ DLL

我尝试在我的C#代码中使用C ++ DLL。
必须将读取的所有数据作为指向结构的指针传递给dll。 我的第一个想法是只保留一些非托管内存,将指针传递给函数并随后提取数据。 问题是函数只会返回一个错误代码,转换为“参数无效”。

从DLL标题(结果和BusPortId缩短)

typedef enum {
    BUS_COM1 = 0x01,  // 2 to 15 ommited
    BUS_COM16 = 0x10,
    BUS_USB1 = 0x101,  // 2 to 15 ommited
    BUS_USB16 = 0x110
} BusPortId;

typedef enum {
    BUS_SUCCESS    = 0,     //!< The operation was completed successfully
    BUS_ERROR      = 0x100,  //!< An error occured
    BUS_INVALIDARG = 0x1000, //!< An argument is not valid
} Result


struct BusPortInfo
{
    ULONG       portInfoSize;
    CHAR        portText[64];
    BOOL        portLocked;
    BusPortId   portId;
};

Result BUSDRV_API busGetAvailablePortCount( ULONG *retCount );

Result BUSDRV_API busGetAvailablePort( ULONG index, BusPortInfo *portInfo );

到目前为止我的C#程序的相关部分

enum BusPortId
{
    BUS_COM1 = 0x01,  // 2 to 15 ommited
    BUS_COM16 = 0x10,
    BUS_USB1 = 0x101,  // 2 to 15 ommited
    BUS_USB16 = 0x110
};

public enum Result
{
    BUS_SUCCESS = 0,       //!< The operation was completed successfully
    BUS_ERROR = 0x100,  //!< An error occured
    BUS_INVALIDARG = 0x1000, //!< An argument is not valid
};

struct BusPortInfo
{
    public ULONG portInfoSize;
    unsafe public fixed char portText[64];
    public BOOL portLocked;
    public BusPortId portId;
}

[DllImport(DLL_Path)]
unsafe static extern Result busGetAvailablePortCount(ULONG* retCount);
[DllImport(DLL_Path)]
unsafe static extern Result busGetAvailablePort(ULONG index, BusPortInfo* portInfo);

ulong count= 0;
Result res = busGetAvailablePortCount(&count);

ulong index = 0;
BusPortInfo info = new BusPortInfo();
Result res = busGetAvailablePort(0, &info);

对busGetAvailablePortCount(和其他类似函数)的调用没有任何问题。 但是当我调用busGetAvailablePort时,我在控制台输出中得到以下内容

Cannot marshal 'parameter #2': Pointers cannot reference marshaled structures. Use ByRef instead.

问题是我可以在C#中更改我的结构,以便我可以传递指针,但是DLL中的函数也会返回“参数无效”

我该怎么做我的结构,所以我可以将指针传递给一个函数,同时仍然被DLL接受?

PS抱歉英语不好,我不是母语人士。

这些声明存在很多问题,当程序员不断破解代码以试图使pinvoke调用工作时,往往会发生这些问题。 该结构最可能的正确声明是:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    struct BusPortInfo {
        public int portInfoSize;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
        public string portText;
        public bool portLocked;
        public BusPortId portId;
    }

强调本机代码中的ULONG是32位类型并且仅fixed不是必需的并且非常笨拙。 由于bool和string成员,这个结构不是blittable,没什么可担心的。

[DllImport]声明需要正确声明第二个参数。 CallingConvention属性总是很重要,我们无法看到BUSDRV_API的含义。 划船:

    [DllImport(DLL_Path, CallingConvention = CallingConvention.StdCall)]
    static extern Result busGetAvailablePortCount(out int retCount );

    [DllImport(DLL_Path, CallingConvention = CallingConvention.StdCall)]
    static extern Result busGetAvailablePort(int index, 
                            [In, Out] ref BusPortInfo portInfo);

电话看起来不正确。 当struct具有“size”成员时,api契约通常要求在调用之前设置它。 这是一种安全措施,它确保当调用者使用错误的结构声明时,api不会破坏内存。 如果设置错误,“无效参数”错误是预期结果。 所以写它类似于:

int count;
Result res = busGetAvailablePortCount(out count);
if (res != Result.BUS_SUCCESS) throw new Exception("Api failure " + res.ToString());

for (int ix = 0; ix < count; ++ix) {
    BusPortInfo info;
    info.portInfoSize = Marshal.SizeOf(typeof(BusPortInfo));   // Important!
    res = busGetAvailablePort(ix, ref info);
    if (res != Result.BUS_SUCCESS) throw new Exception("Api failure " + res.ToString());
    // etc...
}

当然没有经过测试,应该在球场。 如果仍有问题,请验证本机代码中的sizeof(BusPortInfo)是否与C#中的Marshal.SizeOf(typeof(BusPortInfo))的值匹配。 如果全部失败则使用C ++ / CLI,这样您就可以直接使用本机声明。 并与DLL的所有者讨论正确的使用说明,最好是他会为你编写一个pinvoke样本。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM