在C和C#(DLL和P invoke)之间传递包含结构体数组的结构体

4

我有一个包含复杂结构的C动态链接库,而我对C#还是个新手:

typedef struct {
    int a;
    int b;
} simple_struct;

typedef struct {
    int d;
    int e;
    simple_struct f[20];
    short g;
    simple_struct h[20];
    short i;
} complex_struct;

问题在于我无法将我的C#应用程序与这个结构进行接口交互!!在DLL中有一个函数GetData(complex_struct* myStruct),我应该从C#中调用它,因此我创建了:
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    unsafe struct simple_struct {
        public int a;
        public int b;
    } ;

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    unsafe struct complex_struct {
        public int d;
        public int e;
        public simple_struct[] f;
        public short g;
        public simple_struct[] h;
        public short i;
    } ;

但是问题在于当我将 complex_struct 作为 GetData 的参数传递时,所有字段都被填充了,但我的两个 simple_struct 数组(即 f 和 h)的值却为空!

请问有人能帮帮我吗?谢谢。


您好,感谢您的回复,

我按照您所说的方法做了,但是当我调用 GetData 时,进程会崩溃,且没有任何消息(一种异常):

这是我的 C# 代码: namespace dll_test_import_c_sharp { [StructLayout(LayoutKind.Sequential, Pack = 1)] struct simple_struct { public int a; public int b; } ;

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct complex_struct {
            public int d;
            public int e;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            public simple_struct[] f;
            public short g;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            public simple_struct[] h;
            public short i;
        } ;




        [DllImport("test_dll.dll", CharSet = CharSet.Unicode)]
        static extern int GetData(ref complex_struct a);



        static void Main(string[] args)
        {
            complex_struct a = new complex_struct();
            GetData(ref a);
            return;
        }

    }
}

我做了很多printf和GetData,它们都执行得很好,似乎是'return'指令崩溃了!!

我尝试通过ref或out来调用GetData,但两者都不起作用...


你好,谢谢你的回复,

我已经按照你说的做了,但是当我调用GetData时,进程会崩溃,没有任何消息(一种异常):

这是我的C#代码: namespace dll_test_import_c_sharp { class Program { [StructLayout(LayoutKind.Sequential, Pack = 1)] struct simple_struct { public int a; public int b; } ;

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct complex_struct {
            public int d;
            public int e;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            public simple_struct[] f;
            public short g;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            public simple_struct[] h;
            public short i;
        } ;




        [DllImport("test_dll.dll", CharSet = CharSet.Unicode)]
        static extern int GetData(ref complex_struct a);



        static void Main(string[] args)
        {
            complex_struct a = new complex_struct();
            GetData(ref a);
            return;
        }

    }
}

我已经使用了很多printf和GetData,它们都成功执行了,但似乎“return”指令导致程序崩溃!

我尝试通过引用或输出来调用GetData,但两者都不起作用...


为什么要打包?对于本地结构来说,打包是相当不寻常的。 - David Heffernan
这个打包只是为了在我的程序中进一步使用 :) - hzrari
我不明白。如果本地结构体未打包,则您的互操作性很可能会失败。 - David Heffernan
我认为是的,你说得对!!我会在我的代码中稍后打包我的数据,但即使C#结构没有打包,我仍然有相同的行为!! - hzrari
你需要像Jared所说的那样使用 UnmanagedType.ByValArray。你的另一个问题可能是C代码使用了cdecl,但是你的pinvoke使用了stdcall。在 DllImport 属性中添加 CallingConvention = CallingConvention.Cdecl。我真的怀疑你的本地代码是否被打包了。 - David Heffernan
1个回答

7
您需要更改struct上的数组定义,以指定它是按值/内联数组。
[StructLayout(LayoutKind.Sequential, Pack = 1)]
unsafe struct complex_struct {
    public int d;
    public int e;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
    public simple_struct[] f;
    public short g;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
    public simple_struct[] h;
    public short i;
} ;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接