Repository navigation
Creating Your First Plugin
NyxionSoftware edited this page Aug 5, 2026
·
2 revisions
Create a WPF-enabled class library targeting the same framework as the application:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<Reference Include="SimulcastUtility.Plugins">
<HintPath>lib\SimulcastUtility.Plugins.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="SimulcastUtility.Application">
<HintPath>lib\SimulcastUtility.Application.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="SimulcastUtility.Core">
<HintPath>lib\SimulcastUtility.Core.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup>
</Project>Use matching DLLs from the application's published output. Private=false prevents shared host contracts from being copied into the plugin package. Microsoft.Extensions.Logging.Abstractions is already referenced by the plugin contract project; add a matching package reference explicitly if your build environment requires it for logging extension methods.
using Microsoft.Extensions.Logging;
using SimulcastUtility.Plugins.Interfaces;
namespace ExamplePlugin
{
public sealed class Plugin : ISimulcastPlugin
{
private IPluginContext? _context;
public IPluginInfo Info { get; } = new ExamplePluginInfo();
public Task InitializeAsync(IPluginContext pluginContext, CancellationToken cancellationToken = default)
{
_context = pluginContext;
pluginContext.Logger.LogInformation("{PluginName} initialized.", Info.Name);
return Task.CompletedTask;
}
public Task EnableAsync(CancellationToken cancellationToken = default)
{
_context!.ReceiverManager.SelectedReceiverChanged += SelectedReceiverChanged;
_context.Logger.LogInformation("{PluginName} enabled.", Info.Name);
return Task.CompletedTask;
}
public Task DisableAsync(CancellationToken cancellationToken = default)
{
if (_context is not null)
_context.ReceiverManager.SelectedReceiverChanged -= SelectedReceiverChanged;
return Task.CompletedTask;
}
public Task HandleApplicationArgumentsAsync(IReadOnlyList<string> arguments, CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
}
private void SelectedReceiverChanged(object? sender, EventArgs e)
{
_context?.Logger.LogDebug("The selected receiver changed.");
}
}
public sealed class ExamplePluginInfo : IPluginInfo
{
public Guid PluginIdentifier { get; } = Guid.Parse("REPLACE-WITH-A-PERMANENT-GUID");
public string Name => "Example Plugin";
public string Description => "A minimal Simulcast Utility plugin.";
public Version Version => new(1, 0, 0);
public string Author => "Your Name";
}
}Generate the GUID once with Guid.NewGuid() or Visual Studio's Create GUID tool. Never ship the placeholder and never change the published identifier.
- Build the plugin.
- Copy its DLL and private dependencies to a subfolder of the configured plugin directory.
- Open Manage Plugins.
- Select Refresh Installed Plugins.
- Enable the plugin and inspect the application log.
- Disable and re-enable it to test cleanup.
- Delete it through Manage Plugins to confirm the load context can unload.