我已经阅读了使用P / Invoke
here和
here的C Interop上的各种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,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侧写入数组的双打.不过,我想知道:
>这真的是使用P / Invoke的正确方法吗?
>我的签名不是很复杂吗?
>可以更有效地使用P / Invoke来解决这个问题吗?
>我相信我读过可以避免对内置类型的单维数组进行编组. Marshal.Copy有办法吗?
请注意,我们有一个可用的C/C++li版本,但是在第三方库代码中存在与导致崩溃的本地静态相关的一些问题. Microsoft marked this issue as WONTFIX,这就是为什么我在寻找替代品.
解决方法
如果将确定输出长度的代码与填充输出的代码分开是可行的,那么您可以:
>导出返回输出长度的函数.
>从C#代码中调用它,然后分配输出缓冲区.
>再次调用非托管代码,这次要求它填充输出缓冲区.
但我假设你拒绝了这个选项,因为它是不切实际的.在这种情况下,您的代码是解决问题的完美合理方式.事实上,我会说你做得很好.
修复调用约定不匹配后,代码在x86中的工作方式相同.在C方面,调用约定是cdecl,但在C#方面它是stdcall.这与x64无关,因为只有一个调用约定.但是在x86下这将是一个问题.
一些评论:
>您不需要使用[Out]和out.后者意味着前者.>您可以通过分配共享堆来避免导出deallocator.例如,C端的CoTaskMemAlloc,然后在C#端释放Mashal.FreeCoTaskMem.