-
-
Notifications
You must be signed in to change notification settings - Fork 141
Plugin System
The WpfHexEditor Plugin System lets you extend the IDE with new panels, commands, editor features, build backends, solution loaders, and services — packaged as .whxplugin files.
flowchart TD
App["WpfHexEditor.App\nMainWindow.PluginSystem.cs"]
subgraph SDK["WpfHexEditor.SDK (public contracts)"]
IPlugin["IWpfHexEditorPluginV2\n+ LoadPriority"]
ICtx["IIDEHostContext"]
Services["14+ service interfaces\nIHexEditorService · IOutputService\nITerminalService · IUIRegistry\nISolutionLoader · IBuildAdapter\nIEditorToolbarContributor · IQuickInfoProvider\nIGrammarProvider · IIDEEventBus · ..."]
end
subgraph Host["WpfHexEditor.PluginHost (runtime)"]
WpfHost["WpfPluginHost\ndiscovery + sort by priority + load + watchdog"]
ALC["PluginLoadContext\ncollectible AssemblyLoadContext"]
Crash["PluginCrashHandler"]
Watch["PluginWatchdog\nWrapAsync → Task<TimeSpan>"]
PM["PluginManagerControl"]
Monitor["PluginMonitoringViewModel\n1s polling · CPU% · Memory MB"]
end
Sandbox["WpfHexEditor.PluginSandbox\nout-of-process via named-pipe IPC"]
Tools["PackagingTool (whxpack)\nPluginInstaller (WPF dialog)"]
App --> SDK
App --> Host
SDK --> ICtx
ICtx --> Services
Host --> ALC
Host --> Crash
Host --> Watch
Host --> Sandbox
public interface IWpfHexEditorPluginV2
{
string Id { get; } // "com.example.myplugin"
string Name { get; }
string Version { get; }
string? Description { get; }
int LoadPriority { get; } // 0-100; lower = loads first (default: 50)
void Init(IIDEHostContext context);
void Activate();
void Deactivate();
void Dispose();
}
// Optional — auto-registers an Options page under "Plugins"
public interface IPluginWithOptions
{
string OptionsPageTitle { get; }
FrameworkElement CreateOptionsPage();
}public class MyPlugin : IWpfHexEditorPluginV2, IPluginWithOptions
{
private IIDEHostContext? _ctx;
public string Id => "com.example.myplugin";
public string Name => "My Plugin";
public string Version => "1.0.0";
public string? Description => "Does something awesome";
public int LoadPriority => 50;
public string OptionsPageTitle => "My Plugin";
public void Init(IIDEHostContext context)
{
_ctx = context;
context.UIRegistry.RegisterPanel("my-panel", "My Panel", () => new MyPanelView());
context.EventBus.Subscribe<FileOpenedEvent>(e =>
context.OutputService.WriteLine($"Opened: {e.FilePath}"));
}
public void Activate() => _ctx?.UIRegistry.ShowDockablePanel("my-panel");
public void Deactivate() => _ctx?.UIRegistry.HideDockablePanel("my-panel");
public void Dispose() { }
public FrameworkElement CreateOptionsPage() => new MyOptionsPage();
}| Property | Contract | Description |
|---|---|---|
HexEditorService |
IHexEditorService |
Read bytes, search, go to offset |
CodeEditorService |
ICodeEditorService |
Active code editor content |
OutputService |
IOutputService |
Write to Output panel |
ErrorPanelService |
IErrorPanelService |
Post diagnostics (Info/Warning/Error) |
SolutionExplorerService |
ISolutionExplorerService |
Open files, query project tree |
ParsedFieldService |
IParsedFieldService |
Read parsed fields from HexEditor |
TerminalService |
ITerminalService |
Execute commands, write output, history |
UIRegistry |
IUIRegistry |
Show/Hide/Toggle/Focus panels |
EventBus |
IPluginEventBus |
Subscribe/publish IDE-wide events |
IDEEventBus |
IIDEEventBus |
Subscribe to typed domain events (21 event records) |
FocusContextService |
IFocusContextService |
Active editor focus |
PermissionService |
IPermissionService |
Check/request permissions |
ThemeService |
IThemeService |
Current theme, change notifications |
BuildSystem |
IBuildSystem |
Trigger builds, register IBuildAdapter
|
public interface ISolutionLoader : IWpfHexEditorPluginV2
{
int Priority { get; } // Higher = tried first
bool CanLoad(string path); // Called for each dropped/opened file
Task<ISolution> LoadAsync(string path, CancellationToken ct);
Task SaveAsync(ISolution solution, CancellationToken ct);
}Built-in loaders and their priorities:
| Loader | Priority | Handles |
|---|---|---|
SolutionLoader.WH |
95 |
.whsln / .whproj
|
SolutionLoader.VS |
90 |
.sln / .csproj (4 templates) |
SolutionLoader.Folder |
85 |
.whfolder JSON marker, gitignore-aware |
public interface IBuildAdapter : IWpfHexEditorPluginV2
{
bool CanBuild(IProject project);
Task BuildAsync(IProject project, IBuildConfiguration config,
IProgress<BuildProgress> progress, CancellationToken ct);
Task CleanAsync(IProject project, CancellationToken ct);
}Build.MSBuild (priority 85) uses dotnet build CLI and streams output to the Output panel.
public interface IEditorToolbarContributor
{
string TargetEditorId { get; } // e.g. "code-editor"
IReadOnlyList<EditorToolbarItem> GetItems();
}public interface IQuickInfoProvider
{
int Priority { get; }
Task<QuickInfoResult?> GetQuickInfoAsync(QuickInfoRequest request, CancellationToken ct);
}public interface IGrammarProvider
{
string GrammarId { get; }
bool CanApply(string filePath);
Task<GrammarParseResult> ParseAsync(IByteProvider bytes, CancellationToken ct);
}SynalysisGrammar (priority 45) implements IGrammarProvider for UFWB .grammar files.
sequenceDiagram
participant Host as WpfPluginHost
participant ALC as PluginLoadContext
participant Plugin as IWpfHexEditorPluginV2
participant IDE as IIDEHostContext
Host->>ALC: Load assembly (collectible)
ALC->>Plugin: new PluginImpl()
Host->>Plugin: Init(context)
Plugin->>IDE: Register panels, commands, options, solution loaders
Host->>Plugin: Activate()
Note over Plugin: Plugin running
Host->>Plugin: Deactivate()
Host->>Plugin: Dispose()
Host->>ALC: Unload() — clears ALC reference
Note over ALC: GC collects all plugin assemblies (no restart)
{
"id": "com.example.myplugin",
"name": "My Plugin",
"version": "1.0.0",
"description": "Does something awesome",
"author": "Jane Dev",
"entryPoint": "MyPlugin.dll",
"minHostVersion": "0.6.0",
"loadPriority": 50,
"capabilities": ["HexEditor", "Terminal"],
"permissions": ["ReadFile", "WriteOutput"]
}Auto-generate from .csproj with PackagingTool:
<PropertyGroup>
<PluginId>com.example.myplugin</PluginId>
<PluginVersion>1.0.0</PluginVersion>
<PluginEntryPoint>MyPlugin.dll</PluginEntryPoint>
<PluginAuthor>Jane Dev</PluginAuthor>
<PluginLoadPriority>50</PluginLoadPriority>
</PropertyGroup># Build
dotnet build MyPlugin.csproj -c Release
# Package → .whxplugin (ZIP with manifest + DLL)
whxpack --input bin/Release/net8.0-windows --output MyPlugin.whxplugin
# Install (silent for CI)
WpfHexEditor.PluginInstaller.exe --file MyPlugin.whxplugin --silent| Plugin | Priority | Purpose | Options Page |
|---|---|---|---|
SolutionLoader.WH |
95 | Native .whsln/.whproj format |
— |
SolutionLoader.VS |
90 | Visual Studio .sln/.csproj (4 templates) |
— |
SolutionLoader.Folder |
85 | Open-folder mode (gitignore-aware) | — |
Build.MSBuild |
85 |
dotnet build/dotnet run CLI adapter |
Build configs |
DataInspector |
50 | 40+ type interpretations of selected bytes | Display format, endianness |
ParsedFields |
50 | Binary structure overlay in HexEditor | — |
AssemblyExplorer |
40 | .NET PE inspection + C#/IL decompilation | Show non-public, recent files |
SynalysisGrammar |
45 | UFWB binary grammar overlay (IGrammarProvider) |
Grammar paths |
XamlDesigner |
50 | 9 VS-like panels for the XAML Designer | — |
Plugins can subscribe to all 21 typed IDE domain events via IIDEEventBus:
context.IDEEventBus.Subscribe<FileOpenedEvent>(e =>
context.OutputService.WriteLine($"File opened: {e.FilePath}"));
context.IDEEventBus.Subscribe<BuildCompletedEvent>(e =>
context.OutputService.WriteLine($"Build {(e.Success ? "succeeded" : "FAILED")}"));
context.IDEEventBus.Subscribe<GrammarAppliedEvent>(e =>
context.OutputService.WriteLine($"Grammar {e.GrammarId} applied: {e.FieldCount} fields"));Key events: FileOpenedEvent, FileSavedEvent, FileClosedEvent, SolutionOpenedEvent, SolutionClosedEvent, BuildStartedEvent, BuildCompletedEvent, ThemeChangedEvent, DiagnosticRaisedEvent, GrammarAppliedEvent, ActiveEditorChangedEvent.
-
Terminal —
ITerminalServiceusage from plugins - Plugin Monitoring — CPU/memory diagnostics
- Architecture — plugin lifecycle diagram
- FAQ — plugin FAQs
✨ Wpf HexEditor user control, by Derek Tremblay (derektremblay666@gmail.com) coded for your fun! 😊🤟
- API Reference
- Performance
- Services
- Core Components
- ByteProvider
- Rendering Engine
- Search Architecture
- WpfHexEditor.Shell (renamed from Docking.Wpf)
- Code Editor ~90% (NavBar, Inline Hints, Quick Info)
- XAML Visual Designer ~70%
- Shared UndoEngine (coalescing + transactions)
- VS
.sln/.csproj+ Open-Folder mode - Build System (IBuildAdapter + MSBuild plugin)
- Assembly Explorer + NuGet Solution Manager
- Synalysis Grammar Support (IGrammarProvider)