例如,这是来自 .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);
哪个是此函数的正确/最佳签名? (其中只有一个有
[return: MarshalAs(UnmanagedType.Bool)]
,或者[In, Out] ref
等)我注意到在 .NET Framework 源文件中,许多/大多数签名都有
ExactSpelling=true, CharSet=CharSet.Auto
,但在 PInvoke 上却没有。这是必需的吗?
最佳答案
他们都会完成工作。给 pinvoke 猫剥皮的方法不止一种。专门针对这个例子:
ExactSpelling=true
是一种优化,它避免了让 pinvoke 编码器寻找GetWindowRectA
和GetWindowRectW
版本。对于这个特定的 API 函数,它们不存在,因为它不接受字符串参数。看到运行时间的实际差异将是一个奇迹。CharSet=CharSet.Auto
始终是一个好主意,因为默认 (Ansi) 非常低效。它恰好在这里没有任何区别,因为该函数不接受任何字符串参数。[In, Out]
是不必要的,因为这是 blittable 类型的默认值。一个昂贵的词,意思是 pinvoke 编码器可以直接将指针传递给托管内存,不需要转换。尽可能高效。尽管与CharSet
的想法相同,明确说明它有助于创建 self 记录的代码并记住处理异常情况。能够只使用[In]
或[Out]
可以是一个重要的优化,只是不在这里,因为它已经被优化了。 Fwiw,[Out] 会是正确的选择。out
vsref
,思路同上。使用out
更为正确,因为 API 实际上并不使用RECT
中的任何传入值。然而,它在运行时没有任何区别,因为 JIT 编译器无论如何总是初始化一个结构。[return: MarshalAs(UnmanagedType.Bool)]
是不必要的,它是 WindowsBOOL
的默认编码(marshal)处理。不确定为什么 pinvoke.net 总是包含它。
所以简而言之,两者都不是完美的,但它们都可以工作。这就是 pinvoke 的危害。
关于c# - 从 C# 调用 Windows API 函数时,签名的哪个来源信任 : . NET Framework 源代码或 PInvoke?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4305010/