Search code examples
c#pinvokemarshallingref

Should I use the ref keyword here?


I'm new to C# so I looked at this question but I'm still not sure whether I should be including the ref keyword here when marshalling the second parameter of the GetWindoInfo() Win32 API call using p/invoke:

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

From the MSDN documentation for ref:

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

So in that case my code above seems to be correct, right? Would changing the marshalling clause to instead marshal an UnmanagedType.LPStruct and removing the ref keyword result in the same thing? Like so:

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

From the MSDN documentation for GetWindowInfo function:

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

EDIT:

As mentioned in the comments to the answer, the first code example is correct. The second code block is incorrect because passing by pointer and passing by reference are different and reflect a fundamental misunderstanding on my part. I was thinking of C++ dereferencing. See this question for more.


Solution

  • Yes, you should use the ref keyword for the struct.

    First, there's a really great resource for P/Invoke definitions that you can find at www.pinvoke.net - and the particular method you're dealing with is documented here: http://www.pinvoke.net/default.aspx/user32.getwindowinfo. You'll see that it's defined using the ref keyword. This makes sense when you consider that the method is documented as _Inout_ for that parameter in the MSDN docs you linked.

    The reason for this is that the ref keyword will allow that reference to be passed and have the struct you're dealing with before calling the method get updated/modified - rather than passing it in as is and never getting to see what the method actually does to it. In other words, without the ref keyword, your code would never see changes to the struct made within the GetWindowInfo call - GetWindowInfo would be working with its "own" copy of that structure.

    If you want to read a bit more about why your second version wouldn't work, check out JaredPar's great explanation to What is the difference between a C# Reference and a Pointer?