从 C# 调用 Windows API 函数时,应信任哪个签名源:.NET Framework 源代码还是 PInvoke?

发布于 2024-10-04 23:41:43 字数 732 浏览 6 评论 0原文

例如,这是来自 .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(UnmanagementType.Bool)][In, Out] ref 等)

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

For example, this is from .NET Framework source file UnsafeNativeMethods.cs:

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

and this is from PInvoke.Net:

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(HandleRef hwnd, out RECT lpRect);
  1. Which is the correct/best signature for this function? (only one of them has [return: MarshalAs(UnmanagedType.Bool)], or [In, Out] ref, etc.)

  2. I've noticed that in .NET Framework source files many/most signatures have ExactSpelling=true, CharSet=CharSet.Auto, but on PInvoke they don't. Is this required?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

醉态萌生 2024-10-11 23:41:43

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

  • ExactSpelling=true 是一项优化,它避免 pinvoke 编组器查找 GetWindowRectAGetWindowRectW 版本。对于这个特定的 API 函数来说,它们不存在,因为它不接受字符串参数。看到运行时的实际差异将是一个奇迹。

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

  • [In, Out] 是不必要的,因为这是 blittable 类型的默认值。这是一个昂贵的词,意味着 pinvoke 编组器可以直接传递指向托管内存的指针,不需要转换。尽可能高效。不过,与 CharSet 的想法相同,明确它有助于创建自记录代码并记住处理异常情况。只能使用 [In][Out] 可能是一项重大优化,但这里不适用,因为它已经优化了。 Fwiw,[Out] 是正确的选择。

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

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

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

They will both get the job done. There's just more than one way to skin a pinvoke cat. Specifically for this example:

  • ExactSpelling=true is an optimization, it avoids having the pinvoke marshaller looking for the GetWindowRectA and GetWindowRectW versions. They don't exist for this particular API function since it doesn't take a string argument. Seeing an actual difference in run time would be a miracle.

  • CharSet=CharSet.Auto is always a good idea since the default (Ansi) is so inefficient. It just so happens to not make any difference here since the function doesn't take any string arguments.

  • [In, Out] is unnecessary because that's the default for a blittable type. An expensive word that means that the pinvoke marshaller can directly pass a pointer to the managed memory, no conversion is required. As efficient as possible. Same idea as CharSet though, being explicit about it helps to create self-documenting code and to remember to deal with the unusual case. Being able to only use [In] or [Out] can be a significant optimization, just not here since it is already optimized. Fwiw, [Out] would have been the correct choice.

  • out vs ref, same idea as above. Using out is more correct since the API doesn't actually use any passed-in values inside the RECT. It doesn't however make any difference at runtime since the JIT compiler always initializes a struct anyway.

  • [return: MarshalAs(UnmanagedType.Bool)] is unnecessary, it is the default marshaling for a Windows BOOL. Not sure why pinvoke.net always includes it.

So in a nutshell, neither is perfect but they both will work. Such are the hazards of pinvoke.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文