Пример #1
0
        public void GetItems(DkmVisualizedExpression visualizedExpression, DkmEvaluationResultEnumContext enumContext, int startIndex, int count, out DkmChildVisualizedExpression[] items)
        {
            if (count == 0)
            {
                items = new DkmChildVisualizedExpression[0];
                return;
            }

            var rawContextData = enumContext.GetDataItem <RawEnumContextData>();
            var rawContext     = rawContextData != null ? rawContextData.RawContext : enumContext;

            var result = new List <DkmChildVisualizedExpression>(count);

            if (rawContextData != null && rawContextData.PythonView != null)
            {
                if (startIndex == 0)
                {
                    result.Add(rawContextData.PythonView);
                    --count;
                }
                else
                {
                    --startIndex;
                }
            }

            DkmEvaluationResult[] rawItems;
            visualizedExpression.GetItemsCallback(rawContext, startIndex, count, out rawItems);
            for (int i = 0; i < rawItems.Length; ++i)
            {
                var rawItem = rawItems[i];

                var rawSuccessItem          = rawItem as DkmSuccessEvaluationResult;
                DkmExpressionValueHome home = null;
                if (rawSuccessItem != null && rawSuccessItem.Address != null)
                {
                    home = DkmPointerValueHome.Create(rawSuccessItem.Address.Value);
                }
                else
                {
                    home = DkmFakeValueHome.Create(0);
                }

                var item = DkmChildVisualizedExpression.Create(
                    visualizedExpression.InspectionContext,
                    visualizedExpression.VisualizerId,
                    visualizedExpression.SourceId,
                    visualizedExpression.StackFrame,
                    home,
                    rawItem,
                    visualizedExpression,
                    (uint)(startIndex + i),
                    rawItem.GetDataItem <RawEvaluationResultHolder>());
                result.Add(item);
            }

            items = result.ToArray();
        }
Пример #2
0
        public override void GetChildItems(DkmEvaluationResultEnumContext enumContext, int start, int count, out DkmChildVisualizedExpression[] items)
        {
            var props           = GetAllProperties();
            int total_num_props = props.Length;
            int end_idx         = Math.Min(start + count, total_num_props);
            int num_to_return   = end_idx - start;

            items = new DkmChildVisualizedExpression[num_to_return];

            for (int idx = start, out_idx = 0; idx < end_idx; ++idx, ++out_idx)
            {
                // We want to construct our own visualized expression from the eval.
                var eval = props[idx] as DkmSuccessEvaluationResult;
                // @TODO: Perhaps allow for failed evaluations and display anyway with unknown value??
                Debug.Assert(eval != null);

                DkmExpressionValueHome home;
                if (eval.Address != null)
                {
                    home = DkmPointerValueHome.Create(eval.Address.Value);
                }
                else
                {
                    home = DkmFakeValueHome.Create(0);
                }

                var expr = DkmChildVisualizedExpression.Create(
                    expression_.InspectionContext,
                    // @TODO: This is weird... seems to affect whether we get callback.
                    // Obviously the properties can be of any type, UObject or not.
                    // Perhaps best to put back the guid for PropertyValue, even though we don't really need to use it.
                    Guids.Visualizer.PropertyValue,                    //Guids.Visualizer.UObject,//Guids.Visualizer.PropertyList,
                    // Seems that in order for these to be passed back to the EE for default expansion, they need to be given
                    // the SourceId from the originally received root expression.
                    PropListExpression.Parent.SourceId,
                    expression_.StackFrame,
                    home,
                    eval,
                    expression_,
                    (uint)idx,
                    null                        // Don't associate any data with the expression. If the EE calls back to us to expand it, we'll just tell it to use default expansion.
                    );

                items[out_idx] = expr;
            }
        }
Пример #3
0
            private DkmChildVisualizedExpression[] Convert(DkmVisualizedExpression visualizedExpression, DkmEvaluationResult[] itemsAsResult, int startIndex = 0)
            {
                DkmChildVisualizedExpression[] items = new DkmChildVisualizedExpression[itemsAsResult.Length];

                for (int i = 0; i < items.Length; i++)
                {
                    DkmEvaluationResult   result           = itemsAsResult[i];
                    PassThroughVisualizer defaultEvaluator = null;

                    if (result is DkmSuccessEvaluationResult successResult)
                    {
                        defaultEvaluator = new PassThroughVisualizer(successResult);
                        result           = DkmSuccessEvaluationResult.Create(
                            successResult.InspectionContext,
                            successResult.StackFrame,
                            successResult.Name, // Name - Left column
                            successResult.FullName,
                            successResult.Flags,
                            successResult.Value, // Value - Middle column
                            successResult.EditableValue,
                            successResult.Type,  // Type - Right column
                            successResult.Category,
                            successResult.Access,
                            successResult.StorageType,
                            successResult.TypeModifierFlags,
                            successResult.Address,
                            successResult.CustomUIVisualizers,
                            successResult.ExternalModules,
                            successResult.RefreshButtonText,
                            defaultEvaluator);
                    }

                    items[i] = DkmChildVisualizedExpression.Create(
                        visualizedExpression.InspectionContext,
                        visualizedExpression.VisualizerId,
                        visualizedExpression.SourceId,
                        visualizedExpression.StackFrame,
                        null,
                        result,
                        visualizedExpression,
                        (uint)(startIndex + i),
                        defaultEvaluator);
                }
                return(items);
            }
Пример #4
0
        public void EvaluateChildren(DkmChildVisualizedExpression[] output, int startIndex, out int numWritten)
        {
            DkmEvaluationResult          evalResult       = evaluator_(name_, startIndex);
            EvaluationDataItem           originalDataItem = evalResult.GetDataItem <EvaluationDataItem>();
            DkmChildVisualizedExpression childExpr        = DkmChildVisualizedExpression.Create(
                expression_.InspectionContext,
                expression_.VisualizerId,
                expression_.SourceId,
                expression_.StackFrame,
                DkmFakeValueHome.Create(0),
                evalResult,
                expression_,
                (uint)startIndex,
                originalDataItem);

            output[startIndex] = childExpr;
            numWritten         = 1;
        }
Пример #5
0
        public void GetChildren(DkmVisualizedExpression visualizedExpression, int initialRequestSize, DkmInspectionContext inspectionContext, out DkmChildVisualizedExpression[] initialChildren, out DkmEvaluationResultEnumContext enumContext)
        {
            var rawResultHolder = visualizedExpression.GetDataItem <RawEvaluationResultHolder>();

            if (rawResultHolder == null)
            {
                Debug.Fail("PythonViewNativeVisualizer.GetChildren passed a visualized expression that does not have an associated RawEvaluationResultHolder.");
                throw new NotSupportedException();
            }
            var rawResult = rawResultHolder.RawResult;

            DkmEvaluationResult[]          rawInitialChildren;
            DkmEvaluationResultEnumContext rawEnumContext;

            visualizedExpression.GetChildrenCallback(rawResult, 0, inspectionContext, out rawInitialChildren, out rawEnumContext);

            initialChildren = new DkmChildVisualizedExpression[0];
            enumContext     = rawEnumContext;

            if (DebuggerOptions.ShowPythonViewNodes)
            {
                var pythonViewEvalResult = GetPythonView(visualizedExpression);
                var pythonView           = DkmChildVisualizedExpression.Create(
                    visualizedExpression.InspectionContext,
                    visualizedExpression.VisualizerId,
                    visualizedExpression.SourceId,
                    visualizedExpression.StackFrame,
                    visualizedExpression.ValueHome,
                    pythonViewEvalResult,
                    visualizedExpression,
                    (uint)rawEnumContext.Count, null);
                if (pythonView != null)
                {
                    enumContext = DkmEvaluationResultEnumContext.Create(
                        rawEnumContext.Count + 1,
                        rawEnumContext.StackFrame,
                        rawEnumContext.InspectionContext,
                        new RawEnumContextData {
                        RawContext = rawEnumContext, PythonView = pythonView
                    });
                }
            }
        }
Пример #6
0
        public void EvaluateChildren(DkmChildVisualizedExpression[] output, int startIndex, out int numWritten)
        {
            numWritten = 0;
            if (mode_ == ChildDisplayMode.Inline)
            {
                CreateDefaultEnumContext();

                int count = ChildCount;
                DkmEvaluationResult[] results = new DkmEvaluationResult[count];
                expression_.GetItemsCallback(defEnumContext_, 0, count, out results);
                for (int i = 0; i < count; ++i)
                {
                    DkmSuccessEvaluationResult successResult = results[i] as DkmSuccessEvaluationResult;
                    DkmExpressionValueHome     home          = null;
                    if (successResult != null && successResult.Address != null)
                    {
                        home = DkmPointerValueHome.Create(successResult.Address.Value);
                    }
                    else
                    {
                        home = DkmFakeValueHome.Create(0);
                    }

                    output[startIndex + i] = DkmChildVisualizedExpression.Create(
                        defEnumContext_.InspectionContext,
                        Guids.CustomVisualizer.ForceDefault,
                        expression_.SourceId,
                        defEnumContext_.StackFrame,
                        home,
                        results[i],
                        expression_,
                        (uint)startIndex,
                        null);
                    EvaluationDataItem originalDataItem = results[i].GetDataItem <EvaluationDataItem>();
                }
                numWritten = count;
            }
            else
            {
                numWritten = 1;
            }
        }
Пример #7
0
/*		public override DkmChildVisualizedExpression GetMostDerived()
 *              {
 *                      foreach (var child in MemberExpressions)
 *                      {
 *                              var eval = child.Value.EvaluationResult as DkmSuccessEvaluationResult;
 *                              if (eval != null && eval.Category == DkmEvaluationResultCategory.MostDerivedClass)
 *                              {
 *                                      return child.Value;
 *                              }
 *                      }
 *
 *                      return null;
 *              }
 */
        private DkmChildVisualizedExpression CreateNewExpression(string expr_str)
        {
            DkmSuccessEvaluationResult result_eval = null;

            try
            {
                result_eval = DefaultEE.DefaultEval(expr_str, callback_expr_, true) as DkmSuccessEvaluationResult;
            }
            catch (Exception e)
            { }

            if (result_eval == null)
            {
                return(null);
            }

            DkmExpressionValueHome home;

            if (result_eval.Address != null)
            {
                home = DkmPointerValueHome.Create(result_eval.Address.Value);
            }
            else
            {
                home = DkmFakeValueHome.Create(0);
            }

            // @TODO: This is weird. Can I perhaps construct a DkmRootVisualizedExpression instead??
            // Not sure about a couple of the parameters needed to do so, Module especially...
            return(DkmChildVisualizedExpression.Create(
                       result_eval.InspectionContext,
                       expr_.VisualizerId,
                       expr_.SourceId,
                       result_eval.StackFrame,
                       home,
                       result_eval,
                       callback_expr_, //expr_,
                       0,              // ??
                       null
                       ));
        }
Пример #8
0
        /// <summary>
        /// Returns child elements of previous evaluation.
        /// </summary>
        public void GetItems(DkmVisualizedExpression visualizedExpression, DkmEvaluationResultEnumContext enumContext, int startIndex, int count, out DkmChildVisualizedExpression[] items)
        {
            // Check if we want to use passthrough visualizer
            PassThroughVisualizer passThroughVisualizer = enumContext.GetDataItem <PassThroughVisualizer>();

            if (passThroughVisualizer != null)
            {
                passThroughVisualizer.GetItems(visualizedExpression, enumContext, startIndex, count, out items);
                return;
            }

            // Execute our regular visualizer
            VSCustomVisualizerEvaluator evaluator = visualizedExpression.GetDataItem <VSCustomVisualizerEvaluator>();

            IResultVisualizer[] itemsAsResults = evaluator.ResultVisualizer.Children.Skip(startIndex).Take(count).ToArray();

            items = new DkmChildVisualizedExpression[itemsAsResults.Length];
            for (int i = 0; i < items.Length; i++)
            {
                IResultVisualizer           item = itemsAsResults[i];
                DkmEvaluationResultCategory category;

                switch (item.DataType)
                {
                case CompletionDataType.Class:
                    category = DkmEvaluationResultCategory.Class;
                    break;

                case CompletionDataType.Property:
                case CompletionDataType.StaticProperty:
                    category = DkmEvaluationResultCategory.Property;
                    break;

                case CompletionDataType.Event:
                    category = DkmEvaluationResultCategory.Event;
                    break;

                case CompletionDataType.Method:
                    category = DkmEvaluationResultCategory.Method;
                    break;

                case CompletionDataType.Enum:
                case CompletionDataType.EnumValue:
                case CompletionDataType.Keyword:
                case CompletionDataType.Namespace:
                case CompletionDataType.StaticClass:
                case CompletionDataType.StaticEvent:
                case CompletionDataType.StaticMethod:
                case CompletionDataType.StaticVariable:
                case CompletionDataType.Unknown:
                case CompletionDataType.Variable:
                default:
                    category = DkmEvaluationResultCategory.Data;
                    break;
                }

                DkmExpressionValueHome valueHome = visualizedExpression.ValueHome;
                ulong  address  = 0;
                string fullName = string.Empty;
                string typeName = null;

                try
                {
                    if (item.Value is Variable variable)
                    {
                        address   = variable.GetPointerAddress();
                        typeName  = variable.GetCodeType().Name;
                        fullName  = $"*(({typeName}*)0x{address:X})";
                        valueHome = DkmPointerValueHome.Create(address);
                    }
                }
                catch
                {
                }

                DkmEvaluationResult result;
                DkmDataItem         dataItem = null;

                if (item.ShouldForceDefaultVisualizer && !string.IsNullOrEmpty(fullName))
                {
                    using (DkmLanguageExpression languageExpression = DkmLanguageExpression.Create(visualizedExpression.InspectionContext.Language, DkmEvaluationFlags.TreatAsExpression, fullName, null))
                    {
                        visualizedExpression.EvaluateExpressionCallback(visualizedExpression.InspectionContext, languageExpression, visualizedExpression.StackFrame, out result);
                    }

                    if (result is DkmSuccessEvaluationResult successResult)
                    {
                        dataItem = new PassThroughVisualizer(successResult);
                        result   = DkmSuccessEvaluationResult.Create(
                            successResult.InspectionContext,
                            successResult.StackFrame,
                            item.Name, // Name - Left column
                            successResult.FullName,
                            successResult.Flags,
                            successResult.Value, // Value - Middle column
                            successResult.EditableValue,
                            successResult.Type,  // Type - Right column
                            category,
                            successResult.Access,
                            successResult.StorageType,
                            successResult.TypeModifierFlags,
                            successResult.Address,
                            successResult.CustomUIVisualizers,
                            successResult.ExternalModules,
                            successResult.RefreshButtonText,
                            dataItem);
                    }
                }
                else
                {
                    result = DkmSuccessEvaluationResult.Create(
                        visualizedExpression.InspectionContext,
                        visualizedExpression.StackFrame,
                        item.Name,        // Name - Left column
                        fullName,         // FullName - What is being copied when "Add to watch"
                        DkmEvaluationResultFlags.ReadOnly | (item.IsExpandable ? DkmEvaluationResultFlags.Expandable : DkmEvaluationResultFlags.None),
                        item.ValueString, // Value - Middle column
                        "",
                        item.Type ?? "",  // Type - Right column
                        category,
                        DkmEvaluationResultAccessType.None,
                        DkmEvaluationResultStorageType.None,
                        DkmEvaluationResultTypeModifierFlags.None,
                        null,
                        VSUIVisualizerService.GetUIVisualizers(item),
                        null,
                        null);
                    dataItem = new VSCustomVisualizerEvaluator(result, item);
                }
                items[i] = DkmChildVisualizedExpression.Create(
                    visualizedExpression.InspectionContext,
                    visualizedExpression.VisualizerId,
                    visualizedExpression.SourceId,
                    visualizedExpression.StackFrame,
                    valueHome,
                    result,
                    visualizedExpression,
                    (uint)(startIndex + i),
                    dataItem);
            }
        }
Пример #9
0
/*		public override DkmChildVisualizedExpression GetMostDerived()
 *              {
 *                      foreach (var child in MemberExpressions)
 *                      {
 *                              var eval = child.Value.EvaluationResult as DkmSuccessEvaluationResult;
 *                              if (eval != null && eval.Category == DkmEvaluationResultCategory.MostDerivedClass)
 *                              {
 *                                      return child.Value;
 *                              }
 *                      }
 *
 *                      return null;
 *              }
 */
        private void EvaluateChildren()
        {
            MemberExpressions = new Dictionary <string, DkmChildVisualizedExpression>();

            // @TODO: Am assuming that if expr_ is a child expression, it would be more
            // efficient to use its EvaluationResult property instead of invoking the default
            // evaluator again. However, doing this results in using child UObject expressions which
            // have been generated using the custom visualization (since ! specifier is not recursive).
            // We really don't want this since we just want the default expansion so we can navigate
            // through the members and bases of the class.
            // Problem is, don't know how to communicate to the 'UseDefaultEvaluationBehavior'
            // implementation to use a default expansion in this particular case. Setting the data
            // item on expr_ before calling GetItemsCallback doesn't work, since the expression that
            // gets passed through is not actually expr_, but a root visualized expression that was
            // created by the EE when visualizing the parent, which we don't have access to.

            // As it is, now that we inline the default expansion alongside the addition of the
            // 'UE4 Properties' child, this does seem to work. However, not obvious there is any
            // performance improvement, also not 100% sure it's safe to use the stored evaluation.
            DkmEvaluationResult uobj_eval = null;

            if (expr_.TagValue == DkmVisualizedExpression.Tag.ChildVisualizedExpression)
            {
                uobj_eval = ((DkmChildVisualizedExpression)expr_).EvaluationResult;
            }
            else
            {
                uobj_eval = DefaultEE.DefaultEval(callback_expr_, true);
            }
            eval_ = (DkmSuccessEvaluationResult)uobj_eval;

            DkmEvaluationResult[]          children;
            DkmEvaluationResultEnumContext enum_context;

            try
            {
                callback_expr_.GetChildrenCallback(uobj_eval, 0, callback_expr_.InspectionContext, out children, out enum_context);
                // @NOTE: Assuming count will not be large here!!
                callback_expr_.GetItemsCallback(enum_context, 0, enum_context.Count, out children);
            }
            catch
            {
                return;
            }

            uint idx = 0;

            foreach (var child_eval in children)
            {
                if (child_eval.TagValue == DkmEvaluationResult.Tag.SuccessResult)
                {
                    var success_eval = child_eval as DkmSuccessEvaluationResult;
                    Debug.Assert(success_eval != null);

                    DkmExpressionValueHome home;
                    if (success_eval.Address != null)
                    {
                        home = DkmPointerValueHome.Create(success_eval.Address.Value);
                    }
                    else
                    {
                        home = DkmFakeValueHome.Create(0);
                    }
                    DkmChildVisualizedExpression child = DkmChildVisualizedExpression.Create(
                        child_eval.InspectionContext,
                        callback_expr_.VisualizerId,
                        callback_expr_.SourceId,
                        child_eval.StackFrame,
                        home,
                        child_eval,
                        expr_,
                        idx,
                        null
                        );
                    MemberExpressions[child_eval.Name] = child;
                }

                ++idx;
            }
        }
        private DkmChildVisualizedExpression GetPythonView(DkmVisualizedExpression visualizedExpression, uint index)
        {
            var stackFrame    = visualizedExpression.StackFrame;
            var process       = stackFrame.Process;
            var pythonRuntime = process.GetPythonRuntimeInstance();

            if (pythonRuntime == null)
            {
                return(null);
            }

            var home = visualizedExpression.ValueHome as DkmPointerValueHome;

            if (home == null)
            {
                Debug.Fail("PythonViewNativeVisualizer given a visualized expression that has a non-DkmPointerValueHome home.");
                return(null);
            }
            else if (home.Address == 0)
            {
                return(null);
            }

            var exprEval = process.GetDataItem <ExpressionEvaluator>();

            if (exprEval == null)
            {
                Debug.Fail("PythonViewNativeVisualizer failed to obtain an instance of ExpressionEvaluator.");
                return(null);
            }

            string cppTypeName = null;
            var    childExpr   = visualizedExpression as DkmChildVisualizedExpression;

            if (childExpr != null)
            {
                var evalResult = childExpr.EvaluationResult as DkmSuccessEvaluationResult;
                cppTypeName = evalResult.Type;
            }
            else
            {
                object punkTypeSymbol;
                visualizedExpression.GetSymbolInterface(typeof(IDiaSymbol).GUID, out punkTypeSymbol);
                using (ComPtr.Create(punkTypeSymbol)) {
                    var typeSymbol = punkTypeSymbol as IDiaSymbol;
                    if (typeSymbol != null)
                    {
                        cppTypeName = typeSymbol.name;
                    }
                }
            }

            PyObject objRef;

            try {
                objRef = PyObject.FromAddress(process, home.Address);
            } catch {
                return(null);
            }

            var pyEvalResult = new PythonEvaluationResult(objRef, "[Python view]")
            {
                Category   = DkmEvaluationResultCategory.Property,
                AccessType = DkmEvaluationResultAccessType.Private
            };

            var inspectionContext = visualizedExpression.InspectionContext;
            CppExpressionEvaluator cppEval;

            try {
                cppEval = new CppExpressionEvaluator(inspectionContext, stackFrame);
            } catch {
                return(null);
            }

            var pythonContext = DkmInspectionContext.Create(visualizedExpression.InspectionSession, pythonRuntime, stackFrame.Thread,
                                                            inspectionContext.Timeout, inspectionContext.EvaluationFlags, inspectionContext.FuncEvalFlags, inspectionContext.Radix,
                                                            DkmLanguage.Create("Python", new DkmCompilerId(Guids.MicrosoftVendorGuid, Guids.PythonLanguageGuid)), null);
            DkmEvaluationResult pythonView;

            try {
                pythonView = exprEval.CreatePyObjectEvaluationResult(pythonContext, stackFrame, null, pyEvalResult, cppEval, cppTypeName, hasCppView: true);
            } catch {
                return(null);
            }

            return(DkmChildVisualizedExpression.Create(
                       visualizedExpression.InspectionContext,
                       visualizedExpression.VisualizerId,
                       visualizedExpression.SourceId,
                       visualizedExpression.StackFrame,
                       visualizedExpression.ValueHome,
                       pythonView,
                       visualizedExpression,
                       index, null));
        }
Пример #11
0
        public override void GetChildItems(DkmEvaluationResultEnumContext enumContext, int start, int count, out DkmChildVisualizedExpression[] items)
        {
            // Cap the requested number to the total remaining from startIndex
            count = Math.Min(count, enumContext.Count - start);
            items = new DkmChildVisualizedExpression[count];
            uint idx = 0;

            // Retrieve the default expansion enum context
            var default_data = enumContext.GetDataItem <DefaultEnumContextDataItem>();

            if (start < default_data.Context.Count)
            {
                // Requesting default children

                int default_count = Math.Min(count, default_data.Context.Count - start);
                DkmEvaluationResult[] default_evals;
                expression_.GetItemsCallback(default_data.Context, start, default_count, out default_evals);
                for (int dft_idx = 0; dft_idx < default_count; ++dft_idx, ++idx)
                {
                    DkmSuccessEvaluationResult success_eval = default_evals[dft_idx] as DkmSuccessEvaluationResult;
                    DkmExpressionValueHome     home         = null;
                    if (success_eval != null && success_eval.Address != null)
                    {
                        home = DkmPointerValueHome.Create(success_eval.Address.Value);
                    }
                    else
                    {
                        home = DkmFakeValueHome.Create(0);
                    }

                    items[idx] = DkmChildVisualizedExpression.Create(
                        enumContext.InspectionContext,
                        expression_.VisualizerId,                               // @TODO: Check this is what we want. Will we get callbacks for it, regardless of its type?
                        expression_.SourceId,
                        enumContext.StackFrame,
                        home,
                        default_evals[dft_idx],
                        expression_,
                        (uint)start,
                        null
                        );
                }
            }

            if (start + count > default_data.Context.Count)
            {
                // Requesting custom children
                // @NOTE: Currently just assuming only 1 custom child (prop list) and hard coding as such.

                // DkmSuccessEvaluationResult.ExtractFromProperty(IDebugProperty3!!!!!!!) ...............................................

                // @NOTE: Had thought could just create an expression with a null evaluation
                // inside it, and by giving it a visualizer guid, the system would call back
                // to us to evaluate the expression. Seems not to work though, I guess because the
                // visualizer guid identifies the visualizer but not the containing component,
                // and since the expression itself doesn't have a type, it can't know that it
                // should call our component.
                DkmEvaluationResult eval = DkmSuccessEvaluationResult.Create(
                    enumContext.InspectionContext,
                    enumContext.StackFrame,
                    Resources.UE4PropVis.IDS_DISP_BLUEPRINTPROPERTIES,
                    Resources.UE4PropVis.IDS_DISP_BLUEPRINTPROPERTIES,
                    DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Expandable,
                    "",                         // @TODO: something like "[<count> properties]"
                    null,
                    "",                         // Type column
                    DkmEvaluationResultCategory.Other,
                    DkmEvaluationResultAccessType.None,
                    DkmEvaluationResultStorageType.None,
                    DkmEvaluationResultTypeModifierFlags.None,
                    null,
                    null,
                    null,
                    null
                    );

                // This child is just for organization and does not correspond to anything in memory.
                DkmExpressionValueHome valueHome = DkmFakeValueHome.Create(0);

                var prop_list_expr = DkmChildVisualizedExpression.Create(
                    enumContext.InspectionContext,
                    Guids.Visualizer.PropertyList,
                    // Associate the expression with ourselves, since we created it
                    Guids.Component.VisualizerComponent,
                    enumContext.StackFrame,
                    valueHome,
                    eval,
                    expression_,
                    idx,
                    null
                    );

                // Create a visualizer for the property list, and attach it to the expression.
                var prop_list_visualizer = new PropertyListVisualizer(prop_list_expr, access_ctx_);
                prop_list_expr.SetDataItem(DkmDataCreationDisposition.CreateAlways, new ExpressionDataItem(prop_list_visualizer));

                items[idx] = prop_list_expr;
            }
        }