C++/WinRT용 Visual Studio 네이티브 디버그 시각화(natvis)

C++/WinRT Visual Studio Extension(VSIX)은 C++/WinRT 프로젝션 유형의 Visual Studio 네이티브 디버그 시각화(natvis)를 제공합니다. 이를 통해 C# 디버깅과 비슷한 환경을 제공합니다.

참고 항목

VSIX(C++/WinRT Visual Studio Extension)에 대한 자세한 내용은 Visual Studio의 C++/WinRT 지원 및 VSIX를 참조하세요.

natvis 사용

_DEBUG 기호를 정의하면 WINRT_NATVIS가 정의되므로 디버그 빌드에 대해서는 natvis가 자동으로 설정됩니다.

릴리스 빌드에 대해 옵트인하는 방법은 다음과 같습니다.

  • WINRT_NATVIS 기호가 정의된 상태로 코드를 컴파일합니다. 이렇게 하면 디버그 시각화 도우미가 대상 프로세스에서 속성 값을 평가할 수 있는 진입점을 제공하는 WINRT_abi_val 함수를 내보냅니다.
  • 전체 PDB를 생성합니다. 이렇게 하는 것은 디버그 시각화 도우미에서 Visual Studio C++ 식 계산기를 사용하므로 이 계산기에는 표시된 속성 형식에 대한 기호 정의가 필요합니다.
  • 시각화된 형식은 검색 가능한 메타데이터에 정의된 인터페이스나 런타임 클래스를 반드시 보고해야 합니다. IInspectable::GetRuntimeClassName을 구현하여 이 작업을 수행합니다.

위에서 설명한 것처럼 디버그 시각화 도우미는 C:\Windows\System32\WinMetadata 폴더에 메타데이터가 위치하는 Windows 시스템 유형에서 가장 잘 작동합니다. 하지만 .winmd 파일을 제대로 찾을 수 있으면 사용자 정의 형식과 원격 디버깅도 지원할 수 있습니다.

사용자 지정 메타데이터 사용

디버그 시각화 도우미는 .exe 프로세스와 함께 사용자 정의 메타데이터(.winmd 파일)를 찾습니다. RoGetMetaDataFile과 유사한 알고리즘을 사용하여 정규화된 typename의 연속 부분 문자열을 검색합니다. 예를 들어 시각화할 형식이 Contoso.Controls.Widget인 경우 시각화 도우미는 다음을 순서대로 찾습니다.

  • Contoso.Controls.Widget.winmd
  • Contoso.Controls.winmd
  • Contoso.winmd

사용자 지정 메타데이터를 사용하여 원격 디버깅

원격 디버깅을 수행할 경우 .exe 프로세스는 로컬이 아니므로 앞 섹션에서 설명된 사용자 지정 메타데이터 검색이 실패합니다. 이 경우 시각화 도우미는 로컬 캐시 폴더(%TEMP%)로 돌아가 적절한 .winmd 파일을 찾습니다. 파일이 발견되면 파일의 크기와 날짜를 기록한 후 원격 디버깅 대상에서 바이너리와 함께 동일한 .winmd를 검색합니다. 필요한 경우 원격 파일을 다운로드하여 로컬 캐시를 업데이트합니다. 이 전략은 로컬로 캐시된 .winmd을(를) 항상 최신 상태로 유지하며 다음을 수동으로 캐시할 수 있는 방법을 제공할 수 있습니다.winmd 원격으로 찾을 수 없는 경우(예: F5 배포에 포함되지 않은 경우) 수동으로 캐싱할 수 있게 해줍니다.

캐싱 동작 예는 아래의 문제 해결 섹션을 참조하세요.

문제 해결

디버그 시각화 도우미는 Visual Studio C++ 식 계산기를 사용하여 내보낸 WINRT_abi_val 함수를 호출하고 속성 값을 가져옵니다. 일반적으로 시각화 도우미는 처리되지 않은 예외를 포착하고 Visual Studio Watch 창에 "<개체가 초기화되지 않았거나 정보를 사용할 수 없음>"을 표시하면서 정상적으로 저하될 수 있습니다.

이 동작은 시각화 도우미가 수명 범위(예: 생성 전)를 벗어난 로컬 변수를 평가하려고 하는 경우에 유용합니다. 단위 테스트와 같은 일부 컨텍스트에서는 처리되지 않은 예외 필터가 설치됩니다. 이 때문에 C++ 식 계산기 오류로 인해 프로세스가 종료될 수 있습니다. 오류를 방지하기 위해 시각화 도우미는 WINRT_abi_val에서 VirtualQuery 호출을 여러 번 수행합니다.

진단

속성이 올바르게 표시되지 않는 경우 Visual Studio에서 자세한 natvis 진단 정보를 켠 후(도구>옵션>디버깅>출력 창>Natvis 진단 메시지) 출력 창에서 natvis 오류를 살펴봅니다.

다음 발췌 부분에서는 .winmd 파일을 검색하고 원격 대상에서 로컬 캐시 폴더로 다운로드한 후 해당 .winmd 파일을 로드하는 여러 시도를 보여줍니다.

Natvis C++/WinRT: Looking for C:\Users\...\AppData\Local\DevelopmentFiles\ffcddd4f-cfc0-44cb-b736-0b2d026def77VS.Debug_x64....\Consoso.Controls.Widget.winmd
Natvis C++/WinRT: Looking for C:\Users\...\AppData\Local\DevelopmentFiles\ffcddd4f-cfc0-44cb-b736-0b2d026def77VS.Debug_x64....\Consoso.Controls.winmd
Natvis C++/WinRT: Downloading C:\Users\...\AppData\Local\DevelopmentFiles\ffcddd4f-cfc0-44cb-b736-0b2d026def77VS.Debug_x64....\Consoso.Controls.winmd
Natvis C++/WinRT: Loaded C:\Users\...\AppData\Local\Temp\Consoso.Controls.winmd

시각화 도우미가 .winmd 파일을 찾지 못하면 이 오류가 생성됩니다.

Natvis C++/WinRT: Could not find metadata for Consoso.Controls.Widget

전체 진단을 생성하는 다른 여러 가지 오류 시나리오가 있습니다.

메타데이터를 사용할 수 있는 경우에는 출력 진단에 다음과 같은 여러 호출이 나타납니다.

Natvis C++/WinRT: WINRT_abi_val(*(::IUnknown**)0x32dd4ffc18, L"{96369F54-8EB6-48F0-ABCE-C1B211E627C3}", 0).s,sh
Natvis C++/WinRT: WINRT_abi_val(*(::IUnknown**)0x32dd4ffc18, L"{AF86E2E0-B12D-4C6A-9C5A-D7AA65101E90}", -2).s,sh

첫 번째는 복합 형식의 문자열 표현(확장되지 않은 표시 값)을 가져오는 IStringable.ToString 호출입니다.

두 번째는 형식의 속성에 반영하기 위한 IInspectable::GetRuntimeClassName 호출입니다.

이후의 WINRT_abi_val 호출은 형식에서 검색된 각 인터페이스에 대한 속성 평가를 위한 호출입니다.

WINRT_abi_val 호출

Visual Studio 직접/명령 창에서 WINRT_abi_val을 직접 호출하여 문제를 해결할 수 있습니다.

예를 들어 다음과 같이 프로젝션된 변수 stringable에서 IStringable.ToString을 평가할 수 있습니다.

>? WINRT_abi_val((::IUnknown*)&stringable, L"{96369F54-8EB6-48F0-ABCE-C1B211E627C3}", 0).s,sh
L"string"