Skip to content

Commit b69f40d

Browse files
authored
per request, provide implementation-side visualizations. and always show raw data. (#1128)
1 parent 27adc6b commit b69f40d

File tree

4 files changed

+45
-43
lines changed

4 files changed

+45
-43
lines changed

natvis/cppwinrt.natvis

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
<CustomVisualizer Condition="this != 0" VisualizerId="2ec1a02f-997c-4693-840e-88ffa1e21b56"/>
1515
<DisplayString Condition="this == 0">null</DisplayString>
1616
</Type>
17+
<!-- Visualize C++/WinRT object implementations -->
18+
<Type Name="winrt::impl::producer&lt;*&gt;">
19+
<CustomVisualizer Condition="this != 0" VisualizerId="2ec1a02f-997c-4693-840e-88ffa1e21b56"/>
20+
<DisplayString Condition="this == 0">null</DisplayString>
21+
</Type>
1722
<!--Visualize all raw IInspectable pointers-->
1823
<Type Name="IInspectable">
1924
<CustomVisualizer Condition="this != 0" VisualizerId="2ec1a02f-997c-4693-840e-88ffa1e21b56"/>

natvis/cppwinrt_visualizer.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,21 +207,26 @@ HRESULT cppwinrt_visualizer::EvaluateVisualizedExpression(
207207
IF_FAIL_RET(pTypeSymbol->get_name(&bstrTypeName));
208208

209209
// Visualize top-level C++/WinRT objects containing ABI pointers
210-
bool isAbiObject;
210+
ObjectType objectType;
211211
if (wcscmp(bstrTypeName, L"winrt::Windows::Foundation::IInspectable") == 0)
212212
{
213-
isAbiObject = false;
213+
objectType = ObjectType::Projection;
214214
}
215215
// Visualize nested object properties via raw ABI pointers
216216
else if ((wcscmp(bstrTypeName, L"winrt::impl::IInspectable") == 0) ||
217217
(wcscmp(bstrTypeName, L"winrt::impl::inspectable_abi") == 0))
218218
{
219-
isAbiObject = true;
219+
objectType = ObjectType::Abi;
220+
}
221+
// Visualize C++/WinRT object implementations
222+
else if (wcsncmp(bstrTypeName, L"winrt::impl::producer<", wcslen(L"winrt::impl::producer<")) == 0)
223+
{
224+
objectType = ObjectType::Abi;
220225
}
221226
// Visualize all raw IInspectable pointers
222227
else if (wcscmp(bstrTypeName, L"IInspectable") == 0)
223228
{
224-
isAbiObject = true;
229+
objectType = ObjectType::Abi;
225230
}
226231
else
227232
{
@@ -231,7 +236,7 @@ HRESULT cppwinrt_visualizer::EvaluateVisualizedExpression(
231236
return S_OK;
232237
}
233238

234-
IF_FAIL_RET(object_visualizer::CreateEvaluationResult(pVisualizedExpression, isAbiObject, ppResultObject));
239+
IF_FAIL_RET(object_visualizer::CreateEvaluationResult(pVisualizedExpression, objectType, ppResultObject));
235240

236241
return S_OK;
237242
}

natvis/object_visualizer.cpp

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,14 @@ static HRESULT EvaluatePropertyExpression(
9999
_In_ PropertyData const& prop,
100100
_In_ DkmVisualizedExpression* pExpression,
101101
_In_ DkmPointerValueHome* pObject,
102-
bool isAbiObject,
102+
ObjectType objectType,
103103
_Out_ com_ptr<DkmEvaluationResult>& pEvaluationResult
104104
)
105105
{
106106
wchar_t abiAddress[40];
107107
auto process = pExpression->RuntimeInstance()->Process();
108108
bool is64Bit = ((process->SystemInformation()->Flags() & DefaultPort::DkmSystemInformationFlags::Is64Bit) != 0);
109-
swprintf_s(abiAddress, is64Bit ? L"%s0x%I64x" : L"%s0x%08x", isAbiObject ? L"(::IUnknown*)" : L"*(::IUnknown**)", pObject->Address());
109+
swprintf_s(abiAddress, is64Bit ? L"%s0x%I64x" : L"%s0x%08x", objectType == ObjectType::Abi ? L"(::IUnknown*)" : L"*(::IUnknown**)", pObject->Address());
110110
wchar_t wszEvalText[500];
111111
std::wstring propCast;
112112
PCWSTR propField;
@@ -174,12 +174,12 @@ static HRESULT EvaluatePropertyString(
174174
_In_ PropertyData const& prop,
175175
_In_ DkmVisualizedExpression* pExpression,
176176
_In_ DkmPointerValueHome* pObject,
177-
bool isAbiObject,
177+
ObjectType objectType,
178178
_Out_ com_ptr<DkmString>& pValue
179179
)
180180
{
181181
com_ptr<DkmEvaluationResult> pEvaluationResult;
182-
IF_FAIL_RET(EvaluatePropertyExpression(prop, pExpression, pObject, isAbiObject, pEvaluationResult));
182+
IF_FAIL_RET(EvaluatePropertyExpression(prop, pExpression, pObject, objectType, pEvaluationResult));
183183
if (pEvaluationResult->TagValue() != DkmEvaluationResult::Tag::SuccessResult)
184184
{
185185
return E_FAIL;
@@ -195,11 +195,11 @@ static HRESULT EvaluatePropertyString(
195195
static std::string GetRuntimeClass(
196196
_In_ DkmVisualizedExpression* pExpression,
197197
_In_ DkmPointerValueHome* pObject,
198-
bool isAbiObject
198+
ObjectType objectType
199199
)
200200
{
201201
com_ptr<DkmString> pValue;
202-
EvaluatePropertyString({ IID_IInspectable, -2, PropertyCategory::String }, pExpression, pObject, isAbiObject, pValue);
202+
EvaluatePropertyString({ IID_IInspectable, -2, PropertyCategory::String }, pExpression, pObject, objectType, pValue);
203203
if (!pValue || pValue->Length() == 0)
204204
{
205205
return "";
@@ -210,16 +210,11 @@ static std::string GetRuntimeClass(
210210
static HRESULT ObjectToString(
211211
_In_ DkmVisualizedExpression* pExpression,
212212
_In_ DkmPointerValueHome* pObject,
213-
bool isAbiObject,
214-
_Out_ com_ptr<DkmString>& pValue,
215-
bool* unavailable = nullptr
213+
ObjectType objectType,
214+
_Out_ com_ptr<DkmString>& pValue
216215
)
217216
{
218-
if (unavailable)
219-
{
220-
*unavailable = false;
221-
}
222-
if (SUCCEEDED(EvaluatePropertyString({ IID_IStringable, 0, PropertyCategory::String }, pExpression, pObject, isAbiObject, pValue)))
217+
if (SUCCEEDED(EvaluatePropertyString({ IID_IStringable, 0, PropertyCategory::String }, pExpression, pObject, objectType, pValue)))
223218
{
224219
if (pValue && pValue->Length() > 0)
225220
{
@@ -229,25 +224,21 @@ static HRESULT ObjectToString(
229224

230225
// WINRT_abi_val returned 0, which may be success or failure (due to VirtualQuery validation)
231226
// Call back for the runtime class name to determine which it was
232-
if (!GetRuntimeClass(pExpression, pObject, isAbiObject).empty())
227+
if (!GetRuntimeClass(pExpression, pObject, objectType).empty())
233228
{
234229
return DkmString::Create(L"<Expand object to view properties>", pValue.put());
235230
}
236231
}
237232

238233
// VirtualQuery validation failed (as determined by no runtime class name) or an
239234
// exception escaped WINRT_abi_val (e.g, bad pointer, which we try to avoid via VirtualQuery)
240-
if (unavailable)
241-
{
242-
*unavailable = true;
243-
}
244235
return DkmString::Create(L"<Object uninitialized or information unavailable>", pValue.put());
245236
}
246237

247238
static HRESULT CreateChildVisualizedExpression(
248239
_In_ PropertyData const& prop,
249240
_In_ DkmVisualizedExpression* pParent,
250-
bool isAbiObject,
241+
ObjectType objectType,
251242
_Deref_out_ DkmChildVisualizedExpression** ppResult
252243
)
253244
{
@@ -256,7 +247,7 @@ static HRESULT CreateChildVisualizedExpression(
256247
com_ptr<DkmEvaluationResult> pEvaluationResult;
257248
auto valueHome = make_com_ptr(pParent->ValueHome());
258249
com_ptr<DkmPointerValueHome> pParentPointer = valueHome.as<DkmPointerValueHome>();
259-
IF_FAIL_RET(EvaluatePropertyExpression(prop, pParent, pParentPointer.get(), isAbiObject, pEvaluationResult));
250+
IF_FAIL_RET(EvaluatePropertyExpression(prop, pParent, pParentPointer.get(), objectType, pEvaluationResult));
260251
if (pEvaluationResult->TagValue() != DkmEvaluationResult::Tag::SuccessResult)
261252
{
262253
return E_FAIL;
@@ -273,7 +264,7 @@ static HRESULT CreateChildVisualizedExpression(
273264
{
274265
isNonNullObject = true;
275266
IF_FAIL_RET(DkmPointerValueHome::Create(childObjectAddress, pChildPointer.put()));
276-
IF_FAIL_RET(ObjectToString(pParent, pChildPointer.get(), true, pValue));
267+
IF_FAIL_RET(ObjectToString(pParent, pChildPointer.get(), ObjectType::Abi, pValue));
277268
}
278269
}
279270
if(!isNonNullObject)
@@ -335,7 +326,7 @@ static HRESULT CreateChildVisualizedExpression(
335326

336327
if (isNonNullObject)
337328
{
338-
com_ptr<object_visualizer> pObjectVisualizer = make_self<object_visualizer>(pChildVisualizedExpression.get(), true);
329+
com_ptr<object_visualizer> pObjectVisualizer = make_self<object_visualizer>(pChildVisualizedExpression.get(), ObjectType::Abi);
339330
IF_FAIL_RET(pChildVisualizedExpression->SetDataItem(DkmDataCreationDisposition::CreateNew, pObjectVisualizer.get()));
340331
}
341332
else
@@ -492,7 +483,7 @@ void object_visualizer::GetPropertyData()
492483
{
493484
auto valueHome = make_com_ptr(m_pVisualizedExpression->ValueHome());
494485
com_ptr<DkmPointerValueHome> pObject = valueHome.as<DkmPointerValueHome>();
495-
auto rc = GetRuntimeClass(m_pVisualizedExpression.get(), pObject.get(), m_isAbiObject);
486+
auto rc = GetRuntimeClass(m_pVisualizedExpression.get(), pObject.get(), m_objectType);
496487
if (rc.empty())
497488
{
498489
return;
@@ -539,9 +530,9 @@ void object_visualizer::GetTypeProperties(Microsoft::VisualStudio::Debugger::Dkm
539530
}
540531
}
541532

542-
HRESULT object_visualizer::CreateEvaluationResult(_In_ DkmVisualizedExpression* pVisualizedExpression, _In_ bool isAbiObject, _Deref_out_ DkmEvaluationResult** ppResultObject)
533+
HRESULT object_visualizer::CreateEvaluationResult(_In_ DkmVisualizedExpression* pVisualizedExpression, _In_ ObjectType objectType, _Deref_out_ DkmEvaluationResult** ppResultObject)
543534
{
544-
com_ptr<object_visualizer> pObjectVisualizer = make_self<object_visualizer>(pVisualizedExpression, isAbiObject);
535+
com_ptr<object_visualizer> pObjectVisualizer = make_self<object_visualizer>(pVisualizedExpression, objectType);
545536

546537
IF_FAIL_RET(pVisualizedExpression->SetDataItem(DkmDataCreationDisposition::CreateNew, pObjectVisualizer.get()));
547538

@@ -582,7 +573,7 @@ HRESULT object_visualizer::CreateEvaluationResult(_Deref_out_ DkmEvaluationResul
582573
auto address = pPointerValueHome->Address();
583574

584575
com_ptr<DkmString> pValue;
585-
DkmEvaluationResultFlags_t evalResultFlags = DkmEvaluationResultFlags::ReadOnly;
576+
DkmEvaluationResultFlags_t evalResultFlags = DkmEvaluationResultFlags::ReadOnly | DkmEvaluationResultFlags::Expandable;;
586577
if (requires_refresh(address, m_pVisualizedExpression->InspectionContext()->EvaluationFlags()))
587578
{
588579
IF_FAIL_RET(DkmString::Create(L"<Refresh to view properties>", pValue.put()));
@@ -591,12 +582,7 @@ HRESULT object_visualizer::CreateEvaluationResult(_Deref_out_ DkmEvaluationResul
591582
else
592583
{
593584
cache_refresh(address);
594-
bool unavailable;
595-
IF_FAIL_RET(ObjectToString(m_pVisualizedExpression.get(), pPointerValueHome.get(), m_isAbiObject, pValue, &unavailable));
596-
if (!unavailable)
597-
{
598-
evalResultFlags |= DkmEvaluationResultFlags::Expandable;
599-
}
585+
IF_FAIL_RET(ObjectToString(m_pVisualizedExpression.get(), pPointerValueHome.get(), m_objectType, pValue));
600586
}
601587

602588
com_ptr<DkmDataAddress> pAddress;
@@ -689,7 +675,7 @@ HRESULT object_visualizer::GetItems(
689675
{
690676
auto& prop = m_propertyData[i + (size_t)StartIndex];
691677
com_ptr<DkmChildVisualizedExpression> pPropertyVisualized;
692-
if (FAILED(CreateChildVisualizedExpression(prop, pParent, m_isAbiObject, pPropertyVisualized.put())))
678+
if(FAILED(CreateChildVisualizedExpression(prop, pParent, m_objectType, pPropertyVisualized.put())))
693679
{
694680
com_ptr<DkmString> pErrorMessage;
695681
IF_FAIL_RET(DkmString::Create(L"<Property evaluation failed>", pErrorMessage.put()));

natvis/object_visualizer.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ enum class PropertyCategory
2020
Class,
2121
};
2222

23+
enum class ObjectType
24+
{
25+
Abi,
26+
Projection,
27+
};
28+
2329
// Metatdata for resolving a runtime class property value
2430
struct PropertyData
2531
{
@@ -36,17 +42,17 @@ struct PropertyData
3642
struct __declspec(uuid("c7da92da-3bc9-4312-8a93-46f480663980"))
3743
object_visualizer : winrt::implements<object_visualizer, ::IUnknown>
3844
{
39-
object_visualizer(Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, bool isAbiObject)
45+
object_visualizer(Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, ObjectType objectType)
4046
{
4147
m_pVisualizedExpression = make_com_ptr(pVisualizedExpression);
42-
m_isAbiObject = isAbiObject;
48+
m_objectType = objectType;
4349
}
4450

4551
~object_visualizer()
4652
{
4753
}
4854

49-
static HRESULT CreateEvaluationResult(_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, _In_ bool isAbiObject, _Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppResultObject);
55+
static HRESULT CreateEvaluationResult(_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, _In_ ObjectType objectType, _Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppResultObject);
5056

5157
HRESULT CreateEvaluationResult(_Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppResultObject);
5258

@@ -69,7 +75,7 @@ object_visualizer : winrt::implements<object_visualizer, ::IUnknown>
6975
void GetPropertyData();
7076
void GetTypeProperties(Microsoft::VisualStudio::Debugger::DkmProcess* process, std::string_view const& type_name);
7177
winrt::com_ptr<Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression> m_pVisualizedExpression;
72-
bool m_isAbiObject;
78+
ObjectType m_objectType;
7379
std::vector<PropertyData> m_propertyData;
7480
bool m_isStringable{ false };
7581
};

0 commit comments

Comments
 (0)