重要
Visual Studio 2015 では、この方法での式エバリュエーターの実装は非推奨です。 CLR 式エバリュエーターの実装については、CLR 式エバリュエーターに関する記事とマネージド式エバリュエーターのサンプルに関する記事をご覧ください。
GetPropertyInfo は、ローカルの名前と型に加えて、ローカルの値を取得するために呼び出します。 ローカルの値はプログラムの現在の状態に依存するため、ローカルの値はメモリから取得する必要があります。 IDebugBinder オブジェクトは、ローカルを表す IDebugField オブジェクトを、値を格納しているメモリ内の適切な場所にバインドするために使用します。 メモリ内のこの場所は、IDebugObject オブジェクトによって表されます。
ローカルの値を取得するこの機能は、次のタスクを実行するヘルパー関数にカプセル化されています。
IDebugObject
オブジェクトを取得するために、IDebugField
オブジェクトをメモリにバインドし ます。メモリから値を取得します。 この値は、一連のバイトとして表されます。
ローカルの型に基づいて値を書式設定します。
ローカルの値を格納しているジェネリック オブジェクトを返します。 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;
}