從 C# Windows 應用程式呼叫 Win32 API

推薦從 C# 呼叫 Win32 API 的方法是 CsWin32,這是一個源碼產生器,能在編譯時產生型別安全的 P/Invoke 包裝器。 CsWin32 可支援任何 C# 專案類型——WinUI 3、WPF、WinForms、主控台或類別函式庫——並免除手寫DllImportLibraryImport宣告的需求。

你在文字檔中列出你需要的 Win32 函式名稱,CsWin32 會自動從 Windows SDK 的元資料產生正確的簽名、結構式、常數和 COM 介面。

選擇互操作性方法

Approach 何時使用 優點 Cons
CSWin32 (推薦) 從 C# 呼叫任何 Win32/原生 API 型別安全,由官方 Windows SDK 中繼資料產生,可處理編組與結構體,對 AOT 友善,並支援設定 需要 NuGet 套件;生成的程式碼預設不會被看見
LibraryImport (.NET 7+) 一次性通話,你知道確切的簽名 原始碼生成、AOT 相容、無執行時編組 你要手動撰寫並維護每個簽名
DllImport (舊版) 現有程式碼,或 .NET Framework 專案 作品遍布各地,社群範例豐富 執行時分組、易出錯簽名
C#/WinRT Windows 執行階段 API(Windows.*命名空間) 投影的 .NET 類型,自然的 C# 體驗 僅適用於 WinRT API,不適用於原生 Win32

Note

CsWin32 的預設輸出使用 .NET 執行階段封送處理器,且 會自動與 AOT 相容。 關於 NativeAOT 或修剪,請啟用 CsWin32RunAsBuildTaskDisableRuntimeMarshalling—— 請參見 CsWin32 AOT 指引

Tip

如果你需要的 API 位於 Windows.* 命名空間中(例如 Windows.StorageWindows.Media),那麼它就是 Windows 執行階段 API。 使用 WinRT 投影代替 P/Invoke。 請參考從 .NET 應用程式呼叫互操作 API

先決條件

  • Visual Studio 2022(版本 17.4 或更新)或 .NET 8+ SDK
  • 一個現有的 C# 專案(WinUI 3、WPF、WinForms 或控制台)

Note

目標是 .NET 框架還是 .NET 標準? 在你的專案檔案中設定 <LangVersion>9</LangVersion> (或之後),並加入 System.MemorySystem.Runtime.CompilerServices.Unsafe NuGet 套件。

步驟 1:安裝 CsWin32 NuGet 套件

在你的專案目錄中,執行:

dotnet add package Microsoft.Windows.CsWin32

CsWin32 產生的程式碼使用指標和不安全的上下文。 NuGet 套件會自動啟用 AllowUnsafeBlocks 。 如果你的專案明確設定了 <AllowUnsafeBlocks>false</AllowUnsafeBlocks>,請移除那行或改成 true,否則產生的程式碼無法編譯。

步驟 2:請求你需要的 API

在你的專案根目錄(檔案旁邊)建立一個名為 .csproj 的檔案。 每行新增一個 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 的方案總管中,展開 相依性 > 分析器 > 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(作為 HWNDnint)傳遞給 Win32 函式。 如需詳細資訊,請參閱 取得視窗控制代碼 (HWND)

自訂 CsWin32 的行為

在文字檔旁建立一個 NativeMethods.json 檔案,以控制生成選項,例如寬弦與窄字串編組或友善過載:

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

請參閱 CsWin32 設定參考資料 以獲得所有選項。

下一步