例如,这来自.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上却没有。这是必需的吗?
  • 最佳答案

    他们俩都会把工作做好。剥皮猫是不只一种方法。专门针对此示例:

  • ExactSpelling=true是一种优化,它避免了pinvoke编码查找GetWindowRectAGetWindowRectW版本。对于此特定的API函数,它们不存在,因为它不需要字符串参数。看到运行时间的实际差异将是一个奇迹。
  • CharSet=CharSet.Auto始终是一个好主意,因为默认设置(Ansi)效率很低。由于该函数不接受任何字符串参数,因此恰好在这里没有任何区别。
  • [In, Out]是不必要的,因为这是可蓝变类型的默认设置。一个昂贵的词,意味着pinvoke编码器可以直接将指针传递到托管内存,而无需进行转换。尽可能高效。但是,与CharSet相同,但要明确,有助于创建自说明代码并记住处理异常情况。只能使用[In][Out]可能是一项重大的优化,但由于已进行了优化,因此不能在此处使用。首先,[Out]将是正确的选择。
  • outref,与上述相同。使用out更为正确,因为API实际上并未在RECT内部使用任何传入的值。但是,由于JIT编译器始终会始终初始化结构,因此它在运行时没有任何区别。
  • [return: MarshalAs(UnmanagedType.Bool)]是不必要的,它是Windows BOOL的默认编码(marshal)处理。不知道为什么pinvoke.net总是包含它。

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

    关于c# - 从C#调用Windows API函数时,哪个签名来源可以信任: . NET Framework源代码或PInvoke?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4305010/

    10-11 15:06