我必须将非托管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);
答案 0 :(得分:5)
如果Version
是一个与extern Init
函数所期望的结构兼容的结构,那么两者之间没有显着差异,除了ref
版本将是 lot 更容易在C#中使用,因为运行时将为您管理所有的编组和固定。除非你真的想做所有这些工作,否则我会坚持使用ref
选项。
当然,如果没有看到C函数原型,C#中的Version
结构,以及C中用于该参数的结构,我真的只能猜测。
答案 1 :(得分:3)
编辑:基于一些批评迫使我重新思考并进一步研究。我自由地承认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);
我猜你会想要IntPtr版本。区别在于IntPtr是一个管理内存指针的类,而在参数列表中将参数声明为引用(ref关键字)意味着您通过引用传递。通常,当通过P / Invoke调用向非托管dll传递数据时,除非传递的数据是vanilla类型(int,double,string - 具有适当的Marshal装饰),否则我将数据作为IntPtr传递。然后,您可以将IntPtr编组为非托管结构的托管声明。 击>
您应该查看此链接以获取有关P / Invoke呼叫的更多信息: http://msdn.microsoft.com/en-us/magazine/cc164123.aspx
答案 2 :(得分:2)
IntPtr将允许您将所有Externs移动到一个类,而不依赖于调用中使用的结构,这可能在其他地方定义。我喜欢将api适配器与数据结构/类defs保持分离,这似乎更自然地放在下一层。
答案 3 :(得分:-1)
最好使用IntPtr
,因为在将代码编译为x64时,它会使代码更加灵活。 IntPtr
会自动扩展其大小。
IntPtr = 4 bytes on x86
IntPtr = 8 bytes on x64
有些情况下,当为x64编译C中的某些类型时,它们的大小会加倍,但C#对应物(为PInvoke声明)则不会。然后函数调用将失败。如果Version
类包含类似的字段,那么最好使用IntPtr
。