Added MemoryStreamDebugVisualizer
This commit is contained in:
5
MemoryStreamDebugVisualizer/DebugVisualizer.slnx
Normal file
5
MemoryStreamDebugVisualizer/DebugVisualizer.slnx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<Solution>
|
||||||
|
<Project Path="MemoryStreamObjectSource/MemoryStreamObjectSource.csproj" />
|
||||||
|
<Project Path="MemoryStreamVisualizer/MemoryStreamVisualizer.csproj" />
|
||||||
|
<Project Path="TestApp/TestApp.csproj" />
|
||||||
|
</Solution>
|
||||||
14
MemoryStreamDebugVisualizer/Directory.Build.props
Normal file
14
MemoryStreamDebugVisualizer/Directory.Build.props
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<RepoRootPath>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)'))</RepoRootPath>
|
||||||
|
<BaseIntermediateOutputPath>$(RepoRootPath)obj\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
|
||||||
|
<BaseOutputPath Condition=" '$(BaseOutputPath)' == '' ">$(RepoRootPath)bin\$(MSBuildProjectName)\</BaseOutputPath>
|
||||||
|
<SignAssembly>false</SignAssembly>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<DisableImplicitNamespaceImports>true</DisableImplicitNamespaceImports>
|
||||||
|
<EnforceCodeStyleInBuild>false</EnforceCodeStyleInBuild>
|
||||||
|
<EnableNETAnalyzers>false</EnableNETAnalyzers>
|
||||||
|
<AnalysisLevel>latest</AnalysisLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>12</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AdditionalFiles Remove="C:\Users\heilm\source\repos\DebugVisualizer\stylecop.json" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.DebuggerVisualizers" Version="17.6.1032901" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
// <copyright file="MemoryStreamVisualizerObjectSource.cs" company="PlaceholderCompany">
|
||||||
|
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||||
|
// </copyright>
|
||||||
|
|
||||||
|
namespace MemoryStreamObjectSource;
|
||||||
|
|
||||||
|
using Microsoft.VisualStudio.DebuggerVisualizers;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Object source class for the MemoryStreamVisualizer.
|
||||||
|
/// </summary>
|
||||||
|
public class MemoryStreamVisualizerObjectSource : VisualizerObjectSource
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// How many rows will be transfered, at most, responding to a single request.
|
||||||
|
/// </summary>
|
||||||
|
public const int RowsCountPerRequest = 1024;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How many bytes will be transfered for each row.
|
||||||
|
/// </summary>
|
||||||
|
public const int RowLength = 16;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override void TransferData(object target, Stream incomingData, Stream outgoingData)
|
||||||
|
{
|
||||||
|
if (target is not MemoryStream memoryStream)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
using BinaryReader binaryReader = new(incomingData);
|
||||||
|
var index = binaryReader.ReadInt32(); // The extension will send the offset (Int32) to start reading from
|
||||||
|
|
||||||
|
using BinaryWriter binaryWriter = new(outgoingData);
|
||||||
|
var backupPosition = memoryStream.Position;
|
||||||
|
|
||||||
|
// Will reply with the current MemoryStream.Position (Int64),
|
||||||
|
// followed by MemoryStream.Length (Int64),
|
||||||
|
// followed by up to 16KB of data retrieved from the MemoryStream
|
||||||
|
binaryWriter.Write(backupPosition);
|
||||||
|
binaryWriter.Write(memoryStream.Length);
|
||||||
|
if (index < memoryStream.Length)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var data = new byte[RowsCountPerRequest * RowLength];
|
||||||
|
memoryStream.Seek(index, SeekOrigin.Begin);
|
||||||
|
var count = memoryStream.Read(data, 0, data.Length);
|
||||||
|
binaryWriter.Write(data, 0, count);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Make sure to restore the MemoryStream to its original position
|
||||||
|
memoryStream.Seek(backupPosition, SeekOrigin.Begin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binaryWriter.Flush();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
|
namespace MemoryStreamVisualizer;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.VisualStudio.Extensibility;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension entrypoint for the VisualStudio.Extensibility extension.
|
||||||
|
/// </summary>
|
||||||
|
[VisualStudioContribution]
|
||||||
|
internal class ExtensionEntrypoint : Extension
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override ExtensionConfiguration ExtensionConfiguration => new()
|
||||||
|
{
|
||||||
|
Metadata = new(
|
||||||
|
id: "MemoryStreamVisualizer.97a0a2fb-f163-4fa3-91f0-48a2d4ad9f57",
|
||||||
|
version: this.ExtensionAssemblyVersion,
|
||||||
|
publisherName: "Microsoft",
|
||||||
|
displayName: "MemoryStream Debugger Visualizer",
|
||||||
|
description: "A debugger visualizer for MemoryStream"),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void InitializeServices(IServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
|
base.InitializeServices(serviceCollection);
|
||||||
|
|
||||||
|
// You can configure dependency injection here by adding services to the serviceCollection.
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
|
namespace MemoryStreamVisualizer;
|
||||||
|
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ViewModel class representing a row of binary data.
|
||||||
|
/// </summary>
|
||||||
|
[DataContract]
|
||||||
|
public class HexEditorRow
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HexEditorRow"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The index of this row.</param>
|
||||||
|
/// <param name="data">The bytes making up this row of data, in their hex representation.</param>
|
||||||
|
/// <param name="ascii">The bytes making up this row of data, in their Ascii representation.</param>
|
||||||
|
public HexEditorRow(int index, string data, string ascii)
|
||||||
|
{
|
||||||
|
this.Index = index;
|
||||||
|
this.Data = data;
|
||||||
|
this.Ascii = ascii;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the index of this row.
|
||||||
|
/// </summary>
|
||||||
|
[DataMember]
|
||||||
|
public int Index { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the index of this row in hex format.
|
||||||
|
/// </summary>
|
||||||
|
[DataMember]
|
||||||
|
public string HexIndex => $"{this.Index:X8}h";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the bytes making up this row of data, in their hex representation.
|
||||||
|
/// </summary>
|
||||||
|
[DataMember]
|
||||||
|
public string Data { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the bytes making up this row of data, in their Ascii representation.
|
||||||
|
/// </summary>
|
||||||
|
[DataMember]
|
||||||
|
public string Ascii { get; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
|
namespace MemoryStreamVisualizer;
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Windows;
|
||||||
|
using Microsoft.VisualStudio.Extensibility.UI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ViewModel class representing the data contained by a <see cref="MemoryStream"/>.
|
||||||
|
/// </summary>
|
||||||
|
[DataContract]
|
||||||
|
public class MemoryStreamData : NotifyPropertyChangedObject
|
||||||
|
{
|
||||||
|
private long length;
|
||||||
|
private long position;
|
||||||
|
private Visibility loadingVisibility = Visibility.Visible;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the length of the <see cref="MemoryStream"/>.
|
||||||
|
/// </summary>
|
||||||
|
[DataMember]
|
||||||
|
public long Length
|
||||||
|
{
|
||||||
|
get => this.length;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (this.SetProperty(ref this.length, value))
|
||||||
|
{
|
||||||
|
this.RaiseNotifyPropertyChangedEvent(nameof(this.HexLength));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the length of the <see cref="MemoryStream"/> in hex format.
|
||||||
|
/// </summary>
|
||||||
|
[DataMember]
|
||||||
|
public string HexLength => $"{this.length:X}h";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the current position of the <see cref="MemoryStream"/>.
|
||||||
|
/// </summary>
|
||||||
|
[DataMember]
|
||||||
|
public long Position
|
||||||
|
{
|
||||||
|
get => this.position;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (this.SetProperty(ref this.position, value))
|
||||||
|
{
|
||||||
|
this.RaiseNotifyPropertyChangedEvent(nameof(this.HexPosition));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current position of the <see cref="MemoryStream"/> in hex format.
|
||||||
|
/// </summary>
|
||||||
|
[DataMember]
|
||||||
|
public string HexPosition => $"{this.position:X}h";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the data currently contained in the <see cref="MemoryStream"/>.
|
||||||
|
/// </summary>
|
||||||
|
[DataMember]
|
||||||
|
public ObservableList<HexEditorRow> Data { get; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the loading bar should be visible.
|
||||||
|
/// </summary>
|
||||||
|
[DataMember]
|
||||||
|
public Visibility LoadingVisibility
|
||||||
|
{
|
||||||
|
get => this.loadingVisibility;
|
||||||
|
set => this.SetProperty(ref this.loadingVisibility, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
|
namespace MemoryStreamVisualizer;
|
||||||
|
|
||||||
|
using MemoryStreamObjectSource;
|
||||||
|
using Microsoft.VisualStudio.Extensibility;
|
||||||
|
using Microsoft.VisualStudio.Extensibility.DebuggerVisualizers;
|
||||||
|
using Microsoft.VisualStudio.RpcContracts.RemoteUI;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Debugger visualizer provider for <see cref="MemoryStream"/>.
|
||||||
|
/// </summary>
|
||||||
|
[VisualStudioContribution]
|
||||||
|
internal class MemoryStreamDebuggerVisualizerProvider : DebuggerVisualizerProvider
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override DebuggerVisualizerProviderConfiguration DebuggerVisualizerProviderConfiguration => new(
|
||||||
|
[
|
||||||
|
new VisualizerTargetType("%MemoryStreamVisualizer.MemoryStreamDebuggerVisualizerProvider.Name%", typeof(MemoryStream))
|
||||||
|
])
|
||||||
|
{
|
||||||
|
VisualizerObjectSourceType = new VisualizerObjectSourceType(typeof(MemoryStreamVisualizerObjectSource)),
|
||||||
|
Style = VisualizerStyle.ToolWindow,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override Task<IRemoteUserControl> CreateVisualizerAsync(VisualizerTarget visualizerTarget, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return Task.FromResult<IRemoteUserControl>(new MemoryStreamVisualizerUserControl(visualizerTarget));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0-windows8.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>12</LangVersion>
|
||||||
|
<NeutralLanguage>en-US</NeutralLanguage>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AdditionalFiles Remove="C:\Users\heilm\source\repos\DebugVisualizer\stylecop.json" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.14.40608" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.14.40608" PrivateAssets="all" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="MemoryStreamVisualizerUserControl.xaml" />
|
||||||
|
<EmbeddedResource Include="MemoryStreamVisualizerUserControl.xaml" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\MemoryStreamObjectSource\MemoryStreamObjectSource.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="..\bin\MemoryStreamObjectSource\$(Configuration)\netstandard2.0\MemoryStreamObjectSource.dll" Link="netstandard2.0\MemoryStreamObjectSource.dll" CopyToOutputDirectory="PreserveNewest" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
|
|
||||||
|
using MemoryStreamObjectSource;
|
||||||
|
using Microsoft.VisualStudio.Extensibility.DebuggerVisualizers;
|
||||||
|
using Microsoft.VisualStudio.Extensibility.UI;
|
||||||
|
using Microsoft.VisualStudio.RpcContracts.DebuggerVisualizers;
|
||||||
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace MemoryStreamVisualizer;
|
||||||
|
/// <summary>
|
||||||
|
/// Remote UI user control for the MemoryStreamVisualizer.
|
||||||
|
/// </summary>
|
||||||
|
internal class MemoryStreamVisualizerUserControl : RemoteUserControl
|
||||||
|
{
|
||||||
|
private readonly VisualizerTarget visualizerTarget;
|
||||||
|
private readonly MemoryStreamData dataContext;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MemoryStreamVisualizerUserControl"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="visualizerTarget">The visualizer target to be used to retrieve data from.</param>
|
||||||
|
public MemoryStreamVisualizerUserControl(VisualizerTarget visualizerTarget)
|
||||||
|
: base(new MemoryStreamData())
|
||||||
|
{
|
||||||
|
visualizerTarget.Changed += this.VisualizerTargetStateChangedAsync;
|
||||||
|
|
||||||
|
this.dataContext = (MemoryStreamData)this.DataContext!;
|
||||||
|
this.visualizerTarget = visualizerTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task VisualizerTargetStateChangedAsync(VisualizerTargetStateNotification args)
|
||||||
|
{
|
||||||
|
if (args == VisualizerTargetStateNotification.Available || args == VisualizerTargetStateNotification.ValueUpdated)
|
||||||
|
{
|
||||||
|
this.dataContext.Data.Clear();
|
||||||
|
this.dataContext.Position = 0;
|
||||||
|
this.dataContext.Length = 0;
|
||||||
|
this.dataContext.LoadingVisibility = Visibility.Visible;
|
||||||
|
|
||||||
|
return this.RetrieveDataAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RetrieveDataAsync()
|
||||||
|
{
|
||||||
|
ReadOnlySequence<byte> data;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
using MemoryStream memoryStream = new(sizeof(int));
|
||||||
|
using BinaryWriter binaryWriter = new(memoryStream);
|
||||||
|
int index = this.dataContext.Data.Count * MemoryStreamVisualizerObjectSource.RowLength;
|
||||||
|
if (index >= 1024 * 1024)
|
||||||
|
{
|
||||||
|
break; // Let's not retrieve more than 1MB of data
|
||||||
|
}
|
||||||
|
|
||||||
|
binaryWriter.Write(index);
|
||||||
|
binaryWriter.Flush();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
data = (await this.visualizerTarget.ObjectSource.RequestDataAsync(new ReadOnlySequence<byte>(memoryStream.ToArray()), CancellationToken.None)).Value;
|
||||||
|
}
|
||||||
|
#pragma warning disable CA1031 // Do not catch general exception types
|
||||||
|
catch (Exception)
|
||||||
|
#pragma warning restore CA1031 // Do not catch general exception types
|
||||||
|
{
|
||||||
|
// I can get an exception if the debug session is unpaused, so I need to handle it gracefully
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (data.Length > 0 && this.Read(data));
|
||||||
|
|
||||||
|
this.dataContext.LoadingVisibility = Visibility.Hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Read(ReadOnlySequence<byte> data)
|
||||||
|
{
|
||||||
|
int byteInRowCount = 0;
|
||||||
|
StringBuilder binaryText = new();
|
||||||
|
StringBuilder asciiText = new();
|
||||||
|
|
||||||
|
SequenceReader<byte> reader = new(data);
|
||||||
|
if (!reader.TryReadLittleEndian(out long position) || !reader.TryReadLittleEndian(out long length))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dataContext.Position = position;
|
||||||
|
this.dataContext.Length = length;
|
||||||
|
|
||||||
|
if (reader.UnreadSpan.Length == 0)
|
||||||
|
{
|
||||||
|
return false; // We always receive data unless we are at the end of the MemoryStream
|
||||||
|
}
|
||||||
|
|
||||||
|
List<HexEditorRow> rows = new(MemoryStreamVisualizerObjectSource.RowsCountPerRequest);
|
||||||
|
byte[] tmp = new byte[1];
|
||||||
|
while (reader.TryRead(out byte b))
|
||||||
|
{
|
||||||
|
byteInRowCount++;
|
||||||
|
if (byteInRowCount > 1)
|
||||||
|
{
|
||||||
|
binaryText.Append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
binaryText.Append(b.ToString("X2", CultureInfo.InvariantCulture));
|
||||||
|
tmp[0] = b;
|
||||||
|
asciiText.Append(char.IsControl((char)b) || b == 0xAD ? '•' : Encoding.Latin1.GetChars(tmp)[0]);
|
||||||
|
|
||||||
|
if (byteInRowCount == MemoryStreamVisualizerObjectSource.RowLength)
|
||||||
|
{
|
||||||
|
CompleteRow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byteInRowCount > 0)
|
||||||
|
{
|
||||||
|
CompleteRow();
|
||||||
|
this.dataContext.Data.AddRange(rows);
|
||||||
|
return false; // We only receive partial rows at the end of the MemoryStream
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dataContext.Data.AddRange(rows);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
void CompleteRow()
|
||||||
|
{
|
||||||
|
rows.Add(new HexEditorRow(
|
||||||
|
index: (this.dataContext.Data.Count + rows.Count) * MemoryStreamVisualizerObjectSource.RowLength,
|
||||||
|
data: binaryText.ToString(),
|
||||||
|
ascii: asciiText.ToString()));
|
||||||
|
|
||||||
|
byteInRowCount = 0;
|
||||||
|
binaryText.Clear();
|
||||||
|
asciiText.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
<DataTemplate xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:vs="http://schemas.microsoft.com/visualstudio/extensibility/2022/xaml"
|
||||||
|
xmlns:styles="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.15.0"
|
||||||
|
xmlns:colors="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<ProgressBar IsIndeterminate="True" VerticalAlignment="Top" Visibility="{Binding LoadingVisibility}" Style="{StaticResource {x:Static styles:VsResourceKeys.ProgressBarStyleKey}}" />
|
||||||
|
<StackPanel Orientation="Horizontal" Grid.Row="1">
|
||||||
|
<Label VerticalAlignment="Center" Style="{StaticResource {x:Static styles:VsResourceKeys.ThemedDialogLabelStyleKey}}">Position: </Label>
|
||||||
|
<TextBox IsReadOnly="True" Width="75" VerticalAlignment="Center">
|
||||||
|
<TextBox.Style>
|
||||||
|
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Static styles:VsResourceKeys.TextBoxStyleKey}}">
|
||||||
|
<Setter Property="Text" Value="{Binding Position, Mode=OneWay}" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsChecked, ElementName=HexCheck, FallbackValue=True}" Value="True">
|
||||||
|
<Setter Property="Text" Value="{Binding HexPosition, Mode=OneWay}" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</TextBox.Style>
|
||||||
|
</TextBox>
|
||||||
|
<Label Margin="2,0,0,0" VerticalAlignment="Center" Style="{StaticResource {x:Static styles:VsResourceKeys.ThemedDialogLabelStyleKey}}">Length:</Label>
|
||||||
|
<TextBox IsReadOnly="True" Width="100" VerticalAlignment="Center">
|
||||||
|
<TextBox.Style>
|
||||||
|
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Static styles:VsResourceKeys.TextBoxStyleKey}}">
|
||||||
|
<Setter Property="Text" Value="{Binding Length, Mode=OneWay}" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsChecked, ElementName=HexCheck, FallbackValue=True}" Value="True">
|
||||||
|
<Setter Property="Text" Value="{Binding HexLength, Mode=OneWay}" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</TextBox.Style>
|
||||||
|
</TextBox>
|
||||||
|
<CheckBox x:Name="HexCheck" Margin="5,0,0,0" VerticalAlignment="Center" Style="{StaticResource {x:Static styles:VsResourceKeys.CheckBoxStyleKey}}">Hex</CheckBox>
|
||||||
|
</StackPanel>
|
||||||
|
<DataGrid ItemsSource="{Binding Data}"
|
||||||
|
EnableRowVirtualization="True"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
SelectionMode="Extended"
|
||||||
|
SelectionUnit="Cell"
|
||||||
|
CanUserReorderColumns="False"
|
||||||
|
CanUserResizeColumns="False"
|
||||||
|
CanUserResizeRows="False"
|
||||||
|
CanUserSortColumns="False"
|
||||||
|
IsReadOnly="True"
|
||||||
|
Grid.Row="2">
|
||||||
|
<DataGrid.Resources>
|
||||||
|
<Style x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type DataGrid}, ResourceId=DataGridSelectAllButtonStyle}" TargetType="{x:Type Button}">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type Button}">
|
||||||
|
<Rectangle Fill="{DynamicResource {x:Static colors:ThemedDialogColors.GridHeadingBackgroundBrushKey}}"/>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</DataGrid.Resources>
|
||||||
|
<DataGrid.Style>
|
||||||
|
<Style TargetType="{x:Type DataGrid}">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource {x:Static colors:ThemedDialogColors.GridHeadingBackgroundBrushKey}}"/>
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static colors:ThemedDialogColors.GridLineBrushKey}}"/>
|
||||||
|
<Setter Property="BorderThickness" Value="1"/>
|
||||||
|
</Style>
|
||||||
|
</DataGrid.Style>
|
||||||
|
<DataGrid.RowStyle>
|
||||||
|
<Style TargetType="{x:Type DataGridRow}">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource {x:Static colors:ThemedDialogColors.GridHeadingBackgroundBrushKey}}"/>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource {x:Static colors:ThemedDialogColors.WindowPanelTextBrushKey}}"/>
|
||||||
|
</Style>
|
||||||
|
</DataGrid.RowStyle>
|
||||||
|
<DataGrid.RowHeaderStyle>
|
||||||
|
<Style TargetType="{x:Type DataGridRowHeader}">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource {x:Static colors:ThemedDialogColors.GridHeadingBackgroundBrushKey}}"/>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource {x:Static colors:ThemedDialogColors.GridHeadingTextBrushKey}}"/>
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static colors:ThemedDialogColors.GridLineBrushKey}}"/>
|
||||||
|
<Setter Property="Content" Value="{Binding Index, Mode=OneWay}" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsChecked, ElementName=HexCheck, FallbackValue=True}" Value="True">
|
||||||
|
<Setter Property="Content" Value="{Binding HexIndex, Mode=OneWay}" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</DataGrid.RowHeaderStyle>
|
||||||
|
<DataGrid.ColumnHeaderStyle>
|
||||||
|
<Style TargetType="{x:Type DataGridColumnHeader}">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource {x:Static colors:ThemedDialogColors.GridHeadingBackgroundBrushKey}}"/>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource {x:Static colors:ThemedDialogColors.GridHeadingTextBrushKey}}"/>
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static colors:ThemedDialogColors.GridLineBrushKey}}"/>
|
||||||
|
<Setter Property="Padding" Value="2,0,0,0"/>
|
||||||
|
</Style>
|
||||||
|
</DataGrid.ColumnHeaderStyle>
|
||||||
|
<DataGrid.CellStyle>
|
||||||
|
<Style TargetType="{x:Type DataGridCell}">
|
||||||
|
<Style.Triggers>
|
||||||
|
<Trigger Property="IsSelected" Value="True">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource {x:Static colors:ThemedDialogColors.ActionButtonStrokeHoverBrushKey}}"/>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource {x:Static colors:ThemedDialogColors.ActionButtonTextActiveBrushKey}}"/>
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static colors:ThemedDialogColors.ActionButtonStrokeHoverBrushKey}}"/>
|
||||||
|
</Trigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</DataGrid.CellStyle>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Hex value" Binding="{Binding Data}" FontFamily="Consolas" />
|
||||||
|
<DataGridTextColumn Header="Ascii" Binding="{Binding Ascii}" FontFamily="Consolas" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
23
MemoryStreamDebugVisualizer/TestApp/Program.cs
Normal file
23
MemoryStreamDebugVisualizer/TestApp/Program.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// <copyright file="Program.cs" company="PlaceholderCompany">
|
||||||
|
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||||
|
// </copyright>
|
||||||
|
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
// Initialize a MemoryStream to store user input temporarily
|
||||||
|
using MemoryStream userInputStream = new();
|
||||||
|
|
||||||
|
// Convert user input string to byte array
|
||||||
|
string userInput = "Sample user input data";
|
||||||
|
|
||||||
|
byte[] inputData = Encoding.UTF8.GetBytes(userInput);
|
||||||
|
|
||||||
|
// Write user input data to the MemoryStream
|
||||||
|
userInputStream.Write(inputData, 0, inputData.Length);
|
||||||
|
var buffer = new byte[inputData.Length];
|
||||||
|
userInputStream.Position = 0;
|
||||||
|
userInputStream.Read(buffer);
|
||||||
|
var text = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
|
||||||
|
|
||||||
|
// Perform further processing with the stored user input
|
||||||
|
Thread.Sleep(1000);
|
||||||
14
MemoryStreamDebugVisualizer/TestApp/TestApp.csproj
Normal file
14
MemoryStreamDebugVisualizer/TestApp/TestApp.csproj
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<AdditionalFiles Remove="C:\Users\heilm\source\repos\DebugVisualizer\stylecop.json" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Reference in New Issue
Block a user