C# Windows アプリから Win32 API を呼び出す

C# から Win32 API を呼び出す場合に推奨される方法は、コンパイル時にタイプ セーフな P/Invoke ラッパーを生成するソース ジェネレーター である CsWin32 です。 CsWin32 は、任意の C# プロジェクトの種類 (WinUI 3、WPF、WinForms、コンソール、またはクラス ライブラリ) で動作し、DllImportまたはLibraryImport宣言を手動で記述する必要がなくなります。

必要な Win32 関数名をテキスト ファイルに一覧表示すると、CsWin32 は SDK メタデータから正しいシグネチャ、構造体、定数、および COM インターフェイスWindows自動的に生成します。

相互運用アプローチを選択する

Approach いつ使用するか 利点 デメリット
CsWin32 (推奨) C# からの任意の Win32/ネイティブ API 呼び出し 型安全で、公式の Windows SDK メタデータから生成され、マーシャリングや構造体を処理し、設定によりAOT に対応 NuGet パッケージが必要です。生成されたコードは既定では表示されません
LibraryImport (.NET 7 以降) 正確なシグネチャがわかっている一度限りの呼び出し ソース生成、AOT 互換、ランタイム マーシャリングなし すべての署名を手動で記述して維持する
DllImport (レガシ) 既存のコードまたは .NET Framework プロジェクト どこでも動作し、コミュニティによる豊富な作例 ランタイム マーシャリング、エラーを招きやすいシグネチャ
C#/WinRT Windows ランタイム API (Windows.*名前空間) 射影された .NET 型、自然な C# の使用感 未加工の Win32 ではなく、WinRT API の場合のみ

Note

CsWin32 の既定の出力では、.NET ランタイム マーシャラーが使用され、自動的に AOT 互換ではありません。 NativeAOT またはトリミングについては、 CsWin32RunAsBuildTaskDisableRuntimeMarshallingを有効にします。 CsWin32 AOT ガイダンスを参照してください。

Tip

必要な API がWindows.*名前空間 (Windows.StorageWindows.Mediaなど) にある場合は、Windows ランタイム API です。 P/Invoke の代わりに WinRT プロジェクションを使用します。 「.NET アプリからの相互運用 API の呼び出し」を参照してください。

前提条件

  • Visual Studio 2022 (バージョン 17.4 以降) または .NET 8 以降の SDK
  • 既存の C# プロジェクト (WinUI 3、WPF、WinForms、またはコンソール)

Note

.NET Framework または .NET Standard をターゲットにしますか? プロジェクト ファイル <LangVersion>9</LangVersion> (またはそれ以降) を設定し、 System.Memory と nuGet パッケージ System.Runtime.CompilerServices.Unsafe 追加します。

手順 1: CsWin32 NuGet パッケージをインストールする

プロジェクト ディレクトリで、次のコマンドを実行します。

dotnet add package Microsoft.Windows.CsWin32

CsWin32 は、ポインターと安全でないコンテキストを使用するコードを生成します。 NuGet パッケージを使用すると、 AllowUnsafeBlocks が自動的に有効になります。 プロジェクトで <AllowUnsafeBlocks>false</AllowUnsafeBlocks>を明示的に設定している場合は、その行を削除するか、 trueに変更します。そうしないと、生成されたコードはコンパイルされません。

手順 2: 必要な API を要求する

プロジェクト ルート ( ファイルの横) に .csproj という名前のファイルを作成します。 1 行に 1 つの API 名を追加します。 このチュートリアルでは、単純な関数から始めます。

GetTickCount

ファイルを保存します。 CsWin32 はコンパイル時にそれを読み取り、一致する P/Invoke ラッパーを生成します。

手順 3: 生成された API を呼び出す

生成されたコードは、Windows.Win32と呼ばれる静的クラスの下のPInvoke名前空間に存在します。 他の静的メソッドと同様に呼び出します。

using Windows.Win32;

// Get the number of milliseconds since the system started.
uint uptime = PInvoke.GetTickCount();
Console.WriteLine($"System uptime: {uptime} ms");

プロジェクトをビルドする。 NativeMethods.txt の関数名が有効な場合、呼び出しはコンパイルされ、追加の作業なしで実行されます。

一般的な落とし穴

"生成されたコードが表示されない"

CsWin32 はソース ジェネレーターです。既定では、その出力はプロジェクト内のファイルとして表示されません。 生成されたコードを検査するには:

  1. Visual Studio で、ソリューション エクスプローラーの Dependencies > Analyzers > Microsoft.Windows.CsWin32 > Microsoft.Windows.CsWin32.SourceGenerator を展開します。
  2. または、生成されたソースを <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> フォルダーに書き込むには、プロジェクト ファイルにobj/を設定します。

AnyCPU プラットフォーム ターゲット

CsWin32 で生成されたコードは AnyCPU で動作します。 ほとんどの Win32 呼び出しでプラットフォームターゲットを変更する必要はありません。

WinUI 3 での HWND の取得

多くの Win32 API には、ウィンドウ ハンドルが必要です。 WinUI 3 アプリで、 Window インスタンスから HWND を取得します。

using WinRT.Interop;

var hWnd = WindowNative.GetWindowHandle(this);

次に、 hWnd ( HWND または nintとして) Win32 関数に渡します。 詳細については、 ウィンドウ ハンドルの取得 (HWND) に関するページを参照してください。

CsWin32 の動作のカスタマイズ

テキスト ファイルの横に NativeMethods.json ファイルを作成して、ワイドとナローの文字列マーシャリングやわかりやすいオーバーロードなどの生成オプションを制御します。

{
  "$schema": "https://aka.ms/CsWin32.schema.json",
  "emitSingleFile": false,
  "public": true
}

すべてのオプションについては、 CsWin32 構成リファレンスを参照 してください。

次のステップ