Reputation: 28
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.
Upvotes: 1
Views: 618
Reputation: 21641
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?
Upvotes: 1