我必须将非托管的dll导入我的C#应用程序,我想知道IntPtr和ref之间有什么不同,你建议我使用什么,为什么?请注意,这两种方式对我都有用.例如:
[DllImport("mydll.dll", CallingConvention=CallingConvention.Cdecl)]
static extern Result Init(IntPtr versionInfo);
[DllImport("mydll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern Result Init(ref Version versionInfo);
Run Code Online (Sandbox Code Playgroud)
如果Version是一个结构是与该EXTERN的结构兼容的Init功能期待,在这两个之间没有显著差异,只是ref版本将是一个很多更容易从C#使用以来,运行时将管理所有的编组和牵制了您.除非你真的想做所有这些工作,否则我会坚持ref选择.
当然,如果没有看到C函数原型,VersionC#中的结构,以及C中用于该参数的结构,我真的只能猜测.
编辑:基于一些批评迫使我重新思考这一点并进一步研究。我坦率地承认 IntPtr 很容易出错,我认为对于“更难”的含义可能存在一些争论,但是如果框架可以自动编组它并让您不必固定东西等,如果您不使用 IntPtr 那么我认为我同意 IntPtr 会“更难。在我看来,经过进一步的研究,我认为声明你的结构会更容易(当你被迫 P/Invoke 并且无法制作 C++/CLI 包装器时)(在您的情况下版本)在托管代码中,然后通过 ref 参数传递它。
[StructLayout(LayoutKind.Sequential)]
struct Version
{
// Data members
}
[DllImport("mydll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern Result Init(ref Version versionInfo);
Run Code Online (Sandbox Code Playgroud)
我的猜测是你会想要 IntPtr 版本。区别在于 IntPtr 是一个管理指向内存的指针的类,而在参数列表中将参数声明为引用(ref 关键字)意味着您正在通过引用传递。通常,当通过 P/Invoke 调用向非托管 dll 传递数据或从非托管 dll 传递数据时,除非传递的数据是普通类型(int、double、string - 具有适当的 Marshal 装饰),否则我将数据作为 IntPtr 传递。然后,您可以将 IntPtr 编组到非托管结构的托管声明中。
您应该查看此链接以获取有关 P/Invoke 调用的更多信息: http://msdn.microsoft.com/en-us/magazine/cc164123.aspx