Tutorial: Deploy your Enterprise Architect C# add-in with an MSI package

In previous posts I talked about Creating and Testing your Enterprise Architect C# add-in, and how to use the C# add-in template to speed up the development process.

Once created and tested you’ll probably want to install and use the add-in on other computers then your development machine. This tutorial explains how to create an MSI installer package using the open source SharpDevelop and WiX software.

The reason I’m using SharpDevelop as opposed to Visual Studio C# Express is because SharpDevelop is free and open source, and Visual Studio C# Express doesn’t allow to create setup projects, or attach to a running process to debug your add-in.

Requirements

The plan

As explained in Tutorial: Create your first C# Enterprise Architect addin in 10 minutes we need our installer to do three things for us:

  1. Copy the dll’s to a program folder.
  2. Register the add-in dll for COM Interop so Windows knows where to find the add-in dll.
  3. Create the registry key so EA knows about our add-in.

Step 1: Create a setup project

  • Open the solution for your add-in in SharpDevelop. If you have developed the add-in with Visual Studio, that fine. Sharpdevelop uses the exact same project setup as Visual Studio, with the .sln and .csproj files
  • Add a new project and choose for Setup Project – WixUI Minimal
    You can of course choose for another template, but for the purpose of this tutorial the WixUI Minimal is enough.
    New WiX Setup Project
  • SharpDevelop will now have created a new Setup project in your solution containing three files:
    • Files.wxs
      This is were we define wich files and registry keys the installer needs to install
    • license.rtf
      Contains the license for your software
    • Setup.wxs
      Where we define the general setup of the installer like the name, and the components to install.
    • MyAddinProject

Step 2: Edit Setup.wxs

Next we’re going to tell the installer about the application it will install. The .wxs files are actually XML files, and you can edit them directly in SharpDevelop.

  • Open Setup.wxs and edit the highlighted parts
    Setup.wxs
    Notice that we also added a ComponentRef for MyAddinRegEntries.

Step 3: Add the program files

  • Open up the setup files view with View|Setup|Files
  • Rename the installation folder to something sensible
  • Add a component for each ComponentRef we added in the Setup.wxs
  • Right-click on the MyAddinFiles component and choose Add Files…
    MyAddinAddFiles
  •  Now browse to the MyAddin project folder and select all files in the MyAddin\bin\debug or MyAddin\bin\release folder, depending on how you last built your project.
    Not all of these files might be necessary, but I can’t be bothered to figure out exactly which files we need to install the add-in on another computer.
  • This should now have created a line in the files.wxs for each binary file similar to
    <File Id="EAAddinFramework.dll" Name="EAAddinFramework.dll" Source="..\MyAddin\bin\Debug\EAAddinFramework.dll" />
    <File Id="UMLToolingFramework.dll" Name="UMLToolingFramework.dll" Source="..\MyAddin\bin\Debug\UMLToolingFramework.dll" />
    <File Id="EAAddinFramework.pdb" Name="EAAddinFramework.pdb" Source="..\MyAddin\bin\Debug\EAAddinFramework.pdb" />
    <File Id="Interop.EA.dll" Name="Interop.EA.dll" Source="..\MyAddin\bin\Debug\Interop.EA.dll" />
    <File Id="MyAddin.pdb" Name="MyAddin.pdb" Source="..\MyAddin\bin\Debug\MyAddin.pdb" />
    <File Id="MyAddin.tlb" Name="MyAddin.tlb" Source="..\MyAddin\bin\Debug\MyAddin.tlb" />
    <File Id="UMLToolingFramework.pdb" Name="UMLToolingFramework.pdb" Source="..\MyAddin\bin\Debug\UMLToolingFramework.pdb" />
    <File Id="MyAddin.dll" Name="MyAddin.dll" Source="..\MyAddin\bin\Debug\MyAddin.dll" />
    

Step 4: Register MyAddin.dll for COM Interop

The MyAddin.dll is the add-in dll that EA needs to talk to, so this dll needs to be registered for COM Interop. This is the part that is done by regasm.exe when doing a manual installation, but we don’t want to be calling any executables on the target machine during install if we can avoid it. Instead we will just add the same registry keys that regasm.exe creates.

  • Open a command prompt in the folder where MyAddin.dll is located (bin\Debug\)
  • Execute following command:
    "C:\Program Files (x86)\WiX Toolset v3.8\bin\heat.exe" file MyAddin.dll -ag -template fragment -out MyAddin.wxs

    This will have created a file in the same folder with the name MyAddin.wxs.

  • Open that file and copy the contents of the Component tag:
    <Class Id="{10BC65F1-32C0-3ED4-98A0-17661A8C4455}" Context="InprocServer32" Description="MyAddin.MyAddinClass" ThreadingModel="both" ForeignServer="mscoree.dll">
     <ProgId Id="MyAddin.MyAddinClass" Description="MyAddin.MyAddinClass" />
    </Class>
    <File Id="filCC4172BEC1312562EDEF49648E45AE0D" KeyPath="yes" Source="..\MyAddin\bin\Debug\MyAddin.dll" />
    <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value="" Type="string" Action="write" />
    <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32\1.0.0.0" Name="Class" Value="MyAddin.MyAddinClass" Type="string" Action="write" />
    <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32\1.0.0.0" Name="Assembly" Value="MyAddin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" Type="string" Action="write" />
    <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32\1.0.0.0" Name="RuntimeVersion" Value="v4.0.30319" Type="string" Action="write" />
    <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32\1.0.0.0" Name="CodeBase" Value="file:///[#filCC4172BEC1312562EDEF49648E45AE0D]" Type="string" Action="write" />
    <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32" Name="Class" Value="MyAddin.MyAddinClass" Type="string" Action="write" />
    <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32" Name="Assembly" Value="MyAddin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" Type="string" Action="write" />
    <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32" Name="RuntimeVersion" Value="v4.0.30319" Type="string" Action="write" />
    <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32" Name="CodeBase" Value="file:///[#filCC4172BEC1312562EDEF49648E45AE0D]" Type="string" Action="write" />
  • Replace the file tag for MyAddin.dll in your files.wxs by the copied part
  • Add a Name attribute Name=”MyAddin.dll to the file tag for MyAddin.dll so the tag looks like:
    <File Id="filCC4172BEC1312562EDEF49648E45AE0D" Name="MyAddin.dll" KeyPath="yes" Source="..\MyAddin\bin\Debug\MyAddin.dll" /> 

Step 5: Add the EA Addin registry key

This step will instruct the installer to create the add-in registry key that tells EA there is an add-in to load

  • Add following Registry key tag to the MyAddinRegEntries tag in the Files.wxs
    <RegistryKey Root="HKCU" Key="Software\Sparx Systems\EAAddins\MyAddin" Action="createAndRemoveOnUninstall">
    <RegistryValue Type="string" Value="MyAddin.MyAddinClass" />
     </RegistryKey>
    

All xml file editing should now be behind us. The complete Files.wxs should look something like:

<?xml version="1.0"?>
   <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
     <Fragment>
       <DirectoryRef Id="TARGETDIR">
         <Directory Id="ProgramFilesFolder" Name="PFiles">
           <Directory Id="INSTALLDIR" Name="MyAddin">
             <Component Id="MyAddinFiles" Guid="5C526B21-FB62-42AD-9897-F990FEA7E164" DiskId="1">
               <File Id="EAAddinFramework.dll" Name="EAAddinFramework.dll" Source="..\MyAddin\bin\Debug\EAAddinFramework.dll" />
               <File Id="UMLToolingFramework.dll" Name="UMLToolingFramework.dll" Source="..\MyAddin\bin\Debug\UMLToolingFramework.dll" />
               <File Id="EAAddinFramework.pdb" Name="EAAddinFramework.pdb" Source="..\MyAddin\bin\Debug\EAAddinFramework.pdb" />
               <File Id="Interop.EA.dll" Name="Interop.EA.dll" Source="..\MyAddin\bin\Debug\Interop.EA.dll" />
               <File Id="MyAddin.pdb" Name="MyAddin.pdb" Source="..\MyAddin\bin\Debug\MyAddin.pdb" />
               <File Id="MyAddin.tlb" Name="MyAddin.tlb" Source="..\MyAddin\bin\Debug\MyAddin.tlb" />
               <File Id="UMLToolingFramework.pdb" Name="UMLToolingFramework.pdb" Source="..\MyAddin\bin\Debug\UMLToolingFramework.pdb" />
               <Class Id="{10BC65F1-32C0-3ED4-98A0-17661A8C4455}" Context="InprocServer32" Description="MyAddin.MyAddinClass" ThreadingModel="both" ForeignServer="mscoree.dll">
                 <ProgId Id="MyAddin.MyAddinClass" Description="MyAddin.MyAddinClass" />
               </Class>
               <File Id="filCC4172BEC1312562EDEF49648E45AE0D" Name="MyAddin.dll" KeyPath="yes" Source="..\MyAddin\bin\Debug\MyAddin.dll" />
               <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value="" Type="string" Action="write" />
               <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32\1.0.0.0" Name="Class" Value="MyAddin.MyAddinClass" Type="string" Action="write" />
               <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32\1.0.0.0" Name="Assembly" Value="MyAddin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" Type="string" Action="write" />
               <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32\1.0.0.0" Name="RuntimeVersion" Value="v4.0.30319" Type="string" Action="write" />
               <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32\1.0.0.0" Name="CodeBase" Value="file:///[#filCC4172BEC1312562EDEF49648E45AE0D]" Type="string" Action="write" />
               <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32" Name="Class" Value="MyAddin.MyAddinClass" Type="string" Action="write" />
               <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32" Name="Assembly" Value="MyAddin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" Type="string" Action="write" />
               <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32" Name="RuntimeVersion" Value="v4.0.30319" Type="string" Action="write" />
               <RegistryValue Root="HKCR" Key="CLSID\{10BC65F1-32C0-3ED4-98A0-17661A8C4455}\InprocServer32" Name="CodeBase" Value="file:///[#filCC4172BEC1312562EDEF49648E45AE0D]" Type="string" Action="write" />
             </Component>
             <Component Id="MyAddinRegEntries" Guid="8439A7F4-D42F-43AC-B91D-CBF823A89DDE">
              <RegistryKey Root="HKCU" Key="Software\Sparx Systems\EAAddins\MyAddin" Action="createAndRemoveOnUninstall">
                <RegistryValue Type="string" Value="MyAddin.MyAddinClass" />
              </RegistryKey>
            </Component>
          </Directory>
        </Directory>
      </DirectoryRef>
    </Fragment>
 </Wix>

Step 6: Fill in the license details

  • Open license.rft in wordpad, or another rtf editor and fill in the license details
    Do NOT use Microsoft Word to edit the license.rtf as Word will make a horrible mess of the rtf file.

Step 7: Build and test your setup project

Now all we need to do is build and test the setup project. You can run it right from within Sharpdevelop.

If all is well you should see something similar to this:

More resources

Related blog posts

Source code on GitHub

Sparx Systems

Other

  • Examples in the EA installation folder: C:\Program Files\Sparx Systems\EA\Code Samples

Published by

Geert Bellekens

Freelance UML and Enterprise Architect consultant

28 thoughts on “Tutorial: Deploy your Enterprise Architect C# add-in with an MSI package”

  1. Hi Geert,
    I’m using VS2012 and dropped InstallShield as I cannot get the Register COM Interop to work.
    I tried to follow your tutorial however VS and SharpDevelop seem to be very different. Do you think you could suggest the alternative or advise what needs doing in Visual Studio 2012?
    Thanks

    1. Hi Guillaume,

      I know that is it possible now to create Wix installers with Visual Studio as well, but I’ve never done so myself. Surely there must be documentation on the internet about this.
      In this past I did make some VS installers using the standard VS setup project, and that worked fine as well (it was even easier as VS recognises the COM Interop stuff itself, so you don’t have to do the funny stuff with the Wix commands anymore), but I haven’t done any in VS recently, so I can’t help you with VS 2012 specifics.

    2. Hi again.
      I eventually figured how to get it to work based on your information + Wix help. I’ll try to post an article to complete yours for Visual Studio users.

  2. Hi everybody,
    does this way also work with Python. I created my Addin using Python.
    Thanks in advance. 🙂

  3. Geert, is it possible, with only a repository object, in c#, to determine which object, is highlighted in the project browser??

    1. Yes you can, See

    2. GetTreeSelectedElements ()
    3. GetTreeSelectedItem (object SelectedItem)
    4. GetTreeSelectedItemType ()
    5. GetTreeSelectedObject ()
    6. GetTreeSelectedItem ()
    7. GetTreeSelectedPackage ()

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s