C#에서 Win32 API를 호출하는 권장 방법은 컴파일 시간에 형식이 안전한 P/Invoke 래퍼를 생성하는 원본 생성기인 CsWin32입니다. CsWin32는 WinUI 3, WPF, WinForms, 콘솔 또는 클래스 라이브러리와 같은 C# 프로젝트 형식에서 작동하며 직접 작성 DllImport 하거나 LibraryImport 선언할 필요가 없습니다.
텍스트 파일에 필요한 Win32 함수 이름을 나열하면 CsWin32는 Windows SDK 메타데이터에서 자동으로 올바른 서명, 구조체, 상수 및 COM 인터페이스를 생성합니다.
interop 접근 방식 선택
| 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 또는 트리밍의 경우 CsWin32RunAsBuildTask 및 DisableRuntimeMarshalling을 사용하도록 설정하세요. 자세한 내용은 CsWin32 AOT 지침을 참조하세요.
Tip
필요한 API가 네임스페이스(예: Windows.* 또는Windows.Storage)에 Windows.Media 있는 경우 Windows 런타임 API입니다. P/Invoke 대신 WinRT 프로젝션을 사용합니다.
.NET 앱에서 interop API 호출을 참조하세요.
사전 요구 사항
- Visual Studio 2022(버전 17.4 이상) 또는 .NET 8+ SDK
- 기존 C# 프로젝트(WinUI 3, WPF, WinForms 또는 콘솔)
Note
.NET Framework 또는 .NET Standard를 대상으로 지정하시겠습니까? 프로젝트 파일에서 <LangVersion>9</LangVersion>(또는 그 이상)로 설정하고, System.Memory 및 System.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는 원본 생성기이며 출력은 기본적으로 프로젝트에 파일로 표시되지 않습니다. 생성된 코드를 검사하려면 다음을 수행합니다.
- Visual Studio의 솔루션 탐색기에서 종속성 > 분석기 > Microsoft.Windows.CsWin32 > Microsoft.Windows.CsWin32.SourceGenerator를 확장하세요.
- 또는 프로젝트 파일에서
<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 구성 참조를 참조 하세요.
다음 단계
- interop 접근 방식 선택 - 모든 Windows interop 기술에 대한 의사 결정 가이드
- 연습 과정: Win32 interop를 사용하는 WinUI 3 앱 — CsWin32를 사용하여 제목 표시줄을 사용자 지정하는 좀 더 심층적인 예제
- GitHub CsWin32 - 원본, 샘플 및 문제 추적기
- P/Invoke(Platform Invoke) - P/Invoke 기본 사항에 대한 .NET 설명서
- .NET 앱에서 상호 운용 API 호출 — WinRT COM 기반 상호 운용 시나리오(HWND 전달, 선택기 등)의 경우
Windows developer