[英]P/Invoke with arrays of double - marshalling data between C# and C++
我已經在這里和這里閱讀了C ++ Interop與P / Invoke的各種MSDN頁面,但我仍然感到困惑。
我有一些大型的雙打數組,我需要進入本機代碼,以及一些需要返回的結果數組。 我事先並不知道輸出數組的大小。 為簡單起見,我將在示例中僅使用單個數組。 該平台是x64; 我讀到在32位和64位環境之間編組內部是完全不同的,所以這可能很重要。
C#
[DllImport("NativeLib.dll")]
public static extern void ComputeSomething(double[] inputs, int inlen,
[Out] out IntPtr outputs, [Out] out int outlen);
[DllImport("NativeLib.dll")]
public static extern void FreeArray(IntPtr outputs);
public void Compute(double[] inputs, out double[] outputs)
{
IntPtr output_ptr;
int outlen;
ComputeSomething(inputs, inputs.Length, out output_ptr, out outlen);
outputs = new double[outlen];
Marshal.Copy(output_ptr, outputs, 0, outlen);
FreeArray(output_ptr);
}
C ++
extern "C"
{
void ComputeSomething(double* inputs, int input_length,
double** outputs, int* output_length)
{
//...
*output_length = ...;
*outputs = new double[output_length];
//...
}
void FreeArray(double* outputs)
{
delete[] outputs;
}
}
它有效,也就是說,我可以讀出我在C ++端寫入數組的雙打。 不過,我想知道:
請注意,我們有一個有效的C ++ / Cli版本,但是在第三方庫代碼中存在與導致崩潰的本地靜態有關的一些問題。 微軟將此問題標記為WONTFIX ,這就是我尋找替代品的原因。
沒關系。 完全沒有返回錯誤代碼的方法非常糟糕,當數組很大並且程序內存耗盡時會受到傷害。 你得到的嚴重崩潰是非常不可知的。
復制數組並明確釋放它們的需要當然不會贏得任何獎項。 您可以通過讓調用者將指針傳遞給自己的數組來解決這個問題,然后編寫元素。 但是,您需要一個協議讓調用者確定數組需要多大的數量,這需要調用該方法兩次。 第一個調用返回所需的大小,第二個調用完成工作。
樣板示例如下:
[DllImport("foo.dll")]
private static int ReturnData(double[] data, ref int dataLength);
以及樣本用法:
int len = 0;
double[] data = null;
int err = ReturnData(data, ref len);
if (err == ERROR_MORE_DATA) { // NOTE: expected
data = new double[len];
err = ReturnData(data, len);
}
無需復制,無需釋放內存,好事。 如果本地代碼沒有注意傳遞的len ,那么本機代碼可能會損壞GC堆,這不是一件好事。 但當然容易避免。
如果將確定輸出長度的代碼與填充輸出的代碼分開是可行的,那么您可以:
但我假設你拒絕了這個選項,因為它是不切實際的。 在這種情況下,您的代碼是解決問題的完美合理方式。 事實上,我會說你做得很好。
修復調用約定不匹配后,代碼在x86中的工作方式相同。 在C ++方面,調用約定是cdecl
,但在C#方面它是stdcall
。 這與x64無關,因為只有一個調用約定。 但是在x86下這將是一個問題。
一些評論:
[Out]
以及out
。 后者意味着前者。 CoTaskMemAlloc
,然后在C#端釋放Mashal.FreeCoTaskMem
。 如果您事先知道數組大小,則可以編寫一個C ++ / CLI DLL,它將托管數組作為參數,將其固定,並在它獲得的固定指針上調用本機C ++ DLL。
但如果只是輸出,我沒有看到沒有副本的任何版本。 您可以使用SAFEARRAY,因此P / Invoke會復制而不是您,但這就是全部。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.