Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
A estrutura do Visual Studio Natvis personaliza a maneira como os tipos nativos aparecem nas janelas de variáveis do depurador, como as janelas Locals e Watch e no DataTips. As visualizações Natvis podem ajudar a tornar os tipos criados mais visíveis durante a depuração.
Natvis substitui o arquivo autoexp.dat em versões anteriores do Visual Studio com sintaxe XML, melhor diagnóstico, controle de versão e suporte a vários arquivos.
Observação
As personalizações Natvis funcionam com classes e structs, mas não typedefs.
Visualizações Natvis
Você usa a estrutura Natvis para criar regras de visualização para os tipos criados, para que os desenvolvedores possam vê-las mais facilmente durante a depuração.
Por exemplo, a ilustração a seguir mostra uma variável do tipo Windows::UI::XAML::Controls::TextBox em uma janela do depurador sem nenhuma visualização personalizada aplicada.
A linha realçada mostra a propriedade Text da classe TextBox. A hierarquia de classes complexa dificulta a localização dessa propriedade. O depurador não sabe como interpretar o tipo de cadeia de caracteres personalizada, portanto, você não pode ver a cadeia de caracteres mantida dentro da caixa de texto.
A mesma TextBox parece muito mais simples na janela variável quando as regras do visualizador personalizado Natvis são aplicadas. Os membros importantes da classe aparecem juntos e o depurador mostra o valor da cadeia de caracteres subjacente do tipo de cadeia de caracteres personalizada.
Usar arquivos .natvis em projetos C++
Natvis usa arquivos .natvis para especificar regras de visualização. Um ficheiro .natvis é um ficheiro XML com uma extensão .natvis. O esquema Natvis é definido em <Pasta de Instalação VS>\Xml\Schemas\1033\natvis.xsd.
A estrutura básica de um ficheiro .natvis é um ou mais elementos Type que representam entradas de visualização. O nome totalmente qualificado de cada elemento Type é especificado em seu atributo 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>
O Visual Studio fornece alguns arquivos .natvis na pasta de instalação do <VS>pasta de \Common7\Packages\Debugger\Visualizers. Esses arquivos têm regras de visualização para muitos tipos comuns e podem servir como exemplos para escrever visualizações para novos tipos.
Adicionar um arquivo .natvis a um projeto C++
Você pode adicionar um arquivo .natvis a qualquer projeto C++.
Para acrescentar um novo ficheiro .natvis:
Selecione o nó do projeto C++ no Gerenciador de Soluções e selecione Projeto>Adicionar novo itemou clique com o botão direito do mouse no projeto e selecione Adicionar>Novo item.
Se não vires todos os modelos de artigos, escolhe Mostrar todos os modelos.
Na caixa de diálogo Adicionar Novo Item, selecione Visual C++>Utility>Debugger visualization file (.natvis).
Dê um nome ao ficheiro e selecione Adicionar.
O novo arquivo é adicionado ao Gerenciador de Soluções e é aberto no painel de documentos do Visual Studio.
O depurador do Visual Studio carrega ficheiros .natvis em projetos C++ automaticamente e, por padrão, também os inclui no ficheiro .pdb quando o projeto é compilado. Se depurares a aplicação compilada, o depurador carrega o ficheiro .natvis a partir do ficheiro .pdb, mesmo que o projeto não esteja aberto. Caso não queiras que o ficheiro de .natvis seja incluído no .pdb, podes excluí-lo do ficheiro compilado de .pdb.
Para excluir um arquivo de .natvis de um .pdb:
Selecione o arquivo .natvis no Gerenciador de Soluções e selecione o ícone Propriedades , ou clique com o botão direito no arquivo e selecione Propriedades .
Na lista pendente, clique na seta ao lado de Excluído da compilação e selecione Sim, depois selecione OK.
Observação
Para depurar projetos executáveis, use os itens de solução para adicionar quaisquer arquivos .natvis que não estejam no .pdb, porque não há nenhum projeto C++ disponível.
Observação
As regras Natvis carregadas a partir de um .pdb se aplicam apenas aos tipos nos módulos aos quais o .pdb se refere. Por exemplo, se Module1.pdb tiver uma entrada Natvis para um tipo chamado Test, ele só se aplicará à classe Test em Module1.dll. Se outro módulo também definir uma classe chamada Test, a entrada Natvis Module1.pdb não se aplica a ele.
Para instalar e registrar um arquivo .natvis através de um pacote VSIX:
Um pacote VSIX pode instalar e registrar arquivos .natvis. Não importa onde eles estão instalados, todos os arquivos .natvis registrados são automaticamente coletados durante a depuração.
Inclua o ficheiro .natvis no pacote VSIX. Por exemplo, para o seguinte arquivo de projeto:
<?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>Registe o ficheiro .natvis no ficheiro 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>
Locais dos arquivos Natvis
Você pode adicionar arquivos .natvis ao seu diretório de usuário ou a um diretório do sistema, se quiser que eles se apliquem a vários projetos.
Os arquivos de .natvis são avaliados na seguinte ordem:
Quaisquer arquivos .natvis incorporados num .pdb que está a depurar, a menos que exista um ficheiro com o mesmo nome no projeto carregado.
Quaisquer arquivos .natvis que estão em um projeto de C++ carregado ou numa solução de nível superior. Esse grupo inclui todos os projetos C++ carregados, incluindo bibliotecas de classes, mas não projetos em outros idiomas.
Arquivos .natvis instalados e registados através do pacote VSIX.
- O diretório Natvis específico do usuário (por exemplo, %USERPROFILE%\Documents\Visual Studio 2022\Visualizers).
- O diretório Natvis específico do usuário (por exemplo, %USERPROFILE%\Documents\Visual Studio 2019\Visualizers).
- O diretório Natvis em todo o sistema (<pasta de instalação do Microsoft Visual Studio>\Common7\Packages\Debugger\Visualizers). Este diretório tem o .natvis arquivos instalados com o Visual Studio. Se você tiver permissões de administrador, poderá adicionar arquivos a esse diretório.
Modificar arquivos .natvis durante a depuração
Você pode modificar um arquivo .natvis no IDE enquanto depura o seu projeto. Abra o arquivo na mesma instância do Visual Studio com a qual você está depurando, modifique-o e salve-o. Assim que o arquivo é guardado, as janelas de observação Watch e locais Locals são atualizadas para refletir a alteração.
Você pode também adicionar ou excluir arquivos .natvis em uma solução enquanto depura, e o Visual Studio adiciona ou remove as visualizações relevantes.
Não é possível atualizar arquivos .natvis incorporados em arquivos .pdb enquanto estiver depurando.
Se você modificar o arquivo de .natvis fora do Visual Studio, as alterações não terão efeito automaticamente. Para atualizar as janelas do depurador, você pode reavaliar o comando .natvisreload na janela Immediate. As alterações entram em vigor sem reiniciar a sessão de depuração.
Use também o comando .natvisreload para atualizar o arquivo de .natvis para uma versão mais recente. Por exemplo, o arquivo de .natvis pode ser verificado no controle do código-fonte e você deseja pegar as alterações recentes feitas por outra pessoa.
Expressões e formatação
As visualizações Natvis usam expressões C++ para especificar os itens de dados a serem exibidos. Além das melhorias e limitações de expressões C++ no depurador, que são descritas em operador de contexto (C++), esteja ciente do seguinte:
As expressões Natvis são avaliadas no contexto do objeto que está sendo visualizado, não no quadro de pilha atual. Por exemplo,
xem uma expressão Natvis refere-se ao campo chamado x no objeto que está sendo visualizado, não a uma variável local chamada x na função atual. Não é possível acessar variáveis locais em expressões Natvis, embora seja possível acessar variáveis globais.As expressões Natvis não permitem avaliação de funções ou efeitos colaterais. Chamadas de função e operadores de atribuição são ignorados. Como funções intrínsecas do depurador são livres de efeitos colaterais, elas podem ser chamadas livremente a partir de qualquer expressão Natvis, mesmo que outras chamadas de função não sejam permitidas.
Para controlar como uma expressão é exibida, você pode usar qualquer um dos especificadores de formato descritos em especificadores de formato em C++. Os especificadores de formato são ignorados quando a entrada é usada internamente pelo Natvis, como na expressão
Sizeem uma expansão ArrayItems.
Observação
Como o documento Natvis é XML, as suas expressões não podem usar diretamente os operadores &, maior que, menor que, ou operadores de deslocamento. Você deve escapar desses caracteres no corpo do item e nas instruções de condição. Por exemplo:
\<Item Name="HiByte"\>(byte)(_flags \>\> 24),x\</Item\>
\<Item Name="HiByteStatus" Condition="(_flags \& 0xFF000000) == 0"\>"None"\</Item\>
\<Item Name="HiByteStatus" Condition="(_flags \& 0xFF000000) != 0"\>"Some"\</Item\>
Vistas Natvis
Você pode definir diferentes visualizações Natvis para exibir tipos de maneiras diferentes. Por exemplo, o trecho a seguir mostra uma visualização de std::vector que define uma vista simplificada chamada simple. Os elementos DisplayString e ArrayItems são exibidos no modo de exibição padrão e no modo de exibição simple, enquanto os itens [size] e [capacity] não são exibidos no modo de exibição simple.
<Type Name="std::vector<*>">
<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>
Na janela Observação, use o especificador de formato ,view para especificar um modo de exibição alternativo. A vista simples aparece como vec,view(simple):
Erros Natvis
Quando o depurador encontra erros em uma entrada de visualização, ele os ignora. Ele exibe o tipo em sua forma bruta ou escolhe outra visualização adequada. Você pode usar o diagnóstico Natvis para entender por que o depurador ignorou uma entrada de visualização e para ver erros de sintaxe e análise subjacentes.
Para ativar o diagnóstico Natvis:
Abra o painel Ferramentas>Opções e expanda a Todos os Ajustes>Depuração>Geral seção. A açãoOpções de > abre o painel para a mesma seção.
Em Janela de Saída>Configurações Gerais de Saída, defina a opção Mensagens de diagnóstico Natvis (somente C++) como Erro, Aviso ou Detalhado.
Abra a caixa de diálogo Ferramentas>Opções e expanda a seção Depuração>Geral. A ação
Opções de Depuração abre a caixa de diálogo para a mesma secção. Na Janela de Saída>Configurações Gerais de Saída, defina a opção Mensagens de diagnóstico Natvis (somente C++) como Erro, Aviso ou Verbosamente.
Selecione OK.
Os erros aparecem na janela Output.
Referência de sintaxe Natvis
Os seguintes elementos e atributos podem ser usados no arquivo Natvis.
Elemento AutoVisualizer
O elemento AutoVisualizer é o nó raiz do arquivo de .natvis do e contém o atributo xmlns: namespace.
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
.
.
</AutoVisualizer>
O elemento AutoVisualizer pode ter Tipo, HResult, UIVisualizere CustomVisualizer como elementos filhos.
Elemento de Tipo
Um Type básico se parece com este exemplo:
<Type Name="[fully qualified type name]">
<DisplayString Condition="[Boolean expression]">[Display value]</DisplayString>
<Expand>
...
</Expand>
</Type>
O elemento Type especifica:
Para que tipo a visualização deve ser usada (o atributo
Name).Qual deve ser a aparência do valor de um objeto desse tipo (o elemento
DisplayString).Qual deve ser a aparência dos membros do tipo quando o usuário expande o tipo em uma janela variável (o nó
Expand).
Classes modeladas
O atributo Name do elemento Type aceita um asterisco * como um caractere curinga que pode ser usado para nomes de classe com modelo.
No exemplo a seguir, a mesma visualização é usada se o objeto for um CAtlArray<int> ou um CAtlArray<float>. Se houver uma entrada de visualização específica para um CAtlArray<float>, ela terá precedência sobre a genérica.
<Type Name="ATL::CAtlArray<*>">
<DisplayString>{{Count = {m_nSize}}}</DisplayString>
</Type>
Você pode fazer referência a parâmetros de modelo na entrada de visualização usando macros $T 1, $T 2 e assim por diante. Para encontrar exemplos dessas macros, consulte os arquivos .natvis fornecidos com o Visual Studio.
Tipo de correspondência do visualizador
Se uma entrada de visualização falhar na validação, a próxima visualização disponível será usada.
Atributo hereditário
O atributo Inheritable opcional especifica se uma visualização se aplica apenas a um tipo base ou a um tipo base e todos os tipos derivados. O valor padrão de Inheritable é true.
No exemplo a seguir, a visualização se aplica somente ao tipo BaseClass:
<Type Name="Namespace::BaseClass" Inheritable="false">
<DisplayString>{{Count = {m_nSize}}}</DisplayString>
</Type>
Atributo de prioridade
O atributo Priority opcional especifica a ordem na qual usar definições alternativas, se uma definição falhar na análise. Os valores possíveis de Priority são: Low, MediumLow,Medium, MediumHighe High. O valor padrão é Medium. O atributo Priority distingue apenas entre prioridades dentro do mesmo arquivo .natvis .
O exemplo a seguir analisa primeiro a entrada que corresponde à STL de 2015. Se isso não conseguir ser analisado, ele usa a entrada alternativa para a versão 2013 do STL.
<!-- VC 2013 -->
<Type Name="std::reference_wrapper<*>" Priority="MediumLow">
<DisplayString>{_Callee}</DisplayString>
<Expand>
<ExpandedItem>_Callee</ExpandedItem>
</Expand>
</Type>
<!-- VC 2015 -->
<Type Name="std::reference_wrapper<*>">
<DisplayString>{*_Ptr}</DisplayString>
<Expand>
<Item Name="[ptr]">_Ptr</Item>
</Expand>
</Type>
Atributo opcional
Você pode colocar um atributo Optional em qualquer nó. Se uma subexpressão dentro de um nó opcional falhar ao analisar, o depurador ignorará esse nó, mas aplicará o restante das regras de Type. No tipo a seguir, [State] não é opcional, mas [Exception] é opcional. Se MyNamespace::MyClass tiver um campo chamado _M_exceptionHolder, tanto o nó [State] quanto o nó [Exception] aparecerão, mas se não houver campo _M_exceptionHolder, somente o nó [State] aparecerá.
<Type Name="MyNamespace::MyClass">
<Expand>
<Item Name="[State]">_M_State</Item>
<Item Name="[Exception]" Optional="true">_M_exceptionHolder</Item>
</Expand>
</Type>
Atributo de condição
O atributo Condition opcional está disponível para muitos elementos de visualização e especifica quando usar uma regra de visualização. Se a expressão dentro do atributo de condição se resolver em false, a regra de visualização não se aplicará. Se ele for avaliado como true, ou se não houver nenhum Condition atributo, a visualização será aplicada. Você pode usar esse atributo para lógica if-else nas entradas de visualização.
Por exemplo, a visualização seguinte tem dois elementos DisplayString para um tipo de smart pointer. Quando o membro _Myptr está vazio, a condição do primeiro elemento DisplayString é resolvida para true, para que o formulário seja exibido. Quando o _Myptr membro não está vazio, a condição é avaliada como false, e o segundo DisplayString elemento é exibido.
<Type Name="std::auto_ptr<*>">
<DisplayString Condition="_Myptr == 0">empty</DisplayString>
<DisplayString>auto_ptr {*_Myptr}</DisplayString>
<Expand>
<ExpandedItem>_Myptr</ExpandedItem>
</Expand>
</Type>
Atributos IncludeView e ExcludeView
Os atributos IncludeView e ExcludeView especificam elementos a serem exibidos ou não em modos de exibição específicos. Por exemplo, na seguinte especificação Natvis de std::vector, a visualização simple não exibe os itens [size] e [capacity].
<Type Name="std::vector<*>">
<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>
Você pode usar os atributos IncludeView e ExcludeView em tipos e em membros individuais.
Elemento de Versão
O elemento Version define o escopo de uma entrada de visualização para um módulo e uma versão específicos. O elemento Version ajuda a evitar colisões de nomes, reduz incompatibilidades inadvertidas e permite visualizações diferentes para diferentes versões de tipo.
Se um arquivo de cabeçalho comum usado por módulos diferentes definir um tipo, a visualização versionada aparecerá somente quando o tipo estiver na versão do módulo especificado.
No exemplo a seguir, a visualização é aplicável somente para o tipo DirectUI::Border encontrado no Windows.UI.Xaml.dll da versão 1.0 a 1.5.
<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>
Você não precisa de Min e Max. São atributos opcionais. Não há suporte para caracteres curinga.
O atributo Name está no formato filename.ext, como hello.exe ou some.dll. Nenhum nome de caminho é permitido.
Elemento DisplayString
O elemento DisplayString especifica uma cadeia de caracteres para mostrar como o valor de uma variável. Aceita cadeias de caracteres arbitrárias misturadas com expressões. Tudo dentro de chaves encaracolado é interpretado como uma expressão. Por exemplo, a seguinte entrada DisplayString:
<Type Name="CPoint">
<DisplayString>{{x={x} y={y}}}</DisplayString>
</Type>
Significa que as variáveis do tipo CPoint são exibidas como nesta ilustração:
Na expressão DisplayString, x e y, que são membros da CPoint, estão dentro de aparelhos encaracolados, por isso seus valores são avaliados. O exemplo também mostra como você pode escapar de uma cinta encaracolado usando chaves duplas ( {{ ou }} ).
Observação
O elemento DisplayString é o único elemento que aceita cadeias de caracteres arbitrárias e sintaxe de chaves curvas. Todos os outros elementos de visualização aceitam apenas expressões que o depurador pode avaliar.
Elemento StringView
O elemento StringView define um valor que o depurador pode enviar para o visualizador de texto interno. Por exemplo, dada a seguinte visualização para o tipo ATL::CStringT:
<Type Name="ATL::CStringT<wchar_t,*>">
<DisplayString>{m_pszData,su}</DisplayString>
</Type>
O objeto CStringT é exibido em uma janela variável como este exemplo:
Adicionar um elemento StringView informa ao depurador que ele pode exibir o valor como uma visualização de texto.
<Type Name="ATL::CStringT<wchar_t,*>">
<DisplayString>{m_pszData,su}</DisplayString>
<StringView>m_pszData,su</StringView>
</Type>
Durante a depuração, podes selecionar o ícone de lupa ao lado da variável e, em seguida, selecionar Visualizador de Texto para exibir a string para a qual m_pszData aponta.
A expressão {m_pszData,su} inclui um especificador de formato C++ su, para exibir o valor como uma cadeia de caracteres Unicode. Para obter mais informações, consulte especificadores de formato do C++.
Expandir elemento
O nó Expand opcional personaliza os filhos de um tipo visualizado quando você expande o tipo em uma janela variável. O nó Expand aceita uma lista de nós filho que definem os elementos filho.
Se um nó
Expandnão for especificado em uma entrada de visualização, os filhos usarão as regras de expansão padrão.Se um nó
Expandfor especificado sem nós filhos abaixo dele, o tipo não é expansível nas janelas do depurador.
Expansão do item
O elemento Item é o elemento mais básico e comum em um nó Expand.
Item define um único elemento filho. Por exemplo, uma classe CRect com campos top, left, righte bottom tem a seguinte entrada de visualização:
<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>
Na janela do depurador, o tipo CRect se parece com este exemplo:
O depurador avalia as expressões especificadas nos elementos Width e Height e mostra os valores na coluna Value da janela da variável.
O depurador cria automaticamente o nó [Raw View] para cada expansão personalizada. A captura de ecrã anterior mostra o nó [Raw View] expandido, para mostrar como a visualização básica padrão do objeto difere da sua visualização Natvis. A expansão padrão cria uma subárvore para a classe base e lista todos os membros de dados da classe base como filhos.
Observação
Se a expressão do elemento item apontar para um tipo complexo, o nó Item em si será expansível.
Expansão de Itens do Array
Use o nó ArrayItems para que o depurador do Visual Studio interprete o tipo como uma matriz e exiba seus elementos individuais. A visualização para std::vector é um bom exemplo:
<Type Name="std::vector<*>">
<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>
Um std::vector mostra os seus elementos individuais quando expandido na janela de variáveis.
O nó ArrayItems deve ter:
- Uma expressão
Size(que deve ser avaliada como um inteiro) para que o depurador compreenda o comprimento da matriz. - Uma
ValuePointerexpressão que aponta para o primeiro elemento (que deve ser um ponteiro de um tipo de elemento diferente devoid*).
O valor padrão do limite inferior da matriz é 0. Para substituir o valor, use um elemento LowerBound. Os arquivos .natvis fornecidos com o Visual Studio têm exemplos.
Observação
Você pode usar o [] operador, por exemplo vector[i], com qualquer visualização de matriz unidimensional que use ArrayItems, mesmo que o próprio tipo (por exemplo CATLArray) não permita esse operador.
Você também pode especificar matrizes multidimensionais. Nesse caso, o depurador precisa de um pouco mais de informações para exibir corretamente os elementos filho:
<Type Name="Concurrency::array<*,*>">
<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>
-
Directionespecifica se a matriz está em ordem por linhas ou em ordem por colunas. -
Rankespecifica a classificação da matriz. - O elemento
Sizeaceita o parâmetro$iimplícito, que substitui pelo índice de dimensão para encontrar o comprimento da matriz nessa dimensão.- No exemplo anterior, a expressão
_M_extent.M_base[0]deve dar o comprimento da 0ª dimensão,_M_extent._M_base[1]a primeira, e assim por diante.
- No exemplo anterior, a expressão
- O
LowerBoundespecifica o limite inferior de cada dimensão da matriz. Para matrizes multidimensionais, você pode especificar uma expressão que use o parâmetro$iimplícito. O$iparâmetro é substituído pelo índice de dimensão para encontrar o limite inferior da matriz nessa dimensão.- No exemplo anterior, todas as dimensões começam em 0. No entanto, se você tinha
($i == 1) ? 1000 : 100como limite inferior, a 0ª dimensão começa em 100, e a primeira dimensão começa em 1000.- , como
[100, 1000], [100, 1001], [100, 1002], ... [101, 1000], [101, 1001],...
- , como
- No exemplo anterior, todas as dimensões começam em 0. No entanto, se você tinha
Veja como um objeto Concurrency::array bidimensional aparece na janela do depurador:
Expansão IndexListItems
Você pode usar a expansão ArrayItems apenas se os elementos da matriz estiverem dispostos contiguamente na memória. O depurador chega ao próximo elemento simplesmente incrementando seu ponteiro. Se precisar manipular o índice para o nó de valor, utilize os nós IndexListItems. Aqui está uma visualização com um nó IndexListItems:
<Type Name="Concurrency::multi_link_registry<*>">
<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>
A única diferença entre ArrayItems e IndexListItems é o ValueNode, que espera a expressão completa para o ielemento com o parâmetro $i implícito.
Observação
Você pode usar o [] operador, por exemplo vector[i], com qualquer visualização de matriz unidimensional que use IndexListItems, mesmo que o próprio tipo (por exemplo CATLArray) não permita esse operador.
Expansão de LinkedListItems
Se o tipo visualizado representar uma lista vinculada, o depurador poderá exibir seus filhos usando um nó LinkedListItems. A seguinte visualização para o tipo CAtlList usa LinkedListItems:
<Type Name="ATL::CAtlList<*,*>">
<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>
O elemento Size refere-se ao comprimento da lista.
HeadPointer aponta para o primeiro elemento, NextPointer refere-se ao próximo elemento e ValueNode refere-se ao valor do item.
O depurador avalia as expressões NextPointer e ValueNode no contexto do elemento nó LinkedListItems, não o tipo de lista pai. No exemplo anterior, CAtlList tem uma classe CNode (encontrada em atlcoll.h) que é um nó da lista vinculada.
m_pNext e m_element são campos dessa classe CNode, não da classe CAtlList.
ValueNode pode ser deixado vazio ou pode-se usar this para referir-se ao nó LinkedListItems em si.
Expansão de Itens da Lista Personalizada
A expansão CustomListItems permite escrever lógica personalizada para percorrer uma estrutura de dados, como uma hashtable. Use CustomListItems para visualizar estruturas de dados que podem usar expressões C++ para tudo o que você precisa avaliar, mas não se encaixam perfeitamente no molde para ArrayItems, IndexListItemsou LinkedListItems.
Você pode usar Exec para executar código dentro de uma expansão CustomListItems, usando as variáveis e objetos definidos na expansão. Você pode usar operadores lógicos, operadores aritméticos e operadores de atribuição com Exec. Não é possível usar Exec para avaliar funções, exceto no caso de funções intrínsecas do depurador suportadas pelo avaliador de expressões C++.
O visualizador a seguir para CAtlMap é um excelente exemplo onde CustomListItems é apropriado.
<Type Name="ATL::CAtlMap<*,*,*,*>">
<AlternativeType Name="ATL::CMapToInterface<*,*,*>"/>
<AlternativeType Name="ATL::CMapToAutoPtr<*,*,*>"/>
<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>
Expansão TreeItems
Se o tipo visualizado representar uma árvore, o depurador poderá percorrer a árvore e exibir seus filhos usando um nó TreeItems. Aqui está a visualização para o tipo de std::map usando um nó TreeItems:
<Type Name="std::map<*>">
<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>
A sintaxe é semelhante ao nó LinkedListItems.
LeftPointer, RightPointere ValueNode são avaliados no contexto da classe de nó de árvore.
ValueNode pode ser deixado vazio ou usar this para se referir ao nó TreeItems em si.
Expansão de Item Expandido
O elemento ExpandedItem gera uma exibição de filhos agregados ao exibir propriedades de classes base ou membros de dados como se fossem filhos do tipo visualizado. O depurador avalia a expressão especificada e acrescenta à lista de filhos do tipo visualizado os nós filhos do resultado.
Por exemplo, o tipo de ponteiro inteligente auto_ptr<vector<int>> normalmente é exibido como:
de expansão padrão
Para ver os valores do vetor, é necessário descer dois níveis na janela de variáveis, passando pelo membro _Myptr. Ao adicionar um elemento ExpandedItem, você pode eliminar a variável _Myptr da hierarquia e exibir diretamente os elementos vetoriais:
<Type Name="std::auto_ptr<*>">
<DisplayString>auto_ptr {*_Myptr}</DisplayString>
<Expand>
<ExpandedItem>_Myptr</ExpandedItem>
</Expand>
</Type>
O exemplo a seguir mostra como agregar propriedades da classe base em uma classe derivada. Suponha que a classe CPanel deriva de CFrameworkElement. Em vez de repetir as propriedades que vêm da classe base CFrameworkElement, a visualização do nó ExpandedItem adiciona essas propriedades à lista de filhos da classe CPanel.
<Type Name="CPanel">
<DisplayString>{{Name = {*(m_pstrName)}}}</DisplayString>
<Expand>
<Item Name="IsItemsHost">(bool)m_bItemsHost</Item>
<ExpandedItem>*(CFrameworkElement*)this,nd</ExpandedItem>
</Expand>
</Type>
O especificador de formato e, que desativa a correspondência de visualização para a classe derivada, é necessário aqui. Caso contrário, a expressão *(CFrameworkElement*)this faria com que a visualização CPanel fosse aplicada novamente, porque as regras de correspondência de tipo de visualização padrão a consideram a mais apropriada. Use o especificador de formato e para instruir o depurador a usar a visualização da classe base ou a expansão padrão, caso a classe base não tenha visualização.
Expansão de itens sintéticos
Enquanto o elemento ExpandedItem fornece uma visão mais plana dos dados eliminando hierarquias, o nó Synthetic faz o oposto. Ele permite que você crie um elemento filho artificial que não é resultado de uma expressão. O elemento artificial pode ter elementos filhos próprios. No seguinte exemplo, a visualização para o tipo Concurrency::array utiliza um nó Synthetic para mostrar uma mensagem de diagnóstico ao utilizador:
<Type Name="Concurrency::array<*,*>">
<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>
Expansão intrínseca
Uma função intrínseca personalizada que pode ser chamada a partir de uma expressão. Um elemento <Intrinsic> deve ser acompanhado por um componente depurador que implementa a função através da interface IDkmIntrinsicFunctionEvaluator140. Para obter mais informações sobre como implementar uma função intrínseca personalizada, consulte Implementar função intrínseca personalizada NatVis.
<Type Name="std::vector<*>">
<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>
Elemento HResult
O elemento HResult permite personalizar as informações mostradas para um HRESULT nas janelas de depuração. O elemento HRValue deve conter o valor de 32 bits do HRESULT que deve ser personalizado. O elemento HRDescription contém as informações a serem exibidas na janela do depurador.
<HResult Name="MY_E_COLLECTION_NOELEMENTS">
<HRValue>0xABC0123</HRValue>
<HRDescription>No elements in the collection.</HRDescription>
</HResult>
Elemento UIVisualizer
Um elemento UIVisualizer registra um plug-in do visualizador gráfico com o depurador. Um visualizador gráfico cria uma caixa de diálogo ou outra interface que mostra uma variável ou objeto de forma consistente com seu tipo de dados. O plug-in do visualizador deve ser elaborado como um VSPackagee deve expor um serviço que o depurador possa consumir. O arquivo .natvis contém informações de registro para o plug-in, como seu nome, o identificador global exclusivo (GUID) do serviço exposto e os tipos que ele pode visualizar.
Aqui está um exemplo de um elemento 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>
Um par de atributos
ServiceId-Ididentifica umUIVisualizer. OServiceIdé o GUID do serviço que o pacote do visualizador expõe.Idé um identificador exclusivo que diferencia os visualizadores, se um serviço fornecer mais de um. No exemplo anterior, o mesmo serviço de visualização fornece dois visualizadores.O atributo
MenuNamedefine um nome de visualizador a ser exibido na lista suspensa ao lado do ícone de lupa no depurador. Por exemplo:
Cada tipo definido no arquivo de .natvis do deve listar explicitamente todos os visualizadores de interface do usuário que podem exibi-lo. O depurador compara as referências dos visualizadores nas entradas de tipo com os visualizadores registados. Por exemplo, a entrada de tipo a seguir para std::vector faz referência ao UIVisualizer no exemplo anterior.
<Type Name="std::vector<int,*>">
<UIVisualizer ServiceId="{5452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1" />
</Type>
Você pode ver um exemplo de um UIVisualizer na extensão de observação de imagens do usada para exibir bitmaps na memória.
Elemento CustomVisualizer
CustomVisualizer é um ponto de extensibilidade que especifica uma extensão VSIX que você grava para controlar visualizações no Visual Studio Code. Para obter mais informações sobre como escrever extensões VSIX, consulte o Visual Studio SDK.
É muito mais trabalhoso escrever um visualizador personalizado do que uma definição XML do Natvis, mas você está livre de restrições sobre o que o Natvis faz ou não suporta. Os visualizadores personalizados têm acesso ao conjunto completo de APIs de extensibilidade do depurador, que podem consultar e modificar o processo de depuração ou se comunicar com outras partes do Visual Studio.
Você pode usar os atributos Condition, IncludeViewe ExcludeView em CustomVisualizer elementos.
Limitações
As personalizações Natvis funcionam com classes e structs, mas não typedefs.
Natvis não suporta visualizadores para tipos primitivos (por exemplo, int, bool) ou para ponteiros para tipos primitivos. Nesse cenário, uma opção é usar o especificador de formato apropriado para seu caso de uso. Por exemplo, se você usar double* mydoublearray no seu código, pode utilizar um especificador de formato de array na janela de observação do depurador, como a expressão mydoublearray, [100], que mostra os primeiros 100 elementos.