많은 Windows API(푸시 알림, 백그라운드 작업, 공유 대상, 시작 작업, Windows AI API)는 앱에 패키지 ID 있어야 합니다. 개발 중에는 테스트할 때마다 전체 MSIX 설치 관리자를 빌드하지 않고도 애플리케이션에 실시간으로 ID를 부여할 수 있는 winapp의 두 가지 명령을 사용할 수 있습니다.
패키징 프로젝트에서 Visual Studio 사용하시겠습니까? 패키지된 프로젝트에 이미 Visual Studio 사용하고 있는 경우 디버깅을 위해 winapp이 필요하지 않을 수 있습니다. Visual Studio F5에서 패키지 등록, ID, AUMID 활성화, 디버거 첨부 파일 및 활성화 코드 디버깅을 이미 처리하고 있습니다. 또한 다양한 고급 시나리오에 대해 디버그 → 기타 디버그 대상 → 설치된 앱 패키지를 디버그 기능을 제공합니다. 아래 워크플로는 VS Code 사용자, 터미널 기반 워크플로 및 VS가 기본적으로 패키지하지 않는 프레임워크 (Rust, Flutter, Tauri, Electron, 일반 C++)에 가장 유용합니다.
두 가지 방법: winapp run vs create-debug-identity
winapp run |
create-debug-identity |
|
|---|---|---|
| 등록하는 내용 | 전체 분리 레이아웃 패키지(전체 폴더) | 스파스 패키지(단일 exe) |
| 앱 시작 방법 | winapp에서 시작됨(AUMID 활성화 또는 실행 별칭) | exe를 직접 시작합니다(명령줄, IDE 등). |
| MSIX 설치 시뮬레이션 | 예 - 프로덕션 동작에 가장 가깝습니다. | 아니요 - 스파스 ID만 |
| 파일이 제자리에 유지 | AppX 레이아웃 디렉터리에 복사됨 | 예 - exe가 원래 경로에 유지됩니다. |
| 정체성 범위 | 전체 폴더 내용(exe, DLL, 자산) | 단일 실행 파일 |
| 디버거 친화적 | 시작 후 PID에 연결하거나 --no-launch을 사용하여 별칭을 통해 실행하십시오. |
IDE의 디버거에서 직접 실행 - exe 파일은 항상 고유한 정체성을 가지고 있습니다. |
| 콘솔 앱 지원 |
--with-alias 터미널에서 stdin/stdout 유지 |
터미널에서 직접 exe 실행 |
| 최적입니다 | 대부분의 프레임워크(.NET, C++, Rust, Flutter, Tauri) | Electron 또는 전체 IDE 디버거 제어가 필요할 때(F5) |
어떤 것을 언제 사용할지
기본값: winapp run
대부분의 개발 워크플로에 사용합니다 winapp run . 실제 MSIX 설치를 시뮬레이션합니다. 앱은 프로덕션 환경에서와 동일한 ID, 기능 및 파일 연결을 가져옵니다.
# Build your app, then:
winapp run .\build\output
다음과 같은 경우 create-debug-identity를 사용합니다.
-
Exe 파일은 빌드 결과물과 별도로 존재합니다 — 예를 들어,
electron.exe이(가)node_modules/에 위치한 Electron 앱. - 시작 코드를 디버그해야 하며 AUMID 시작 후 디버거를 충분히 빠르게 연결할 수 없습니다.
-
AUMID를 사용하여 시작할 수 없고 시작된 프로세스
create-debug-identity에서 ID가 필요한 일부 디버거에서 exe를 등록하여 시작 방법에 관계없이 ID가 있도록 합니다. - 스파스 패키지 동작을 구체적으로 테스트하고 있습니다 (AllowExternalContent, TrustedLaunch)
# Register identity for an exe, then launch it however you want:
winapp create-debug-identity .\bin\Debug\myapp.exe
.\bin\Debug\myapp.exe # or F5 in your IDE
디버깅 시나리오
시나리오 A: ID를 사용하여 실행
가장 간단한 워크플로인 빌드, ID로 실행, 완료.
winapp run .\build\Debug
Winapp은 폴더를 느슨한 레이아웃 패키지로 등록하고 앱을 시작합니다. ID가 필요한 API는 즉시 작동합니다. 대부분의 개발 및 테스트 시나리오를 다룹니다.
현재 터미널에서 stdin/stdout이 필요한 콘솔 앱 의 경우 다음을 추가 --with-alias합니다.
winapp run .\build\Debug --with-alias
시나리오 B: 실행 중인 앱에 디버거 연결
winapp run로 시작하고 PID를 기록한 다음 IDE의 디버거를 연결합니다.
winapp run .\build\Debug
# Output: Process ID: 12345
그런 다음, IDE에서 다음을 수행합니다.
- VS Code: 실행 및 디버그 → "연결" 구성 선택(아래 IDE 설정 참조)
-
WinDbg:
windbg -p 12345
제한: 연결하기 전에 실행되는 코드가 누락됩니다. 시작 디버깅의 경우 시나리오 D(
create-debug-identity)를 사용합니다.
시나리오 C: ID를 등록한 다음, AUMID 또는 IDE의 별칭을 통해 시작합니다.
--no-launch 패키지를 등록한 다음 run에서 보고된 AUMID 또는 IDE의 실행 별칭을 통해 앱을 시작합니다.
1단계: 시작하지 않고 패키지를 등록합니다.
winapp run .\build\Debug --no-launch
2단계: AUMID 또는 실행 별칭 (exe 직접이 아님)을 통해 시작하도록 IDE를 구성합니다.
- AUMID를 사용하여 시작: 명령을
start shell:AppsFolder\<AUMID>사용합니다.winapp run는 앱이 등록될 때 AUMID를 출력합니다. - 별칭을 사용하여 시작: 별칭은 매니페스트에 정의되어야 합니다(
Package.appxmanifest기본 설정,appxmanifest.xml지원됨).
중요: 단순히 빌드 폴더에서 exe를 시작하면 ID가 부여 되지 않습니다 . AUMID 활성화 또는 실행 별칭을 통해 앱을 시작해야 합니다. 이것이 느슨한 레이아웃 패키지의 작동 방식입니다. ID는 exe 파일이 아닌 활성화 경로에 연결됩니다.
시나리오 D: ID를 사용하여 IDE에서 시작(시작 디버깅)
이는 전체 IDE 제어를 사용하여 시작 코드를 디버깅하는 가장 좋은 방법입니다. IDE의 디버거는 첫 번째 명령에서 프로세스를 제어하고 exe는 시작 방법에 관계없이 ID를 가집니다.
winapp create-debug-identity .\build\Debug\myapp.exe
이제 터미널, VS Code의 F5, 스크립트에서 원하는 방식으로 exe를 시작합니다. Windows가 exe 파일을 직접 가리키는 sparse 패키지를 등록했기 때문에 exe에 정체성이 부여됩니다.
winapp run의 차이점:create-debug-identity을 사용하면 ID는Add-AppxPackage -ExternalLocation를 통해 exe 파일 자체에 연결됩니다. IDwinapp run는 레이아웃 패키지와 느슨하게 연결되어 있으므로, 앱은 AUMID 또는 별칭을 통해 시작해야 합니다. 이렇게 하면create-debug-identityexe를 직접 시작하고 디버그하는 데 IDE가 필요할 때 더 나은 선택을 할 수 있습니다.
exe 경로가 원본 디렉터리와 다른 Electron 앱 에 가장 적합한 방법이기도 합니다.
시나리오 E: 디버그 출력 및 크래시 진단 캡처
OutputDebugString 메시지와 첫 기회의 예외를 인라인으로 캡처합니다. 프레임워크 노이즈(WinUI, COM, DirectX 내부 추적)는 콘솔에서 필터링되므로 앱의 디버그 메시지만 표시됩니다. 모든 항목이 전체 조사를 위해 로그 파일에 기록됩니다.
앱이 충돌하면 미니덤프가 자동으로 캡처되고 분석됩니다.
winapp run .\build\Debug --debug-output
충돌 시 출력에는 원본 파일 및 줄 번호가 포함된 예외 유형, 메시지 및 스택 추적이 포함됩니다(빌드 출력 폴더의 PDB에서 확인됨). 관리되는(.NET) 크래시는 외부 도구 없이 즉시 분석됩니다. 네이티브(C++/WinRT) 크래시가 모듈 이름과 오프셋을 표시합니다. 완전한 함수 이름을 얻으려면 PDB 심볼을 다운로드할 --symbols를 추가하세요.
winapp run .\build\Debug --debug-output --symbols
중요: 그러면 winapp이 디버거로 연결됩니다. Windows 프로세스당 하나의 디버거만 허용하므로 Visual Studio, VS Code 또는 WinDbg도 연결할 수 없습니다.
WinUI 저장된 예외 분류
대부분의 WinUI 충돌은 XAML 이벤트 처리기 내부에서 시작되며, 나중에 디스패처에서 다시 발생하는 보관된 예외(0xC000027B)로 나타나므로 일반적인 스택 추적은 더 이상 실제 원인을 가리키지 않습니다. 충돌한 앱이 로드되었을 때 Microsoft.UI.Xaml.dll, winapp은 저장된 예외와 네이티브 XAML 디스패치 체인(Microsoft.UI.Xaml → CXcpDispatcher → CoreMessagingXP → CLR 호스트)을 디코딩하는 추가 트리아지 단계를 자동으로 수행합니다. 결과는 디버그 로그에 추가됩니다. 플래그가 필요하지 않습니다. WinUI 덤프에 대해 자동으로 사용하도록 설정됩니다. 디스패치 체인에서 완전히 해석된 함수 이름에 --symbols를 추가합니다.
이를 가능하게 하려면, winapp은 첫 번째 기회(first-chance) 스레드 컨텍스트를 유지한 상태에서 종료를 유발한 stowed exception의 레코드(및 stowed-exception 배열을 가리키는 해당 매개 변수)와 함께 크래시 덤프를 캡처하므로, 표준 관리 코드 분석은 여전히 원래 사용자 프레임을 복구 하고 triage 단계는 stowed exception을 찾을 수 있습니다.
이 패스는 WinUI 팀의 WinDbg JavaScript 확장으로 DbgEng을 호스트합니다. 디버깅 엔진은 NuGet에서 제공됩니다. JsProvider.dll (NuGet에 게시되지 않은 JavaScript 호스트)는 공식 WinDbg 다운로드에서 처음 사용할 때 가져옵니다. 둘 다 버전이 고정되며 로드되기 전에 검증됩니다 — SHA-512 콘텐츠 해시와 JsProvider.dll에 대한 Microsoft Authenticode 서명 검사로 검증되며 — 검증에 실패하면 검증되지 않은 코드를 로드하는 대신 트리아지를 건너뜁니다. 모든 항목이 winapp 전역 디렉터리 아래에 캐시되므로 나중에 실행이 오프라인 상태입니다.
사용 중인 환경에서 해당 다운로드가 차단되는 경우, Debugging Tools for Windows를 설치하거나(Windows SDK를 통해 설치) JsProvider.dll 및 WINAPP_DBGTOOLS_DIR이 포함된 디버거 디렉터리로 dbgeng.dll를 설정하세요.
WINAPP_DBGTOOLS_DIR 설정된 경우 신뢰할 수 있으며 해당 디렉터리만 참조되며 불완전한 경우 로그에 누락된 구성 요소의 이름을 지정합니다.
심사에 성공하면 콘솔에 한 줄의 평결(보관된 예외의 오류 코드/메시지)이 표시됩니다. 실행할 수 없으면 콘솔에서 이를 표시하고 로그에서 이유를 설명하고 표준 관리/네이티브 분석이 계속 실행됩니다.
트리아지 패스는 수명이 짧은 자식 프로세스에서 실행되는데, 이는 winapp의 메인 프로세스가 이미 시스템 dbghelp.dll을 로드한 상태이며 최신 dbgeng.dll은 그것과 함께 바인딩할 수 없기 때문입니다. 또한 보관된 예외 구조를 디코딩하려면 OS 기호(--symbols)가 필요하며, 이는 combase.dll Microsoft 공용 기호 서버에서 다운로드합니다. 해당 기호가 게시되지 않은 빌드에서는 분류 과정에서 여전히 보관된 예외를 식별할 수 있지만, 이를 완전히 해석할 수는 없습니다.
IDE 설정
VS Code
WinApp VS Code 확장은 패키지 ID로 앱을 시작하고 디버거를 연결할 수 있는 사용자 지정 winapp 디버그 유형을 제공하며, 이 모든 작업을 F5 키 한 번으로 수행할 수 있습니다.
Visual Studio Marketplace에서 설치합니다. 원본 및 문제 추적기는 microsoft/WinAppVSCE 리포지토리에 라이브로 저장됩니다.
ID를 사용하여 F5 디버깅 한 번 누르기
시작 구성을 winapp에 추가합니다..vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "winapp",
"request": "launch",
"name": "WinApp: Launch and Attach"
}
]
}
F5 키를 누르면 다음을 수행합니다.
- 확장은 작업 영역을 검색하여
.exe파일이 포함된 빌드 출력 디렉터리를 찾습니다. - 실행할 빌드 폴더를 선택하거나 프롬프트를 건너뛰도록 설정합니다
inputFolder. -
winapp run를 통해 앱을 시작하여 패키지 ID를 제공합니다. - 자식 디버그 세션은 지정한 디버거를 사용하여 실행 중인 프로세스에 연결됩니다.
디버거가 연결되면 전체 VS Code 디버깅 환경을 얻게 됩니다. 즉, 여백을 클릭하여 중단점을 설정하고, 코드를 한 줄씩 실행하고(F10), 함수를 한 단계씩 실행(F11), 변수 창에서 변수를 검사하고, 디버그 콘솔에서 식을 평가합니다. 앱은 전체 패키지 ID를 사용하여 실행되므로 ID 종속 API는 프로덕션에서와 동일하게 작동합니다.
중요: 디버그 형식은
winapp프로젝트를 자동으로 빌드 하지 않습니다. 코드를 변경한 후 F5 키를 누르기 전에 다시 빌드합니다.
preLaunchTask를 사용하여 빌드를 자동화하십시오
다시 빌드하는 것을 잊으려면 모든 디버그 세션 전에 프로젝트를 빌드하는 항목을 추가 preLaunchTask 합니다.
-
.vscode/tasks.json(예: .NET)에서 빌드 작업을 정의합니다.{ "version": "2.0.0", "tasks": [ { "label": "build", "command": "dotnet", "type": "process", "args": ["build", "${workspaceFolder}"], "problemMatcher": "$msCompile" } ] } - 다음에서 이를 참조하세요
launch.json.{ "type": "winapp", "request": "launch", "name": "WinApp: Launch and Attach", "preLaunchTask": "build" }
구성 속성
| 재산 | Type | Default | Description |
|---|---|---|---|
inputFolder |
string | 앱 이진 파일이 포함된 빌드 출력 폴더의 경로입니다(예: ${workspaceFolder}/bin/Debug/net8.0-windows10.0.22621). 설정하지 않으면 폴더를 선택하라는 메시지가 표시됩니다. |
|
manifest |
string | AppX 매니페스트 파일(예: AppxManifest.xmlPackage.appxmanifestappxmanifest.xml또는)에 대한 경로입니다. 설정하지 않으면 CLI가 입력 폴더 또는 현재 디렉터리에서 자동으로 검색됩니다. |
|
debuggerType |
string | coreclr |
사용할 기본 디버거(coreclr또는cppvsdbgnode)입니다. |
workingDirectory |
string | 작업 영역 폴더 | 애플리케이션의 작업 디렉터리입니다. |
args |
string | 애플리케이션에 전달할 명령줄 인수입니다. | |
outputAppxDirectory |
string | 느슨한 레이아웃 패키지의 출력 디렉터리입니다. 기본값은 입력 폴더 내의 AppX 폴더입니다. |
|
port |
number | 9229 |
(node 만) Node.js --inspect 수신기 및 연결 연결에 사용되는 포트입니다. 기본 포트가 이미 사용 중인 경우 무시합니다. |
지원되는 디버거
debuggerType |
Language | 필수 확장 기능 |
|---|---|---|
coreclr(기본값) |
C# / .NET | C# 개발 키트 |
cppvsdbg |
C/C++ | C/C++ |
node |
Node.js / 전자 | 기본 제공 |
C++ 프로젝트의 예:
{
"type": "winapp",
"request": "launch",
"name": "WinApp: Launch C++ App",
"debuggerType": "cppvsdbg"
}
디버그 ID 만들기를 사용한 시작 디버깅
첫 번째 명령에서 시작 코드를 디버그해야 하는 경우 F5 연결 접근 방식이 초기 코드를 놓칠 수 있습니다. 대신 명령 팔레트()에서 Ctrl+Shift+P 명령을 사용하여 실행 파일에 대한 스파스 패키지를 등록한 다음, 표준 디버거로 시작합니다.
{
"name": "Launch (with identity)",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}/bin/Debug/net8.0-windows10.0.22621/myapp.exe"
}
create-debug-identity exe 자체에 ID를 등록하므로 앱에는 표준 VS Code 시작 구성을 포함하여 앱이 어떻게 시작되었는지에 관계없이 ID가 있습니다.
실행 중인 프로세스에 연결
터미널에서 winapp run로 시작한 후 연결하려면 표준 연결 구성을 사용하세요.
{
"name": "Attach to Process",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
C++/Rust의 경우 "type": "cppvsdbg" (MSVC)을 사용하거나 "type": "lldb" (LLDB)을 사용하십시오.
{
"name": "Attach (C++)",
"type": "cppvsdbg",
"request": "attach",
"processId": "${command:pickProcess}"
}
정리 중
테스트가 완료되면 명령 팔레트에서 WinApp: 패키지 등록 취소 를 실행하여 VS Code를 종료하지 않고 테스트용으로 로드된 개발 패키지를 제거합니다.
Windows developer