2010-11-29 34 views
6

Par exemple, cela est du fichier source .NET Framework UnsafeNativeMethods.cs:Lors de l'appel de fonctions API Windows à partir de C#, quelle source pour les signatures à approuver: code source .NET Framework ou PInvoke?

[DllImport(ExternDll.User32, ExactSpelling=true, CharSet=CharSet.Auto)] 
public static extern bool GetWindowRect(HandleRef hWnd, 
    [In, Out] ref NativeMethods.RECT rect); 

, ce qui est de PInvoke.Net:

[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
public static extern bool GetWindowRect(HandleRef hwnd, out RECT lpRect); 
  1. Quelle est la bonne/meilleure signature pour cette fonction? (Un seul d'entre eux a [return: MarshalAs(UnmanagedType.Bool)] ou [In, Out] ref, etc.)

  2. J'ai remarqué que dans la source .NET Framework fichiers de nombreux/la plupart des signatures ont ExactSpelling=true, CharSet=CharSet.Auto, mais ils ne sont pas PInvoke. Est-ce nécessaire?

Répondre

20

Ils feront tous deux le travail. Il y a juste plus d'une façon de peler un chat pinvoke. Plus précisément pour cet exemple:

  • ExactSpelling=true est une optimisation, il évite d'avoir la PInvoke placier recherche pour les versions GetWindowRectA et GetWindowRectW. Ils n'existent pas pour cette fonction API particulière, car elle ne prend pas d'argument de chaîne. Voyant une différence réelle dans le temps d'exécution serait un miracle.

  • CharSet=CharSet.Auto est toujours une bonne idée puisque le défaut (Ansi) est si inefficace. Il arrive juste de ne faire aucune différence ici puisque la fonction ne prend aucun argument de chaîne.

  • [In, Out] est inutile car c'est le type par défaut pour un type blittable. Un mot cher qui signifie que le marshaller pinvoke peut directement passer un pointeur vers la mémoire gérée, aucune conversion n'est requise. Aussi efficace que possible. Même idée que CharSet cependant, être explicite à ce sujet aide à créer du code auto-documenté et à se souvenir de traiter le cas inhabituel. Pouvoir seulement utiliser [In] ou [Out] peut être une optimisation significative, mais pas ici car il est déjà optimisé. Fwiw, [Out] aurait été le bon choix.

  • out par rapport à ref, même idée que ci-dessus. L'utilisation de out est plus correcte car l'API n'utilise pas réellement de valeurs transmises à l'intérieur du RECT. Cela ne fait cependant aucune différence au moment de l'exécution car le compilateur JIT initialise toujours une structure de toute façon.

  • [return: MarshalAs(UnmanagedType.Bool)] est inutile, il s'agit du marshaling par défaut pour un Windows BOOL. Je ne sais pas pourquoi pinvoke.net l'inclut toujours.

Donc, en un mot, aucun n'est parfait mais ils fonctionneront tous les deux. Tels sont les dangers de Pinvoke.

+0

+1 Pour une excellente explication. –

+1

FxCop se plaindra si vous n'indiquez pas explicitement le type de marshalling où il est ambigu. C'est le cas pour bool (puisqu'il y a Win32 BOOL, C++ bool et VARIANT_BOOL) ou pour les chaînes. –