/// <summary> /// Evaluates the specified visualized expression using our custom evaluator. /// </summary> public void EvaluateVisualizedExpression(DkmVisualizedExpression visualizedExpression, out DkmEvaluationResult resultObject) { VSContext.InitializeInteractiveExecution(); VSCustomVisualizerEvaluator evaluator = new VSCustomVisualizerEvaluator(visualizedExpression); resultObject = evaluator.EvaluationResult; visualizedExpression.SetDataItem(DkmDataCreationDisposition.CreateAlways, evaluator); }
/// <summary> /// Function that is being called when user wants custom UI visualizer to visualize evaluated expression. /// </summary> /// <param name="ownerHwnd">Owner HWND. It looks like it is always 0.</param> /// <param name="visualizerId">Visualizer type. <see cref="VSUIVisualizerType"/></param> /// <param name="debugProperty">Evaluated expression.</param> /// <returns>S_OK if succeeds, or HRESULT error otherwise.</returns> public int DisplayValue(uint ownerHwnd, uint visualizerId, IDebugProperty3 debugProperty) { VSUIVisualizerType visualizerType = (VSUIVisualizerType)visualizerId; try { // Extract data DkmSuccessEvaluationResult evaluationResult = DkmSuccessEvaluationResult.ExtractFromProperty(debugProperty); int processId = evaluationResult.InspectionSession?.Process?.LivePart?.Id ?? 0; string moduleName = evaluationResult.ExternalModules?.FirstOrDefault()?.Module?.Name ?? evaluationResult.StackFrame?.ModuleInstance?.Module?.Name; string typeString = evaluationResult.Type; ulong? address = evaluationResult.Address?.Value; string fullName = evaluationResult.FullName; if (!string.IsNullOrEmpty(typeString) && !string.IsNullOrEmpty(moduleName) && address.HasValue) { // Create variable Process process = Process.All.First(p => p.SystemId == processId); Module module = process.ModulesByName[System.IO.Path.GetFileNameWithoutExtension(moduleName)]; CodeType codeType = VSCustomVisualizerEvaluator.ResolveCodeType(process, module, typeString); Variable variable = codeType.IsPointer ? Variable.CreatePointer(codeType, address.Value, fullName) : Variable.Create(codeType, address.Value, fullName); // Open visualizer window switch (visualizerType) { case VSUIVisualizerType.InteractiveWindow: // Add this variable to interactive window and make it visible. VSInteractiveWindowCommand.Instance.ShowToolWindow(); AddVariable("temp", variable, VSInteractiveWindowCommand.Instance.InteractiveWindowTool.InteractiveControl.ContentControl); break; default: case VSUIVisualizerType.ModalWindow: // Open new modal window that will visualize this variable UI.InteractiveWindow.ShowModalWindow((interactiveWindow) => { AddVariable("result", variable, interactiveWindow.ContentControl); }); break; } } } catch (Exception ex) { return(ex.HResult); } return(0); }
/// <summary> /// Returns number of child elements in previous evaluation. /// </summary> public void GetChildren(DkmVisualizedExpression visualizedExpression, int initialRequestSize, DkmInspectionContext inspectionContext, out DkmChildVisualizedExpression[] initialChildren, out DkmEvaluationResultEnumContext enumContext) { // Check if we want to use passthrough visualizer PassThroughVisualizer passThroughVisualizer = visualizedExpression.GetDataItem <PassThroughVisualizer>(); if (passThroughVisualizer != null) { passThroughVisualizer.GetChildren(visualizedExpression, initialRequestSize, inspectionContext, out initialChildren, out enumContext); return; } // Execute our regular visualizer VSCustomVisualizerEvaluator evaluator = visualizedExpression.GetDataItem <VSCustomVisualizerEvaluator>(); initialChildren = new DkmChildVisualizedExpression[0]; enumContext = DkmEvaluationResultEnumContext.Create(evaluator.ResultVisualizer?.Children.Count() ?? 0, visualizedExpression.StackFrame, visualizedExpression.InspectionContext, evaluator); }
/// <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); } }