중요합니다
Visual Studio 2015에서는 식 계산기를 구현하는 이러한 방법이 더 이상 사용되지 않습니다. CLR 식 계산기 구현에 대한 자세한 내용은 CLR 식 계산기 및 관리 식 계산기 샘플을 참조하세요.
Visual Studio가 조사식의 값을 표시할 준비가 되면 EvaluateSync를 호출하여, 이후 EvaluateSync를 연이어 호출합니다. 이 프로세스는 식의 값과 형식을 포함하는 IDebugProperty2 개체를 생성합니다.
이 구현 IDebugParsedExpression::EvaluateSync에서는 식이 구문 분석되고 동시에 평가됩니다. 이 구현은 다음 작업을 수행합니다.
식을 구문 분석하고 평가하여 값과 해당 형식을 보유하는 제네릭 개체를 생성합니다. C#에서는 이것이
object로 표시되고, C++에서는 이것이VARIANT로 표시됩니다.CValueProperty라는 클래스(이 예제에서는)를 인스턴스화하여IDebugProperty2인터페이스를 구현하고 반환할 값을 클래스에 저장합니다.CValueProperty개체에서IDebugProperty2인터페이스를 반환합니다.
관리 코드
이는 관리 코드의 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;
}