Lors de l'appel des fonctions API de Windows à partir de C #, la source pour les signatures de confiance: code source .NET Framework ou PInvoke?
-
29-09-2019 - |
Question
Par exemple, cela est du fichier source .NET Framework UnsafeNativeMethods.cs :
[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);
-
Quelle est la bonne / meilleure signature pour cette fonction? (Un seul d'entre eux a
[return: MarshalAs(UnmanagedType.Bool)]
ou[In, Out] ref
, etc.) -
Je l'ai remarqué que dans la source .NET Framework fichiers beaucoup / la plupart des signatures ont
ExactSpelling=true, CharSet=CharSet.Auto
, mais PInvoke ils ne le font pas. Est-ce nécessaire?
La solution
Ils seront tous deux faire le travail. Il y a un peu plus d'une façon à la peau d'un chat PInvoke. Plus précisément pour cet exemple:
-
ExactSpelling=true
est une optimisation, il évite d'avoir le PInvoke placier chercher les versionsGetWindowRectA
etGetWindowRectW
. Ils n'existent pas pour cette fonction API particulière car il ne prend pas un argument de chaîne. En voyant une différence réelle dans le temps d'exécution serait un miracle. -
CharSet=CharSet.Auto
est toujours une bonne idée car la valeur par défaut (Ansi) est si inefficace. Il se trouve juste à ne faire aucune différence ici puisque la fonction ne prend aucun argument de chaîne. -
[In, Out]
est inutile parce que c'est la valeur par défaut pour un type blittable. Un mot coûteux qui signifie que le placier de PInvoke peut passer directement un pointeur vers la mémoire gérée, aucune conversion est nécessaire. Aussi efficace que possible. Même idée queCharSet
cependant, être explicite à ce sujet aide à créer le code d'auto-documentation et de se rappeler de traiter le cas inhabituel. Être capable de ne 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
vsref
, même idée que ci-dessus. L'utilisationout
est plus correct puisque l'API n'utilise en fait une refacturés en valeurs à l'intérieur duRECT
. Il n'a pas cependant fait aucune différence lors de l'exécution depuis le compilateur JIT toujours initialise struct de toute façon. -
[return: MarshalAs(UnmanagedType.Bool)]
est inutile, il est le marshaling par défaut pour unBOOL
de Windows. Je ne sais pas pourquoi pinvoke.net comprend toujours.
Donc, en un mot, ni est parfait, mais ils ont tous deux fonctionnera. Tels sont les dangers de PInvoke.