Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When calling Windows API functions from C#, which source for signatures to trust: .NET Framework source code or PInvoke?

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);
  1. Which is the correct/best signature for this function? (only one of them has [return: MarshalAs(UnmanagedType.Bool)], or [In, Out] ref, etc.)

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

like image 546
Alex Vang Avatar asked Nov 29 '10 15:11

Alex Vang


People also ask

Is Windows API C or C++?

The windows API is implemented in the C programming language.

What language is the Windows API written in?

The Windows API (Win32) is focused mainly on the programming language C in that its exposed functions and data structures are described in that language in recent versions of its documentation.

How do I use API on windows?

To call a Windows API using the DllImport attributeOpen a new Windows Application project by clicking New on the File menu, and then clicking Project. The New Project dialog box appears. Select Windows Application from the list of Visual Basic project templates. The new project is displayed.

Where are Windows API function stored?

Windows API functions are located inside Windows DLLs. The name of the . dll in which the requested function is located is usually identical to the Import Library section in the function's documentation.


1 Answers

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.

like image 79
Hans Passant Avatar answered Oct 05 '22 02:10

Hans Passant