Вызов API Win32 из приложения Windows C#

Для вызова API Win32 из C# рекомендуется использовать CsWin32 — генератор исходного кода, который создает типобезопасные оболочки P/Invoke на этапе компиляции. CsWin32 работает с проектами C# любого типа — WinUI 3, WPF, WinForms, консольными приложениями или библиотеками классов — и избавляет от необходимости вручную писать объявления DllImport или LibraryImport.

Вы перечисляете имена функций Win32, необходимые в текстовом файле, и CsWin32 создает правильные подписи, структуры, константы и COM-интерфейсы автоматически из метаданных пакета SDK Windows.

Выберите подход к обеспечению взаимодействия

Approach Когда использовать Плюсы Минусы
CsWin32 (рекомендуется) Любой вызов Win32 или нативного API из C# Типобезопасный, созданный на основе официальных метаданных Windows SDK, поддерживает маршалинг и структуры, совместим с AOT с возможностью настройки Требуется пакет NuGet; Созданный код по умолчанию не отображается
LibraryImport (.NET 7+) Разовые вызовы, для которых точно известна сигнатура Генерируемый источником, совместимый с AOT, без маршалинга во время выполнения Вы записываете и обслуживаете каждую подпись вручную
DllImport (устаревшая версия) Существующий код или проекты платформы .NET Работает везде, множество примеров от сообщества Маршалинг среды выполнения, сигнатуры, подверженные ошибкам
C#/WinRT API среда выполнения Windows (Windows.* пространства имен) Проецируемые типы .NET, естественная работа с C# Только для API WinRT, не для чистого Win32

Note

По умолчанию выходные данные CsWin32 используют маршаллировщик среды выполнения .NET и не обеспечивают автоматическую совместимость с AOT. Включите CsWin32RunAsBuildTask и DisableRuntimeMarshalling для NativeAOT или тримминга — см. руководство по AOT для CsWin32.

Tip

Если нужный вам API находится в пространстве имён Windows.* (например, Windows.Storage или Windows.Media), то это API среда выполнения Windows. Используйте проекцию WinRT вместо P/Invoke. См. Вызов API взаимодействия из приложения .NET.

Необходимые условия

  • Visual Studio 2022 (версия 17.4 или более поздней версии) или пакет SDK .NET 8+
  • Существующий проект C# (WinUI 3, WPF, WinForms или консоль)

Note

Ориентация на .NET Framework или .NET Standard? Задайте в файле проекта значение <LangVersion>9</LangVersion> (или более позднюю версию) и добавьте пакеты NuGet System.Memory и System.Runtime.CompilerServices.Unsafe.

Шаг 1. Установка пакета NuGet CsWin32

В каталоге проекта выполните следующую команду:

dotnet add package Microsoft.Windows.CsWin32

CsWin32 создает код, использующий указатели и небезопасные контексты. Пакет NuGet автоматически включает AllowUnsafeBlocks. Если проект явно задает <AllowUnsafeBlocks>false</AllowUnsafeBlocks>, удалите эту строку или измените ее trueна, в противном случае созданный код не будет компилироваться.

Шаг 2. Запрос необходимых API

Создайте файл с именемNativeMethods.txt в корневом каталоге проекта (рядом с файлом .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.

Получение HWND в WinUI 3

Для многих API Win32 требуется дескриптор окна. В приложении WinUI 3 получите HWND из вашего Window экземпляра:

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, чтобы ознакомиться со всеми параметрами.

Дальнейшие действия