Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Creating Secure Trial Versions for .NET Applications - A Tutorial

, 16 Oct 2012 CPOL
Implement trial licensing model for your .NET applications with minimal costs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using SoftActivate.Licensing;
using System.Threading;

namespace SampleTrialAppCS
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            settings = new AppSettings();
            settings.Load();

            BeginLicenseValidation();
        }

        void BeginLicenseValidation()
        {
            // check the license validity on a different thread, it can take a second or so, we do not want to block the application startup while doing it
            Thread licenseValidationThread = new Thread(new ParameterizedThreadStart(LicenseValidationThread));
            licenseValidationThread.Start();
        }

        void LicenseValidationThread(object param)
        {
            string registrationStatus = "NOT REGISTERED";
            string clockManipulationStatus = "NOT DETECTED";
            bool validLicense = false;
            DateTime licenseExpirationDate = default(DateTime);

            if (!(String.IsNullOrEmpty(settings.GetProperty("ActivationKey"))
                  || String.IsNullOrEmpty(settings.GetProperty("ActivationHardwareId"))
                  || String.IsNullOrEmpty(settings.GetProperty("LicenseKey"))))
            {
                LicensingClient licensingClient = new LicensingClient(
                                                             CreateLicenseKeyTemplate(),
                                                             settings.GetProperty("LicenseKey"),
                                                             null,
                                                             settings.GetProperty("ActivationHardwareId"),
                                                             settings.GetProperty("ActivationKey"));

                if (licensingClient.IsLicenseValid())
                {
                    validLicense = true;
                    licenseExpirationDate = licensingClient.LicenseExpirationDate;
                    registrationStatus = (settings.GetProperty("LicenseKey") == trialLicenseKey) ? "TRIAL" + " (" + (1 + (licenseExpirationDate - DateTime.UtcNow).Days) + " days remaining)" : "REGISTERED";
                }
                else
                {
                    registrationStatus = "INVALID LICENSE ";
                    switch (licensingClient.LicenseStatus)
                    {
                        case LICENSE_STATUS.Expired:
                            registrationStatus += "(expired on " + licensingClient.LicenseExpirationDate.Month + "/" 
                                                                 + licensingClient.LicenseExpirationDate.Day + "/" 
                                                                 + licensingClient.LicenseExpirationDate.Year + ")";
                            break;

                        case LICENSE_STATUS.InvalidActivationKey:
                            registrationStatus += "(invalid activation key)";
                            break;

                        case LICENSE_STATUS.InvalidHardwareId:
                            registrationStatus += "(invalid hardware id)";
                            break;

                        default:
                            registrationStatus += "(unknown reason)";
                            break;
                    }
                }
            }

            // since we are on a different thread from the UI thread, 
            // we cannot directly update the textboxes from here, we need to call a method on the UI thread to do this
            Invoke(new SetTextBoxValueDelegate(SetTextBoxValue), new object[] { txtRegistrationStatus, registrationStatus });
            Invoke(new SetTextBoxValueDelegate(SetTextBoxValue), new object[] { txtLicenseKey, settings.GetProperty("LicenseKey") });
            Invoke(new SetTextBoxValueDelegate(SetTextBoxValue), new object[] { txtActivationHardwareId, settings.GetProperty("ActivationHardwareId") });
            Invoke(new SetTextBoxValueDelegate(SetTextBoxValue), new object[] { txtActivationKey, settings.GetProperty("ActivationKey") });

            if (validLicense)
            {
                if (ClockManipulationDetector.DetectClockManipulation(licenseExpirationDate))
                    clockManipulationStatus = "CLOCK MANIPULATION DETECTED !";
            }

            Invoke(new SetTextBoxValueDelegate(SetTextBoxValue), new object[] { txtClockManipulationStatus, clockManipulationStatus });
        }

        public delegate void SetTextBoxValueDelegate(TextBox textBox, string value);

        void SetTextBoxValue(TextBox textBox, string value)
        {
            textBox.Text = value;
        }

        private void btnExit_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void btnStartTrial_Click(object sender, EventArgs e)
        {
            ActivationForm activationForm = new ActivationForm("Acquiring trial license...", trialLicenseKey);
            activationForm.ActivateLicense();

            if (activationForm.IsActivated)
            {
                settings.SetProperty("LicenseKey", trialLicenseKey);
                settings.SetProperty("ActivationKey", activationForm.ActivationKey);
                settings.SetProperty("ActivationHardwareId", activationForm.HardwareId);

                BeginLicenseValidation();
            }
        }

        private void btnDeleteRegistrationData_Click(object sender, EventArgs e)
        {
            settings.SetProperty("LicenseKey", "");
            settings.SetProperty("ActivationKey", "");
            settings.SetProperty("ActivationHardwareId", "");

            settings.Save();

            txtLicenseKey.Clear();
            txtActivationKey.Clear();
            txtActivationHardwareId.Clear();
            txtRegistrationStatus.Text = "NOT REGISTERED";

            MessageBox.Show("Registration data was deleted for the sample application, but in order to be able to request another trial license you must connect to the licensing service database (look in Tools\\LicensingService\\App_Data folder) and delete the records from the Activations table.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);
            settings.Save();
        }

        private KeyTemplate CreateLicenseKeyTemplate()
        {
            return new KeyTemplate(5, // number of groups of characters in the license key  
                                               5, // number of character in each group
                                               "doxzyMNu7n46whM=", // the public key used to verify the license key signature
                                               null, // private key is not needed for license key validation ! 
                                               109,  // signature size of the license key is 109 bits
                                               16,   // data size embedded in the license key is 16 bits
                                               "ProductId" // this is the name of the data field embedded in the license key
                                               );
        }

        AppSettings settings;
        const int productId = 12345;
        const string trialLicenseKey = "X62DG-94SDT-A4TBZ-949CK-KMZB5";
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Ansel Reynard

United States United States
No Biography provided

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141216.1 | Last Updated 16 Oct 2012
Article Copyright 2012 by Ansel Reynard
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid