【问题标题】:Should I use the ref keyword here?我应该在这里使用 ref 关键字吗?
【发布时间】:2017-03-11 23:40:54
【问题描述】:

我是 C# 新手,所以我查看了 this 问题,但我仍然不确定在编组 GetWindoInfo() 的第二个参数时是否应该在此处包含 ref 关键字使用 p/invoke 调用 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

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
);

编辑:

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

【问题讨论】:

  • 我阅读了您问题的第一部分“我是 C# 的新手...”并查看了您的示例代码,然后我想,“也许 Windows API 不是最好的起点”。然后我看到你有使用 C++ 的经验,并意识到你对编程并不陌生,只是 C#。继续。

标签: c# pinvoke marshalling ref


【解决方案1】:

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

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

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

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

【讨论】:

  • 嘿,感谢您对我的第一个 SO 问题的第一个回答!是的,我知道 pinvoke.net,并且我已经在 VS2015 中使用了他们的扩展。那么当你说是时,你的意思是我的代码是正确的,还是说第二种实现方式也可以?
  • 抱歉,经过编辑澄清 - 是的,您应该使用 ref
  • 为了澄清一下,在我的第二个代码示例中,我更改了编组,以便编组一个非托管结构并因此需要使用 ref 关键字,我只是编组了一个非托管结构指针。我要问的两个代码示例本质上是一样的吗?
  • 传递指针和通过引用传递是不同的 - 所以不,那是行不通的
  • 我添加了一个指向另一个问题的链接,该问题更深入地解释了通过 ref 传递或使用指针之间的区别
猜你喜欢
  • 2011-02-03
  • 2014-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多