6

例如,这是来自 .NET Framework 源文件UnsafeNativeMethods.cs

[DllImport(ExternDll.User32, ExactSpelling=true, CharSet=CharSet.Auto)] 
public static extern bool GetWindowRect(HandleRef hWnd, 
    [In, Out] ref NativeMethods.RECT rect);

这是来自 PInvoke.Net:

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(HandleRef hwnd, out RECT lpRect);
  1. 此功能的正确/最佳签名是哪个?(其中只有一个有[return: MarshalAs(UnmanagedType.Bool)]、 或[In, Out] ref等)

  2. 我注意到在 .NET Framework 源文件中,许多/大多数签名都有ExactSpelling=true, CharSet=CharSet.Auto,但在 PInvoke 上却没有。这是必需的吗?

4

1 回答 1

20

他们都会完成工作。剥皮猫的方法不止一种。专门针对此示例:

  • ExactSpelling=true是一种优化,它避免了 pinvoke marshaller 寻找GetWindowRectAandGetWindowRectW版本。对于这个特定的 API 函数,它们不存在,因为它不接受字符串参数。看到运行时间的实际差异将是一个奇迹。

  • CharSet=CharSet.Auto总是一个好主意,因为默认(Ansi)效率很低。碰巧在这里没有任何区别,因为该函数不接受任何字符串参数。

  • [In, Out] 是不必要的,因为这是 blittable 类型的默认设置。一个昂贵的词,意味着 pinvoke marshaller 可以直接将指针传递给托管内存,不需要转换。尽可能高效。同样的想法CharSet,明确说明它有助于创建自记录代码并记住处理不寻常的情况。只能使用[In][Out]可以是一个重要的优化,只是不在这里,因为它已经被优化了。Fwiw,[Out] 将是正确的选择。

  • outvs ref,与上述相同的想法。使用out更正确,因为 API 实际上并没有使用RECT. 然而,它在运行时没有任何区别,因为 JIT 编译器总是初始化一个结构。

  • [return: MarshalAs(UnmanagedType.Bool)]是不必要的,它是 Windows 的默认封送处理BOOL。不知道为什么 pinvoke.net 总是包含它。

所以简而言之,两者都不是完美的,但它们都会起作用。这就是 pinvoke 的危害。

于 2010-11-29T16:03:58.113 回答