计算监视表达式
重要
在 Visual Studio 2015 中,这种实现表达式计算器的方法已弃用。 有关实现 CLR 表达式计算器的信息,请参阅 CLR 表达式计算器和托管表达式计算器示例。
当 Visual Studio 准备好显示监视表达式的值时,它将调用 EvaluateSync,后者又调用 EvaluateSync。 此过程生成一个 IDebugProperty2 对象,该对象包含表达式的值和类型。
在此实现中 IDebugParsedExpression::EvaluateSync
,将同时分析并计算表达式。 此实现执行以下任务:
分析和计算表达式以生成一个保存值的泛型对象及其类型。 在 C# 中,此表示为 C++ 中的一段时间
object
,它表示为一个VARIANT
。实例化一个类(在此示例中调用
CValueProperty
),该IDebugProperty2
类实现接口并存储在要返回的值的类中。从
IDebugProperty2
对象返回CValueProperty
接口。
托管代码
这是托管代码的 IDebugParsedExpression::EvaluateSync
实现。 帮助程序方法 Tokenize
将表达式分析为分析树。 帮助程序函数 EvalToken
将令牌转换为值。 帮助程序函数 FindTerm
以递归方式遍历分析树,调用 EvalToken
表示值的每个节点,并在表达式中应用任何操作(加法或减法)。
namespace EEMC
{
public class CParsedExpression : IDebugParsedExpression
{
public HRESULT EvaluateSync(
uint evalFlags,
uint timeout,
IDebugSymbolProvider provider,
IDebugAddress address,
IDebugBinder binder,
string resultType,
out IDebugProperty2 result)
{
HRESULT retval = COM.S_OK;
this.evalFlags = evalFlags;
this.timeout = timeout;
this.provider = provider;
this.address = address;
this.binder = binder;
this.resultType = resultType;
try
{
IDebugField field = null;
// Tokenize, then parse.
tokens = Tokenize(expression);
result = new CValueProperty(
expression,
(int) FindTerm(EvalToken(tokens[0], out field),1),
field,
binder);
}
catch (ParseException)
{
result = new CValueProperty(expression, "Huh?");
retval = COM.E_INVALIDARG;
}
return retval;
}
}
}
非托管代码
这是非托管代码的 IDebugParsedExpression::EvaluateSync
实现。 帮助程序函数 Evaluate
分析并计算表达式,并 VARIANT
返回保留结果值。 帮助程序函数 VariantValueToProperty
将捆绑 VARIANT
到对象 CValueProperty
中。
STDMETHODIMP CParsedExpression::EvaluateSync(
in DWORD evalFlags,
in DWORD dwTimeout,
in IDebugSymbolProvider* pprovider,
in IDebugAddress* paddress,
in IDebugBinder* pbinder,
in BSTR bstrResultType,
out IDebugProperty2** ppproperty )
{
// dwTimeout parameter is ignored in this implementation.
if (pprovider == NULL)
return E_INVALIDARG;
if (paddress == NULL)
return E_INVALIDARG;
if (pbinder == NULL)
return E_INVALIDARG;
if (ppproperty == NULL)
return E_INVALIDARG;
else
*ppproperty = 0;
HRESULT hr;
VARIANT value;
BSTR bstrErrorMessage = NULL;
hr = ::Evaluate( pprovider,
paddress,
pbinder,
m_expr,
&bstrErrorMessage,
&value );
if (hr != S_OK)
{
if (bstrErrorMessage == NULL)
return hr;
//we can display better messages ourselves.
HRESULT hrLocal = S_OK;
VARIANT varType;
VARIANT varErrorMessage;
VariantInit( &varType );
VariantInit( &varErrorMessage );
varErrorMessage.vt = VT_BSTR;
varErrorMessage.bstrVal = bstrErrorMessage;
CValueProperty* valueProperty = new CValueProperty();
if (valueProperty != NULL)
{
hrLocal = valueProperty->Init(m_expr, varType, varErrorMessage);
if (SUCCEEDED(hrLocal))
{
hrLocal = valueProperty->QueryInterface( IID_IDebugProperty2,
reinterpret_cast<void**>(ppproperty) );
}
}
VariantClear(&varType);
VariantClear(&varErrorMessage); //frees BSTR
if (!valueProperty)
return hr;
valueProperty->Release();
if (FAILED(hrLocal))
return hr;
}
else
{
if (bstrErrorMessage != NULL)
SysFreeString(bstrErrorMessage);
hr = VariantValueToProperty( pprovider,
paddress,
pbinder,
m_radix,
m_expr,
value,
ppproperty );
VariantClear(&value);
if (FAILED(hr))
return hr;
}
return S_OK;
}