.net C# P/Invoke封送行程结构的可变长度数组

yduiuuwa  于 2022-11-19  发布在  .NET
关注(0)|答案(1)|浏览(131)

我想调用Net6 C#库的一个函数。函数需要一个指向结构的指针。结构内部是一个变长数组。我不知道如何正确地封送这个数组。
下面的代码是演示该问题的测试代码。
这是C程序库的标题:

typedef struct SubTest
{
   char *name;
   int num1;
} SubTest;

typedef struct Test
{
   char *name;
   int num1;
   float num2;
   SubTest *testarray;
   int testarraylen;
} Test;

void PrintTestStruct(Test *teststruct);

下面是PrintTestStruct的实现:

void PrintTestStruct(Test *teststruct)
{
    printf("Name: %s \n", teststruct->name);
    printf("Num1: %d \n", teststruct->num1);
    printf("Num2: %f \n", teststruct->num2);

    printf("Array content: \n");

    for(int i=0; i < teststruct->testarraylen; i++)
    {
        printf("Array Name %d: %s \n", i,teststruct->testarray[i].name);
        printf("Array Number %d: %d \n", i,teststruct->testarray[i].num1);
    }
}

下面是C#中的定义:

[StructLayout(LayoutKind.Sequential)]
    public struct Test
    {
        public string name;
        public int num1;
        public float num2;
        public IntPtr testarray;
        public int testarraylen;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SubTest
    {
        public string name;
        public int num1;
    }

[DllImport("cshared")]
private static extern void PrintTestStruct(ref Test teststruct);

这就是我所尝试的:

public static void Main(string[] args)
{
      var data = new Test();
      data.name = "Hello from C#";
      data.num1 = 5;
      data.num2 = 3.2f;
      data.testarraylen = 2;

      var field1 = new SubTest();
      field1.name = "Testarray 1";
      field1.num1 = 1;

      var field2 = new SubTest();
      field2.name = "Testarray 2";
      field1.num1 = 2;

      SubTest[] subarray = {field1, field2};
            
      IntPtr mem = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(SubTest)) * data.testarraylen);
      
      for (int ix = 0; ix < 2; ix++)
      {
           Marshal.StructureToPtr<SubTest>(subarray[ix], mem, false);
           mem += Marshal.SizeOf(subarray[ix]);
      }

      data.testarray = mem;

      PrintTestStruct(ref data);
}

不幸的是结果是垃圾,数组的数据没有正确打印。我遵循了我在stackoverflow上找到的所有建议,但无法得到任何更好的结果。

问题:
1.有办法解决这个问题吗?
1.由于我可以访问C库的源代码,是否有更好的方法在C#和C之间传输这些类型的可变长度数组?我是否可以以某种方式更改C库以使其更容易?

wbgh16ku

wbgh16ku1#

问题是您已经更改了mem的地址,但没有还原它。

mem += Marshal.SizeOf(subarray[ix]);

因此,解决方案是将偏移地址添加到men,而不是在循环中更改。

var sizeOfSubTest = Marshal.SizeOf(typeof(SubTest));
IntPtr mem = Marshal.AllocCoTaskMem(sizeOfSubTest * data.testarraylen);

for (int ix = 0; ix < 2; ix++)
{
    Marshal.StructureToPtr(subarray[ix], mem + sizeOfSubTest * ix, false);
}

我能以某种方式改变C库使之更容易吗?
IMO这是最简单的。

相关问题