Expression evaluator architecture
Applies to: Visual Studio Visual Studio for Mac
Note
This article applies to Visual Studio 2017. If you're looking for the latest Visual Studio documentation, see Visual Studio documentation. We recommend upgrading to the latest version of Visual Studio. Download it here
Important
In Visual Studio 2015, this way of implementing expression evaluators is deprecated. For information about implementing CLR expression evaluators, see CLR expression evaluators and Managed expression evaluator sample.
Integrating a proprietary language into the Visual Studio debug package means you must set up the required expression evaluator (EE) interfaces and call the common language run-time symbol provider (SP) and binder interfaces. The SP and binder objects, together with the current execution address, are the context in which expressions are evaluated. The information that these interfaces produce and consume represents the key concepts in the architecture of an EE.
Overview
Parse the Expression
When you are debugging a program, expressions are evaluated for a number of reasons but always when the program being debugged has been stopped at a breakpoint (either a breakpoint placed by the user or one caused by an exception). It is at this moment when Visual Studio obtains a stack frame, as represented by the IDebugStackFrame2 interface, from the debug engine (DE). Visual Studio then calls GetExpressionContext to get the IDebugExpressionContext2 interface. This interface represents a context in which expressions can be evaluated; ParseText is the entry point to the evaluation process. Up until this point, all interfaces are implemented by the DE.
When IDebugExpressionContext2::ParseText
is called, the DE instantiates the EE associated with the language of the source file where the breakpoint occurred (the DE also instantiates the SH at this point). The EE is represented by the IDebugExpressionEvaluator interface. The DE then calls Parse to convert the expression (in text form) to a parsed expression, ready for evaluation. This parsed expression is represented by the IDebugParsedExpression interface. The expression is typically parsed and not evaluated at this point.
The DE creates an object that implements the IDebugExpression2 interface, puts the IDebugParsedExpression
object into the IDebugExpression2
object, and returns the IDebugExpression2
object from IDebugExpressionContext2::ParseText
.
Evaluate the expression
Visual Studio calls either EvaluateSync or EvaluateAsync to evaluate the parsed expression. Both of these methods call EvaluateSync (IDebugExpression2::EvaluateSync
calls the method immediately, while IDebugExpression2::EvaluateAsync
calls the method through a background thread) to evaluate the parsed expression and return an IDebugProperty2 interface that represents the value and type of the parsed expression. IDebugParsedExpression::EvaluateSync
uses the supplied SH, address, and binder to convert the parsed expression into an actual value, represented by the IDebugProperty2
interface.
For example
After a breakpoint is hit in a running program, the user chooses to view a variable in the QuickWatch dialog box. This dialog box shows the variable's name, its value, and its type. The user can typically change the value.
When the QuickWatch dialog box is shown, the name of the variable being examined is sent as text to ParseText. This returns an IDebugExpression2 object representing the parsed expression, in this case, the variable. EvaluateSync is then called to produce an IDebugProperty2
object that represents the variable's value and type, as well as its name. It is this information that is displayed.
If the user changes the variable's value, SetValueAsString is called with the new value, which changes the value of the variable in memory so it will be used when the program resumes running.
See Displaying locals for more details on this process of displaying the values of variables. See Changing the value of a local for more details on how a variable's value is changed.
In this section
Evaluation context Provides the arguments that are passed when the DE calls the EE.
Key expression evaluator interfaces Describes the crucial interfaces needed when writing an EE, along with the evaluation context.