WiX Script for installing Live Writer Plugins

Here's a WiX install script to build an MSI to install a Windows Live Writer (WLW) plugin dll, by xcopying the plugin dll to the Plugins directory. You can then upload your MSI to the WLW Gallery and share your plugin with others.

WLW Plugins are very easy to write, so it's nice to have them easy to install too.

(An MSI is a Windows Installer Binary that contains both the content to install and the directions for installation. )  You could also use VS Deployment projects is an alternative way to produce MSIs. (That's probably worthy of its own entry, but see "How to: Use a Registry Launch Condition to Specify a Target Directory" for hints).

 

Disclaimer + Thanks

See the rules for distributing WLW plugins. In this case, I'll xcopy the plugin.dll to %installDir%\PlugIn, where %installDir% is where WLW is installed, as determined by the "InstallDir" registry value at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Live\Writer.  (Note this value changed with Beta 3). There are other install options.

I'm not an installer guy. This was a pertinent reason to learn more about installers. WiX documenation is rarer than gold, but there's a nice tutorial and various Wix Ninjas (thanks Daniel Harvey!) kindly helped me worked through some WiX learning curve issues.

I started with Bonnie's wix script here. (This was what I used for my first plugin. Unfortunately, that script was subject to the beta 3 breaking changes).  Bonnie and Joe Cheng kindly helped me get it working for my plugin. 

This script starts with Bonnie's and has a few updates:

  1. It's updated for Wix 2.0.5325.0. (thanks Bonnie!)
  2. It properly looks up %InstallDir% in the registry,  (instead of using "%ProgramFiles%\Windows Live Writer").
  3. It detects pre-Beta 3 installs and gives a specific upgrade message (instead of not finding WLW installs for pre-beta 3)
  4. Originally, I also added a way to remove the per-plugin options storage (which is under HKCU), but later figured that was a bad idea after reading.  So that code is commented out below.
  5. Added more comments about what was going on. WiX is code and like any code, comments make it more understandable.

 

Getting down to business.

So here's step-by-step:

1) Download the WiX toolset, if you don't already have it. This is tested against Wix, 2.0.5325.0, which you can download from here.

2) Take this WiX Script and substitute all {%...%} with appropriate values. Descriptions and sample values are given below.

 

 <?xml version="1.0" encoding="utf-8" ?>
<Wix xmlns="https://schemas.microsoft.com/wix/2003/01/wi">

  
  <!--
  Wix Installer for a WLW PlugIn.
  Verified against Wix version 2.0.5325.0. 
  
  This is adapted from https://bplo.spaces.live.com/blog/cns!CF2831C0AE64E81B!210.entry.  
  
  See https://msdn2.microsoft.com/en-us/library/aa738841.aspx for rules on distributing plug-ins.
  
  1) The RegKey "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Live\Writer\InstallDir" tells what 
  directory WLW is installed in. This is valid in Beta 3.
  
  2) If "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Live\Writer InstallDir" is defined instead,
  then a pre-Beta 3 version is installed.
  
  3) Copy the Files to the PlugIn sub-directory of that #1.
  
  Other caveats:
  - This does not support Upgrading a PlugIn.
  - To specify a License, include 'License.rtf' file in the current directory when you run Light.exe.
  - This uses a minimal UI.
  -->

  
  <Product Name="{%Installed Name%}" Id="{%guid #1%}"
        Language="1033" Codepage="1252" Version="1.0.0"
        Manufacturer="{%Manufacturer%}">
    <Package
      Id="????????-????-????-????-????????????"
      Description="{%Description%}"
      Manufacturer="{%Manufacturer%}"
      InstallerVersion="200"
      Compressed="yes" />


    <!-- This script is very basic and doesn't have any custom UI -->
    <UIRef Id="WixUI_Minimal" />

    <!-- Lookup the installation directory from the registry. 
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Live\Writer\InstallDir
    
    This registry key moved with Beta 3, so lookup the old key to detect pre-beta 3 installs 
    and advise an upgrade.
      INSTALLDIR is where the new (beta 3 and beyond) registry entry is.
      INSTALLDIR_OLD is where the old (pre-beta 3) registry entry is.
    -->
    <Property Id="INSTALLDIR">
      <RegistrySearch Id='GetInstallDir' Type='raw'
        Root='HKLM' Key='SOFTWARE\Microsoft\Windows Live\Writer' Name='InstallDir' />
    </Property>

    <Property Id="INSTALLDIR_OLD">
      <RegistrySearch Id='GetOldInstallDir' Type='raw'
        Root='HKLM' Key='SOFTWARE\Microsoft\Windows Live Writer' Name='InstallDir' />
    </Property>

    <!-- Launch Conditions.
    Ensure that WLW is actually installed -->
    <Condition Message="An old version of Windows Live Writer is installed. 
                        Please upgrade to the latest version at https://writer.live.com .">
      <![CDATA[ NOT (INSTALLDIR_OLD AND (NOT INSTALLDIR))  ]]>
    </Condition>

    
    <Condition Message="Windows Live Writer is not installed. 
                        Please install Windows Live Writer from https://writer.live.com .">
      <![CDATA[  NOT ((NOT INSTALLDIR) AND (NOT INSTALLDIR_OLD)) ]]>
    </Condition>
    
    <!-- End of Launch conditions -->

    <Media Id="1" Cabinet="{%PluginName%}.cab" EmbedCab="yes" DiskPrompt="CD-ROM #1" />

    <Property Id="DiskPrompt" Value="{%PluginName%} Installation [1]" />

    <Directory Id="TARGETDIR" Name="SourceDir">
          <Directory Id="INSTALLDIR">
            <Directory Id="Plugins" Name="Plugins">
              <Component Id="{%PluginName%}" Guid="{%guid #3%}">
                <!-- The raw dll to copy to the PlugIns folder -->
                <File 
                  Id="File_{%PluginName%}" 
                  Name="{%PluginShortFilename%}"
                  LongName="{%PluginLongFilename%}" 
                  DiskId="1" 
                  Source="{%FullPath%}" 
                  Vital="yes" />
                
                <!-- The IProperties backing storage to delete. This key is populated if 
                the PlugIn stores options via IProperties. Remove it on uninstall 
                to ensure that the plugin options get reset. 
                 <!-- Uncomment this to remove IProperties storage on uninstall. This just removes the current user.
                <Registry 
                  Id='FoobarRegInstallDir' 
                  Root='HKCU' 
                  Key='Software\Microsoft\Windows Live\Writer\Preferences\PostEditor\ContentSources\{%PlugIn Guid%}' 
                  Action='removeKeyOnUninstall'
                  />
                -->

 

                  <!-- {note: other files could be included here an necessary; if you 
                distribute help files or supporting graphics}
                -->
              </Component>
            </Directory>
          </Directory>
        </Directory>


    <!-- Components are grouped into "Features". 
    As a plug-in, we have a single feature, which is to copy the plugin dll.
    We don't have any UI to select features.
    -->
    <Feature Id="Complete" 
             Level="1"
             Title="{%PluginName%}"
             Description="{%Description%}"
             Display="expand">
      <ComponentRef Id="{%PluginName%}" />
    </Feature>
  </Product>
</Wix>

 

The values I used for my Verse-of-the-Day plugin were:

Key Description Sample Value
Guid #1 A unique guid for the product. {YOURGUID-ca12-470b-ade3-3cfca0c7d4c3}
Guid #3 A unique guid for the component. {YOURGUID-ca12-470b-ade3-3cfca0c7d4c3}
Installed Name The name that shows in Control Panel's Add/Remove programs list. Verse-of-the-Day Live Writer PlugIn
Manufacturer Your name. Mike Stall
Description A description of your plugin, which may be presented to the end-user. Insert a verse of the Day from BibleGateway
PluginName The name of your plugin. This is used internally for WiX property names and not displayed to the end user. VerseOfTheDay
PluginShortFilename a 8.3 dll name for your plugin. VOTD.dll
PluginLongFilename A long dll name for your plugin. VerseOfTheDay.dll
FullPath The path to the dll on your target machine. WiX will  copy this into the MSI. C:\temp\msi\3\votd\VerseOfTheDay.dll
PlugIn Guid The Guid in the Plugin attribute. {6F75058E-EED6-4f8c-BBE5-BE0D6126358D}

 

Random guids (Guid #1, etc) can be generated from GuidGen (in VS, "Tools | Create GUID"), or C# code like: Guid.NewGuid().ToString("b").

(FWIW, substituting the {%...%} was what motivated my Replacer tool)

 

3) Compile with WiX.

First, set WIXUI_PATH to the wix installation (where candle.exe lives). And then run these Wix commands:

 

 C:\temp\msi\3\votd>  %WIXUI_PATH%\candle.exe -out foo.wixobj votd.wxsMicrosoft (R) Windows Installer Xml Compiler version 2.0.5325.0Copyright (C) Microsoft Corporation 2003. All rights reserved.votd.wxsC:\temp\msi\3\votd>  %WIXUI_PATH%\light.exe foo.wixobj %WIXUI_PATH%\WixUI.wixlib -loc %WIXUI_PATH%\WixUI_en-us.wxl -out  MyVOTD.msiMicrosoft (R) Windows Installer Xml Linker version 2.0.5325.0Copyright (C) Microsoft Corporation 2003. All rights reserved.

 

This takes in the wix file (votd.wxs) and produces an output file, MyVOTD.msi, which you can then submit to the WLW Gallery.