How To: Install SLPS Runtime Components (KB7)

This article offers guidance on how to ensure the SLPS Runtime components are installed correctly before execution of any protected code.  In order to offer a consistent and clear experience to end users, the amended behaviour in SLPS V3 is that the Runtime will now - prior to the first attempt to execute protected code - consistently throw an exception up front if it is invoked without having been installed and configured correctly.

SLPS V2 Registry Behaviour

Prior to SLPS V3, in protected applications that use the SVM/Runtime (including the License Administrator tool), the first application instance that tries to read or write the license store (which by default is registry-based) will attempt to create the registry key if it is not present. Unfortunately, in order to be able to perform in this manner consistently, administrative privilege is required.

On Windows versions from Vista forward (i.e., Vista, 7, Server 2008,Server 2008 R2 etc.) the security model defaults all applications (even ones invoked by Admin users) to running with a restricted token which grants only the permissions a normal user would have.

This implies that it's would not be possible to create entries in the appropriate area of the registry across all types of users without requiring all protected apps to be run as Administrator (just in case it needs to create the registry entries). In other words, a machine with User Account Control (on by default with Vista and later) would require a Continue button to be clicked before opening the app.

Even on Windows XP and Windows Server 2003, the V2 behaviour can lead to a range of confusing conditions in the case of regular users without Administrator privileges, i.e., Admin users will be able to run the software successfully but regular users can encounter exceptions on the same machine.

For the License Administrator tool (or the runtime in your app) to continue to try to silently fix up the installation if it sees something wrong, it would need administrative privilege to be able to complete this consistently regardless of the OS involved and whether the user is an administrator. To meet this requirement would have required the following:

  1.  Add an App Manifest that demands UAC elevation (e.g. require a UAC pop-up with Continue on Vista/7/2008/2008R2 or later).
  2. On XP and Windows Server 2003, the software would need to check whether the user has administrative privileges and display a "This application needs to be run as administrator, please log out and re-invoke" if the user isn't an administrator.

SLPS V3 Registry Behaviour

For the reasons outlined above, in order to offer a consistent and clear experience to users, the amended behaviour in SLPS V3 is that the Runtime will now - prior to the first attempt to execute protected code - consistently throw an exception up front if it is invoked without having been installed and configured correctly.

The aim of this new approach is to provide a consistent behaviour across all platforms which will minimise the testing and troubleshooting effort required of you the ISV.
Therefore the recommended approach to installation of V3 runtime components is -

  1. As part of the installation of the application, have your installer invoke a .NET Installer class based on the Installer class included in the SLPS v3 runtime . As is normal for an installer, this portion needs to run elevated, (i.e., as Administrator on Windows Server 2003, XP or with UAC off / elevated on a systems with UAC)
  2. At the start of the application's Main(), add a check that the installation has been carried out properly which displays an appropriate diagnostic message (for example License Administrator in the SLPS Runtime V3 does this when it is run on a machine without having been installed). This check does not require admin privilege or elevation.

While this might appear to make deployment more complex, this approach does mean that the only point at which a SLPS-protected application requires Admin user rights is during the first installation. This approach is in accordance with Windows Logo requirements for Vista and later Operating Systems.

Implementation Steps

The following are the steps to ensure the Runtime components are correctly installed during application installation, avoiding downstream errors at application runtime:

  1. Add a reference to the SLPS Runtime DLL belonging to your permutation to your application project
     
  2. Add an installer class to your app:-
     
  3. using System.ComponentModel;
    using Slps.Licensing.Installation;
    
    namespace Slps.VendorTools.MinimalProtectedApp
    {
        [RunInstaller(true)]
        public class Installer : PermutationInstallerBase
        {
            public Installer()
                : base( "123XX") // TODO substitute in your permutation short code
            {
            }
        }
    }
  4. Add an installation check to your Main():
     
  5. using System;
    using Microsoft.Licensing;
    
    namespace Slps.VendorTools.MinimalProtectedApp
    {
        class Program
        {
            [STAThread]
            static void Main(string [] args)
            {
                try
                {
                    if (VerifyInstalled())
                        Execute();
                }
                catch (Exception exception)
                {
                        MessageBox.Show(exception.ToString(), "Unhandled Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
           
            static bool VerifyInstalled()
            {
                try
                {
                    using ( var installer = new Installer(  ) )
                        installer.VerifyInstalled();
                    return true;
                }
                catch (StorageInaccessibleException ex)
                {
                    MessageBox.Show(ex.Message, "Licensing installation issue", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;
                }
            }
           
            static void Execute()
            {
                // Invoke The rest of your app
            }
        }
    }
  6. Add a call to the .NET Managed Installer class from your installer:
    1. Visual Studio Deployment Projects (.vdproj projects) have a Custom Action option - simply tell it to run the Installer during the "Install" phase. Add "Primary Output from YourApp.exe" to the "Install" step, and set the InstallerClass property to True
    2. InstallShield 2009 (and probably earlier versions) have a simple flag for this - you simply indicate that your app's managed installer is to be invoked by ticking a checkbox. Competing products have equivalent features.
    3. WiX has a custom action called ManagedInstall in InstallUtilLib. For some more info, see FAQ141.
    4.  InnoSetup doesnt have any direct .NET support. This means the simplest solution is to run %windir%\Microsoft.NET\Framework<64 if you are targetting x64>\<.NET version you are targeting>\installutil.exe <your assembly containing the Installer class>.<dll/exe> from your installer (this needs to happen elevated as with any other approach).e.g.
      %windir%\Microsoft.NET\Framework\v2.0.50727\installutil.exe <your assembly containing the Installer class>.<dll/exe>

All of the above are equivalent to using the standard .NET utility 'installutil.exe' which is a standard component of .NET CRL versions 1.1, 2.0 and 4.0. (This approach is also the standard way in which .NET based Windows [NT] Services get registered)

Setup without Installer using XCopy Deploy

If you're just trying to do a quick "xcopy deploy" for test purposes, you could use one of the following approaches. Note each of these needs to run elevated, i.e., you need to start a command prompt with “run as Administrator” to run the commands successfully.

A) Use Slps.Runtime.Configuration.exe

  1. Copy Slps.Runtime.Configuration.exe and its dependencies:-
    1. Slps.Runtime.Configuration.exe
    2. Slps.Runtime.Installer.dll
    3. Microsoft.Licensing.Utils2.0.DLL
    4. Microsoft.Licensing.Runtime2.0.DLL
    5. Microsoft.Licensing.Permutation2.0.dll or, as of 3.0.1910 release of Code Protector, your custom Microsoft.Licensing.Permutation_123XX_2.0.dll".
  2. Run:

Slps.Runtime.Configuration /Install.

B) Use installutil on Slps.Runtime.Installer.dll

  1. Copy Slps.Runtime.Installer.dll and its dependencies:-
    1. Slps.Runtime.Installer.dll
    2. Microsoft.Licensing.Utils2.0.DLL
    3. Microsoft.Licensing.Runtime2.0.DLL
    4. Microsoft.Licensing.Permutation2.0.dll or, as of 3.0.1910 release of Code Protector, your custom Microsoft.Licensing.Permutation_123XX_2.0.dll".
  2. Run:

%windir%\Microsoft.NET\Framework\v2.0.50727\installutil.exe Slps.Runtime.Installer.dll

Please note that the approaches A and B above are not intended for end-user usage - they're advanced tools that are intended for people developing custom licensing and/or installation schemes.

C) Use InstallUtil on your EXE/DLL containing your Managed Installer

  1. Add an installer to your software as covered in steps 1 and 2 of Implementation steps
  2. Run:

%windir%\Microsoft.NET\Framework\v2.0.50727\installutil.exe <your assembly containing the Installer class>.<dll/exe>

D) Add a self-installation command line option to your EXE

  1. Prior to your VerifyInstalled() step in your EXE, add processing for commandline arguments that executes the Installer if requested:
     
  2. [STAThread]
    static void Main()
    {
    	try
    	{
    		var singleArgument = args.Length == 1 ? args[0] : string.Empty;
    		if (singleArgument.Equals("-install", StringComparison.OrdinalIgnoreCase))
    			ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
    		else if (singleArgument.Equals("-uninstall", StringComparison.OrdinalIgnoreCase))
    			ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
    		else if (VerifyInstalled())
    			Execute();
    	}
    	catch (Exception exception)
    	{
    		MessageBox.Show(exception.ToString(), "Unhandled Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
    	}
    }
  3. Run <your assembly containing the Installer class>. exe -install
    either interactively or via your installation script. Again, elevation is required as usual in order to run the installation portion (but your application should run normally unelevated).

 

Error Messages associated with incorrect installation

You may see one of the following error messages if the SLPS Runtime components are not correctly installed.

Slps.Licensing.StorageNotConfiguredException: Licensing storage is not configured. Please ensure software has been installed correctly

This is thrown from PermutationInstallerBase.VerifyInstalled() (normally you’ll have an Installer class derived from this) if the installation has not been completed when the installation check in your protected application’s Main is triggered by the user starting the application. Typically the code block in the application involved is as follows:
 

static bool VerifyInstalled()
{
    try
    {
        using ( var installer = new Installer(  ) )
            installer.VerifyInstalled();
        return true;
    }
    catch (StorageInaccessibleException ex)
    {
        MessageBox.Show(ex.Message, "Licensing installation issue", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return false;
    }
}

The above code

  1. Lets the exception get thrown if there’s a problem
  2. Reports the problem to the user
  3. Returns false if there is a problem, so that the calling code can abort the running of the application – at this point the user needs to reinstall or otherwise remedy the fact that installation has not completed successfully

Microsoft.Licensing.StorageInaccessibleException: Licensing storage is inaccessible. The installation needs to be run with Administrator privileges in order to be able to configure the system correctly.

(The exception text has been updated to read Microsoft.Licensing.StorageInaccessibleException: Licensing storage is inaccessible. The license store has insufficient permissions. An Installer needs to have successfully completed (with Administrator privileges) in order to execute protected code.)

This is thrown from the SLM runtime when an application is trying to execute protected code and indicates that there is a problem accessing the registry store. The likely cause is that registry permissions have not been assigned correctly (e.g., the key may exist, but as the installation has not completed correctly, the registry cannot be accessed in the current context. In this case, the remedy is to ensure that installation has successfully completed prior to the first attempt to execute protected code via a VerifyInstalled() method as detailed earlier in this document.

Storage not configured correctly at time of session opening - has storage been configured? Not throwing Slps.Licensing.StorageNotConfiguredException (this is acceptable if one is only calling ConfigurePermissions)

The above message gets written into the log whenever there is an attempt to execute protected code without there being a license store in place. Typically the only reason for this to arise is that one is running the Install step (i.e., you will always see this during the install step the very first time an SLP-protected application is being installed). If you see this entry in the SLP Log at any other time (e.g., during normal running of the application), this indicates that installation has not been installed correctly. As in the other cases, the best remedy for this condition is to add a VerifyInstalled method to your application’s Main().

Microsoft.Licensing.Utils.GenException: Failed to set registry parameter [_tmpbalikeda63] to value System.Byte[] ---> Microsoft.Licensing.Utils.GenException: SLPS not installed correctly, please ensure the root node has been created and the permissions have been applied correctly
at Microsoft.Licensing.Utils.RegistryUtil.VerifyInstallation()

(in later versions: at Slps.Common.Internal.Registry.GlobalRegistryRootManager.VerifyInstalled)
May include InnerException: Microsoft.Licensing.Utils.GenException: SLPS not installed correctly, please ensure the root node has been created and the permissions have been applied correctly
As with the other exceptions, this is a symptom of installation not having completed successfully prior to an attempt to run protected code. The remedy, as in the other cases, is to add a VerifyInstalled() method call to your application’s Main().