From b69f40d6ecc7d852aebb0682e099322b60cc34e3 Mon Sep 17 00:00:00 2001 From: Scott Jones Date: Thu, 24 Mar 2022 10:06:41 -0700 Subject: [PATCH] per request, provide implementation-side visualizations. and always show raw data. (#1128) --- natvis/cppwinrt.natvis | 5 ++++ natvis/cppwinrt_visualizer.cpp | 15 ++++++---- natvis/object_visualizer.cpp | 54 +++++++++++++--------------------- natvis/object_visualizer.h | 14 ++++++--- 4 files changed, 45 insertions(+), 43 deletions(-) diff --git a/natvis/cppwinrt.natvis b/natvis/cppwinrt.natvis index 168b5542e..7fad2e26c 100644 --- a/natvis/cppwinrt.natvis +++ b/natvis/cppwinrt.natvis @@ -14,6 +14,11 @@ null + + + + null + diff --git a/natvis/cppwinrt_visualizer.cpp b/natvis/cppwinrt_visualizer.cpp index 1e2539910..b44be1268 100644 --- a/natvis/cppwinrt_visualizer.cpp +++ b/natvis/cppwinrt_visualizer.cpp @@ -207,21 +207,26 @@ HRESULT cppwinrt_visualizer::EvaluateVisualizedExpression( IF_FAIL_RET(pTypeSymbol->get_name(&bstrTypeName)); // Visualize top-level C++/WinRT objects containing ABI pointers - bool isAbiObject; + ObjectType objectType; if (wcscmp(bstrTypeName, L"winrt::Windows::Foundation::IInspectable") == 0) { - isAbiObject = false; + objectType = ObjectType::Projection; } // Visualize nested object properties via raw ABI pointers else if ((wcscmp(bstrTypeName, L"winrt::impl::IInspectable") == 0) || (wcscmp(bstrTypeName, L"winrt::impl::inspectable_abi") == 0)) { - isAbiObject = true; + objectType = ObjectType::Abi; + } + // Visualize C++/WinRT object implementations + else if (wcsncmp(bstrTypeName, L"winrt::impl::producer<", wcslen(L"winrt::impl::producer<")) == 0) + { + objectType = ObjectType::Abi; } // Visualize all raw IInspectable pointers else if (wcscmp(bstrTypeName, L"IInspectable") == 0) { - isAbiObject = true; + objectType = ObjectType::Abi; } else { @@ -231,7 +236,7 @@ HRESULT cppwinrt_visualizer::EvaluateVisualizedExpression( return S_OK; } - IF_FAIL_RET(object_visualizer::CreateEvaluationResult(pVisualizedExpression, isAbiObject, ppResultObject)); + IF_FAIL_RET(object_visualizer::CreateEvaluationResult(pVisualizedExpression, objectType, ppResultObject)); return S_OK; } diff --git a/natvis/object_visualizer.cpp b/natvis/object_visualizer.cpp index 4b1f7efd5..8bcb86877 100644 --- a/natvis/object_visualizer.cpp +++ b/natvis/object_visualizer.cpp @@ -99,14 +99,14 @@ static HRESULT EvaluatePropertyExpression( _In_ PropertyData const& prop, _In_ DkmVisualizedExpression* pExpression, _In_ DkmPointerValueHome* pObject, - bool isAbiObject, + ObjectType objectType, _Out_ com_ptr& pEvaluationResult ) { wchar_t abiAddress[40]; auto process = pExpression->RuntimeInstance()->Process(); bool is64Bit = ((process->SystemInformation()->Flags() & DefaultPort::DkmSystemInformationFlags::Is64Bit) != 0); - swprintf_s(abiAddress, is64Bit ? L"%s0x%I64x" : L"%s0x%08x", isAbiObject ? L"(::IUnknown*)" : L"*(::IUnknown**)", pObject->Address()); + swprintf_s(abiAddress, is64Bit ? L"%s0x%I64x" : L"%s0x%08x", objectType == ObjectType::Abi ? L"(::IUnknown*)" : L"*(::IUnknown**)", pObject->Address()); wchar_t wszEvalText[500]; std::wstring propCast; PCWSTR propField; @@ -174,12 +174,12 @@ static HRESULT EvaluatePropertyString( _In_ PropertyData const& prop, _In_ DkmVisualizedExpression* pExpression, _In_ DkmPointerValueHome* pObject, - bool isAbiObject, + ObjectType objectType, _Out_ com_ptr& pValue ) { com_ptr pEvaluationResult; - IF_FAIL_RET(EvaluatePropertyExpression(prop, pExpression, pObject, isAbiObject, pEvaluationResult)); + IF_FAIL_RET(EvaluatePropertyExpression(prop, pExpression, pObject, objectType, pEvaluationResult)); if (pEvaluationResult->TagValue() != DkmEvaluationResult::Tag::SuccessResult) { return E_FAIL; @@ -195,11 +195,11 @@ static HRESULT EvaluatePropertyString( static std::string GetRuntimeClass( _In_ DkmVisualizedExpression* pExpression, _In_ DkmPointerValueHome* pObject, - bool isAbiObject + ObjectType objectType ) { com_ptr pValue; - EvaluatePropertyString({ IID_IInspectable, -2, PropertyCategory::String }, pExpression, pObject, isAbiObject, pValue); + EvaluatePropertyString({ IID_IInspectable, -2, PropertyCategory::String }, pExpression, pObject, objectType, pValue); if (!pValue || pValue->Length() == 0) { return ""; @@ -210,16 +210,11 @@ static std::string GetRuntimeClass( static HRESULT ObjectToString( _In_ DkmVisualizedExpression* pExpression, _In_ DkmPointerValueHome* pObject, - bool isAbiObject, - _Out_ com_ptr& pValue, - bool* unavailable = nullptr + ObjectType objectType, + _Out_ com_ptr& pValue ) { - if (unavailable) - { - *unavailable = false; - } - if (SUCCEEDED(EvaluatePropertyString({ IID_IStringable, 0, PropertyCategory::String }, pExpression, pObject, isAbiObject, pValue))) + if (SUCCEEDED(EvaluatePropertyString({ IID_IStringable, 0, PropertyCategory::String }, pExpression, pObject, objectType, pValue))) { if (pValue && pValue->Length() > 0) { @@ -229,7 +224,7 @@ static HRESULT ObjectToString( // WINRT_abi_val returned 0, which may be success or failure (due to VirtualQuery validation) // Call back for the runtime class name to determine which it was - if (!GetRuntimeClass(pExpression, pObject, isAbiObject).empty()) + if (!GetRuntimeClass(pExpression, pObject, objectType).empty()) { return DkmString::Create(L"", pValue.put()); } @@ -237,17 +232,13 @@ static HRESULT ObjectToString( // VirtualQuery validation failed (as determined by no runtime class name) or an // exception escaped WINRT_abi_val (e.g, bad pointer, which we try to avoid via VirtualQuery) - if (unavailable) - { - *unavailable = true; - } return DkmString::Create(L"", pValue.put()); } static HRESULT CreateChildVisualizedExpression( _In_ PropertyData const& prop, _In_ DkmVisualizedExpression* pParent, - bool isAbiObject, + ObjectType objectType, _Deref_out_ DkmChildVisualizedExpression** ppResult ) { @@ -256,7 +247,7 @@ static HRESULT CreateChildVisualizedExpression( com_ptr pEvaluationResult; auto valueHome = make_com_ptr(pParent->ValueHome()); com_ptr pParentPointer = valueHome.as(); - IF_FAIL_RET(EvaluatePropertyExpression(prop, pParent, pParentPointer.get(), isAbiObject, pEvaluationResult)); + IF_FAIL_RET(EvaluatePropertyExpression(prop, pParent, pParentPointer.get(), objectType, pEvaluationResult)); if (pEvaluationResult->TagValue() != DkmEvaluationResult::Tag::SuccessResult) { return E_FAIL; @@ -273,7 +264,7 @@ static HRESULT CreateChildVisualizedExpression( { isNonNullObject = true; IF_FAIL_RET(DkmPointerValueHome::Create(childObjectAddress, pChildPointer.put())); - IF_FAIL_RET(ObjectToString(pParent, pChildPointer.get(), true, pValue)); + IF_FAIL_RET(ObjectToString(pParent, pChildPointer.get(), ObjectType::Abi, pValue)); } } if(!isNonNullObject) @@ -335,7 +326,7 @@ static HRESULT CreateChildVisualizedExpression( if (isNonNullObject) { - com_ptr pObjectVisualizer = make_self(pChildVisualizedExpression.get(), true); + com_ptr pObjectVisualizer = make_self(pChildVisualizedExpression.get(), ObjectType::Abi); IF_FAIL_RET(pChildVisualizedExpression->SetDataItem(DkmDataCreationDisposition::CreateNew, pObjectVisualizer.get())); } else @@ -492,7 +483,7 @@ void object_visualizer::GetPropertyData() { auto valueHome = make_com_ptr(m_pVisualizedExpression->ValueHome()); com_ptr pObject = valueHome.as(); - auto rc = GetRuntimeClass(m_pVisualizedExpression.get(), pObject.get(), m_isAbiObject); + auto rc = GetRuntimeClass(m_pVisualizedExpression.get(), pObject.get(), m_objectType); if (rc.empty()) { return; @@ -539,9 +530,9 @@ void object_visualizer::GetTypeProperties(Microsoft::VisualStudio::Debugger::Dkm } } -HRESULT object_visualizer::CreateEvaluationResult(_In_ DkmVisualizedExpression* pVisualizedExpression, _In_ bool isAbiObject, _Deref_out_ DkmEvaluationResult** ppResultObject) +HRESULT object_visualizer::CreateEvaluationResult(_In_ DkmVisualizedExpression* pVisualizedExpression, _In_ ObjectType objectType, _Deref_out_ DkmEvaluationResult** ppResultObject) { - com_ptr pObjectVisualizer = make_self(pVisualizedExpression, isAbiObject); + com_ptr pObjectVisualizer = make_self(pVisualizedExpression, objectType); IF_FAIL_RET(pVisualizedExpression->SetDataItem(DkmDataCreationDisposition::CreateNew, pObjectVisualizer.get())); @@ -582,7 +573,7 @@ HRESULT object_visualizer::CreateEvaluationResult(_Deref_out_ DkmEvaluationResul auto address = pPointerValueHome->Address(); com_ptr pValue; - DkmEvaluationResultFlags_t evalResultFlags = DkmEvaluationResultFlags::ReadOnly; + DkmEvaluationResultFlags_t evalResultFlags = DkmEvaluationResultFlags::ReadOnly | DkmEvaluationResultFlags::Expandable;; if (requires_refresh(address, m_pVisualizedExpression->InspectionContext()->EvaluationFlags())) { IF_FAIL_RET(DkmString::Create(L"", pValue.put())); @@ -591,12 +582,7 @@ HRESULT object_visualizer::CreateEvaluationResult(_Deref_out_ DkmEvaluationResul else { cache_refresh(address); - bool unavailable; - IF_FAIL_RET(ObjectToString(m_pVisualizedExpression.get(), pPointerValueHome.get(), m_isAbiObject, pValue, &unavailable)); - if (!unavailable) - { - evalResultFlags |= DkmEvaluationResultFlags::Expandable; - } + IF_FAIL_RET(ObjectToString(m_pVisualizedExpression.get(), pPointerValueHome.get(), m_objectType, pValue)); } com_ptr pAddress; @@ -689,7 +675,7 @@ HRESULT object_visualizer::GetItems( { auto& prop = m_propertyData[i + (size_t)StartIndex]; com_ptr pPropertyVisualized; - if (FAILED(CreateChildVisualizedExpression(prop, pParent, m_isAbiObject, pPropertyVisualized.put()))) + if(FAILED(CreateChildVisualizedExpression(prop, pParent, m_objectType, pPropertyVisualized.put()))) { com_ptr pErrorMessage; IF_FAIL_RET(DkmString::Create(L"", pErrorMessage.put())); diff --git a/natvis/object_visualizer.h b/natvis/object_visualizer.h index 2c84a4a94..08cc40f72 100644 --- a/natvis/object_visualizer.h +++ b/natvis/object_visualizer.h @@ -20,6 +20,12 @@ enum class PropertyCategory Class, }; +enum class ObjectType +{ + Abi, + Projection, +}; + // Metatdata for resolving a runtime class property value struct PropertyData { @@ -36,17 +42,17 @@ struct PropertyData struct __declspec(uuid("c7da92da-3bc9-4312-8a93-46f480663980")) object_visualizer : winrt::implements { - object_visualizer(Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, bool isAbiObject) + object_visualizer(Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, ObjectType objectType) { m_pVisualizedExpression = make_com_ptr(pVisualizedExpression); - m_isAbiObject = isAbiObject; + m_objectType = objectType; } ~object_visualizer() { } - static HRESULT CreateEvaluationResult(_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, _In_ bool isAbiObject, _Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppResultObject); + static HRESULT CreateEvaluationResult(_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, _In_ ObjectType objectType, _Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppResultObject); HRESULT CreateEvaluationResult(_Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppResultObject); @@ -69,7 +75,7 @@ object_visualizer : winrt::implements void GetPropertyData(); void GetTypeProperties(Microsoft::VisualStudio::Debugger::DkmProcess* process, std::string_view const& type_name); winrt::com_ptr m_pVisualizedExpression; - bool m_isAbiObject; + ObjectType m_objectType; std::vector m_propertyData; bool m_isStringable{ false }; };