Marshal [in] reference without ref - c#

Some functions, especially in COM interfaces, expose a REFIID parameter that is used to specify the type of the interface the methods should return. Here's such an example method:
[DllImport("shell32.dll", PreserveSig=false)]
[return: MarshalAs(UnmanagedType.IUnknown)]
static extern object SHBindToObject(IShellFolder psf, IntPtr pidl, [MarshalAs(UnmanagedType.IUnknown)]object pbc, [In]ref Guid riid);
The fourth parameter is input-only, and should not be changed by SHBindToObject, so by C# conventions, it makes no sense passing it as a reference (aside from performance). I can't recall it clearly, but I remember that there should be some custom attribute or something that is designated for this case, to tell the marshaller that it should be really marshalled as if it were ref Guid, while it is specified without ref in the signature.
I looked for attributes in the System.Runtime.InteropServices names, fields on MarshalAsAttribute, and in the UnmanagedType enum, but without success.
Does there happen to be something similar, or is my memory incorrect? Is it good using such a thing in this case?

You're looking for MarshalAs(UnmanagedType.LPStruct):
[DllImport("shell32.dll")]
[return: MarshalAs(UnmanagedType.IUnknown)]
static extern object SHBindToObject(
IShellFolder psf,
IntPtr pidl,
[MarshalAs(UnmanagedType.IUnknown)] object pbc,
[MarshalAs(UnmanagedType.LPStruct)] Guid riid);

Related

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.
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?

Constraints vs abstract class using SafeHandle

There is a method within BCryptNative called GetInt32Property.
It has the following signature:
internal static int GetInt32Property<T>(T algorithm, string property) where T : SafeHandle
This method only works when T is of type SafeBCryptAlgorithmHandle or SafeBCryptHashHandle. It calls native methods which are explicitly defined with those types of handles:
[DllImport("bcrypt.dll", EntryPoint = "BCryptGetProperty", CharSet = CharSet.Unicode)]
internal static extern ErrorCode BCryptGetAlgorithmProperty(SafeBCryptAlgorithmHandle hObject,
string pszProperty,
[MarshalAs(UnmanagedType.LPArray), In, Out] byte[] pbOutput,
int cbOutput,
[In, Out] ref int pcbResult,
int flags);
[DllImport("bcrypt.dll", EntryPoint = "BCryptGetProperty", CharSet = CharSet.Unicode)]
internal static extern ErrorCode BCryptGetHashProperty(SafeBCryptHashHandle hObject,
string pszProperty,
[MarshalAs(UnmanagedType.LPArray), In, Out] byte[] pbOutput,
int cbOutput,
[In, Out] ref int pcbResult,
int flags);
Microsoft uses function pointers / delegates to point to the correct native function. My question is, why didn't Microsoft just implemented the GetInt32Property method with the following signature:
internal static int GetInt32Property(SafeHandle algorithm, string property)
with the following native method:
[DllImport("bcrypt.dll", CharSet = CharSet.Unicode)]
internal static extern ErrorCode BCryptGetProperty(SafeHandle hObject,
string pszProperty,
[MarshalAs(UnmanagedType.LPArray), In, Out] byte[] pbOutput,
int cbOutput,
[In, Out] ref int pcbResult,
int flags);
Are there any downsides to this? (assuming that the SafeHandle passed to GetInt32Property is always either a SafeBCryptAlgorithmHandle or SafeBCryptHashHandle).
I'm just wondering about why Microsoft implemented this so relatively complicated.
Does it have to with:
Security-Transparent Code?
Type safety? (So that you never use any other than those two types)
Is it allowed to use SafeHandle explicitly?
According to the documentation the class must be inherited, and it is, however does a P/Invoked function handle it properly when given an abstract class of SafeHandle? Does it increment and decrement the reference counts appropriately?
It's hard to tell why Microsoft chose to implement something in one way or another, but I can answer your points.
The code isn't complex. The usage is clear (something like GetInt32Property(algorithm, str).
It doesn't force you to send one of the types you mentioned, you can still call it with a different class, as long as it implements SafeHandle.
The native methods that are used are actually the same. This is kind of odd, but I'm not an expert on this specific library so it may be for a good reason.
There's a hidden benefit for generic methods like this one. The typeof(T) == typeof(SafeBCryptHashHandle) type checks are not done in runtime, but in JIT time. This means that the method should perform slightly faster then a regular runtime check like algorith is SafeBCrypthHashHandle.
The SafeHandle class is an abstract class. This means that you cannot create an instance of it, but you can inherit it. The native function only get marshaled data, they don't get real references to objects. Don't worry about reference counting.

Automatic casting for string DllImport arguments vs Marshal.StringToCoTaskMemUni

Consider the WM_SETTEXT message that you can use to set the text of another window via old school Win32 API. There are probably a multitude of ways of doing this in .NET, here's two that I know:
[DllImport("USER32", EntryPoint = "SendMessage", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, string lParam);
SendMessage(handle, WM_SETTEXT, IntPtr.Zero, "Magic String");
[DllImport("USER32", EntryPoint = "SendMessage", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
IntPtr textPointer = Marshal.StringToCoTaskMemUni("Magic String");
SendMessage(handle, WM_SETTEXT, IntPtr.Zero, textPointer);
Marshal.FreeCoTaskMem(textPointer);
The first one uses a string in the declaration of the dll import and lets .NET handle it. This second uses an IntPtr and explicitly creates a pointer using Marshal.StringToCoTaskMemUni and then freed using Marshal.FreeCoTaskMem. Both of these approaches work happily as far as I can tell.
Note I normally do the former (which in fact I used to do many years ago as a VB6 programmer), but I came across the latter on a comment on another StackOverflow post and was curious if the former was another bad habit that needed squashing.
I have also seen a variant of the first example using a char[] array in the declaration and passing in a StringBuilder
My question is simple - which (if any) is the correct way of doing it? For example, the SendMessage Win32 call only accepts pointers anyway, so "something" must be creating pointers behind the scenes for the first version, and if so does it do the cleaning up, or is it better to be verbose and use the explicit allocation and deallocation of pointers.
When you declare a parameter of string, the p/invoke marshaller will, behind the scenes, marshal that to a pointer to a null-terminated array of characters. The marshaller will handle all memory allocation and deallocation. You can do it yourself with an IntPtr parameter, but it comes to the same in the end.
Which you choose comes down to whether or not you plan to use the SendMessage declaration for any other messages that you send.
If you only ever call SendMessage for WM_SETTEXT, then you declare it to receive a string parameter.
If you also use SendMessage to send other messages, then you can declare the parameter to be IntPtr and perform the marshalling manually.
And yet another option is to declare multiple overloaded variants so that you can make the code that calls SendMessage as convenient as possible for the programmer.
Now, let's pick up that last option. Suppose you needed to send WM_GETTEXT as well as WM_SETTEXT. For WM_SETTEXT you need to pass string data from managed to native, so you'd prefer string. For WM_GETTEXT, you need to supply a buffer so that the native code can fill out the window text. And that means you want to use StringBuilder. So, declare two overloads, one receiving string and one receiving StringBuilder. Use the former for WM_SETTEXT and the latter for WM_GETTEXT.

When Importing a DLL Why Do Methods Have To Be Declared Static and Extern?

As the title asks, when you import a DLL such as User32.dll and declare methods to call methods on that DLL why do the methods need to be declared as Static and Extern.
I.E, this was taken from another StackOverflow answer, but demonstrates what I'm asking.
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, UIntPtr dwExtraInfo);
static - As they do not need instance of the class, those method's are call to system API and do not need any Initialization, can be used in static / non-static block
extern - The extern modifier is used to declare a method that is implemented externally. Since API methods are not declared in the class file itself, extern tell the compiler that method declared else-where.
While I do not really know whether there are technical details to this, I'd say the reasons are:
static
Methods that reside in external DLLs can not be bound to any object instance. If they were bound to an object instance, the DLL would have to track which instance is calling the method every time.
extern
I guess this is just a keyword telling the compiler to insert code for binding the DLL instead of expecting the method to be implemented in C#.

c# using const with DllImport

I have a code example from a SDK, the DLL is written in C and calls for the following:
int getAttribute(const RawDevControl *control, RawDevAttribute *attribute)
I'm using
[DllImport(#"Dev.dll",
SetLastError = true)]
internal static extern int getAttribute(const RControl *control, RAttribute *attribute);
But of course you can not use const as a type when defining this reference function.
How can I make this work with c#?
Since C# doesn't have the concept of const references, you don't really need to worry about it. On the DLL side, the code will still think you have a const pointer. Thus, your import changes to this:
[DllImport(#"Dev.dll", SetLastError = true)]
internal static extern int getAttribute(RControl control, RAttribute attribute);
This, of course, assumes that both RControl and RAttribute have been defined in C#. If they are structs, follow the examples on MSDN for defining structs for use with P/Invoke. If they are classes, that's a different set of problems. In that case, it is best if the classes are COM-based.
The declaration promises that the function doesn't alter the passed object. So take advantage of that, tell the pinvoke marshaller that there's no point in copying it back. Apply the [In] attribute:
[DllImport(#"Dev.dll", SetLastError = true)]
static extern int getAttribute([In] ref RControl control, out RAttribute attribute);
Omit the ref or out keyword if you declared the argument types as classes instead of structs.

Categories

Resources