将包含未知大小的 int 数组的结构从 c# 传递到 c 并返回 [英] Passing a struct containing an int array of unknown size from c# to c and back

查看:70
本文介绍了将包含未知大小的 int 数组的结构从 c# 传递到 c 并返回的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始为这个问题而苦恼.我已经搜索并寻求帮助,但我尝试过的一切似乎都不起作用.我显然做错了什么.

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.

无论如何 - 我有一个 c# 结构定义为:

Anyway - i have a c# structure defined as:

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

在我的 c# 代码的主体中,我有:

and in the main body of my c# code i have:

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));
   }
}

现在是 C++ 部分.从结构开始:

So now for the c++ part. Starting with the structure:

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

现在的功能:

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;  
}

所以 - 我遇到的问题是,当我将结构放回 C# 时,我的结构不是它应该的样子.我可以看到 num 字段已正确填写:它显示 15.但是,IntPtr 仍然设置为零.在c++中创建的数组并没有贯彻到c#中.

So - the problem i'm having, is that when i get the structure back into c#, my structure is not how it should be. 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. The array creation done in c++ has not been carried through to c#.

如果我尝试退后一步,并返回到 dll 函数,我可以看到数组创建正常并且仍然​​保留信息.

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.

因此,结构中的 c# intptr 没有被设置为在 c++ 中创建的指针(如果有意义的话).

So the c# intptr in the struct, is not being set to the pointer being created in c++ (if that makes sense).

所以我的问题真的是 - 如何使它正常工作?

So my question really is - how does one make this work correctly?

我希望能够从 dll 中取回,这是一个包含我需要的所有信息的结构.也就是说,在这个例子中,元素的数量,以及指向数组的指针.这样,我就可以在 intptr 上执行 Marshal.Copy 以获取数组.

I want to be able to get back from the dll, a structure which contains all the information that i need. 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.

如果有其他方法可以做到这一点,我很乐意这样做.我已经尝试了多种方法,都无济于事.这包括在 c# 中尝试以下结构(其中包含 int 数组,而不是 intptr):

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):

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;
}

而且我还尝试通过引用本身而不是 intptr 传递结构.对此事的任何帮助将不胜感激.我无法更改 c++ 代码,但可以更改 c# 代码.

And i've also tried passing the structure by reference itself, rather than an 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++ 代码更改为仅使用一级间接:

First of all change the C++ code to use only one level of indirection:

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;  
}

在 C# 方面,您需要:

On the C# side you want this:

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
}

您还需要导出一个函数,该函数将释放您使用 C++ 堆分配的数组.否则你会泄露的.

You'll also need to export a function that will deallocate the array you allocated using the C++ heap. Otherwise you'll leak it.

也许更简单的方法是更改​​设计,让调用方分配缓冲区.

Perhaps an easier approach would be to change the design to have the caller allocating the buffer.

这篇关于将包含未知大小的 int 数组的结构从 c# 传递到 c 并返回的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆