我应该在这里使用 ref 关键字吗?

Should I use the ref keyword here?

我是 C# 的新手,所以我查看了 this 问题,但我仍然不确定在整理使用 p/invoke:

的 GetWindoInfo() Win32 API 调用的第二个参数
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", EntryPoint = "GetWindowInfo", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool GetWindowInfo(IntPtr hwnd, [MarshalAs(UnmanagedType.Struct)] ref tagWINDOWINFO pwi);

来自 MSDN documentation for ref:

The ref keyword causes an argument to be passed by reference, not by value.

所以在那种情况下我上面的代码似乎是正确的,对吧?将编组子句更改为编组 UnmanagedType.LPStruct 并删除 ref 关键字会导致相同的结果吗?像这样:

[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", EntryPoint = "GetWindowInfo", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool GetWindowInfo(IntPtr hwnd, [MarshalAs(UnmanagedType.LPStruct)] tagWINDOWINFO pwi);

来自 MSDN documentation GetWindowInfo 函数:

BOOL WINAPI GetWindowInfo(
  _In_    HWND        hwnd,
  _Inout_ PWINDOWINFO pwi
);

编辑:

如答案评论中所述,第一个代码示例是正确的。第二个代码块不正确,因为通过指针传递和通过引用传递是不同的,反映了我的根本误解。我在考虑 C++ 取消引用。有关更多信息,请参阅 this 问题。

是的,您应该为结构使用 ref 关键字。

首先,您可以在 www.pinvoke.net 找到有关 P/Invoke 定义的非常好的资源 - 您正在处理的特定方法记录在此处:http://www.pinvoke.net/default.aspx/user32.getwindowinfo。您会看到它是使用 ref 关键字定义的。当您认为该方法在您链接的 MSDN 文档中针对该参数记录为 _Inout_ 时,这是有道理的。

原因是 ref 关键字将允许传递该引用并在调用方法 get updated/modified 之前拥有您正在处理的结构 - 而不是将其传入照原样,永远看不到该方法实际对它做了什么。换句话说,如果没有 ref 关键字,您的代码将永远不会看到在 GetWindowInfo 调用中对 struct 所做的更改 - GetWindowInfo 将使用其 "own" 该结构的副本。

如果您想详细了解为什么您的第二个版本不起作用,请查看 JaredPar 对 What is the difference between a C# Reference and a Pointer?

的精彩解释