接收pinvoke结构的垃圾值

时间:2017-05-09 11:31:18

标签: c# .net pinvoke

我正在尝试通过PINVOKE

将结构从c#发送到c ++ dll

这是我的代码

C ++函数

struct sampleStruct
{
int* intP;
char** charP;
};

TESTDLL_API int testStructCall(int *iPtr,char **cPtr,sampleStruct* st)
{ return 42;}

C#调用

[StructLayout(LayoutKind.Sequential)]
struct sampleStruct
{
   public int[] intArr; 
   public string[] strArr;}

[DllImport("testDll.dll", CallingConvention = CallingConvention.Cdecl,   CharSet = CharSet.Ansi)]
    static private extern int testStructCall( int[] intArr, string[] strArr, ref sampleStruct st);


        string[] strArr = { "string 1", "string 2" };
        int[] intArr = { 10, 20, 30, 40 };

        sampleStruct struc = new sampleStruct();
        struc.intArr = intArr;
        struc.strArr = strArr;
        testStructCall( intArr,  strArr, ref struc);

这里用C ++,我可以正确接收前两个参数,但结构成员显示垃圾值。我在这里失踪了什么?

1 个答案:

答案 0 :(得分:1)

结构中的数组无法编组为UnmanagedType.LPArray,这是这些成员访问非托管代码所需的内容。

正如您可能知道的那样,当数组作为函数的参数出现时,它们会被正确编组。如果必须在结构中传递这些数组,则需要在C#结构声明中将成员声明为IntPtr,并手动编写编组代码。这对于整数数组来说并不是很困难,它只是固定数组的一种情况。对于字符串数组,那么还有更多工作要做。您需要一个IntPtr数组,然后使用Marshal.StringToCoTaskMemAnsi调用填充。

它看起来像这样:

var intHandle = GCHandle.Alloc(intArr, GCHandleType.Pinned);
struc.intArr = intHandle.AddrOfPinnedObject();

var strPtrArr = new IntPtr[strArr.Length];
for (int i = 0; i < strPtrArr.Length; i++)
    strPtrArr[i] = Marshal.StringToCoTaskMemAnsi(strArr[i]);
var strHandle = GCHandle.Alloc(strPtrArr, GCHandleType.Pinned);
struc.strArr = strHandle.AddrOfPinnedObject();

testStructCall(intArr, strArr, ref struc);

intHandle.Free();
strHandle.Free();
for (int i = 0; i < strPtrArr.Length; i++)
    Marshal.FreeCoTaskMem(strPtrArr[i]);