Pobieranie wartości lokalnych
Ważne
W programie Visual Studio 2015 ten sposób implementowania ewaluatorów wyrażeń jest przestarzały. Aby uzyskać informacje na temat implementowania ewaluatorów wyrażeń CLR, zobacz clR expression evaluators and Managed expression evaluator sample (Przykład ewaluatora wyrażeń zarządzanych).
Aby uzyskać wartość lokalną, program Visual Studio wywołuje metodę GetPropertyInfo dla tego lokalnego. W tej implementacji klasa CFieldProperty
implementuje interfejs IDebugProperty2 dla każdego lokalnego.
Ta implementacja wykonuje IDebugProperty2::GetPropertyInfo
następujące zadania:
Pobiera nazwę, właściwość i atrybuty lokalne z struktury FIELD_INFO wypełnionej, gdy klasa została utworzona i zainicjowana.
Pobiera typ lokalnego z obiektu IDebugField .
Pobiera wartość lokalną
IDebugField
z obiektu . To pole jest powiązane z lokalizacją pamięci lokalnego przy użyciu obiektu IDebugBinder , a wartość jest uzyskiwana z wynikowego obiektu IDebugObject .Zwraca wszystkie żądane właściwości w strukturze DEBUG_PROPERTY_INFO .
Kod zarządzany
W tym przykładzie pokazano implementację IDebugProperty2::GetPropertyInfo
metody lokalnej w kodzie zarządzanym. Przedstawia również funkcję pomocnika , Field.GetType
która służy do pobierania typu pola. Field.GetValue
jest wyświetlany w obszarze Ocena ustawień lokalnych. Funkcja Field.MapModifiersToAttributes
pomocnika (nie jest wyświetlana) po prostu konwertuje flagi FIELD_MODIFIERS pola na wartości DBG_ATTRIB_FLAGS.
namespace EEMC
{
public class CFieldProperty : IDebugProperty2
{
public HRESULT GetPropertyInfo(
uint dwFields,
uint radix,
uint timeout,
IDebugReference2[] refArgs,
uint argCount,
DEBUG_PROPERTY_INFO[] infoArray)
{
DEBUGPROP_INFO_FLAGS flags = (DEBUGPROP_INFO_FLAGS) dwFields;
DEBUGPROP_INFO_FLAGS infoFields = DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_NONE;
// Initialize the structure.
DEBUG_PROPERTY_INFO info = infoArray[0];
info.pProperty = null;
// Fill in the full name, if requested.
if (0 != (flags & DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_FULLNAME))
{
info.bstrFullName = fieldInfo.bstrFullName;
infoFields |= DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_FULLNAME;
}
// Fill in the name, if requested.
if (0 != (flags & DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_NAME))
{
info.bstrName = fieldInfo.bstrName;
infoFields |= DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_NAME;
}
// Fill in the type, if requested.
if (0 != (flags & DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_TYPE))
{
if (fieldType == null)
fieldType = Field.GetType(field, out fieldSize);
if (fieldType == null)
info.bstrType = "unknown";
else
info.bstrType = fieldType.ToString();
infoFields |= DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_TYPE;
}
// The property associated with this property is this property.
if (0 != (flags & DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_PROP))
{
info.pProperty = this;
infoFields |= DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_PROP;
}
// Get the property value, if requested.
if (0 != (flags & DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_VALUE))
{
if (fieldType == null)
fieldType = Field.GetType(field, out fieldSize);
if (fieldType == null)
info.bstrValue = "?";
else
{
object o = Field.GetValue(binder, field, fieldType, fieldSize);
if (o == null)
info.bstrValue = "?";
else
info.bstrValue = o.ToString();
}
infoFields |= DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_VALUE;
}
// Get the property attributes, if requested.
if (0 != (flags & DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_ATTRIB))
{
info.dwAttrib =
(ulong) Field.MapModifiersToAttributes(
(FIELD_MODIFIERS) fieldInfo.dwModifiers,
fieldKind);
infoFields |= DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_ATTRIB;
}
info.dwFields = (uint) infoFields;
infoArray[0] = info;
return COM.S_OK;
}
}
//----------------------------------------------------------------------------
internal class Field
{
internal static Type GetType(IDebugField field, out uint size)
{
size = 0;
IDebugField fieldType = null;
field.GetType(out fieldType);
if (fieldType == null) return null;
// Get field size.
fieldType.GetSize(out size);
// Get approximate type name.
FIELD_INFO[] fieldTypeInfo = new FIELD_INFO[1];
fieldType.GetInfo((uint) FIELD_INFO_FIELDS.FIF_NAME,
fieldTypeInfo);
// Map approximate name to type name.
switch (fieldTypeInfo[0].bstrName)
{
case "whole":
switch (size)
{
case 1: return typeof(sbyte);
case 2: return typeof(short);
case 4: return typeof(int);
case 8: return typeof(long);
}
break;
case "uwhole":
switch (size)
{
case 1: return typeof(byte);
case 2: return typeof(char);
case 4: return typeof(uint);
case 8: return typeof(ulong);
}
break;
case "real":
switch (size)
{
case 4: return typeof(float);
case 8: return typeof(double);
}
break;
case "bool": return typeof(bool);
case "string": return typeof(string);
}
return null;
}
}
Niezarządzany kod
W tym przykładzie pokazano implementację IDebugProperty2::GetPropertyInfo
metody lokalnej w kodzie niezarządzanym. Przedstawia również dwie funkcje pomocnicze, FieldGetType
które FieldGetValue
są używane do pobierania odpowiednio typu i wartości pola. Wartości VARIANT
są używane dla wartości i typu pola, ponieważ VARIANT
mogą obsługiwać szeroką gamę typów wartości. W tej implementacji zwraca obiekt IDebugField, FieldGetValue
który jest później konwertowany na wartość w wywołaniu metody FieldGetPrimitiveValue
(która jest wyświetlana w sekcji Ocena ustawień lokalnych).
STDMETHODIMP CFieldProperty::GetPropertyInfo(
in DEBUGPROP_INFO_FLAGS infoFlags,
in DWORD radix,
in DWORD timeout,
in IDebugReference2** ppargs,
in DWORD argCount,
out DEBUG_PROPERTY_INFO* ppropertyInfo
)
{
if (!ppropertyInfo)
return E_INVALIDARG;
else
memset(ppropertyInfo,0,sizeof(*ppropertyInfo));
if (infoFlags & DEBUGPROP_INFO_FULLNAME)
{
ppropertyInfo->dwFields |= DEBUGPROP_INFO_FULLNAME;
ppropertyInfo->bstrFullName = SysAllocString( m_fieldInfo.bstrFullName );
}
if (infoFlags & DEBUGPROP_INFO_NAME)
{
ppropertyInfo->dwFields |= DEBUGPROP_INFO_NAME;
ppropertyInfo->bstrName = SysAllocString( m_fieldInfo.bstrName );
}
if (infoFlags & DEBUGPROP_INFO_TYPE)
{
ppropertyInfo->dwFields |= DEBUGPROP_INFO_TYPE;
VARIANT type;
if (SUCCEEDED(FieldGetType( m_field, &type )))
{
// Convert the variant's type to a string
VariantTypeToString( type, &(ppropertyInfo->bstrType) );
VariantClear(&type);
}
if (ppropertyInfo->bstrType == NULL)
ppropertyInfo->bstrType = SysAllocString( GetString(IDS_MSG_UNKNOWNTYPE) );
}
if (infoFlags & DEBUGPROP_INFO_PROP)
{
ppropertyInfo->dwFields |= DEBUGPROP_INFO_PROP;
QueryInterface( IID_IDebugProperty2,
reinterpret_cast<void**>(&(ppropertyInfo->pProperty)) );
}
if (infoFlags & DEBUGPROP_INFO_VALUE)
{
ppropertyInfo->dwFields |= DEBUGPROP_INFO_VALUE;
//only show primitive values
VARIANT value;
if (SUCCEEDED(FieldGetValue(m_field, &value)))
{
VariantValueToString( radix, m_binder, value,
&(ppropertyInfo->bstrValue) );
VariantClear(&value);
}
if (ppropertyInfo->bstrValue == NULL)
ppropertyInfo->bstrValue = SysAllocString( GetString(IDS_MSG_UNKNOWNVALUE) );
}
if (infoFlags & DEBUGPROP_INFO_VALUE_AUTOEXPAND)
{
// AUTOEXPAND is ignored in this example
}
if (infoFlags & DEBUGPROP_INFO_ATTRIB)
{
ppropertyInfo->dwFields |= DEBUGPROP_INFO_ATTRIB;
FIELD_MODIFIERS modifiers = m_fieldInfo.dwModifiers;
DBG_ATTRIB_FLAGS attrib = DBG_ATTRIB_NONE;
//access
if (modifiers & FIELD_MOD_ACCESS_PUBLIC)
attrib |= DBG_ATTRIB_ACCESS_PUBLIC;
if (modifiers & FIELD_MOD_ACCESS_PRIVATE)
attrib |= DBG_ATTRIB_ACCESS_PRIVATE;
if (modifiers & FIELD_MOD_ACCESS_PROTECTED)
attrib |= DBG_ATTRIB_ACCESS_PROTECTED;
if (modifiers & FIELD_MOD_FINAL)
attrib |= DBG_ATTRIB_ACCESS_FINAL;
//constant
if (modifiers & FIELD_MOD_CONSTANT)
attrib |= DBG_ATTRIB_VALUE_READONLY;
//storage
if (m_fieldKind & FIELD_SYM_GLOBAL)
attrib |= DBG_ATTRIB_STORAGE_GLOBAL;
if (modifiers & FIELD_MOD_STATIC)
attrib |= DBG_ATTRIB_STORAGE_STATIC;
//type modifier
if (modifiers & FIELD_MOD_VIRTUAL)
attrib |= DBG_ATTRIB_TYPE_VIRTUAL;
if (modifiers & FIELD_MOD_CONSTANT)
attrib |= DBG_ATTRIB_TYPE_CONSTANT;
if (modifiers & FIELD_MOD_SYNCHRONIZED)
attrib |= DBG_ATTRIB_TYPE_SYNCHRONIZED;
if (modifiers & FIELD_MOD_VOLATILE)
attrib |= DBG_ATTRIB_TYPE_VOLATILE;
//type
if (m_fieldKind & FIELD_TYPE_METHOD)
attrib |= DBG_ATTRIB_METHOD;
if (m_fieldKind & FIELD_TYPE_PROP)
attrib |= DBG_ATTRIB_PROPERTY;
if (m_fieldKind & FIELD_TYPE_CLASS)
attrib |= DBG_ATTRIB_CLASS;
if (m_fieldKind & FIELD_TYPE_INTERFACE)
attrib |= DBG_ATTRIB_INTERFACE;
if (m_fieldKind & FIELD_TYPE_INNERCLASS)
attrib |= DBG_ATTRIB_INNERCLASS;
if (m_fieldKind & FIELD_KIND_SYMBOL)
attrib |= DBG_ATTRIB_DATA;
//set the debug attributes
ppropertyInfo->dwAttrib = attrib;
}
return S_OK;
}
//////////////////////////////////////////////////////////////////////
// Helper functions
struct PrimitiveTypeInfo
{
LPCOLESTR pszName;
UINT size;
VARTYPE vt;
};
PrimitiveTypeInfo primitiveTypeTable[] =
{
{ OLE("string"), 0, VT_BSTR },
{ OLE("whole"), 1, VT_I1 },
{ OLE("whole"), 2, VT_I2 },
{ OLE("whole"), 4, VT_I4 },
{ OLE("whole"), 8, VT_I8 },
{ OLE("uwhole"), 1, VT_UI1 },
{ OLE("uwhole"), 2, VT_UI2 },
{ OLE("uwhole"), 4, VT_UI4 },
{ OLE("uwhole"), 8, VT_UI8 },
{ OLE("real"), 4, VT_R4 },
{ OLE("real"), 8, VT_R8 },
{ OLE("bool"), 1, VT_BOOL },
{ OLE("bool"), 2, VT_BOOL },
{ OLE("bool"), 4, VT_BOOL },
{ OLE("System.String"), 0, VT_BSTR },
{ OLE("System.SByte"), 1, VT_I1 },
{ OLE("System.Int16"), 2, VT_I2 },
{ OLE("System.Int32"), 4, VT_I4 },
{ OLE("System.Int64"), 8, VT_I8 },
{ OLE("System.Byte"), 1, VT_UI1 },
{ OLE("System.Char"), 1, VT_UI2 },
{ OLE("System.UInt16"), 2, VT_UI2 },
{ OLE("System.UInt32"), 4, VT_UI4 },
{ OLE("System.UInt64"), 8, VT_UI8 },
{ OLE("System.Single"), 4, VT_R4 },
{ OLE("System.Double"), 8, VT_R8 },
{ OLE("System.Boolean"), 1, VT_BOOL },
{ OLE("System.Boolean"), 2, VT_BOOL },
{ OLE("System.Boolean"), 4, VT_BOOL },
{ NULL, 0, VT_EMPTY }
};
HRESULT FieldGetType( in IDebugField* pfield, out VARIANT* pvarType )
{
HRESULT hr;
if (pfield == NULL)
return E_INVALIDARG;
if (pvarType == NULL)
return E_INVALIDARG;
else
*pvarType = 0;
//get type size and name
DWORD fieldTypeSize;
FIELD_INFO fieldTypeInfo;
IDebugField* pfieldType = NULL;
hr = pfield->GetType( &pfieldType );
if (FAILED(hr))
return hr;
hr = pfieldType->GetSize( &fieldTypeSize );
if (FAILED(hr))
{
pfieldType->Release();
return hr;
}
hr = pfieldType->GetInfo( FIF_NAME, &fieldTypeInfo );
if (FAILED(hr))
{
pfieldType->Release();
return hr;
}
//check for primitive types
memset( pvarType, 0, sizeof(*pvarType) );
VariantInit(pvarType);
for (PrimitiveTypeInfo* pprimTypeInfo = primitiveTypeTable;
pprimTypeInfo->pszName != NULL;
pprimTypeInfo++)
{
if (pprimTypeInfo->size == fieldTypeSize &&
(wcscmp(pprimTypeInfo->pszName,fieldTypeInfo.bstrName) == 0))
{
pvarType->vt = pprimTypeInfo->vt;
break;
}
}
//VT_UNKNOWN is used for all other (structured) types
if (pvarType->vt == VT_EMPTY)
{
pvarType->vt = VT_UNKNOWN;
pvarType->punkVal = pfieldType;
pvarType->punkVal->AddRef();
}
if (fieldTypeInfo.bstrName != NULL)
SysFreeString(fieldTypeInfo.bstrName);
pfieldType->Release();
return S_OK;
}
//----------------------------------------------------------------------------
HRESULT FieldGetValue( in IDebugField* pfield, out VARIANT* pvarValue )
{
if (pvarValue == NULL)
return E_INVALIDARG;
else
*pvarValue = 0;
if (pfield == NULL)
return E_INVALIDARG;
//we delay getting the primitive value by just setting VT_UNKNOWN
pvarValue->vt = VT_UNKNOWN;
pvarValue->punkVal = pfield;
pvarValue->punkVal->AddRef();
return S_OK;
}