private TreeViewItem CreateTreeItem(TreeListView tree, IResultVisualizer resultVisualizer, int level) { UIElement value = resultVisualizer.Value as UIElement; if (value == null) { value = new TextBlock() { Text = resultVisualizer.ValueString, }; } TreeViewItem item = CreateTreeItem(tree, resultVisualizer.Name, resultVisualizer.Image, level, value, resultVisualizer.Type); item.Tag = new TreeViewItemTag() { ResultTreeItem = resultVisualizer, Level = level, }; if (resultVisualizer.IsExpandable) { item.Items.Add(ExpandingItemText); item.Expanded += TreeViewItem_Expanded; } return(item); }
public object Output(object obj) { // We don't visualize null if (obj == null) { return(null); } // Primitive types and strings are visualized as ToString if (obj.GetType().IsPrimitive || obj is string) { return(obj.ToString()); } // UI elements should be resurfaced back. if (obj is UIElement) { return(obj); } // All other should be visualized in a table IResultVisualizer resultTreeItem = ResultVisualizer.Create(obj, obj.GetType(), "result", null, this); resultTreeItem.Initialize(); return(new LazyUIResult(() => Visualize(resultTreeItem))); }
/// <summary> /// Evaluates visual expression and converts it to result visualizer. /// </summary> private void Evaluate() { if (VisualizedExpression.TagValue == DkmVisualizedExpression.Tag.RootVisualizedExpression) { DkmRootVisualizedExpression rootVisualizedExpression = VisualizedExpression as DkmRootVisualizedExpression; int processId = rootVisualizedExpression.InspectionSession?.Process?.LivePart?.Id ?? 0; string moduleName = rootVisualizedExpression.Module?.Name; string typeString = rootVisualizedExpression.Type; ulong address = 0; bool hasAddress = false; if (VisualizedExpression.ValueHome.TagValue == DkmExpressionValueHome.Tag.PointerValueHome) { address = (VisualizedExpression.ValueHome as DkmPointerValueHome).Address; hasAddress = true; } if (string.IsNullOrEmpty(typeString) || string.IsNullOrEmpty(moduleName) || !hasAddress) { string displayString = "{...CsDebugScript failure...}"; EvaluationResult = DkmSuccessEvaluationResult.Create( VisualizedExpression.InspectionContext, VisualizedExpression.StackFrame, rootVisualizedExpression.Name, rootVisualizedExpression.FullName, DkmEvaluationResultFlags.ReadOnly, displayString, "", rootVisualizedExpression.Type, DkmEvaluationResultCategory.Other, DkmEvaluationResultAccessType.None, DkmEvaluationResultStorageType.None, DkmEvaluationResultTypeModifierFlags.None, null, null, null, null); return; } string title; try { Process process = Process.All.First(p => p.SystemId == processId); Module module = process.ModulesByName[System.IO.Path.GetFileNameWithoutExtension(moduleName)]; CodeType codeType = ResolveCodeType(process, module, typeString); Variable = codeType.IsPointer ? Variable.CreatePointer(codeType, address) : Variable.Create(codeType, address); title = Variable.ToString(); ResultVisualizer = CsDebugScript.UI.ResultVisualizers.ResultVisualizer.Create(Variable, Variable.GetType(), "result", CompletionDataType.Unknown, dummyInteractiveResultVisualizer); } catch { title = "{...CsDebugScript...}"; } DkmDataAddress dkmDataAddress = DkmDataAddress.Create(VisualizedExpression.RuntimeInstance, address, rootVisualizedExpression.StackFrame?.InstructionAddress); EvaluationResult = DkmSuccessEvaluationResult.Create( VisualizedExpression.InspectionContext, VisualizedExpression.StackFrame, rootVisualizedExpression.Name, rootVisualizedExpression.FullName, DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Expandable, title, "", rootVisualizedExpression.Type, DkmEvaluationResultCategory.Other, DkmEvaluationResultAccessType.None, DkmEvaluationResultStorageType.None, DkmEvaluationResultTypeModifierFlags.None, dkmDataAddress, VSUIVisualizerService.GetUIVisualizers(ResultVisualizer), null, null); return; } // This should never happen... throw new NotImplementedException(); }
/// <summary> /// Initializes the <see cref="VSCustomVisualizerEvaluator"/> class. /// </summary> /// <param name="evaluationResult"></param> /// <param name="resultVisualizer"></param> public VSCustomVisualizerEvaluator(DkmEvaluationResult evaluationResult, IResultVisualizer resultVisualizer) { EvaluationResult = evaluationResult; ResultVisualizer = resultVisualizer; }
private void TreeViewItem_Expanded(object sender, RoutedEventArgs e) { try { TreeViewItem item = e.Source as TreeViewItem; TreeListView tree = null; FrameworkElement parent = item?.Parent as FrameworkElement; while (tree == null && parent != null) { tree = parent as TreeListView; parent = parent.Parent as FrameworkElement; } if ((item.Items.Count == 1) && (item.Items[0].ToString() == ExpandingItemText)) { TreeViewItemTag tag = item.Tag as TreeViewItemTag; System.Threading.Tasks.Task.Run(() => { IResultVisualizer resultTreeItem = tag.ResultTreeItem as IResultVisualizer; IEnumerable <IResultVisualizer> children = tag.ResultTreeItem as IEnumerable <IResultVisualizer>; try { if (resultTreeItem != null) { List <Tuple <string, IEnumerable <IResultVisualizer> > > customChildren = new List <Tuple <string, IEnumerable <IResultVisualizer> > >(); foreach (Tuple <string, IEnumerable <IResultVisualizer> > customChild in resultTreeItem.Children) { if (customChild.Item2.Any()) { if (customChild.Item1 == "[Expanded]") { List <IResultVisualizer> cachedItems = customChild.Item2.ToList(); customChildren.Add(Tuple.Create(customChild.Item1, (IEnumerable <IResultVisualizer>)cachedItems)); foreach (IResultVisualizer child in cachedItems) { child.Initialize(); } } else { customChildren.Add(customChild); } } } item.Dispatcher.InvokeAsync(() => { try { int level = tag.Level; item.Items.Clear(); foreach (Tuple <string, IEnumerable <IResultVisualizer> > customChild in customChildren) { if (customChild.Item1 == "[Expanded]") { foreach (IResultVisualizer child in customChild.Item2) { item.Items.Add(CreateTreeItem(tree, child, level + 1)); } } else { TreeViewItem customItem = CreateTreeItem(tree, customChild.Item1, CompletionData.GetImage(CompletionDataType.Namespace), level + 1, nameItalic: true); customItem.Tag = new TreeViewItemTag() { Level = level + 1, ResultTreeItem = customChild.Item2, }; customItem.Items.Add(ExpandingItemText); customItem.Expanded += TreeViewItem_Expanded; item.Items.Add(customItem); } } } catch (Exception ex3) { MessageBox.Show(ex3.ToString()); } }); } else if (children != null) { List <IResultVisualizer> cachedItems = children.ToList(); foreach (IResultVisualizer child in children) { child.Initialize(); } item.Dispatcher.InvokeAsync(() => { try { int level = tag.Level; item.Items.Clear(); foreach (IResultVisualizer child in cachedItems) { item.Items.Add(CreateTreeItem(tree, child, level + 1)); } } catch (Exception ex3) { MessageBox.Show(ex3.ToString()); } }); } } catch (Exception ex2) { MessageBox.Show(ex2.ToString()); } }); } } catch (Exception ex) { MessageBox.Show(ex.ToString()); } }
private UIElement Visualize(IResultVisualizer resultVisualizer) { // Create tree and its columns TreeListView tree = new TreeListView(); tree.Columns.Add(new GridViewColumn() { Header = "Name", CellTemplate = new DataTemplate() { VisualTree = CreateStackPanelFactory("Name") }, Width = 200, }); tree.Columns.Add(new GridViewColumn() { Header = "Value", CellTemplate = new DataTemplate() { VisualTree = CreateStackPanelFactory("Value") }, Width = 600, }); tree.Columns.Add(new GridViewColumn() { Header = "Type", CellTemplate = new DataTemplate() { VisualTree = CreateStackPanelFactory("Type") }, Width = 200, }); // Create header row TreeViewItem header = new TreeViewItem(); header.Header = new GridViewHeaderRowPresenter() { Columns = tree.Columns, }; tree.Items.Add(header); // Create result item TreeViewItem resultItem = CreateTreeItem(tree, resultVisualizer, 0); tree.Items.Add(resultItem); resultItem.IsExpanded = true; // Initialize tree events tree.PreviewMouseWheel += Tree_PreviewMouseWheel; tree.PreviewKeyDown += Tree_PreviewKeyDown; tree.LostFocus += (a, b) => { var item = tree.SelectedItem as TreeViewItem; if (item != null) { item.IsSelected = false; } }; tree.GotFocus += (a, b) => { var item = tree.SelectedItem as TreeViewItem; if (item == null) { if (interactiveWindowContent.TraverseDirection.HasValue) { if (interactiveWindowContent.TraverseDirection == FocusNavigationDirection.Next) { item = tree.Items[1] as TreeViewItem; } else { item = tree.Items[tree.Items.Count - 1] as TreeViewItem; while (item.IsExpanded) { item = item.Items[item.Items.Count - 1] as TreeViewItem; } } } else { item = tree.Items[1] as TreeViewItem; } if (item != null) { item.IsSelected = true; } } }; dispatcher = tree.Dispatcher; return(tree); }
/// <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); } }
/// <summary> /// Finds best collection of UI visualizers that will be used for result visualizer. /// </summary> /// <param name="resultVisualizer">Result visualizer.</param> /// <returns>Best collection of UI visualizers</returns> internal static ReadOnlyCollection <DkmCustomUIVisualizerInfo> GetUIVisualizers(IResultVisualizer resultVisualizer) { // Get resulting object that is being visualized object result = (resultVisualizer as ResultVisualizer)?.Result; // Variable can be visualized in all UI visualizers if (result is Variable) { return(AllCustomUiVisualizers); } // TODO: There are many examples of different visualizers, for example CodeType can be visualized per byte usage return(null); }
public object Output(object obj) { // We don't visualize null if (obj == null) { return(null); } // Primitive types and strings are visualized as ToString if (obj.GetType().IsPrimitive || obj is string) { return(obj.ToString()); } // UI elements should be resurfaced back. if (obj is UIElement) { return(obj); } // Drawing objects should be resurfaced back. IDrawing drawing = obj as IDrawing; if (drawing != null) { return(new LazyUIResult(() => new DrawingViewer(drawing))); } // All other should be visualized in a table IResultVisualizer resultTreeItem = ResultVisualizer.Create(obj, obj.GetType(), "result", CompletionDataType.Unknown, this); resultTreeItem.Initialize(); // Check if we can also represent resulting object as a drawing IDrawingVisualizerObject drawingVisualizerObject = obj as IDrawingVisualizerObject; if (drawingVisualizerObject != null && drawingVisualizerObject.CanVisualize()) { Graphics graphics = new Graphics(dispatcher); drawing = drawingVisualizerObject.CreateDrawing(graphics); } if (drawing != null) { // Create panel that will hold both elements. return(new LazyUIResult(() => { StackPanel panel = new StackPanel(); panel.Orientation = Orientation.Vertical; panel.Children.Add(Visualize(resultTreeItem)); panel.Children.Add(new DrawingViewer(drawing)); return panel; })); } // Check if it is console printer if (obj is IConsoleVisualizer consoleVisualizer) { consoleVisualizer.PrintOnConsole(); return(null); } return(new LazyUIResult(() => Visualize(resultTreeItem))); }