我有一些大型的双打数组,我需要进入本机代码,以及一些需要返回的结果数组.我事先并不知道输出数组的大小.为简单起见,我将在示例中仅使用单个数组.该平台是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.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。