Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions natvis/cppwinrt.natvis
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
<CustomVisualizer Condition="this != 0" VisualizerId="2ec1a02f-997c-4693-840e-88ffa1e21b56"/>
<DisplayString Condition="this == 0">null</DisplayString>
</Type>
<!-- Visualize C++/WinRT object implementations -->
<Type Name="winrt::impl::producer&lt;*&gt;">
<CustomVisualizer Condition="this != 0" VisualizerId="2ec1a02f-997c-4693-840e-88ffa1e21b56"/>
<DisplayString Condition="this == 0">null</DisplayString>
</Type>
<!--Visualize all raw IInspectable pointers-->
<Type Name="IInspectable">
<CustomVisualizer Condition="this != 0" VisualizerId="2ec1a02f-997c-4693-840e-88ffa1e21b56"/>
Expand Down
15 changes: 10 additions & 5 deletions natvis/cppwinrt_visualizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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;
}
Expand Down
54 changes: 20 additions & 34 deletions natvis/object_visualizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,14 @@ static HRESULT EvaluatePropertyExpression(
_In_ PropertyData const& prop,
_In_ DkmVisualizedExpression* pExpression,
_In_ DkmPointerValueHome* pObject,
bool isAbiObject,
ObjectType objectType,
_Out_ com_ptr<DkmEvaluationResult>& 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;
Expand Down Expand Up @@ -174,12 +174,12 @@ static HRESULT EvaluatePropertyString(
_In_ PropertyData const& prop,
_In_ DkmVisualizedExpression* pExpression,
_In_ DkmPointerValueHome* pObject,
bool isAbiObject,
ObjectType objectType,
_Out_ com_ptr<DkmString>& pValue
)
{
com_ptr<DkmEvaluationResult> 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;
Expand All @@ -195,11 +195,11 @@ static HRESULT EvaluatePropertyString(
static std::string GetRuntimeClass(
_In_ DkmVisualizedExpression* pExpression,
_In_ DkmPointerValueHome* pObject,
bool isAbiObject
ObjectType objectType
)
{
com_ptr<DkmString> 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 "";
Expand All @@ -210,16 +210,11 @@ static std::string GetRuntimeClass(
static HRESULT ObjectToString(
_In_ DkmVisualizedExpression* pExpression,
_In_ DkmPointerValueHome* pObject,
bool isAbiObject,
_Out_ com_ptr<DkmString>& pValue,
bool* unavailable = nullptr
ObjectType objectType,
_Out_ com_ptr<DkmString>& 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)
{
Expand All @@ -229,25 +224,21 @@ 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"<Expand object to view properties>", pValue.put());
}
}

// 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"<Object uninitialized or information unavailable>", pValue.put());
}

static HRESULT CreateChildVisualizedExpression(
_In_ PropertyData const& prop,
_In_ DkmVisualizedExpression* pParent,
bool isAbiObject,
ObjectType objectType,
_Deref_out_ DkmChildVisualizedExpression** ppResult
)
{
Expand All @@ -256,7 +247,7 @@ static HRESULT CreateChildVisualizedExpression(
com_ptr<DkmEvaluationResult> pEvaluationResult;
auto valueHome = make_com_ptr(pParent->ValueHome());
com_ptr<DkmPointerValueHome> pParentPointer = valueHome.as<DkmPointerValueHome>();
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;
Expand All @@ -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)
Expand Down Expand Up @@ -335,7 +326,7 @@ static HRESULT CreateChildVisualizedExpression(

if (isNonNullObject)
{
com_ptr<object_visualizer> pObjectVisualizer = make_self<object_visualizer>(pChildVisualizedExpression.get(), true);
com_ptr<object_visualizer> pObjectVisualizer = make_self<object_visualizer>(pChildVisualizedExpression.get(), ObjectType::Abi);
IF_FAIL_RET(pChildVisualizedExpression->SetDataItem(DkmDataCreationDisposition::CreateNew, pObjectVisualizer.get()));
}
else
Expand Down Expand Up @@ -492,7 +483,7 @@ void object_visualizer::GetPropertyData()
{
auto valueHome = make_com_ptr(m_pVisualizedExpression->ValueHome());
com_ptr<DkmPointerValueHome> pObject = valueHome.as<DkmPointerValueHome>();
auto rc = GetRuntimeClass(m_pVisualizedExpression.get(), pObject.get(), m_isAbiObject);
auto rc = GetRuntimeClass(m_pVisualizedExpression.get(), pObject.get(), m_objectType);
if (rc.empty())
{
return;
Expand Down Expand Up @@ -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<object_visualizer> pObjectVisualizer = make_self<object_visualizer>(pVisualizedExpression, isAbiObject);
com_ptr<object_visualizer> pObjectVisualizer = make_self<object_visualizer>(pVisualizedExpression, objectType);

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

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

com_ptr<DkmString> 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"<Refresh to view properties>", pValue.put()));
Expand All @@ -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<DkmDataAddress> pAddress;
Expand Down Expand Up @@ -689,7 +675,7 @@ HRESULT object_visualizer::GetItems(
{
auto& prop = m_propertyData[i + (size_t)StartIndex];
com_ptr<DkmChildVisualizedExpression> pPropertyVisualized;
if (FAILED(CreateChildVisualizedExpression(prop, pParent, m_isAbiObject, pPropertyVisualized.put())))
if(FAILED(CreateChildVisualizedExpression(prop, pParent, m_objectType, pPropertyVisualized.put())))
{
com_ptr<DkmString> pErrorMessage;
IF_FAIL_RET(DkmString::Create(L"<Property evaluation failed>", pErrorMessage.put()));
Expand Down
14 changes: 10 additions & 4 deletions natvis/object_visualizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ enum class PropertyCategory
Class,
};

enum class ObjectType
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this change from bool can be ignored - thought I'd need a tri-state for implementations, but just decided to keep it.

the only real meat is winrt::impl::producer addition and removing the condition on expanding (which permits raw data to always be visible)

{
Abi,
Projection,
};

// Metatdata for resolving a runtime class property value
struct PropertyData
{
Expand All @@ -36,17 +42,17 @@ struct PropertyData
struct __declspec(uuid("c7da92da-3bc9-4312-8a93-46f480663980"))
object_visualizer : winrt::implements<object_visualizer, ::IUnknown>
{
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);

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