使用数组的非托管导出

我正在使用RGiesecke DLLExport库生成一个可以从Delphi动态加载的C#DLL。 我有一个方法,如:

[DllExport("GetVals", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)] static void GetVals([In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] int[] valueList, int len) { valueList = new int[3]; int[] arrList = new int[] { 1, 2, 3 }; int idx = 0; foreach (int s in arrList) { valueList[idx] = s; idx++; } } 

我希望能够从这个调用中返回一个数组,问题是我不会事先知道数组的大小,这只会在RunTime中确定。

测试我做了以下(也在C#中)

 IntPtr hLibrary = NativeWinAPI.LoadLibrary(DLLFileName); IntPtr pointerToFunction1 = NativeWinAPI.GetProcAddress(hLibrary, "GetVals"); if (pointerToFunction1 != IntPtr.Zero) { GetVals getfunction = (GetVals)Marshal.GetDelegateForFunctionPointer(pointerToFunction, typeof(GetVals)); int[] valList= null; int fCnt = 3; getfunction(valList, fCnt); if (valList != null) { } } 

得到错误“尝试读取或写入受保护的内存”这是可以理解的,因为我没有在调用者上分配内存。 在实际使用中我不知道要返回的数组的大小,因此无法预先分配内存。 把东西放在那里最基本的我试图简单地从GetVals返回一个未知大小的数组。

您必须以不受GC影响的方式分配arrays。 你用Marshal.AllocHGlobal做到了:

 [DllExport] static void GetVals(out IntPtr unmanagedArray, out int length) { var valueList = new[] { 1, 2, 3 }; length = valueList.Length; unmanagedArray = Marshal.AllocHGlobal(valueList.Length * Marshal.SizeOf(typeof(int))); Marshal.Copy(valueList, 0, unmanagedArray, length); } 

在Delphi端,您将获得指向第一个元素和大小的指针。 要读取它,您可以将指针arraySize-1递增并将其放入列表或Delphi管理的数组中:

 uses SysUtils, Windows; procedure GetVals(out unmanagedArray : PInteger; out arraySize : Integer); stdcall; external 'YourCSharpLib'; function GetValsAsArray : TArray; var unmanagedArray, currentLocation : PInteger; arraySize, index : Integer; begin GetVals(unmanagedArray, arraySize); try SetLength(result, arraySize); if arraySize = 0 then exit; currentLocation := unmanagedArray; for index := 0 to arraySize - 1 do begin result[index] := currentLocation^; inc(currentLocation); end; finally LocalFree(Cardinal(unmanagedArray)); end; end; var valuesFromCSharp : TArray; index : Integer; begin valuesFromCSharp := GetValsAsArray(); for index := low(valuesFromCSharp) to high(valuesFromCSharp) do Writeln(valuesFromCSharp[index]); end.