Reputation: 5821
For example, this is from .NET Framework source file UnsafeNativeMethods.cs:
[DllImport(ExternDll.User32, ExactSpelling=true, CharSet=CharSet.Auto)]
public static extern bool GetWindowRect(HandleRef hWnd,
[In, Out] ref NativeMethods.RECT rect);
and this is from PInvoke.Net:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(HandleRef hwnd, out RECT lpRect);
Which is the correct/best signature for this function? (only one of them has [return: MarshalAs(UnmanagedType.Bool)]
, or [In, Out] ref
, etc.)
I've noticed that in .NET Framework source files many/most signatures have ExactSpelling=true, CharSet=CharSet.Auto
, but on PInvoke they don't. Is this required?
Upvotes: 6
Views: 1163
Reputation: 942518
They will both get the job done. There's just more than one way to skin a pinvoke cat. Specifically for this example:
ExactSpelling=true
is an optimization, it avoids having the pinvoke marshaller looking for the GetWindowRectA
and GetWindowRectW
versions. They don't exist for this particular API function since it doesn't take a string argument. Seeing an actual difference in run time would be a miracle.
CharSet=CharSet.Auto
is always a good idea since the default (Ansi) is so inefficient. It just so happens to not make any difference here since the function doesn't take any string arguments.
[In, Out]
is unnecessary because that's the default for a blittable type. An expensive word that means that the pinvoke marshaller can directly pass a pointer to the managed memory, no conversion is required. As efficient as possible. Same idea as CharSet
though, being explicit about it helps to create self-documenting code and to remember to deal with the unusual case. Being able to only use [In]
or [Out]
can be a significant optimization, just not here since it is already optimized. Fwiw, [Out] would have been the correct choice.
out
vs ref
, same idea as above. Using out
is more correct since the API doesn't actually use any passed-in values inside the RECT
. It doesn't however make any difference at runtime since the JIT compiler always initializes a struct anyway.
[return: MarshalAs(UnmanagedType.Bool)]
is unnecessary, it is the default marshaling for a Windows BOOL
. Not sure why pinvoke.net always includes it.
So in a nutshell, neither is perfect but they both will work. Such are the hazards of pinvoke.
Upvotes: 20