Compartir vía


Evaluación de una expresión de inspección

Importante

En Visual Studio 2015, esta forma de implementar evaluadores de expresiones está en desuso. Para obtener información sobre cómo implementar evaluadores de expresiones CLR, vea Evaluadores de expresiones CLR y Ejemplo de evaluador de expresiones administradas.

Cuando Visual Studio está listo para mostrar el valor de una expresión de inspección, llama a EvaluateSync, que a su vez llama a EvaluateSync. Este proceso genera un objeto IDebugProperty2 que contiene el valor y el tipo de la expresión.

En esta implementación de IDebugParsedExpression::EvaluateSync, la expresión se analiza y evalúa al mismo tiempo. Esta implementación realiza las siguientes tareas:

  1. Analiza y evalúa la expresión para generar un objeto genérico que contiene el valor y su tipo. En C#, esto se representa como un object elemento while en C++, se representa como .VARIANT

  2. Crea una instancia de una clase (denominada CValueProperty en este ejemplo) que implementa la IDebugProperty2 interfaz y almacena en la clase el valor que se va a devolver.

  3. Devuelve la interfaz IDebugProperty2 desde el objeto CValueProperty.

Código administrado

Se trata de una implementación de IDebugParsedExpression::EvaluateSync en código administrado. El método Tokenize auxiliar analiza la expresión en un árbol de análisis. La función EvalToken auxiliar convierte el token en un valor. La función FindTerm auxiliar recorre recursivamente el árbol de análisis, llamando EvalToken a para cada nodo que representa un valor y aplicando cualquier operación (suma o resta) en la expresión.

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;
        }
    }
}

Código no administrado

Se trata de una implementación de IDebugParsedExpression::EvaluateSync en código no administrado. La función Evaluate auxiliar analiza y evalúa la expresión, devolviendo un que VARIANT contiene el valor resultante. La función VariantValueToProperty auxiliar agrupa el objeto VARIANT en un CValueProperty objeto .

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;
}