C#からWindows API機能を呼び出すとき、どの署名のソースを信頼するか:.NETフレームワークソースコードまたはPinvoke?
-
29-09-2019 - |
質問
たとえば、これは.NETフレームワークソースファイルからです unsafenativemethods.cs:
[DllImport(ExternDll.User32, ExactSpelling=true, CharSet=CharSet.Auto)]
public static extern bool GetWindowRect(HandleRef hWnd,
[In, Out] ref NativeMethods.RECT rect);
これはPinvoke.netからです:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(HandleRef hwnd, out RECT lpRect);
この関数の正しい/最高の署名はどれですか? (そのうちの1人だけが持っています
[return: MarshalAs(UnmanagedType.Bool)]
, 、 また[In, Out] ref
, 、など).NETフレームワークソースファイルでは、多くの署名があることに気付きました
ExactSpelling=true, CharSet=CharSet.Auto
, 、しかし、ピンボークではそうではありません。これは必要ですか?
解決
彼らは両方とも仕事を終わらせるでしょう。ピンボーク猫を皮を剥ぐ方法は複数あります。具体的には、この例については:
ExactSpelling=true
最適化であり、Pinvoke Marshallerが探してもらうことを避けますGetWindowRectA
とGetWindowRectW
バージョン。文字列引数を取得しないため、この特定のAPI関数には存在しません。実行時間の実際の違いを見るのは奇跡です。CharSet=CharSet.Auto
デフォルト(ANSI)が非常に非効率的であるため、常に良いアイデアです。関数が文字列引数を取得しないため、ここで違いはありません。[In, Out]
それがブリット可能なタイプのデフォルトであるため、不要です。 Pinvoke Marshallerが管理されたメモリへのポインターを直接渡すことができることを意味する高価な単語。変換は必要ありません。可能な限り効率的です。と同じアイデアCharSet
しかし、それについて明示的であることは、自己文書化コードを作成し、珍しいケースに対処することを忘れないでください。使用することができる[In]
また[Out]
既に最適化されているため、ここではそうではありません。 fwiw、[out]は正しい選択だったでしょう。out
vsref
, 、上記と同じアイデア。使用out
APIは実際には内部に渡された値を実際に使用していないため、より正しいですRECT
. 。ただし、JITコンパイラは常に構造体を初期化するため、実行時に違いはありません。[return: MarshalAs(UnmanagedType.Bool)]
不要です、それはウィンドウのデフォルトのマーシャリングですBOOL
. 。 Pinvoke.netが常にそれを含める理由はわかりません。
したがって、一言で言えば、どちらも完璧ではありませんが、どちらも機能します。これがピンボークの危険です。