Implementace vlastní vnitřní funkce NatVis pro C++
V tomto článku se dozvíte o pokynech pro implementaci vlastní vnitřní funkce ve vizualizaci NatVis. Další informace o NatVis naleznete v tématu Vytvoření vlastních zobrazení objektů C++.
Syntax
Soubor NatVis může definovat vnitřní funkci pomocí následující syntaxe:
<Intrinsic Name="Func" Expression="arg + 1">
<Parameter Name="arg" Type="int" />
</Intrinsic>
Jakmile definice existuje, může jakýkoli výraz ladicího programu volat funkci, stejně jako jakoukoli jinou funkci. Například pomocí předchozí definice NatVis se výraz Func(3)
vyhodnotí jako 4.
Prvek <Intrinsic>
se může objevit buď na úrovni souboru, nebo uvnitř <Type>
elementu před jinými prvky. Vnitřní funkce definované v rámci <Type>
definují členské funkce daného typu, zatímco vnitřní funkce definované mimo <Type>
definují globální funkce. Například:
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="std::vector<*>">
<Intrinsic Name="size" Expression="_Mypair._Myval2._Mylast - _Mypair._Myval2._Myfirst" />
<Intrinsic Name="capacity" Expression="_Mypair._Myval2._Myend - _Mypair._Myval2._Myfirst" />
</Type>
<Intrinsic Name="LOWORD" Expression="arg & 0xFFFF">
<Parameter Name="arg" Type="unsigned int" />
</Intrinsic>
</AutoVisualizer>
V předchozím příkladu jsou size()
a capacity()
definovány jako členské funkce třídy std::vector
, takže pokaždé, když výraz vyhodnotí vector.size()
, ve skutečnosti vyhodnotí vector._Mypair._Myval2._Mylast - vector._Mypair._Myval2._Myfirst
, místo provádění func-eval.
Podobně LOWORD(0x12345678)
vrátí 0x5678
, také bez func-eval.
Další příklad naleznete vnitřní rozšíření.
Pokyny pro použití vnitřní funkce
Při použití vnitřní funkce mějte na paměti následující pokyny:
Vnitřní funkce mohou být přetíženy buď pomocí funkcí definovaných PDB, nebo samy mezi sebou.
Když vnitřní funkce koliduje s funkcí definovanou pdB se stejným názvem a seznamem argumentů, vnitřní funkce vyhraje. Funkci PDB nelze vyhodnocovat, pokud existuje ekvivalentní vnitřní funkce.
Nemůžete zjistit adresu intrinsické funkce; můžete ji pouze zavolat.
Vnitřní členské funkce musí patřit do výchozího zobrazení příslušného typu, aby mohly být vyhodnoceny ve výrazu. Například položka typu s omezením
IncludeView
nemusí určovat vnitřní funkci.Vnitřní funkce mohou být volány z libovolného výrazu, včetně výrazů NatVis. Vnitřní funkce se také mohou navzájem volat. Vnitřní funkce, které používají rekurze, se v současné době nepodporují. Například:
<!-- OK --> <Intrinsic Name="Func2" Expression="this->Func3(arg + 1)"> <Parameter Name="arg" Type="int" /> </Intrinsic> <Intrinsic Name="Func3" Expression="arg + 1"> <Parameter Name="arg" Type="int"/> </Intrinsic> <!-- Unsupported --> <Intrinsic Name="Func2" Expression="this->Func3(arg + 1)"> <Parameter Name="arg" Type="int" /> </Intrinsic> <Intrinsic Name="Func3" Expression="Func2(arg + 1)"> <Parameter Name="arg" Type="int"/> </Intrinsic> <!-- Also unsupported--> <Intrinsic Name="Fib" Expression="(n <= 1) ? 1 : Fib(n - 1) + Fib(n - 2)"> <Parameter Name="n" Type="int"/> </Intrinsic>
Ve výchozím nastavení se předpokládá, že vnořené funkce jsou bez vedlejších účinků. To znamená, že mohou být volány v kontextech, které nepovolují vedlejší účinky, a výraz implementace nesmí obsahovat vedlejší účinky.
Definice může toto chování přepsat zadáním atributu
SideEffect
v deklaraci. Pokud je funkce označena jako mající vedlejší účinky, vedlejší účinky ve výrazech implementace se povolí. Vyvolání funkce v kontextech, kde jsou zakázány vedlejší účinky, však již není povoleno.Když definice dvou vnitřních funkcí vzájemně kolidují (stejný název, stejný podpis), poslední z nich vyhraje (ve stejném souboru).
V různých souborech instance v souboru s vyšší prioritou vyhraje (projekt je vyšší než uživatelský adresář, který je vyšší než instalační adresář). Pokud definice s vyšší prioritou obsahuje výraz, který se neanalyduje, je tato definice ignorována a místo toho se použije definice s nejvyšší prioritou.
Pokyny k implementaci vnitřní funkce
Vnitřní funkce podporují dvě možné formy implementace:
Založené na výrazech
Soubor NatVis definuje výraz, který se vyhodnotí jako návratová hodnota funkce. Výraz může použít libovolné argumenty předané do něj a deklarované jako
<Parameter>
prvky. Funkce definované v rámci třídy se také předpokládají jako "instance" funkce a mohou přistupovat také k "tomuto" ukazateli.Založené na rozšíření
Soubor NatVis poskytuje pokyny pro skutečné vyhodnocení funkce vyvoláním rozšíření ladicího programu. Rozšíření ladicího programu má úplný přístup k rozhraní Concord API a má možnost provádět úlohy, které nejsou v rámci výrazu NatVis možné.
Pokud chcete poskytnout implementaci založenou na rozšíření, měl by prvek <Intrinsic>
vynechat atribut Expression
a místo toho zadat SourceId
, LanguageId
, Id
a ReturnType
atributy, jak je uvedeno v následujícím příkladu:
<Intrinsic Name="MyFunc" SourceId="a665fa54-6e7d-480e-a80b-1fc1202e9646" LanguageId="3a12d0b7-c26c-11d0-b442-00a0244a1dd2" Id="1000" ReturnType="double">
<Parameter Type="int" />
<Parameter Type="int" />
<Parameter Type="int" />
</Intrinsic>
K implementaci funkce musí rozšíření ladicího programu implementovat IDkmIntrinsicFunctionEvaluator140
rozhraní pomocí LanguageId
a SourceId
filtrů, které odpovídají hodnotám elementu <Intrinsic>
v souboru NatVis. Při volání funkce se volání přeloží do Execute()
metody komponenty:
STDMETHOD(Execute)(
_In_ Evaluation::IL::DkmILExecuteIntrinsic* pExecuteIntrinsic,
_In_ Evaluation::DkmILContext* pILContext,
_In_ Evaluation::IL::DkmCompiledILInspectionQuery* pInspectionQuery,
_In_ const DkmArray<Evaluation::IL::DkmILEvaluationResult*>& Arguments,
_In_opt_ DkmReadOnlyCollection<Evaluation::DkmCompiledInspectionQuery*>* pSubroutines,
_Out_ DkmArray<Evaluation::IL::DkmILEvaluationResult*>* pResults,
_Out_ Evaluation::IL::DkmILFailureReason* pFailureReason
);
Komponenta přijímá bajty jednotlivých argumentů prostřednictvím argumentu Arguments
. Pokud je daná funkce členskou funkcí, ukazatel this
je uveden jako první, následovaný explicitními argumenty. Komponenta by měla vrátit výsledek přidělením pole o jednom prvku v pResults
, ukládající bajty návratové hodnoty.
K implementaci funkcí použijte následující pokyny:
Není možné "kombinovat a spárovat" dvě formy implementace. To znamená, že nemůžete zahrnout výraz i ID zdroje.
Zadání návratového typu pro implementaci založenou na výrazu je povoleno, ale nevyžaduje se. Pokud je zadán návratový typ, návratový typ výrazu se musí přesně shodovat (není povoleno implicitní přetypování). Pokud není zadaný návratový typ, je návratový typ odvozen z výrazu. Jakákoli implementace založená na rozšíření musí uvést návratový typ v souboru NatVis.
Jsou povolena nerekurzivní volání jiných vnitřních funkcí. Rekurze není povolená.
Pokud má funkce vedlejší účinky, je nutné zadat
SideEffect="true"
v deklaraci. Je nezákonné, aby implementace založená na výrazu měla vedlejší účinky ve výrazu bez deklarování funkce, že má vedlejší účinky. Vyvolání implementace založené na rozšíření tak, aby měla vedlejší účinky, aniž by deklarovala funkci jako nežádoucí účinky, je nedefinované chování a mělo by se jim vyhnout.Vnitřní funkce Varargs jsou povolené. Chcete-li deklarovat funkci varargs, zadejte
Varargs="true"
v deklaraci. I když je legální, aby implementace založená na výrazech deklarovala funkcivararg
, v současné době mají způsob přístupu k argumentům proměnné pouze implementace založené na rozšíření. Při implementaci založené na rozšíření funkceExecute()
obdrží všechny argumenty, které jsou skutečně předány, nejen deklarované argumenty.Vnitřní funkce, které jako typ argumentu využívají typ třídy, struktury nebo sjednocení, nejsou podporované. Vrácení typu třídy, struktury nebo sjednocení je v pořádku. (Ukazatel nebo odkaz na typ třídy,struktury/sjednocení je v pořádku jako typ argumentu).
Přizpůsobte ikonu volání vnitřních funkcí.
Ve výchozím nastavení je při volání vnitřní funkce výraz uvedena růžová kosočtverec ikona v Kukátko okno přidružené k volání funkce. Toto chování můžete přepsat zadáním atributu Category
pomocí jedné z následujících hodnot:
- Metoda. Použijte ikonu růžového kosočtverce, která se obvykle používá s voláními metod (výchozí).
- Vlastnost. Použijte černou ikonu klíče, která se obvykle používá s vlastnostmi.
- Data. Použijte ikonu modrého kosočtverce, která se obvykle používá s daty.
Kombinací vnitřních funkcí s elementem <Item>
je možné vytvořit soubor NatVis, kde výrazy položek mají ikonu vlastnosti klíče:
<Type Name="MyClass">
<Intrinsic Name="GetValue" ReturnType="int" Expression="m_value" Category="Property" />
<Expand>
<Item Name="Value">this->GetValue()</Item>
</Expand>
</Type>
Poznámka
Umístění ikony na úroveň funkce, nikoli na úroveň <Item>
, zabraňuje problémům, kdy se při vyhodnocení celého názvu ztratí přizpůsobení ikony. Protože úplný název obsahuje volání funkce, má stejné přizpůsobení ikony jako samotný <Item>
.