简体   繁体   English

将包含未知大小的int数组的结构从c#传递到c并返回

[英]Passing a struct containing an int array of unknown size from c# to c and back

I'm starting to struggle with this problem. 我开始努力解决这个问题。 I've searched and searched for help, and everything i've tried doesn't seem to work. 我一直在寻找帮助,而我尝试过的一切似乎都没有用。 I'm obviously doing something wrong. 我显然做错了。

Anyway - i have ac# structure defined as: 无论如何-我将ac#结构定义为:

public struct TestStruct
[StructLayout(LayoutKind.Sequential)]
{
   public int num;
   public IntPtr intArrayPtr;
}

and in the main body of my c# code i have: 在我的C#代码主体中,我有:

public class Testing
{
   [DllImport("testing.dll")]
   static extern void Dll_TestArray(out IntPtr intArrayPtr);

   public GetArray()
   {
      IntPtr structPtr = IntPtr.Zero;
      TestStruct testStruct;
      structPtr = Marshal.AllocHGlobal(Marshal.SizeOf(testStruct));
      Marshal.StructureToPtr(testStruct, structPtr, false);

      Dll_TestArray(structPtr);

      testStruct = (TestStruct) Marshal.PtrToStructure(structPtr, typeof(TestStruct));
   }
}

So now for the c++ part. 因此,现在介绍c ++部分。 Starting with the structure: 从结构开始:

struct TestStruct
{
   public:
     int  num;
     int* intArray;
}

and now the functions: 现在的功能:

extern "C" __declspec(dllexport) void Dll_TestArray(TestStruct *&testStruct)
{
   int num = 15;
   testStruct->num = num;
   testStruct->intArray = new int[num];

   for (int i = 0; i < num; i++)
     testStruct->intArray[i] = i+1;  
}

So - the problem i'm having, is that when i get the structure back into c#, my structure is not how it should be. 所以-我遇到的问题是,当我将结构恢复为C#时,我的结构不是应该的样子。 I can see that the num field has been filled in correctly: it shows 15. However, it is the IntPtr that is still set to zero. 我可以看到num字段已正确填写:显示为15。但是,仍然是IntPtr设置为零。 The array creation done in c++ has not been carried through to c#. 用c ++完成的数组创建尚未进行到c#中。

If i try go step back, and go back into the dll function, i can see that the array was created ok and still retains the information. 如果我尝试退后一步,然后再回到dll函数中,则可以看到该数组已创建成功,并且仍保留了该信息。

So the c# intptr in the struct, is not being set to the pointer being created in c++ (if that makes sense). 因此,未将结构中的c#intptr设置为在c ++中创建的指针(如果可以的话)。

So my question really is - how does one make this work correctly? 所以我的问题确实是-如何使这项工作正常进行?

I want to be able to get back from the dll, a structure which contains all the information that i need. 我希望能够从dll(一种包含所有我需要的信息)的结构中找回。 That is, in this example, the number of elements, and the pointer to the array. 也就是说,在此示例中,元素的数量以及指向数组的指针。 That way, i can then do a Marshal.Copy on the intptr, to get the array. 这样,我就可以在intptr上执行Marshal.Copy以获得数组。

If there's another way to do this, i'm more than happy to do it. 如果还有另一种方法可以做到,那么我将非常高兴。 I've tried several ways already, to no avail. 我已经尝试了几种方法,但没有成功。 This includes trying the following structure in c# (which contains the int array, rather than the intptr): 这包括尝试在c#中使用以下结构(该结构包含int数组,而不是intptr):

public struct TestStruct
{
   public int num;

   // i have tried various methods to marshal this- eg:
   // [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_I4]
   public int[] intArray;
}

And i've also tried passing the structure by reference itself, rather than an intptr. 而且我还尝试通过引用本身而不是intptr传递结构。 Any help on this matter would be massively appreciated. 在此问题上的任何帮助将不胜感激。 I am unable to change the c++ code, but the c# code can be changed. 我无法更改c ++代码,但是可以更改c#代码。

First of all change the C++ code to use only one level of indirection: 首先,将C ++代码更改为仅使用一个间接级别:

extern "C" __declspec(dllexport) void Dll_TestArray(TestStruct &testStruct)
{
     const int num = 15;
     testStruct.num = num;
     testStruct.intArray = new int[num];
     for (int i=0; i<num; i++)
         testStruct.intArray[i] = i+1;  
}

On the C# side you want this: 在C#方面,您需要这样做:

public struct TestStruct
{
    public int num;
    public IntPtr intArray;
}

[DllImport("testing.dll", CallingConvention=CallingConvention.Cdecl)]
static extern void Dll_TestArray(out TestStruct testStruct);

public GetArray()
{
    TestStruct testStruct;
    Dll_TestArray(out testStruct);
    int[] arr = new int[testStruct.num];
    Marshal.Copy(testStruct.intArray, arr, 0, arr.Length);
    // need to call back to DLL to ask it to deallocate testStruct.intArray
}

You'll also need to export a function that will deallocate the array you allocated using the C++ heap. 您还需要导出一个函数,该函数将取消分配使用C ++堆分配的数组。 Otherwise you'll leak it. 否则会泄漏它。

Perhaps an easier approach would be to change the design to have the caller allocating the buffer. 也许更简单的方法是更改​​设计,以使调用方分配缓冲区。

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

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