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

Ale*_*ang 6 c# pinvoke winapi interop signatures

例如,这是来自.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);
Run Code Online (Sandbox Code Playgroud)

这来自PInvoke.Net:

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

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

Han*_*ant 20

他们都会完成工作.只有不止一种方法来修饰一只pinvoke猫.特别针对此示例:

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

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

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

  • outvs ref,与上面相同的想法.使用out更正确,因为API实际上并未使用任何传入的值RECT.但是它在运行时没有任何区别,因为JIT编译器总是初始化一个struct.

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

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