Partager via


Évaluer une expression espionne

Important

Dans Visual Studio 2015, cette façon d’implémenter des évaluateurs d’expression est déconseillée. Pour plus d’informations sur l’implémentation d’évaluateurs d’expression CLR, consultez l’exemple d’évaluateur d’expression CLR et d’évaluateur d’expression managée.

Lorsque Visual Studio est prêt à afficher la valeur d’une expression espionne, elle appelle EvaluateSync, qui appelle à son tour EvaluateSync. Ce processus produit un objet IDebugProperty2 qui contient la valeur et le type de l’expression.

Dans cette implémentation de IDebugParsedExpression::EvaluateSync, l’expression est analysée et évaluée en même temps. Cette implémentation effectue les tâches suivantes :

  1. Analyse et évalue l’expression pour produire un objet générique qui contient la valeur et son type. En C#, il s’agit d’un object moment en C++, il est représenté sous la forme d’un VARIANT.

  2. Instancie une classe (appelée CValueProperty dans cet exemple) qui implémente l’interface IDebugProperty2 et stocke dans la classe la valeur à retourner.

  3. Retourne l’interface IDebugProperty2 de l’objet CValueProperty .

Code managé

Il s’agit d’une implémentation du IDebugParsedExpression::EvaluateSync code managé. La méthode Tokenize d’assistance analyse l’expression dans une arborescence d’analyse. La fonction EvalToken d’assistance convertit le jeton en valeur. La fonction FindTerm d’assistance traverse de manière récursive l’arborescence d’analyse, en appelant EvalToken chaque nœud représentant une valeur et en appliquant toutes les opérations (addition ou soustraction) dans l’expression.

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

Code non managé

Il s’agit d’une implémentation du IDebugParsedExpression::EvaluateSync code non managé. La fonction Evaluate d’assistance analyse et évalue l’expression, retournant une VARIANT conservation de la valeur résultante. La fonction VariantValueToProperty d’assistance regroupe l’objet VARIANT dans un CValueProperty objet.

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