从C#调用Windows API函数时,哪个要信任的签名来源:.NET Framework源代码或PinVoke?
-
29-09-2019 - |
题
例如,这是从.NET框架源文件 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
, , ETC。)我注意到在.NET框架源文件中,许多/大多数签名都有
ExactSpelling=true, CharSet=CharSet.Auto
, ,但在Pinvoke上没有。这需要吗?
解决方案
他们都会完成工作。只有一种不止一种方法可以剥皮猫。专门针对此示例:
ExactSpelling=true
是一种优化,它避免让Pinvoke Manshaller寻找GetWindowRectA
和GetWindowRectW
版本。它们不存在此特定API函数,因为它不使用字符串参数。看到运行时间的实际差异将是一个奇迹。CharSet=CharSet.Auto
始终是一个好主意,因为默认值(ANSI)如此效率低下。碰巧在这里没有任何区别,因为该函数没有任何字符串参数。[In, Out]
是不必要的,因为这是可杀灭类型的默认值。一个昂贵的词,这意味着Pinvoke Manshaller可以直接将指针传递给托管内存,无需转换。尽可能高效。与CharSet
不过,对其进行明确说明有助于创建自我记录的代码,并记住处理异常情况。只能使用[In]
或者[Out]
可以是一个重要的优化,只是在这里不在这里,因为它已经进行了优化。 fwiw,[out]将是正确的选择。out
vsref
, ,与上面相同的想法。使用out
更正确,因为API实际上没有使用任何传递的值RECT
. 。但是,在运行时没有任何区别,因为JIT编译器始终将结构初始化。[return: MarshalAs(UnmanagedType.Bool)]
是不必要的,这是窗口的默认信息BOOL
. 。不知道为什么pinvoke.net总是包含它。
因此,简而言之,两者都不是完美的,但它们俩都会起作用。这就是Pinvoke的危害。