PInvoke - 如何编组'SomeType * []'?
Posted
技术标签:
【中文标题】PInvoke - 如何编组\'SomeType * []\'?【英文标题】:PInvoke - How to marshal for 'SomeType* []'?PInvoke - 如何编组'SomeType * []'? 【发布时间】:2012-01-05 11:40:23 【问题描述】:我有一个本机库,其中包含一些本机 ntype
,并希望在其中 p/调用一些函数。
我能够编组:
foo1(ntype** p) ==> foo1(IntPtr[] p)
但不知道该怎么做:
foo1(ntype*[] p) ==> foo1(<???> p)
至少IntPtr[]
不起作用。
编辑
我试图编组的非托管函数是:
extern mxArray* mclCreateSimpleFunctionHandle(mxFunctionPtr fcn);
mxFunctionPtr
在哪里:
typedef void(*mxFunctionPtr)(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]);
这表示对以下 matlab 函数签名的调用:
function [varargout] = callback(varargins)
%[
%% Do callback code %%
%]
显然,按照我的预期,这个函数指针应该为我提供 2 个mxArray*
列表:
目前从我所做的测试来看,它只返回plhs
和prhs
列表中的第一个mxArray*
【问题讨论】:
接受指针和数组的 C 函数是完全模棱两可的。 ntype** 和 ntype*[] 之间没有区别,除非您在代码中以某种方式赋予它不同的语义。 【参考方案1】:首先要做的是将您的原生ntype
转换为托管struct
。
例如:
public struct Ntype
public int Field1;
public long Field2;
然后,您在 C# 代码中使用简单的 IntPtr
参数定义您的方法。
[DllImport]
static void foo1(IntPtr myParam);
最后是你如何使用它:
IntPtr buffer = IntPtr.Zero;
try
// Allocates a buffer. The size must be known
buffer = Marshal.AllocHGlobal(0x1000);
// Call to your unmanaged method that fills the buffer
foo1(buffer);
// Casting the unmanaged memory to managed structure that represents
// your data
Ntype obj = (Ntype)Marshal.PtrToStructure(buffer, typeof(Ntype));
finally
// Free unmanaged memory
if (buffer != IntPtr.Zero)
Marshal.FreeHGlobal(buffer);
【讨论】:
感谢@ken2k 和@Ramhound 的帮助。我想我真的不需要这个结构,只有一个指向它的指针对我来说就可以了。事实上,我正在尝试解决调用mclCreateSimpleFunctionHandle
的问题,如link 中所述。显然,这个函数只返回一个指向第一个 mxArray*
的指针,我正在尝试获取 mxArray*
的完整列表(我对 mxArray
本身不感兴趣)......至少对于读者来说这另一个帖子,我想我正在修复它的路上。【参考方案2】:
知道了
“SomeTime* []
”的正确编组:
extern mxArray* mclCreateSimpleFunctionHandle(mxFunctionPtr fcn);
typedef void(*mxFunctionPtr)(int nlhs, mxArray* plhs[], int nrhs, mxArray* prhs[]);
是:
// For function pointer
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public delegate void MCRInteropDelegate(int nlhs,
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.SysInt, SizeParamIndex = 0)][Out] IntPtr[] plhs,
int nrhs,
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.SysInt, SizeParamIndex = 2)][In] IntPtr[] prhs);
// For API function
[DllImport(DLLNAME, EntryPoint = "mclCreateSimpleFunctionHandle", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
private static extern IntPtr _mclCreateSimpleFunctionHandle(MCRInteropDelegate fctn);
说明
MarshalAs
属性指示将SomeTime*[]
编组为LPArray
的LPArray
,其中数组的大小包含在从零开始的索引SizeParamIndex
处的函数参数中
【讨论】:
以上是关于PInvoke - 如何编组'SomeType * []'?的主要内容,如果未能解决你的问题,请参考以下文章
在 c# 和 c++ 之间将 double 类型的二维多维数组作为输入和输出的 pinvoke 编组