這很重要
在 Visual Studio 2015 中,這種實作運算式評估器的方式已被取代。 如需實作 CLR 運算式評估工具的相關資訊,請參閱 CLR 運算式評估工具 和 Managed 運算式評估工具範例。
透過呼叫 GetPropertyInfo 來取得本地變數的值,以及本地變數的名稱和類型。 由於局部的值取決於程式的當前狀態,因此必須從記憶體中取得局部的值。 IDebugBinder 物件可用來將代表本機的 IDebugField 物件系結至記憶體中包含值的適當位置。 記憶體中的此位置是由 IDebugObject 物件表示。
此擷取本機值的功能會封裝在一個執行下列工作的輔助函數中:
將物件繫結
IDebugField至記憶體,以取得物件IDebugObject。從記憶體取得值。 此值會表示為一系列位元組。
根據本地端的類型來對值進行格式化。
傳回包含本地值的泛型物件。 在 C# 中,這是一個
object,在 C++ 中,這是一個VARIANT。
受控程式碼
這是函式的實作,用於取回受控代碼中本地變數的值。
namespace EEMC
{
internal class Field
{
internal static object GetValue(
IDebugBinder binder,
IDebugField field,
Type t,
uint size)
{
if (t == null || size == 0) return null;
IDebugObject debugObject = null;
binder.Bind(null, field, out debugObject);
byte[] buffer = new byte[size];
for (int i = 0; i < size; i++) buffer[i] = 0;
debugObject.GetValue(buffer, size);
if (t == typeof(sbyte)) return (sbyte) buffer[0];
if (t == typeof(short)) return BitConverter.ToInt16(buffer, 0);
if (t == typeof(int)) return BitConverter.ToInt32(buffer, 0);
if (t == typeof(long)) return BitConverter.ToInt64(buffer, 0);
if (t == typeof(byte)) return buffer[0];
if (t == typeof(char)) return BitConverter.ToChar(buffer, 0);
if (t == typeof(uint)) return BitConverter.ToUInt32(buffer, 0);
if (t == typeof(ulong)) return BitConverter.ToUInt64(buffer, 0);
if (t == typeof(float)) return BitConverter.ToSingle(buffer, 0);
if (t == typeof(double)) return BitConverter.ToDouble(buffer, 0);
if (t == typeof(bool)) return BitConverter.ToBoolean(buffer, 0);
if (t == typeof(string)) return BitConverter.ToString(buffer, 0);
return null;
}
}
}
非受控程式碼
這是函數實作,用於擷取非受控程式碼中的本地變數的值。
FieldGetType 顯示在 獲取本機值中。
HRESULT FieldGetPrimitiveValue(
in IDebugBinder* pbinder,
in IDebugField* pfield,
out VARIANT* pvarValue
)
{
if (pvarValue == NULL)
return E_INVALIDARG;
else
*pvarValue = 0;
if (pfield == NULL)
return E_INVALIDARG;
if (pbinder == NULL)
return E_INVALIDARG;
HRESULT hr;
UINT valueSize = 0;
BYTE* pvalueBits = NULL;
IDebugObject* pobject = NULL;
//get the value as bits
hr = pbinder->Bind( NULL, pfield, &pobject );
if (FAILED(hr))
return hr;
hr = pobject->GetSize( &valueSize );
if (FAILED(hr))
{
pobject->Release();
return hr;
}
pvalueBits = reinterpret_cast<BYTE *>(malloc(valueSize * sizeof(BYTE)));
if (!pvalueBits)
{
pobject->Release();
return E_OUTOFMEMORY;
}
hr = pobject->GetValue( pvalueBits, valueSize );
pobject->Release();
if (FAILED(hr))
{
free(pvalueBits);
return hr;
}
//get the type
VARIANT valueType;
hr = FieldGetType( pfield, &valueType );
if (FAILED(hr))
{
free(pvalueBits);
return hr;
}
//copy a primitive value
switch (valueType.vt)
{
case VT_BSTR:
{
pvarValue->vt = VT_BSTR;
if (valueSize == 0)
pvarValue->bstrVal = SysAllocString( OLE("") );
else
pvarValue->bstrVal =
SysAllocStringByteLen( reinterpret_cast<char*>(pvalueBits),
valueSize );
}
case VT_BOOL:
case VT_I1:
case VT_I2:
case VT_I4:
case VT_I8:
case VT_UI1:
case VT_UI2:
case VT_UI4:
case VT_UI8:
case VT_R4:
case VT_R8:
pvarValue->vt = valueType.vt;
if (valueSize > 8)
valueSize = 8;
memcpy( &(pvarValue->iVal), pvalueBits, valueSize );
break;
case VT_VOID:
case VT_EMPTY:
pvarValue->vt = valueType.vt;
break;
default:
//not a primitive type
VariantClear(&valueType);
free(pvalueBits);
return E_FAIL;
}
free(pvalueBits);
VariantClear(&valueType);
return S_OK;
}