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

时间:2017-03-11 23:40:54

标签: c# pinvoke marshalling ref

我是C#的新手,所以我查看了this问题,但我仍然不确定在编组第二个问题时是否应该包含 ref 关键字使用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获取参考

  

ref关键字导致参数通过引用传递,而不是通过引用传递   值。

所以在这种情况下我的代码似乎是正确的,对吧?是否会更改编组子句而不是封送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问题。

1 个答案:

答案 0 :(得分:1)

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

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

这样做的原因是ref关键字将允许传递该引用并在调用方法获取更新/修改之前使用您正在处理的结构 - 而不是按原样传递它而从不传递看看方法实际上对它做了什么。换句话说,如果没有ref关键字,您的代码将永远不会看到struct调用中GetWindowInfo所做的更改 - GetWindowInfo将使用其“自己的”副本那种结构。

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

的重要解释