123 lines
4.7 KiB
C#
123 lines
4.7 KiB
C#
![]() |
using System;
|
||
|
using System.ComponentModel.Composition;
|
||
|
using System.IO;
|
||
|
using dnSpy.Contracts.Decompiler;
|
||
|
using dnSpy.Contracts.Documents;
|
||
|
using dnSpy.Contracts.Documents.Tabs.DocViewer;
|
||
|
using dnSpy.Contracts.Documents.TreeView;
|
||
|
using dnSpy.Contracts.Images;
|
||
|
using dnSpy.Contracts.Text;
|
||
|
|
||
|
// Adds a new IDsDocument that can be loaded into the document treeview. It gets its own DsDocumentNode.
|
||
|
// Open a .txt/.xml/.cs/.vb (see supportedExtensions) file to trigger this code.
|
||
|
|
||
|
namespace Example2.Extension {
|
||
|
// All root nodes in the document treeview contain a IDsDocument instance. They don't need to be
|
||
|
// .NET files or even PE files, they can be any file or even non-file (eg. in-memory data).
|
||
|
sealed class MyDsDocument : DsDocument {
|
||
|
//TODO: Use your own guid
|
||
|
public static readonly Guid THE_GUID = new Guid("9058B02C-1FE0-4EC4-93D3-A378D4B6FCE1");
|
||
|
|
||
|
// We support serialization, so return a non-null value
|
||
|
public override DsDocumentInfo? SerializedDocument => new DsDocumentInfo(Filename, THE_GUID);
|
||
|
|
||
|
// Since we open files from disk, we return a FilenameKey.
|
||
|
// If this gets changed, also update MyDsDocumentProvider.CreateKey()
|
||
|
public override IDsDocumentNameKey Key => new FilenameKey(Filename);
|
||
|
|
||
|
// Used by MyDsDocumentNode.Decompile() to show the file in the text editor
|
||
|
public string Text {
|
||
|
get {
|
||
|
if (text is not null)
|
||
|
return text;
|
||
|
try {
|
||
|
return text = File.ReadAllText(Filename);
|
||
|
}
|
||
|
catch {
|
||
|
return text = $"Couldn't read the file: {Filename}";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
string? text;
|
||
|
|
||
|
public static MyDsDocument? TryCreate(string filename) {
|
||
|
if (!File.Exists(filename))
|
||
|
return null;
|
||
|
return new MyDsDocument(filename);
|
||
|
}
|
||
|
|
||
|
MyDsDocument(string filename) => Filename = filename;
|
||
|
}
|
||
|
|
||
|
// Gets called by the IDsDocumentService instance to create IDsDocument instances. If it's a .txt file
|
||
|
// or our MyDsDocument.THE_GUID, then create a MyDsDocument instance.
|
||
|
[Export(typeof(IDsDocumentProvider))]
|
||
|
sealed class MyDsDocumentProvider : IDsDocumentProvider {
|
||
|
public double Order => 0;
|
||
|
|
||
|
public IDsDocument? Create(IDsDocumentService documentService, DsDocumentInfo documentInfo) {
|
||
|
if (documentInfo.Type == MyDsDocument.THE_GUID)
|
||
|
return MyDsDocument.TryCreate(documentInfo.Name);
|
||
|
// Also check for normal files
|
||
|
if (documentInfo.Type == DocumentConstants.DOCUMENTTYPE_FILE && IsSupportedFile(documentInfo.Name))
|
||
|
return MyDsDocument.TryCreate(documentInfo.Name);
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public IDsDocumentNameKey? CreateKey(IDsDocumentService documentService, DsDocumentInfo documentInfo) {
|
||
|
if (documentInfo.Type == MyDsDocument.THE_GUID)
|
||
|
return new FilenameKey(documentInfo.Name); // Must match the key in MyDsDocument.Key
|
||
|
// Also check for normal files
|
||
|
if (documentInfo.Type == DocumentConstants.DOCUMENTTYPE_FILE && IsSupportedFile(documentInfo.Name))
|
||
|
return new FilenameKey(documentInfo.Name); // Must match the key in MyDsDocument.Key
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
static bool IsSupportedFile(string filename) {
|
||
|
foreach (var ext in supportedExtensions) {
|
||
|
if (filename.EndsWith(ext, StringComparison.OrdinalIgnoreCase))
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
static readonly string[] supportedExtensions = new string[] {
|
||
|
".txt", ".xml", ".cs", ".vb",
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// Gets called by dnSpy to create a DsDocumentNode
|
||
|
[ExportDsDocumentNodeProvider]
|
||
|
sealed class MyDsDocumentNodeProvider : IDsDocumentNodeProvider {
|
||
|
public DsDocumentNode? Create(IDocumentTreeView documentTreeView, DsDocumentNode? owner, IDsDocument document) {
|
||
|
if (document is MyDsDocument myDocument)
|
||
|
return new MyDsDocumentNode(myDocument);
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Our MyDsDocument tree node class. It implements IDecompileSelf to "decompile" itself. You could
|
||
|
// also export a IDecompileNode instance to do it, see TreeNodeDataProvider.cs for an example.
|
||
|
// Or you could create a completely new DocumentTabContent for these nodes, see AssemblyChildNodeTabContent.cs
|
||
|
sealed class MyDsDocumentNode : DsDocumentNode, IDecompileSelf {
|
||
|
//TODO: Use your own guid
|
||
|
public static readonly Guid THE_GUID = new Guid("4174A21D-D746-4658-9A44-DB8235EE5186");
|
||
|
|
||
|
readonly MyDsDocument document;
|
||
|
|
||
|
public override Guid Guid => THE_GUID;
|
||
|
|
||
|
public MyDsDocumentNode(MyDsDocument document)
|
||
|
: base(document) => this.document = document;
|
||
|
|
||
|
protected override ImageReference GetIcon(IDotNetImageService dnImgMgr) => DsImages.TextFile;
|
||
|
protected override void WriteCore(ITextColorWriter output, IDecompiler decompiler, DocumentNodeWriteOptions options) =>
|
||
|
output.WriteFilename(Path.GetFileName(document.Filename));
|
||
|
|
||
|
public bool Decompile(IDecompileNodeContext context) {
|
||
|
context.ContentTypeString = ContentTypes.PlainText;
|
||
|
context.Output.Write(document.Text, BoxedTextColor.Text);
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|