LicenPro
Documentation.NET SDKWinForms

WinForms integration

WinForms hosts the same LicenPro NuGet package as any other .NET desktop app. There is no separate LicenPro.WinForms package — you wire validation, cache, sessions, and updates with LicenseClient, SdkBootstrap, and optional UI built in your forms. The patterns below mirror the official Licenses-Test-Winforms-App sample shipped beside the SDK.

1. Program entry

Use STAThread, initialize WinForms configuration, run bootstrap, then show your main form.

using System.Windows.Forms;
using LicenPro.SDK.AppHosting;

internal static class Program
{
    [STAThread]
    static void Main()
    {
        ApplicationConfiguration.Initialize();
        SdkBootstrap.OnApplicationStartup();
        Application.Run(new MainForm());
    }
}

2. Async startup on the UI form

Keep Main synchronous; perform license work on the first Shown event (or a small splash/bootstrap flow) with async void handlers or Task orchestration you prefer. Always dispose the active LicenseClient on application exit so session heartbeats release cleanly.

using LicenPro.SDK;

public partial class MainForm : Form
{
    private LicenseClient? _licenseClient;

    public MainForm()
    {
        Shown += async (_, __) => await RunStartupLicenseCheckAsync();
        FormClosing += async (_, __) =>
        {
            if (_licenseClient is not null)
                await _licenseClient.DisposeAsync();
        };
    }

    private async Task RunStartupLicenseCheckAsync()
    {
        if (!LicenseCache.Exists()) return;

        var r = await LicenseClient.TryAutoValidateAsync(
            string.IsNullOrWhiteSpace(txtLicenseKey.Text) ? null : txtLicenseKey.Text,
            string.IsNullOrWhiteSpace(txtPublicKey.Text) ? null : txtPublicKey.Text);

        if (r.IsSuccess && r.Client is not null)
        {
            _licenseClient = r.Client;
            // Update status strip; optionally show ExpiryNotice from r.ValidationResult
            return;
        }

        // Handle LicenseKeyRequired / CacheCorrupted / ValidationFailed with clear UX
    }
}

3. First-time activation (validate + cache)

When the user picks a license.bin and enters their key, call LicenseClient.ValidateAndCacheAsync(path, publicKey, licenseKey, expectedLicenseType: null, productId). Pass the dashboard product GUID when the license file does not embed product id — it improves license-aware update checks. Strip PEM headers from the public key file before passing the string (the sample uses SecurityUtils.StripPemHeaders from the SDK utilities).

4. Manual “validate from cache”

Bind a button to the same TryAutoValidateAsync path used at startup so support staff can refresh state without reopening the app.

5. Surfacing failures and expiry

For failures, call LicenseValidationFeedback.From(result) to populate dialog text and status strip colors consistently. For subscriptions nearing renewal, read result.ExpiryNotice after validation or listen to LicenseClient.LicenseExpiringSoon for non-blocking reminders on auto-validation.

6. Optional: sessions and updates

After a successful validate, you may call await _licenseClient.ConnectSessionAsync() on a background task so UI stays responsive. Enable EnableAutoUpdates from SdkUpdateExtensions once you know the app version string (for example via SdkAssemblyInfo.GetSemanticVersionString).

Next steps

Read the .NET SDK page for the full option matrix, then map your activation UX (wizard vs single form) on top of the same primitives.