다음을 통해 공유


Natvis 프레임워크를 사용하여 디버거에서 C++ 개체의 사용자 지정 보기 만들기

Visual Studio Natvis 프레임워크는 LocalsWatch 창과 같은 디버거 변수 창과 DataTips네이티브 형식이 표시되는 방식을 사용자 지정합니다. Natvis 시각화를 사용하면 디버깅 중에 만드는 형식이 더 잘 표시되도록 할 수 있습니다.

Natvis는 이전 버전의 Visual Studio에서 autoexp.dat 파일을 XML 구문, 더 나은 진단, 버전 관리 및 여러 파일 지원으로 바꿉니다.

메모

Natvis 사용자 지정은 클래스 및 구조체에서 작동하지만 typedef는 작동하지 않습니다.

Natvis 시각화

Natvis 프레임워크를 사용하여, 개발자들이 디버깅 중에 사용자가 정의한 유형을 보다 쉽게 볼 수 있도록 시각화 규칙을 만듭니다.

예를 들어 다음 그림에서는 사용자 지정 시각화가 적용되지 않은 디버거 창에서 Windows::UI::XAML::Controls::TextBox 형식의 변수를 보여 줍니다.

TextBox 기본 시각화

강조 표시된 행에는 Text 클래스의 TextBox 속성이 표시됩니다. 복잡한 클래스 계층 구조로 인해 이 속성을 찾기가 어렵습니다. 디버거는 사용자 지정 문자열 형식을 해석하는 방법을 모르므로 텍스트 상자 내에 있는 문자열을 볼 수 없습니다.

Natvis 사용자 지정 시각화 도우미 규칙이 적용될 때 변수 창에서 동일한 TextBox 훨씬 더 간단해 보입니다. 클래스의 중요한 멤버가 함께 나타나고 디버거는 사용자 지정 문자열 형식의 기본 문자열 값을 표시합니다.

시각화 도우미를 사용하여 TextBox 데이터

C++ 프로젝트에서 .natvis 파일 사용

Natvis는 .natvis 파일을 사용하여 시각화 규칙을 지정합니다. .natvis 파일은 확장명은 .natvis XML 파일입니다. Natvis 스키마는 <VS 설치 폴더>\Xml\Schemas\1033\natvis.xsd정의됩니다.

.natvis 파일의 기본 구조는 시각화 항목을 나타내는 하나 이상의 Type 요소입니다. 각 Type 요소의 정규화된 이름은 해당 Name 특성에 지정됩니다.

<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
  <Type Name="MyNamespace::CFoo">
    .
    .
  </Type>

  <Type Name="...">
    .
    .
  </Type>
</AutoVisualizer>

Visual Studio는 > 폴더에 .natvis 파일을 제공합니다. 이러한 파일에는 많은 공통 형식에 대한 시각화 규칙이 있으며 새 형식에 대한 시각화를 작성하는 예제로 사용될 수 있습니다.

C++ 프로젝트에 .natvis 파일 추가

모든 C++ 프로젝트에 .natvis 파일을 추가할 수 있습니다.

.natvis 파일을 추가하려면

  1. 솔루션 탐색기C++ 프로젝트 노드를 선택하고 Project>새 항목추가를 선택하거나 프로젝트를 마우스 오른쪽 단추로 클릭하고 >새 항목추가를 선택합니다.

    항목 템플릿이 모두 보이지 않으면 모든 템플릿 표시를 클릭하세요.

  2. 새 항목 추가 대화 상자에서 Visual C++>유틸리티>디버거 시각화 파일(.natvis)를 선택합니다.

  3. 파일 이름을 지정하고 추가를 선택합니다.

    새 파일이 솔루션 탐색기추가되고 Visual Studio 문서 창에서 열립니다.

Visual Studio 디버거는 C++ 프로젝트의 .natvis 파일을 자동으로 로드하고, 기본 설정으로 프로젝트가 빌드될 때 해당 파일을 .pdb 파일에 포함시킵니다. 빌드된 앱을 디버그하는 경우 프로젝트가 열려 있지 않더라도 디버거는 .pdb 파일에서 .natvis 파일을 로드합니다. .natvis 파일을 .pdb파일에 포함하지 않으려면, 빌드된 .pdb 파일에서 제외할 수 있습니다.

.pdb.natvis 파일을 제외하려면:

  1. 솔루션 탐색기.natvis 파일을 선택하고 속성 아이콘을 선택하거나 파일을 마우스 오른쪽 단추로 클릭하고 속성선택합니다.

  2. 드롭다운 목록에서 빌드에서 제외 옆의 화살표를 클릭하고 를 선택한 다음 확인을 선택합니다.

메모

사용 가능한 C++ 프로젝트가 없기 때문에, 실행 파일 프로젝트를 디버깅하려면 솔루션 항목을 사용하여 .pdb에 없는 .natvis 파일을 추가합니다.

메모

.pdb 에서 로드된 Natvis 규칙은 .pdb 가 참조하는 모듈의 형식에만 적용됩니다. 예를 들어 Module1.pdb 파일에 Test형식에 대한 Natvis 항목이 있는 경우, 이는 Test 클래스에만 적용됩니다. 다른 모듈이 Test클래스도 정의하는 경우 Module1.pdb Natvis 항목은 적용되지 않습니다.

VSIX 패키지를 통해 .natvis 파일을 설치하고 등록하려면:

VSIX 패키지는 .natvis 파일을 설치하고 등록할 수 있습니다. 설치 위치에 관계없이 등록된 모든 .natvis 파일은 디버깅 중에 자동으로 선택됩니다.

  1. VSIX 패키지에 .natvis 파일을 포함합니다. 예를 들어 다음 프로젝트 파일의 경우:

    <?xml version="1.0" encoding="utf-8"?>
    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="14.0">
      <ItemGroup>
        <VSIXSourceItem Include="Visualizer.natvis" />
      </ItemGroup>
    </Project>
    
  2. .natvis 파일을 source.extension.vsixmanifest 파일에 등록합니다.

    <?xml version="1.0" encoding="utf-8"?>
    <PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
      <Assets>
        <Asset Type="NativeVisualizer" Path="Visualizer.natvis"  />
      </Assets>
    </PackageManifest>
    

Natvis 파일 위치

여러 프로젝트에 적용하려면 .natvis 파일을 사용자 디렉터리 또는 시스템 디렉터리에 추가할 수 있습니다.

.natvis 파일은 다음 순서로 평가됩니다.

  1. 로드된 프로젝트에 동일한 이름의 파일이 없는 한 .natvis는 디버깅할 .pdb에 포함된 파일을.

  2. 로드된 C++ 프로젝트 또는 최상위 솔루션 내에 있는 모든 .natvis 파일. 이 그룹에는 클래스 라이브러리를 포함하여 로드된 모든 C++ 프로젝트가 포함되지만 다른 언어의 프로젝트는 포함되지 않습니다.

  3. .natvis 파일은 VSIX 패키지를 통해 설치 및 등록되어 있습니다.

  1. 사용자별 Natvis 디렉터리(예: %USERPROFILE%\Documents\Visual Studio 2022\Visualizers)입니다.
  1. 사용자별 Natvis 디렉터리(예: %USERPROFILE%\Documents\Visual Studio 2019\Visualizers)입니다.
  1. 시스템 차원의 Natvis 디렉터리(<Microsoft Visual Studio 설치 폴더>\Common7\Packages\Debugger\Visualizers)입니다. 이 디렉터리에는 Visual Studio와 함께 설치된 .natvis 파일이 있습니다. 관리자 권한이 있는 경우 이 디렉터리에 파일을 추가할 수 있습니다.

디버깅하는 동안 .natvis 파일 수정

프로젝트를 디버깅하는 동안 IDE에서 .natvis 파일을 수정할 수 있습니다. 디버깅 중인 Visual Studio의 동일한 인스턴스에서 파일을 열고 수정한 다음 저장합니다. 파일이 저장되는 즉시 Watch 창과 Locals 창이 변경 내용을 반영하도록 업데이트됩니다.

디버깅 중인 솔루션에서 .natvis 파일을 추가하거나 삭제할 수 있으며, Visual Studio는 이에 따라 관련 시각화를 자동으로 추가하거나 제거합니다.

디버깅하는 동안 .pdb 파일에 포함된 .natvis 파일을 업데이트할 수 없습니다.

Visual Studio 외부에서 .natvis 파일을 수정하는 경우 변경 내용이 자동으로 적용되지 않습니다. 디버거 창을 업데이트하려면 직접 실행 창에서 .natvisreload 명령을 다시 평가하면 됩니다. 그러면 디버깅 세션을 다시 시작하지 않고 변경 내용이 적용됩니다.

또한 .natvisreload 명령을 사용하여 .natvis 파일을 최신 버전으로 업그레이드합니다. 예를 들어 .natvis 파일이 소스 제어에 체크인되었거나 다른 사용자가 최근에 변경한 내용을 반영하려고 합니다.

표현식 및 서식 지정

Natvis 시각화는 C++ 식을 사용하여 표시할 데이터 항목을 지정합니다. 디버거에서 C++ 식의 향상된 기능 및 제한 사항에 대해서는 Context 연산자(C++)에 설명되어 있으며, 이 외에도 다음 사항에 유의하세요.

  • Natvis 표현은 현재 스택 프레임이 아닌 시각화되는 객체의 맥락에서 평가됩니다. 예를 들어, Natvis 식에서 x은 시각화되는 개체의 x 필드를 참조하며, 현재 함수의 x이라는 로컬 변수를 참조하는 것이 아닙니다. 전역 변수에 액세스할 수는 있지만 Natvis 식에서 지역 변수에 액세스할 수 없습니다.

  • Natvis 식은 함수 평가 또는 부작용을 허용하지 않습니다. 함수 호출 및 할당 연산자는 무시됩니다. 디버거 내장 함수는 부작용이 없으므로 다른 함수 호출이 허용되지 않더라도 Natvis 식에서 자유롭게 호출될 수 있습니다.

  • 식이 표시되는 방식을 제어하려면 C++형식 지정자에 설명된 형식 지정자를 사용할 수 있습니다. Natvis에서 내부적으로 항목을 사용하는 경우, Size 식처럼 형식 지정자는 무시됩니다.

메모

Natvis 문서는 XML이므로 식에서 앰퍼샌드(&), 대괄호(>), 소괄호(<), 또는 쉬프트 연산자를 직접 사용할 수 없습니다. 항목 본문과 조건문 모두에서 이러한 문자를 이스케이프해야 합니다. 예를 들어:
\<Item Name="HiByte"\>(byte)(_flags \&gt;\&gt; 24),x\</Item\>
\<Item Name="HiByteStatus" Condition="(_flags \&amp; 0xFF000000) == 0"\>"None"\</Item\>
\<Item Name="HiByteStatus" Condition="(_flags \&amp; 0xFF000000) != 0"\>"Some"\</Item\>

Natvis 보기

여러 가지 방법으로 형식을 표시하도록 다양한 Natvis 뷰를 정의할 수 있습니다. 예를 들어 std::vector의 시각화는 simple이라는 단순화된 뷰로 정의됩니다. DisplayStringArrayItems 요소는 기본 보기와 simple 보기에 표시되지만 [size][capacity] 항목은 simple 보기에 표시되지 않습니다.

<Type Name="std::vector&lt;*&gt;">
    <DisplayString>{{ size={_Mylast - _Myfirst} }}</DisplayString>
    <Expand>
        <Item Name="[size]" ExcludeView="simple">_Mylast - _Myfirst</Item>
        <Item Name="[capacity]" ExcludeView="simple">_Myend - _Myfirst</Item>
        <ArrayItems>
            <Size>_Mylast - _Myfirst</Size>
            <ValuePointer>_Myfirst</ValuePointer>
        </ArrayItems>
    </Expand>
</Type>

조사식 창에서 ,view 서식 지정자를 사용하여 대체 보기를 지정합니다. 단순 보기는 vec, view(단순)표시됩니다.

간단한 보기가 있는 조사식 창

Natvis 오류

디버거는 시각화 항목에서 발생하는 오류를 무시합니다. 형식을 원시 형식으로 표시하거나 다른 적합한 시각화를 선택합니다. Natvis 진단을 사용하여 디버거가 시각화 항목을 무시한 이유를 이해하고 기본 구문 및 구문 분석 오류를 확인할 수 있습니다.

Natvis 진단을 켜려면:

  • 도구옵션(또는 디버그옵션) 출력 창디버깅에서 Natvis 진단 메시지를 설정합니다. (C++에만 해당) 오류, 경고또는 자세한 정보 표시 확인선택합니다.

오류는 출력 창에 표시됩니다.

Natvis 구문 참조

Natvis 파일에서 다음 요소와 특성을 사용할 수 있습니다.

AutoVisualizer 요소

AutoVisualizer 요소는 .natvis 파일의 루트 노드이며 네임스페이스 xmlns: 특성을 포함합니다.

<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
.
.
</AutoVisualizer>

AutoVisualizer 요소에는 Type, HResult, UIVisualizerCustomVisualizer 자식 요소가 있을 수 있습니다.

타입 요소

기본 Type 다음 예제와 같습니다.

<Type Name="[fully qualified type name]">
  <DisplayString Condition="[Boolean expression]">[Display value]</DisplayString>
  <Expand>
    ...
  </Expand>
</Type>

Type 요소는 다음을 지정합니다.

  1. 시각화에서 사용될 형식(Name 특성)은 무엇입니까?

  2. 해당 형식의 개체 값이 어떻게 표시되어야 하는지(DisplayString 요소)

  3. 사용자가 변수 창(Expand 노드)에서 형식을 확장할 때 형식의 멤버 모양입니다.

템플릿 클래스

Name 요소의 Type 특성은 템플릿 클래스 이름에 사용될 수 있는 와일드카드 문자로 별표 *를 허용합니다.

다음 예제에서는 개체가 CAtlArray<int> 또는 CAtlArray<float>관계없이 동일한 시각화가 사용됩니다. CAtlArray<float>대한 특정 시각화 항목이 있는 경우 제네릭 항목보다 우선합니다.

<Type Name="ATL::CAtlArray&lt;*&gt;">
    <DisplayString>{{Count = {m_nSize}}}</DisplayString>
</Type>

매크로 $T 1, $T 2 등을 사용하여 시각화 항목에서 템플릿 매개 변수를 참조할 수 있습니다. 이러한 매크로의 예제를 찾으려면 Visual Studio와 함께 제공되는 .natvis 파일을 참조하세요.

비주얼라이저 유형 일치

시각화 항목의 유효성을 검사하지 못하면 사용 가능한 다음 시각화가 사용됩니다.

상속 가능한 특성

선택적 Inheritable 특성은 시각화가 기본 형식에만 적용되는지, 기본 형식과 모든 파생 형식에만 적용되는지 여부를 지정합니다. Inheritable 기본값은 true.

다음 예제에서 시각화는 BaseClass 형식에만 적용됩니다.

<Type Name="Namespace::BaseClass" Inheritable="false">
    <DisplayString>{{Count = {m_nSize}}}</DisplayString>
</Type>

우선순위 속성

선택적 Priority 속성은 정의가 구문 분석에 실패할 경우 대체 정의를 사용하는 순서를 지정합니다. Priority의 가능한 값은 Low, MediumLow,Medium, MediumHighHigh입니다. 기본값은 Medium. Priority 특성은 동일한 .natvis 파일 내의 우선 순위만 구분합니다.

다음 예제에서는 먼저 2015 STL과 일치하는 항목을 구문 분석합니다. 구문 분석에 실패하면 STL의 2013 버전에 대한 대체 항목을 사용합니다.

<!-- VC 2013 -->
<Type Name="std::reference_wrapper&lt;*&gt;" Priority="MediumLow">
     <DisplayString>{_Callee}</DisplayString>
    <Expand>
        <ExpandedItem>_Callee</ExpandedItem>
    </Expand>
</Type>

<!-- VC 2015 -->
<Type Name="std::reference_wrapper&lt;*&gt;">
    <DisplayString>{*_Ptr}</DisplayString>
    <Expand>
        <Item Name="[ptr]">_Ptr</Item>
    </Expand>
</Type>

선택적 특성

모든 노드에 Optional 특성을 배치할 수 있습니다. 선택적 노드 내의 하위 식이 구문 분석에 실패하면, 디버거는 해당 노드를 무시하지만 나머지 Type 규칙을 계속 적용합니다. 다음 형식에서는 [State] 선택 사항이 아니지만 [Exception] 선택 사항입니다. MyNamespace::MyClass _M_exceptionHolder필드가 있는 경우 [State] 노드와 [Exception] 노드가 모두 표시되지만 _M_exceptionHolder 필드가 없으면 [State] 노드만 나타납니다.

<Type Name="MyNamespace::MyClass">
    <Expand>
      <Item Name="[State]">_M_State</Item>
      <Item Name="[Exception]" Optional="true">_M_exceptionHolder</Item>
    </Expand>
</Type>

조건 속성

선택적 Condition 특성은 많은 시각화 요소에 사용할 수 있으며 시각화 규칙을 사용할 시기를 지정합니다. 조건 속성 내의 식이 false로 해석되면 시각화 규칙이 적용되지 않습니다. true으로 평가되거나 Condition 특성이 없는 경우, 시각화가 적용됩니다. 시각화 항목에서 if-else 논리에 이 특성을 사용할 수 있습니다.

예를 들어 다음 시각화에는 스마트 포인터 형식에 대한 두 개의 DisplayString 요소가 있습니다. _Myptr 멤버가 비어 있으면 첫 번째 DisplayString 요소의 조건이 true로 해결되므로 양식이 표시됩니다. _Myptr 멤버가 비어 있지 않으면 조건이 false로 간주되고 두 번째 DisplayString 요소가 표시됩니다.

<Type Name="std::auto_ptr&lt;*&gt;">
  <DisplayString Condition="_Myptr == 0">empty</DisplayString>
  <DisplayString>auto_ptr {*_Myptr}</DisplayString>
  <Expand>
    <ExpandedItem>_Myptr</ExpandedItem>
  </Expand>
</Type>

IncludeView 및 ExcludeView 특성

IncludeViewExcludeView 특성은 특정 보기에 표시하거나 표시하지 않을 요소를 지정합니다. 예를 들어, 다음 std::vectorNatvis 사양에서는 simple 보기에서 [size][capacity] 항목이 표시되지 않습니다.

<Type Name="std::vector&lt;*&gt;">
    <DisplayString>{{ size={_Mylast - _Myfirst} }}</DisplayString>
    <Expand>
        <Item Name="[size]" ExcludeView="simple">_Mylast - _Myfirst</Item>
        <Item Name="[capacity]" ExcludeView="simple">_Myend - _Myfirst</Item>
        <ArrayItems>
            <Size>_Mylast - _Myfirst</Size>
            <ValuePointer>_Myfirst</ValuePointer>
        </ArrayItems>
    </Expand>
</Type>

형식 및 개별 멤버에서 IncludeViewExcludeView 특성을 사용할 수 있습니다.

Version 요소

Version 요소는 시각화 항목의 범위를 특정 모듈 및 버전으로 지정합니다. Version 요소는 이름 충돌을 방지하고, 실수로 인한 불일치를 줄이고, 다른 형식 버전에 대해 다양한 시각화를 허용합니다.

다른 모듈에서 사용되는 공통 헤더 파일이 형식을 정의하는 경우 형식이 지정된 모듈 버전에 있을 때만 버전이 지정된 시각화가 나타납니다.

다음 예제에서 시각화는 버전 1.0에서 1.5까지 해당하는 DirectUI::BorderWindows.UI.Xaml.dll 형식에만 적용됩니다.

<Type Name="DirectUI::Border">
  <Version Name="Windows.UI.Xaml.dll" Min="1.0" Max="1.5"/>
  <DisplayString>{{Name = {*(m_pDO->m_pstrName)}}}</DisplayString>
  <Expand>
    <ExpandedItem>*(CBorder*)(m_pDO)</ExpandedItem>
  </Expand>
</Type>

MinMax모두 필요하지 않습니다. 선택적 특성입니다. 와일드카드 문자는 지원되지 않습니다.

Name 특성은 filename.ext, 예를 들어 hello.exe 또는 some.dll형식입니다. 경로 이름은 허용되지 않습니다.

디스플레이 문자열 요소

DisplayString 요소는 변수 값으로 표시할 문자열을 지정합니다. 식과 혼합된 임의의 문자열을 허용합니다. 중괄호 안의 모든 항목은 식으로 해석됩니다. 예를 들어 다음과 같은 DisplayString 항목이 있습니다.

<Type Name="CPoint">
  <DisplayString>{{x={x} y={y}}}</DisplayString>
</Type>

형식 CPoint의 변수가 다음 그림처럼 표시된다는 것을 의미합니다.

DisplayString 요소 사용 사용

DisplayString 식에서 x의 멤버인 yCPoint가 중괄호 안에 있으므로, 그 값들이 평가됩니다. 이 예제에서는 이중 중괄호({{ 또는 }})를 사용하여 중괄호를 이스케이프하는 방법도 보여 줍니다.

메모

DisplayString 요소는 임의의 문자열과 중괄호 구문을 허용하는 유일한 요소입니다. 다른 모든 시각화 요소는 디버거가 평가할 수 있는 식만 허용합니다.

StringView 요소

StringView 요소는 디버거가 기본 제공 텍스트 시각화 도우미에 보낼 수 있는 값을 정의합니다. 예를 들어 ATL::CStringT 형식에 대한 다음 시각화가 제공됩니다.

<Type Name="ATL::CStringT&lt;wchar_t,*&gt;">
  <DisplayString>{m_pszData,su}</DisplayString>
</Type>

CStringT 개체는 다음 예제와 같이 변수 창에 표시됩니다.

CStringT DisplayString 요소

StringView 요소를 추가하면 디버거에 값을 텍스트 시각화로 표시할 수 있습니다.

<Type Name="ATL::CStringT&lt;wchar_t,*&gt;">
  <DisplayString>{m_pszData,su}</DisplayString>
  <StringView>m_pszData,su</StringView>
</Type>

디버깅하는 동안 변수 옆에 있는 돋보기 아이콘을 선택한 다음 텍스트 시각화 도우미 선택하여 m_pszData 가리키는 문자열을 표시할 수 있습니다.

StringView 시각화 도우미를 사용하여 CStringT 데이터

표현식 {m_pszData,su}su을 포함하는 C++ 형식 지정자를 사용하여 값을 유니코드 문자열로 표시합니다. 자세한 내용은 C++형식 지정자를 참조하세요.

요소 확장

선택적 Expand 노드는 변수 창에서 형식을 확장할 때 시각화된 형식의 자식을 사용자 지정합니다. Expand 노드는 자식 요소를 정의하는 자식 노드 목록을 허용합니다.

  • 시각화 항목에 Expand 노드가 지정되지 않은 경우 자식은 기본 확장 규칙을 사용합니다.

  • Expand 노드 아래에 자식 노드가 없으면 디버거 창에서 형식을 확장할 수 없습니다.

항목 확장

Item 요소는 Expand 노드에서 가장 기본적이고 일반적인 요소입니다. Item 단일 자식 요소를 정의합니다. 예를 들어, CRect 클래스는 필드 top, left, rightbottom가 있으며, 다음과 같은 시각화 항목이 있습니다.

<Type Name="CRect">
  <DisplayString>{{top={top} bottom={bottom} left={left} right={right}}}</DisplayString>
  <Expand>
    <Item Name="Width">right - left</Item>
    <Item Name="Height">bottom - top</Item>
  </Expand>
</Type>

디버거 창에서 CRect 형식은 다음 예제와 같습니다.

CRect와 Item 요소 확장

디버거는 WidthHeight 요소에 지정된 식을 평가하고 변수 창의 열에 있는 값을 표시합니다.

디버거는 모든 사용자 지정 확장에 대한 [원시 보기] 노드를 자동으로 만듭니다. 앞의 스크린샷은 개체의 기본 원시 뷰가 Natvis 시각화와 어떻게 다른지 보여주기 위해 확장된 [원시 보기] 노드 표시합니다. 기본 확장은 기본 클래스에 대한 하위 트리를 만들고 기본 클래스의 모든 데이터 멤버를 자식으로 나열합니다.

메모

항목 요소의 식이 복합 형식을 가리키는 경우 Item 노드 자체를 확장할 수 있습니다.

배열 항목 확장

ArrayItems 노드를 사용하여 Visual Studio 디버거가 형식을 배열로 해석하고 개별 요소를 표시하도록 합니다. std::vector 시각화가 좋은 예입니다.

<Type Name="std::vector&lt;*&gt;">
  <DisplayString>{{size = {_Mylast - _Myfirst}}}</DisplayString>
  <Expand>
    <Item Name="[size]">_Mylast - _Myfirst</Item>
    <Item Name="[capacity]">(_Myend - _Myfirst)</Item>
    <ArrayItems>
      <Size>_Mylast - _Myfirst</Size>
      <ValuePointer>_Myfirst</ValuePointer>
    </ArrayItems>
  </Expand>
</Type>

std::vector은 변수 창에서 확장될 때 그 개별 요소들을 보여줍니다.

std::vector를 사용하여 arrayItems 확장 std::vector를 사용하여 arrayItems 확장

ArrayItems 노드에는 다음이 있어야 합니다.

  • 배열의 길이를 이해하기 위해 디버거에 대한 Size 식(정수로 계산해야 합니다)입니다.
  • 첫 번째 요소(ValuePointer아닌 요소 형식의 포인터여야 합니다)를 가리키는 void* 식입니다.

배열 하한의 기본값은 0입니다. 값을 재정의하려면 LowerBound 요소를 사용합니다. Visual Studio와 함께 제공되는 .natvis 파일에는 예제가 있습니다.

메모

형식 자체(예: [])가 이 연산자를 허용하지 않더라도 vector[i]사용하는 1차원 배열 시각화와 함께 ArrayItemsCATLArray 연산자를 사용할 수 있습니다.

다차원 배열을 지정할 수도 있습니다. 이 경우 디버거는 자식 요소를 올바르게 표시하기 위해 약간 더 많은 정보가 필요합니다.

<Type Name="Concurrency::array&lt;*,*&gt;">
  <DisplayString>extent = {_M_extent}</DisplayString>
  <Expand>
    <Item Name="extent">_M_extent</Item>
    <ArrayItems Condition="_M_buffer_descriptor._M_data_ptr != 0">
      <Direction>Forward</Direction>
      <Rank>$T2</Rank>
      <Size>_M_extent._M_base[$i]</Size>
      <ValuePointer>($T1*) _M_buffer_descriptor._M_data_ptr</ValuePointer>
      <LowerBound>0</LowerBound>
    </ArrayItems>
  </Expand>
</Type>
  • Direction 배열이 행 주 순서인지 열 주 순서인지를 지정합니다.
  • Rank 배열의 순위를 지정합니다.
  • Size 요소는 암시적 $i 매개 변수를 허용합니다. 이 매개 변수는 차원 인덱스로 대체하여 해당 차원의 배열 길이를 찾습니다.
    • 이전 예제에서 _M_extent.M_base[0] 표현식은 0차원의 길이를, _M_extent._M_base[1]은 첫 번째 차원의 길이를, 그 다음으로 이어서 지정해야 합니다.
  • LowerBound 배열의 각 차원의 하한을 지정합니다. 다차원 배열의 경우 암시적 $i 매개 변수를 사용하는 식을 지정할 수 있습니다. $i 매개 변수는 차원 인덱스로 대체되어 해당 차원에서 배열의 하한을 찾습니다.
    • 이전 예제에서 모든 차원은 0에서 시작됩니다. 만약 하한으로 ($i == 1) ? 1000 : 100을 사용한다면, 0차원은 100에서 시작하고, 첫 번째 차원은 1000에서 시작됩니다.
      • 예: [100, 1000], [100, 1001], [100, 1002], ... [101, 1000], [101, 1001],...

디버거 창에서 2차원 Concurrency::array 개체의 모양은 다음과 같습니다.

2차원 배열 ArrayItems 확장을 사용한 2차원 배열

IndexListItems 확장

배열 요소가 메모리에 연속적으로 배치되는 경우에만 ArrayItems 확장을 사용할 수 있습니다. 디버거는 단순히 포인터를 증가시켜 다음 요소로 이동합니다. 값 노드에 대한 인덱스를 조작해야 하는 경우 IndexListItems 노드를 사용합니다. IndexListItems 노드를 사용하는 시각화는 다음과 같습니다.

<Type Name="Concurrency::multi_link_registry&lt;*&gt;">
  <DisplayString>{{size = {_M_vector._M_index}}}</DisplayString>
  <Expand>
    <Item Name="[size]">_M_vector._M_index</Item>
    <IndexListItems>
      <Size>_M_vector._M_index</Size>
      <ValueNode>*(_M_vector._M_array[$i])</ValueNode>
    </IndexListItems>
  </Expand>
</Type>

ArrayItemsIndexListItems의 유일한 차이점은 암시적 ValueNode 매개변수를 사용하여 i번째 요소로의 전체 표현식을 예상하는 $i입니다.

메모

형식 자체(예: [])가 이 연산자를 허용하지 않더라도 vector[i]사용하는 1차원 배열 시각화와 함께 IndexListItemsCATLArray 연산자를 사용할 수 있습니다.

LinkedList 항목 확장

시각화된 형식이 연결된 목록을 나타내는 경우 디버거는 LinkedListItems 노드를 사용하여 자식을 표시할 수 있습니다. CAtlList 형식에 대한 다음 시각화는 LinkedListItems사용합니다.

<Type Name="ATL::CAtlList&lt;*,*&gt;">
  <DisplayString>{{Count = {m_nElements}}}</DisplayString>
  <Expand>
    <Item Name="Count">m_nElements</Item>
    <LinkedListItems>
      <Size>m_nElements</Size>
      <HeadPointer>m_pHead</HeadPointer>
      <NextPointer>m_pNext</NextPointer>
      <ValueNode>m_element</ValueNode>
    </LinkedListItems>
  </Expand>
</Type>

Size 요소는 목록의 길이를 나타냅니다. HeadPointer 첫 번째 요소를 가리키고 NextPointer 다음 요소를 참조하고 ValueNode 항목의 값을 참조합니다.

디버거는 부모 목록 형식이 아닌 NextPointer 노드 요소의 컨텍스트에서 ValueNodeLinkedListItems 식을 평가합니다. 앞의 예제에서, CAtlList은 연결 목록의 노드인 CNode 클래스(atlcoll.h에 있음)를 가집니다. m_pNextm_elementCNode 클래스가 아닌 해당 CAtlList 클래스의 필드입니다.

ValueNode 비워 두거나 this 사용하여 LinkedListItems 노드 자체를 참조할 수 있습니다.

CustomListItems 확장

CustomListItems 확장을 사용하면 해시 테이블과 같은 데이터 구조를 트래버스하기 위한 사용자 지정 논리를 작성할 수 있습니다. CustomListItems을 사용하여 평가에 필요한 모든 것을 C++ 표현식으로 사용할 수 있지만 ArrayItems, IndexListItems, 또는 LinkedListItems의 유형에는 맞지 않는 데이터 구조를 시각화합니다.

Exec 사용하여 확장에 정의된 변수 및 개체를 사용하여 CustomListItems 확장 내에서 코드를 실행할 수 있습니다. Exec와 함께 논리 연산자, 산술 연산자 및 대입 연산자를 사용할 수 있습니다. C++ 식 계산기에서 지원하는 디버거 내장 함수를 제외하고 Exec 사용하여 함수를 평가할 없습니다.

CAtlMap의 다음 시각화는 CustomListItems이 적합한 좋은 사례입니다.

<Type Name="ATL::CAtlMap&lt;*,*,*,*&gt;">
    <AlternativeType Name="ATL::CMapToInterface&lt;*,*,*&gt;"/>
    <AlternativeType Name="ATL::CMapToAutoPtr&lt;*,*,*&gt;"/>
    <DisplayString>{{Count = {m_nElements}}}</DisplayString>
    <Expand>
      <CustomListItems MaxItemsPerView="5000" ExcludeView="Test">
        <Variable Name="iBucket" InitialValue="-1" />
        <Variable Name="pBucket" InitialValue="m_ppBins == nullptr ? nullptr : *m_ppBins" />
        <Variable Name="iBucketIncrement" InitialValue="-1" />

        <Size>m_nElements</Size>
        <Exec>pBucket = nullptr</Exec>
        <Loop>
          <If Condition="pBucket == nullptr">
            <Exec>iBucket++</Exec>
            <Exec>iBucketIncrement = __findnonnull(m_ppBins + iBucket, m_nBins - iBucket)</Exec>
            <Break Condition="iBucketIncrement == -1" />
            <Exec>iBucket += iBucketIncrement</Exec>
            <Exec>pBucket = m_ppBins[iBucket]</Exec>
          </If>
          <Item>pBucket,na</Item>
          <Exec>pBucket = pBucket->m_pNext</Exec>
        </Loop>
      </CustomListItems>
    </Expand>
</Type>

트리 항목 확장

시각화된 형식이 트리를 나타내는 경우 디버거는 TreeItems 노드를 사용하여 트리를 탐색하고 자식을 표시할 수 있습니다. std::map 노드를 사용하는 TreeItems 형식에 대한 시각화는 다음과 같습니다.

<Type Name="std::map&lt;*&gt;">
  <DisplayString>{{size = {_Mysize}}}</DisplayString>
  <Expand>
    <Item Name="[size]">_Mysize</Item>
    <Item Name="[comp]">comp</Item>
    <TreeItems>
      <Size>_Mysize</Size>
      <HeadPointer>_Myhead->_Parent</HeadPointer>
      <LeftPointer>_Left</LeftPointer>
      <RightPointer>_Right</RightPointer>
      <ValueNode Condition="!((bool)_Isnil)">_Myval</ValueNode>
    </TreeItems>
  </Expand>
</Type>

구문은 LinkedListItems 노드와 유사합니다. LeftPointer, RightPointerValueNode 트리 노드 클래스의 컨텍스트에서 평가됩니다. ValueNode 비워 두거나 this 사용하여 TreeItems 노드 자체를 참조할 수 있습니다.

확장된 항목 확장

ExpandedItem 요소는 기본 클래스 또는 데이터 멤버의 속성을 시각화된 형식의 자식인 것처럼 표시하여 집계된 자식 뷰를 생성합니다. 디버거는 지정된 식을 평가하고 결과의 자식 노드를 시각화된 형식의 자식 목록에 추가합니다.

예를 들어 스마트 포인터 형식 auto_ptr<vector<int>> 일반적으로 다음과 같이 표시됩니다.

auto_ptr<벡터<int>> 기본 확장

벡터의 값을 보려면 변수 창에서 두 단계로 들어가서 _Myptr 멤버를 지나야 합니다. ExpandedItem 요소를 추가하여 계층 구조에서 _Myptr 변수를 제거하고 벡터 요소를 직접 볼 수 있습니다.

<Type Name="std::auto_ptr&lt;*&gt;">
  <DisplayString>auto_ptr {*_Myptr}</DisplayString>
  <Expand>
    <ExpandedItem>_Myptr</ExpandedItem>
  </Expand>
</Type>

auto_ptr<벡터<int>> ExpandedItem 확장

다음 예제에서는 파생 클래스의 기본 클래스에서 속성을 집계하는 방법을 보여 있습니다. CPanel 클래스가 CFrameworkElement파생한다고 가정합니다. 기본 CFrameworkElement 클래스에서 오는 속성을 반복하는 대신 ExpandedItem 노드 시각화는 해당 속성을 CPanel 클래스의 자식 목록에 추가합니다.

<Type Name="CPanel">
  <DisplayString>{{Name = {*(m_pstrName)}}}</DisplayString>
  <Expand>
    <Item Name="IsItemsHost">(bool)m_bItemsHost</Item>
    <ExpandedItem>*(CFrameworkElement*)this,nd</ExpandedItem>
  </Expand>
</Type>

여기서는 파생 클래스에 대한 시각화 일치를 해제하는 nd 형식 지정자가 필요합니다. 그렇지 않으면, 식 *(CFrameworkElement*)this는 기본 시각화 형식 일치 규칙에 의해 가장 적합한 것으로 간주되어, CPanel 시각화가 다시 적용됩니다. 형식 지정자를 사용하여 디버거에 베이스 클래스 시각화를 사용하도록 지시하거나, 베이스 클래스에 시각화가 없는 경우 기본 확장 방식을 사용합니다.

가상 항목 확장

ExpandedItem 요소는 계층 구조를 제거하여 데이터의 단순한 뷰를 제공하지만 Synthetic 노드는 그 반대의 역할을 합니다. 이는 표현식의 결과가 아닌 인공 자식 요소를 만들 수 있게 합니다. 인공 요소는 그 자체로 자식 요소를 가질 수 있습니다. 다음 예제에서 Concurrency::array 형식의 시각화는 Synthetic 노드를 사용하여 사용자에게 진단 메시지를 표시합니다.

<Type Name="Concurrency::array&lt;*,*&gt;">
  <DisplayString>extent = {_M_extent}</DisplayString>
  <Expand>
    <Item Name="extent" Condition="_M_buffer_descriptor._M_data_ptr == 0">_M_extent</Item>
    <ArrayItems Condition="_M_buffer_descriptor._M_data_ptr != 0">
      <Rank>$T2</Rank>
      <Size>_M_extent._M_base[$i]</Size>
      <ValuePointer>($T1*) _M_buffer_descriptor._M_data_ptr</ValuePointer>
    </ArrayItems>
    <Synthetic Name="Array" Condition="_M_buffer_descriptor._M_data_ptr == 0">
      <DisplayString>Array members can be viewed only under the GPU debugger</DisplayString>
    </Synthetic>
  </Expand>
</Type>

동시성::배열과 인공 요소 확장

본질적 확장

식에서 호출할 수 있는 사용자 지정 내장 함수입니다. <Intrinsic> 요소에는 IDkmIntrinsicFunctionEvaluator140 인터페이스를 통해 함수를 구현하는 디버거 구성 요소가 함께 있어야 합니다. 사용자 지정 내장 함수 구현에 대한 자세한 내용은 NatVis 사용자 지정 내장 함수구현을 참조하세요.

<Type Name="std::vector&lt;*&gt;">
  <Intrinsic Name="size" Expression="(size_t)(_Mypair._Myval2._Mylast - _Mypair._Myval2._Myfirst)" />
  <Intrinsic Name="capacity" Expression="(size_t)(_Mypair._Myval2._Myend - _Mypair._Myval2._Myfirst)" />
  <DisplayString>{{ size={size()} }}</DisplayString>
  <Expand>
    <Item Name="[capacity]" ExcludeView="simple">capacity()</Item>
    <Item Name="[allocator]" ExcludeView="simple">_Mypair</Item>
    <ArrayItems>
      <Size>size()</Size>
      <ValuePointer>_Mypair._Myval2._Myfirst</ValuePointer>
    </ArrayItems>
  </Expand>
</Type>

HResult 요소

HResult 요소를 사용하면 디버거 창에서 HRESULT 대해 표시되는 정보를 사용자 지정할 수 있습니다. HRValue 요소는 사용자 지정할 HRESULT 32비트 값을 포함해야 합니다. HRDescription 요소에는 디버거 창에 표시할 정보가 포함되어 있습니다.


<HResult Name="MY_E_COLLECTION_NOELEMENTS">
  <HRValue>0xABC0123</HRValue>
  <HRDescription>No elements in the collection.</HRDescription>
</HResult>

UIVisualizer 요소

UIVisualizer 요소는 그래픽 시각화 도우미 플러그 인을 디버거에 등록합니다. 그래픽 시각화 도우미는 데이터 형식과 일치하는 방식으로 변수 또는 개체를 표시하는 대화 상자 또는 기타 인터페이스를 만듭니다. 시각화 도우미 플러그-인은 VSPackage로 작성되어야 하며, 디버거에서 사용할 수 있는 서비스를 제공해야 합니다. .natvis 파일에는 플러그 인의 이름, 노출된 서비스의 GUID(Globally Unique Identifier) 및 시각화할 수 있는 형식과 같은 플러그 인에 대한 등록 정보가 포함되어 있습니다.

다음은 UIVisualizer 요소의 예입니다.

<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
    <UIVisualizer ServiceId="{5452AFEA-3DF6-46BB-9177-C0B08F318025}"
        Id="1" MenuName="Vector Visualizer"/>
    <UIVisualizer ServiceId="{5452AFEA-3DF6-46BB-9177-C0B08F318025}"
        Id="2" MenuName="List Visualizer"/>
.
.
</AutoVisualizer>
  • ServiceId - Id 특성 쌍은 UIVisualizer식별합니다. ServiceId 시각화 도우미 패키지가 노출하는 서비스의 GUID입니다. Id 서비스에서 둘 이상을 제공하는 경우 시각화 도우미를 구분하는 고유 식별자입니다. 앞의 예제에서 동일한 시각화 도우미 서비스는 두 개의 시각화 도우미를 제공합니다.

  • MenuName 특성은 디버거의 돋보기 아이콘 옆에 있는 드롭다운 목록에 표시할 시각화 도우미 이름을 정의합니다. 예를 들어:

    UIVisualizer 메뉴 바로 가기 메뉴

.natvis 파일에 정의된 각 형식은 표시할 수 있는 UI 시각화 도우미를 명시적으로 나열해야 합니다. 디버거는 형식 항목에 있는 시각화 도우미 참조를 등록된 시각화 도우미와 대조합니다. 예를 들어 std::vector 다음 형식 항목은 이전 예제의 UIVisualizer 참조합니다.

<Type Name="std::vector&lt;int,*&gt;">
  <UIVisualizer ServiceId="{5452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1" />
</Type>

메모리 내 비트맵을 보는 데 사용되는 UIVisualizer 확장에서 예를 볼 수 있습니다.

CustomVisualizer 요소

CustomVisualizer Visual Studio Code에서 시각화를 제어하기 위해 작성하는 VSIX 확장을 지정하는 확장성 지점입니다. VSIX 확장 작성에 대한 자세한 내용은 visual Studio SDK참조하세요.

XML Natvis 정의보다 사용자 지정 시각화 도우미를 작성하는 작업은 훨씬 더 많지만 Natvis가 수행하거나 지원하지 않는 작업에 대한 제약 조건은 없습니다. 사용자 지정 시각화 도우미는 디버기 프로세스를 쿼리 및 수정하거나 Visual Studio의 다른 부분과 통신할 수 있는 디버거 확장성 API의 전체 집합에 액세스할 수 있습니다.

Condition 요소에서 IncludeView, ExcludeViewCustomVisualizer 특성을 사용할 수 있습니다.

제한사항

Natvis 사용자 지정은 클래스 및 구조체에서 작동하지만 typedef는 작동하지 않습니다.

Natvis는 기본 형식(예: int, bool) 또는 기본 형식에 대한 포인터에 대한 시각화 도우미를 지원하지 않습니다. 이 시나리오에서 한 가지 옵션은 사용 사례에 적합한 형식 지정자를 사용하는 것입니다. 예를 들어, 코드에서 double* mydoublearray을 사용하면 디버거의 조사식 창에서 배열 형식 지정자를 사용할 수 있습니다. 이때, 예를 들어 mydoublearray, [100]이라는 식을 사용하여 처음 100개 요소를 표시할 수 있습니다.