将包含未知大小的 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.
无论如何 - 我有一个 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屋!