I'm searching for the correct syntax to pass a struct array to an unmanaged C++ dll.
我正在寻找将struct数组传递给非托管C ++ dll的正确语法。
my dll imports are called like this
我的dll导入就像这样调用
#define _DllImport [DllImport("Controller.dll", CallingConvention = CallingConvention::Cdecl)] static
_DllImport bool _Validation(/* array of struct somehow */);
In my client code I have
在我的客户端代码中
List<MyStruct^> list;
MyObject::_Validation(/* list*/);
I know System::Runtime::InteropServices::Marshal has a lot of useful methods for doing stuff like this but I'm not sure about which to use.
我知道System :: Runtime :: InteropServices :: Marshal有很多有用的方法来做这样的事情,但我不确定使用哪个。
2 个解决方案
#1
Create a managed version of the unmanaged struct using StructLayout.Sequential (make sure to put things in the same order). You should then be able to pass it like you'd pass it to any managed function (e.g., Validation(MyStruct[] pStructs).
使用StructLayout.Sequential创建非托管结构的托管版本(确保以相同的顺序放置内容)。然后,您应该能够将其传递给任何托管函数(例如,验证(MyStruct [] pStructs)。
For example, let's say our native function has this prototype:
例如,假设我们的原生函数有这个原型:
extern "C" {
STRUCTINTEROPTEST_API int fnStructInteropTest(MYSTRUCT *pStructs, int nItems);
}
and the native MYSTRUCT is defined as follows:
并且本机MYSTRUCT定义如下:
struct MYSTRUCT
{
int a;
int b;
char c;
};
Then in C#, you define a managed version of the struct as follows:
然后在C#中,您定义结构的托管版本,如下所示:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct MYSTRUCT
{
public int a;
public int b;
public byte c;
}
And the managed prototype as follows:
托管原型如下:
[System.Runtime.InteropServices.DllImportAttribute("StructInteropTest.dll", EntryPoint = "fnStructInteropTest")]
public static extern int fnStructInteropTest(MYSTRUCT[] pStructs, int nItems);
You can then call the function passing it an array of MYSTRUCT structs as follows:
然后,您可以调用函数传递一个MYSTRUCT结构数组,如下所示:
static void Main(string[] args)
{
MYSTRUCT[] structs = new MYSTRUCT[5];
for (int i = 0; i < structs.Length; i++)
{
structs[i].a = i;
structs[i].b = i + structs.Length;
structs[i].c = (byte)(60 + i);
}
NativeMethods.fnStructInteropTest(structs, structs.Length);
Console.ReadLine();
}
#2
You can use Marshall.StructureToPtr to get an IntPtr which could be passed into a native MyStruct* array.
您可以使用Marshall.StructureToPtr获取可以传递到本机MyStruct *数组的IntPtr。
However, I'm not sure how to do this from a List directly. I believe you need to convert this to an array and use a pin_ptr (to prevent the GC from moving your memory) prior to passing it to the native code.
但是,我不确定如何直接从List执行此操作。我相信你需要将它转换为数组并使用pin_ptr(以防止GC移动你的内存),然后再将它传递给本机代码。
#1
Create a managed version of the unmanaged struct using StructLayout.Sequential (make sure to put things in the same order). You should then be able to pass it like you'd pass it to any managed function (e.g., Validation(MyStruct[] pStructs).
使用StructLayout.Sequential创建非托管结构的托管版本(确保以相同的顺序放置内容)。然后,您应该能够将其传递给任何托管函数(例如,验证(MyStruct [] pStructs)。
For example, let's say our native function has this prototype:
例如,假设我们的原生函数有这个原型:
extern "C" {
STRUCTINTEROPTEST_API int fnStructInteropTest(MYSTRUCT *pStructs, int nItems);
}
and the native MYSTRUCT is defined as follows:
并且本机MYSTRUCT定义如下:
struct MYSTRUCT
{
int a;
int b;
char c;
};
Then in C#, you define a managed version of the struct as follows:
然后在C#中,您定义结构的托管版本,如下所示:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct MYSTRUCT
{
public int a;
public int b;
public byte c;
}
And the managed prototype as follows:
托管原型如下:
[System.Runtime.InteropServices.DllImportAttribute("StructInteropTest.dll", EntryPoint = "fnStructInteropTest")]
public static extern int fnStructInteropTest(MYSTRUCT[] pStructs, int nItems);
You can then call the function passing it an array of MYSTRUCT structs as follows:
然后,您可以调用函数传递一个MYSTRUCT结构数组,如下所示:
static void Main(string[] args)
{
MYSTRUCT[] structs = new MYSTRUCT[5];
for (int i = 0; i < structs.Length; i++)
{
structs[i].a = i;
structs[i].b = i + structs.Length;
structs[i].c = (byte)(60 + i);
}
NativeMethods.fnStructInteropTest(structs, structs.Length);
Console.ReadLine();
}
#2
You can use Marshall.StructureToPtr to get an IntPtr which could be passed into a native MyStruct* array.
您可以使用Marshall.StructureToPtr获取可以传递到本机MyStruct *数组的IntPtr。
However, I'm not sure how to do this from a List directly. I believe you need to convert this to an array and use a pin_ptr (to prevent the GC from moving your memory) prior to passing it to the native code.
但是,我不确定如何直接从List执行此操作。我相信你需要将它转换为数组并使用pin_ptr(以防止GC移动你的内存),然后再将它传递给本机代码。