How To: Install SLPS Components for ClickOnce and VSTO Applications (KB11)

The guidance has been superseeded by that in KB14.  If one receives the following exception one needs to adjust the code as described in KB14:

System.InvalidOperationException: SLPS: FATAL ERROR: Limiting machine licenses to user due to appSetting: Slps.RedirectMachineToUser is no longer supported. Please refer to http://support.inishtech.com/KB11 for details regarding suitable migration and workaround approaches.

This article provides guidance on how to correctly install SLPS components with ClickOnce and VSTO applications.  The default per-machine licensing approach uses a license store located in the registry under HKEY_LOCAL_MACHINE.  However, due to installation restrictions of ClickOnce and VSTO applications there is no central place on a computer where one could store licenses and still allow all the users to access a shared single license.  Therefore SLPS runtime versions 3.0.1908 and later inspect a .NET appSetting in order to allow per-machine licenses to be redirected to instead be stored on a per-user basis.

Per-user and Per-machine Licensing

NOTE: For background information which may be useful in understanding how the SLPS ClickOnce and VSTO support works, please read http://support.inishtech.com/KB7


The default license store for SLPS needs write access to its key in the Registry under HKEY_LOCAL_MACHINE.

For normal applications, one adds a step to one’s MSI installer which, while running with elevated privileges at installation time, configures the registry in such a way as to allow the requisite actions to be performed when the application runs even when running as a normal user without elevated privileges.

In the case of ClickOnce and VSTO applications, there is no 'install step', and even FullTrust does not give one a way to elevate in any normal-user accessible manner.  Another key underpinning of ClickOnce is that apps should not know about each other or be able to share data in any way.  For this reason, the install directory name internally is a random GUID deep inside the user's profile, which is effectively treated as a cache by the loader - the canonical source of the application is really the .application manifest file on the source download site.

As a result of these restrictions, there is not a central place on a computer where one could store things such as licenses (even in a file) yet still allow all the users to store a shared single license.

Therefore SLPS runtime versions 3.0.1908 and later inspect a .NET appSetting in order to allow per-machine licenses to be redirected to instead be stored on a per-user basis.

ClickOnce EXE Applications (e.g. WPF, WinForms etc.)

The easiest way to allow SLPS licensing to work seamlessly is to add the following appSetting to one's app.config file in the main EXE project:-

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="Slps.RedirectMachineToUser" value="True" />
  </appSettings>
</configuration>

Protected DLLs in a restricted context within a hosting EXE (e.g., VSTO):

In the case of VSTO, as your code is not the main hosting EXE, there isn't an easy way to adjust the application settings as one is not deploying (or even in control of) the EXE itself (the exe in this case being EXCEL.EXE / WINWORD.EXE etc.).

You could attempt to put the same setting as you'd use for a ClickOnce app (see above) in an EXCEL.exe.config (or WINWORD.exe.config etc.) file in the same directory as your DLL. The problem is that this is error-prone (e.g., if someone renames their excel.exe it would not be picked up etc.). There are a variety of other mechanisms to substitute in appSettings for particular contexts, but these can be cumbersome to understand, troubleshoot and maintain.

In order to route around the issues involved in managing appSettings in such a context., SLPS runtime versions 3.0.1908 and later offer an alternative installer class (ClickOncePermutationManagerBase) that is appropriate for ClickOnce applications.  This provides similar installation verification capabilities as provided by PermutationInstaller class but also provides a RedirectMachineToUser() method so that one can programmatically initiate redirection in that per-machine licenses are actually maintained on a per-user basis instead.

Recommended Approach:

The recommended approach for both ClickOnce and VSTO applications is to:

  1. Add the following class:
    /// <summary>
    /// ClickOnce-compatible SLPS 'installer'
    /// Provides a similar set of management services for verifying the permutation has been installed as a normal app gets from PermutationInstallerBase
    /// </summary>
    public class Installer : ClickOncePermutationManagerBase
    {
    	public const string STR_MyCompanyPermutationShortId = TODOPutInYourShortCodeHere: "abc12";
    
    	public Installer()
    		: base( STR_MyCompanyPermutationShortId )
    	{
    	}
    }
  2. Add a call to Installer.RedirectMachineToUser() to perform the redirection programmatically before executing protected code. A good place for this is in the AddIn_Startup handler:
    namespace Slps.Samples.Minimal.Vsto.WordAddIn
    {
        public partial class ThisAddIn
        {
            private void ThisAddIn_Startup(object sender, System.EventArgs e)
            {
                Installer.RedirectMachineToUser();
                VerifyInstalled();
            }
    	}
    }

 Troubleshooting

  1. Regardless of which approach is in force, you should always be able to:

    Debug.Assert( ClickOncePermutationManagerBase.IsMachineRedirectedToUser() );
     
  2. The PermutationInstallerBase.VerifyInstalled() function will report success even if the redirection has NOT taken place if other SLPS-protected applications (such as SLP Code Protector) are present on the machine. Hence the installer in a ClickOnce or VSTO application must derive from ClickOncePermutationManagerBase, not PermutationInstallerBase. This implementation checks ClickOncePermutationManagerBase.IsMachineRedirectedToUser() first in order to ensure that the storage has been correctly redirected as required - either via the appSetting or programmatically.
     
  3. Note that when running Visual Studio as administrator (e.g., in order to be able to Publish Click Once apps, run against IIS etc.), the instance of the browser (e.g., Internet Explorer) that gets invoked to show the ClickOnce publish page is ALSO ELEVATED IF VISUAL STUDIO IS. This means that clicking on the install button will behave differently (even on Vista and later versions of Windows) than starting a new [non-elevated] browser window and going to the same URL. In other words, if you want to test what your users will experience, you need to copy the URL from the browser Visual Studio shows after the publish into a manually loaded IE (i.e., to ensure that the Click Once app and/or VSTO app will NOT be elevated during the ClickOnce invocation)