Winstaller.Sdk 0.0.3

dotnet add package Winstaller.Sdk --version 0.0.3
                    
NuGet\Install-Package Winstaller.Sdk -Version 0.0.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Winstaller.Sdk" Version="0.0.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Winstaller.Sdk" Version="0.0.3" />
                    
Directory.Packages.props
<PackageReference Include="Winstaller.Sdk" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Winstaller.Sdk --version 0.0.3
                    
#r "nuget: Winstaller.Sdk, 0.0.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Winstaller.Sdk@0.0.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Winstaller.Sdk&version=0.0.3
                    
Install as a Cake Addin
#tool nuget:?package=Winstaller.Sdk&version=0.0.3
                    
Install as a Cake Tool

Winstaller.Sdk

The official developer SDK containing interfaces, base classes, attributes, and services for extending the Winstaller installation engine.

This package provides the core contracts required to build:

  • Custom Wizard Steps: Cross-target installation steps (IStep, StepModelBase).
  • WPF GUI Presentation: Graphical views for Windows installer targets (StepViewBase, IStepView, [WindowsView]).
  • Console CUI Presentation: Interactive terminal views for CLI installer targets (IConsoleStepView, IConsoleContext, [ConsoleView]).
  • Lifecycle Hook Scripts: Headless pre-install and post-install hooks (IScript, [PluginName]).
  • Specialized Step Interfaces: Progress-driven install (IInstallStep), uninstall (IUninstallStep), license resolution (ILicenseStep), and conditional step visibility (IStepVisibility).
  • Background Tasks: Long-running background operations with progress reporting (IBackgroundRunnableStep, InstallationProgress).
  • Engine Services: Logging, modal dialogs, path variable resolution, localization, and embedded resource retrieval.

Target Framework & Requirements

  • Target Framework: .NET Framework 4.5 (net45) — chosen for maximum out-of-the-box compatibility on client Windows machines without requiring external runtime dependencies.
  • UI Stack: WPF (UseWPF enabled) for graphical views.
  • Language Support: C# 10+ / latest, Nullable Reference Types enabled.

Installation

Add the package to your plugin, custom step, or script project:

dotnet add package Winstaller.Sdk

Or reference it directly in your .csproj:

<ItemGroup>
  <PackageReference Include="Winstaller.Sdk" Version="0.0.1" />
</ItemGroup>

Architecture & Core Concepts

1. Step Orchestration & Decoupled Views

In Winstaller, step business logic is completely decoupled from UI presentation:

  • IStep defines the lifecycle, state, initialization, and navigation logic.
  • [WindowsView(typeof(TView))] binds a step to a WPF GUI view (StepViewBase / IStepView).
  • [ConsoleView(typeof(TConsoleView))] binds a step to an interactive Console view (IConsoleStepView).

This decoupled design enables a single step definition to run seamlessly across all target build configurations:

  • target: "windows" — loads the WPF GUI view.
  • target: "console" — loads the Console terminal view.
  • target: "both" — dual-target installer executable capable of running in either GUI or Console mode.
  • Silent mode (--silent) — runs headless without rendering views.

2. Identifying Steps and Plugins

  • [Step("StepName")]: Declares the unique name/identifier for a wizard step. Configured in installer.json under steps or uninstallSteps.
  • [PluginName("PluginName")]: Declares the identifier for a script plugin (IScript) or provides backward-compatible step naming.

Implementing Custom Steps

A full custom step consists of the step model and its corresponding presentation views.

1. Step Logic (IStep)

using System;
using System.Threading.Tasks;
using Winstaller.Sdk;

namespace MyCompany.Winstaller.Plugins
{
    [Step("MyCustomStep")]
    [WindowsView(typeof(MyCustomStepView))]
    [ConsoleView(typeof(MyCustomStepConsoleView))]
    public class MyCustomStep : IStep
    {
        public InstallerContext Context { get; set; } = null!;
        public int CurrentStep { get; set; }
        public int TotalSteps { get; set; }

        public event EventHandler? Canceled;
        public event EventHandler? Next;
        public event EventHandler? Back;

        public void Initialize(StepConfig config)
        {
            // Read custom properties defined in installer.json
            if (config.Properties.TryGetValue("DefaultPort", out var port))
            {
                // Process custom properties
            }
        }

        public void Start(IView? view)
        {
            if (Context.IsSilent)
            {
                // In silent/headless mode, advance immediately
                RaiseNext();
                return;
            }

            // Instruct the presentation host to render this step
            view?.DisplayStep(this);
        }

        public void End()
        {
            // Cleanup resources if necessary
        }

        public Task RollbackAsync()
        {
            // Roll back any changes if installation is aborted
            return Task.FromResult(0);
        }

        public void RaiseNext() => Next?.Invoke(this, EventArgs.Empty);
        public void RaiseBack() => Back?.Invoke(this, EventArgs.Empty);
        public void RaiseCanceled() => Canceled?.Invoke(this, EventArgs.Empty);
    }
}

2. WPF GUI View (StepViewBase)

Custom GUI views inherit from StepViewBase (a WPF UserControl implementing IStepView and INotifyPropertyChanged). It provides built-in properties to configure navigation buttons in the wizard shell:

Property Type Description
Title string Wizard window title.
Header string Top header / banner title.
IsNextVisible / IsNextEnabled bool Controls the Next button.
IsBackVisible / IsBackEnabled bool Controls the Back button.
IsCancelVisible / IsCancelEnabled bool Controls the Cancel button.
IsFinishVisible / IsFinishEnabled bool Controls the Finish button on completion steps.
IsPerformingCriticalWork bool Disables wizard buttons during critical operations to prevent aborting.
View Code-Behind (MyCustomStepView.xaml.cs):
using System.Windows;
using Winstaller.Sdk;

namespace MyCompany.Winstaller.Plugins
{
    public partial class MyCustomStepView : StepViewBase
    {
        private readonly MyCustomStep _step;

        public MyCustomStepView(MyCustomStep step)
        {
            _step = step;
            Step = step;
            InitializeComponent();
            Loaded += MyCustomStepView_Loaded;
        }

        private void MyCustomStepView_Loaded(object sender, RoutedEventArgs e)
        {
            Title = "Configuration";
            Header = "Configure Service Options";

            IsBackVisible = true;
            IsNextVisible = true;
            IsNextEnabled = true;
            IsCancelVisible = true;
        }

        public override void OnNext()
        {
            // Save state into shared context data
            _step.Context.Data["PortNumber"] = PortTextBox.Text;
            _step.RaiseNext();
        }

        public override void OnBack() => _step.RaiseBack();
        public override void OnCancel() => _step.RaiseCanceled();
    }
}

3. Console CUI View (IConsoleStepView)

For console and dual-target installers, implement IConsoleStepView. The IConsoleContext abstraction provides formatted, colored output and user prompt utilities:

using System.Threading.Tasks;
using Winstaller.Sdk;

namespace MyCompany.Winstaller.Plugins
{
    public class MyCustomStepConsoleView : IConsoleStepView
    {
        public Task ExecuteAsync(IStep step, IConsoleContext console)
        {
            if (step is MyCustomStep customStep)
            {
                console.WriteLine("==================================================");
                console.WriteSuccess($"  Configuration: {customStep.Context.AppName}");
                console.WriteLine("==================================================");
                console.WriteLine();

                // Interactive prompt with default value
                string port = console.Prompt("Enter service port", defaultValue: "8080");
                customStep.Context.Data["PortNumber"] = port;

                // Confirm proceeding
                bool proceed = console.PromptYesNo("Proceed with this configuration?", defaultYes: true);
                if (proceed)
                {
                    customStep.RaiseNext();
                }
                else
                {
                    customStep.RaiseCanceled();
                }
            }

            return Task.FromResult(0);
        }
    }
}

Specialized Step Interfaces

Winstaller provides optional specialized interfaces for custom step behavior:

IStepVisibility

Determines dynamically whether a step should appear in the wizard flow based on the current context:

public interface IStepVisibility
{
    bool ShouldShow(InstallerContext context);
}

Example: Skip database configuration steps if an existing installation already has connection strings configured.

IInstallStep

Handles standard installation execution, progress reporting, and transaction rollback:

public interface IInstallStep
{
    Task ExecuteInstallAsync(IStep step, IProgress<InstallationProgress>? progress);
    Task RollbackAsync(IStep step);
}

IUninstallStep

Handles standard uninstallation execution and progress reporting:

public interface IUninstallStep
{
    Task ExecuteUninstallAsync(IStep step, IProgress<InstallationProgress>? progress);
}

ILicenseStep

Reads and resolves localized license documents (plain text or Rich Text Format .rtf):

public interface ILicenseStep
{
    Stream? GetLicenseStream(InstallerContext context);
    string GetLicenseText(InstallerContext context);
    bool IsRtfFormat(InstallerContext context);
}

IBackgroundRunnableStep

Designed for background workers and operations where fine-grained progress reporting is required:

public interface IBackgroundRunnableStep
{
    Task ExecuteAsync(IProgress<InstallationProgress>? progress);
}

Lifecycle Hook Scripts (IScript)

Scripts run headless at specific installation phases (preInstallScripts or postInstallScripts). They are ideal for environment checks, stopping services, file cleanup, or running custom provisioning tasks:

using Winstaller.Sdk;

namespace MyCompany.Winstaller.Plugins
{
    [PluginName("CleanupOldFilesScript")]
    public class CleanupOldFilesScript : IScript
    {
        public void Execute(InstallerContext context)
        {
            var logger = context.GetService<ILogger>();
            logger?.Info("Starting pre-installation cleanup...");

            string targetDir = context.InstallationPath;
            // Perform file manipulation or cleanup here
        }
    }
}

Engine Services & InstallerContext

InstallerContext

Passed to all steps, scripts, and views. It contains the shared installation state and engine utilities:

Property Type Description
AppName string Name of the application being installed.
AppVersion string Version of the application.
Publisher string Publisher name.
ProductCode string Unique product code identifier.
InstallationPath string Target installation folder (maps to %installation%).
WorkingInstallationPath string Temporary staging folder during installation.
BackupInstallationPath string Backup directory used during updates before committing.
Data Dictionary<string, string> Shared key-value dictionary for passing data between steps and scripts.
IsSilent bool true if running in headless/silent command-line mode.
IsUninstall bool true if running an uninstallation workflow.
IsUpdate bool true if performing an in-place application upgrade.
IsBackground bool true if executing within a background worker.
CancellationToken CancellationToken Token to observe for aborting long-running tasks.
Localization ILocalizationService Localization service instance for current culture.
GetService<T>() method Resolves services registered in the engine DI container.

Available Services

Resolve engine services via context.GetService<T>():

1. ILogger

Logs messages to the installer log file and debug listeners:

var logger = context.GetService<ILogger>();
logger?.Debug("Debug details...");
logger?.Info("Installation step started.");
logger?.Warning("Optional file not found; skipping.");
logger?.Error("Encountered unexpected error.");
logger?.LogException(ex, "Failed to initialize component");
2. IDialogService (Winstaller.Sdk.Services)

Displays modal dialogs and alerts:

using Winstaller.Sdk.Services;

var dialogs = context.GetService<IDialogService>();
var result = dialogs?.Show("Do you want to create a desktop shortcut?", "Shortcut", DialogButton.YesNo, DialogIcon.Question);
if (result == DialogResult.Yes)
{
    // User agreed
}

// Show retry prompt on failure
bool retry = dialogs?.ShowRetry("Connection timed out.", "Network Error") ?? false;
3. IPathVariableResolver (Winstaller.Sdk.Services)

Resolves standard installer and system directory variables (e.g. %programfiles%, %installation%, %appname%):

using Winstaller.Sdk.Services;

var resolver = context.GetService<IPathVariableResolver>();
string resolvedPath = resolver?.Resolve(@"%programfiles%\%appname%\config.json") ?? "";
4. IPathService (Winstaller.Sdk.Services)

Checks permissions and path attributes:

using Winstaller.Sdk.Services;

var pathService = context.GetService<IPathService>();
bool needsAdmin = pathService?.RequiresAdminToSave(context.InstallationPath) ?? true;
5. IResourceProvider

Accesses embedded resources compiled directly into the installer package:

var resources = context.GetService<IResourceProvider>();
if (resources?.HasResource("banner.png") == true)
{
    byte[] imageBytes = resources.GetResourceBytes("banner.png");
}

Localization & Translations

Translations are defined in the installer configuration (installer.json) under the translations object:

"translations": {
  "en": {
    "PortStep_Title": "Port Configuration",
    "PortStep_Prompt": "Enter listening port for {0}:"
  },
  "pl": {
    "PortStep_Title": "Konfiguracja portu",
    "PortStep_Prompt": "Wprowadź port nasłuchiwania dla {0}:"
  }
}

Accessing Translations in Code

Use the static TranslationProvider class or context.Localization:

using Winstaller.Sdk;

// Simple string lookup
string title = TranslationProvider.GetString("PortStep_Title");

// Formatted string with parameters
string prompt = TranslationProvider.GetString("PortStep_Prompt", context.AppName);

Standard Exceptions (Winstaller.Sdk.Exceptions)

The SDK provides specific exception types to report standard installer failures cleanly:

  • AppLockedException: Thrown when application files are locked by running processes or folders cannot be modified. Contains RunningProcesses and LockedFiles collections.
  • ElevationRejectedException: Thrown when UAC elevation is rejected by the user or administrator rights cannot be acquired.
  • ServiceRunningException: Thrown when an active Windows Service could not be stopped.
using Winstaller.Sdk.Exceptions;

if (IsServiceRunning("MyService"))
{
    throw new ServiceRunningException("MyService", "The Windows Service 'MyService' is active and must be stopped.");
}

Backward Compatibility Note

For compatibility with older plugins written for earlier versions of Winstaller, the Winstaller.Interfaces and Winstaller.Interfaces.Services namespaces are preserved via type aliases in Compatibility.cs. For all new development, use the Winstaller.Sdk namespaces.


License

Refer to the LICENSE.txt file packed with this package.

Product Compatible and additional computed target framework versions.
.NET Framework net45 is compatible.  net451 was computed.  net452 was computed.  net46 was computed.  net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETFramework 4.5

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.3 95 9/8/2026
0.0.2 87 9/7/2026
0.0.1 87 9/7/2026