in CppCustomVisualizer/dll/_EntryPoint.cpp [9:135]
HRESULT STDMETHODCALLTYPE CCppCustomVisualizerService::EvaluateVisualizedExpression(
_In_ Evaluation::DkmVisualizedExpression* pVisualizedExpression,
_Deref_out_opt_ Evaluation::DkmEvaluationResult** ppResultObject
)
{
HRESULT hr;
// This method is called to visualize a FILETIME variable. Its basic job is to create
// a DkmEvaluationResult object. A DkmEvaluationResult is the data that backs a row in the
// watch window -- a name, value, and type, a flag indicating if the item can be expanded, and
// lots of other additional properties.
Evaluation::DkmPointerValueHome* pPointerValueHome = Evaluation::DkmPointerValueHome::TryCast(pVisualizedExpression->ValueHome());
if (pPointerValueHome == nullptr)
{
// This sample only handles visualizing in-memory FILETIME structures
return E_NOTIMPL;
}
DkmRootVisualizedExpression* pRootVisualizedExpression = DkmRootVisualizedExpression::TryCast(pVisualizedExpression);
if (pRootVisualizedExpression == nullptr)
{
// This sample doesn't provide child evaluation results, so only root expressions are expected
return E_NOTIMPL;
}
// Read the FILETIME value from the target process
DkmProcess* pTargetProcess = pVisualizedExpression->RuntimeInstance()->Process();
FILETIME value;
hr = pTargetProcess->ReadMemory(pPointerValueHome->Address(), DkmReadMemoryFlags::None, &value, sizeof(value), nullptr);
if (FAILED(hr))
{
// If the bytes of the value cannot be read from the target process, just fall back to the default visualization
return E_NOTIMPL;
}
// Format this FILETIME as a string
CString strValue;
hr = FileTimeToText(value, /*ref*/strValue);
if (FAILED(hr))
{
strValue = "<Invalid Value>";
}
CString strEditableValue;
// If we are formatting a pointer, we want to also show the address of the pointer
if (pRootVisualizedExpression->Type() != nullptr && wcschr(pRootVisualizedExpression->Type()->Value(), '*') != nullptr)
{
// Make the editable value just the pointer string
UINT64 address = pPointerValueHome->Address();
if ((pTargetProcess->SystemInformation()->Flags()& DefaultPort::DkmSystemInformationFlags::Is64Bit) != 0)
{
strEditableValue.Format(L"0x%08x%08x", static_cast<DWORD>(address >> 32), static_cast<DWORD>(address));
}
else
{
strEditableValue.Format(L"0x%08x", static_cast<DWORD>(address));
}
// Prefix the value with the address
CString strValueWithAddress;
strValueWithAddress.Format(L"%s {%s}", static_cast<LPCWSTR>(strEditableValue), static_cast<LPCWSTR>(strValue));
strValue = strValueWithAddress;
}
CComPtr<DkmString> pValue;
hr = DkmString::Create(DkmSourceString(strValue), &pValue);
if (FAILED(hr))
{
return hr;
}
CComPtr<DkmString> pEditableValue;
hr = DkmString::Create(strEditableValue, &pEditableValue);
if (FAILED(hr))
{
return hr;
}
CComPtr<DkmDataAddress> pAddress;
hr = DkmDataAddress::Create(pVisualizedExpression->RuntimeInstance(), pPointerValueHome->Address(), nullptr, &pAddress);
if (FAILED(hr))
{
return hr;
}
DkmEvaluationResultFlags_t resultFlags = DkmEvaluationResultFlags::Expandable;
if (strEditableValue.IsEmpty())
{
// We only allow editting pointers, so mark non-pointers as read-only
resultFlags |= DkmEvaluationResultFlags::ReadOnly;
}
CComPtr<DkmSuccessEvaluationResult> pSuccessEvaluationResult;
hr = DkmSuccessEvaluationResult::Create(
pVisualizedExpression->InspectionContext(),
pVisualizedExpression->StackFrame(),
pRootVisualizedExpression->Name(),
pRootVisualizedExpression->FullName(),
resultFlags,
pValue,
pEditableValue,
pRootVisualizedExpression->Type(),
DkmEvaluationResultCategory::Class,
DkmEvaluationResultAccessType::None,
DkmEvaluationResultStorageType::None,
DkmEvaluationResultTypeModifierFlags::None,
pAddress,
nullptr,
(DkmReadOnlyCollection<DkmModuleInstance*>*)nullptr,
// This sample doesn't need to store any state associated with this evaluation result, so we
// pass `DkmDataItem::Null()` here. A more complicated extension which had associated
// state such as an extension which took over expansion of evaluation results would likely
// create an instance of the extension's data item class and pass the instance here.
// More information: https://github.com/Microsoft/ConcordExtensibilitySamples/wiki/Data-Container-API
DkmDataItem::Null(),
&pSuccessEvaluationResult
);
if (FAILED(hr))
{
return hr;
}
*ppResultObject = pSuccessEvaluationResult.Detach();
return S_OK;
}