C# 为什么编组后,数组中只有一个元素包含值? 我从C代码中调用C++函数。而且我使用的是编组,但是当从C++代码返回时,在我的C代码中,只有一个元素填充了这个数组。

C# 为什么编组后,数组中只有一个元素包含值? 我从C代码中调用C++函数。而且我使用的是编组,但是当从C++代码返回时,在我的C代码中,只有一个元素填充了这个数组。,c#,c++,pinvoke,C#,C++,Pinvoke,我的C++结构:< /P> typedef struct DEV_SUB_STATE_ITEM_s { char err_text[NAME_MAX_LENGTH]; uint32_t state; char obj_name[NAME_MAX_LENGTH]; char name[NAME_MAX_LENGTH]; } DEV_SUB_STATE_ITEM_t; C#中的我的结构: 我的C++函数原型: int COMSpClient::GetSubSlotList (UINT32 obj_

我的C++结构:< /P>

typedef struct DEV_SUB_STATE_ITEM_s
{
char err_text[NAME_MAX_LENGTH];
uint32_t state;
char obj_name[NAME_MAX_LENGTH];
char name[NAME_MAX_LENGTH];
} DEV_SUB_STATE_ITEM_t;
C#中的我的结构:

我的C++函数原型:

int COMSpClient::GetSubSlotList (UINT32 obj_rid, DEV_SUB_STATE_ITEM_t** subSlotItems);
我的C#函数原型:

我在C#中的用法:


这是一个稍微笨拙的封送函数。非托管代码分配数组并将指向数组的指针返回给调用方。因此,签名中存在双指针。不能使用p/invoke自动封送

您需要使用一个
IntPtr
,作为
out
参数传递,然后自己进行剩余的编组

[DllImport(...)]
public static extern int GetSubSlotList(
    IntPtr p_hHandle, 
    uint obj_rid, 
    out IntPtr sub_slot_items
);
此时,
sub_slot_items
指向数组的第一个元素。然后需要使用
Marshal.PtrToStructure
读取每个项目,并在执行过程中增加点数

您可能需要回调非托管代码,要求它释放内存

当然,这很混乱。如果您可以控制接口,更好的设计是让调用方分配数组。代码如下所示:

int COMSpClient::GetSubSlotList(
    UINT32 obj_rid, 
    DEV_SUB_STATE_ITEM_t subSlotItems[]
);
您可能还希望传递数组的长度,除非双方都知道它的其他原因

在C端,代码是:

[DllImport(...)]
public static extern int GetSubSlotList(
    IntPtr p_hHandle, 
    uint obj_rid, 
    [Out] DEVICE_Sub_State_Item[] sub_slot_items
);

编组到字符串比最初看起来要烦人得多。将字符串封送到固定字节缓冲区,然后像这样构造字符串可能更容易:

public unsafe struct DEVICE_Sub_State_Item
{
    public fixed byte err_text[50];
    public UInt32 state;
    public fixed byte obj_name[50];
    public fixed byte name[50];

    public string ErrorText
    {
        get
        {
            byte[] buffer = new byte[50];

            fixed (byte* b = err_text)
                Marshal.Copy(new IntPtr(b), buffer, 0, buffer.Length);

            return Encoding.UTF8.GetString(buffer);
        }
    }
}
实际错误文本将作为指针保留在结构中,只有在调用其上的
ErrorText
属性时,才会正确读取并转换为字符串


如果您决定这样做,则需要在项目的构建选项下启用不安全代码。

但我将在c#中使用[out]参数,因此我可以使用**子脚本项。因为数组指针?抱歉,我不理解这个注释。我在C++中使用了参数子SuxStLoWiTes项,但是C++代码中没有使用输出参数,只是在您的解决方案上使用数组。İ是吗?函数名中的单词“list”很麻烦,看起来它实际上并没有返回列表。如果它返回一个数组,那么基本问题是:客户机代码如何知道数组中有多少个元素?pinvoke marshaller当然不知道,它只能返回一个元素。我确信它会返回一个列表。然后结构应该包含一个字段,该字段是指向列表中下一个元素的指针。没有。C++ C++代码,显示了这个函数如何被调用。是的,但是这个函数正在返回一个数组,它是Struts数组。所以下一个元素不需要指针。我解决了我的问题。每个人都可以在以下链接中找到此解决方案:
int COMSpClient::GetSubSlotList(
    UINT32 obj_rid, 
    DEV_SUB_STATE_ITEM_t subSlotItems[]
);
[DllImport(...)]
public static extern int GetSubSlotList(
    IntPtr p_hHandle, 
    uint obj_rid, 
    [Out] DEVICE_Sub_State_Item[] sub_slot_items
);
public unsafe struct DEVICE_Sub_State_Item
{
    public fixed byte err_text[50];
    public UInt32 state;
    public fixed byte obj_name[50];
    public fixed byte name[50];

    public string ErrorText
    {
        get
        {
            byte[] buffer = new byte[50];

            fixed (byte* b = err_text)
                Marshal.Copy(new IntPtr(b), buffer, 0, buffer.Length);

            return Encoding.UTF8.GetString(buffer);
        }
    }
}