Click here to Skip to main content
Email Password   helpLost your password?

Introduction

Having developed a Visual Studio 2005 add-in recently, I found that when it comes to deploying the add-in, there is no setup project automatically created any more. As described in the following excerpt from MSDN online, Visual Studio 2005 now relies on the .addin file for add-in deployment:

In Visual Studio .NET 2002 and Visual Studio .NET 2003, you were required to register add-in assemblies with Windows as COM components by using the Assembly Registration Tool (regasm.exe). Also, you were required to register the add-in with Visual Studio by using keys in the Windows registry before the add-in would appear in the Add-In Manager.

These steps have changed in Visual Studio 2005. You no longer need to register the .NET assemblies with Windows by using regasm. Instead, you simply place the assembly .DLL file into a specific directory along with an XML file that has an .Addin file extension. This XML file describes the information that Visual Studio requires to display the add-in in the Add-In Manager. When Visual Studio starts, it looks in the .Addin File location (listed below) for any available .Addin files. If it finds any, it reads the XML file and provides the Add-In Manager with the information needed to start the add-in when it is clicked.

This simplified registration method allows XCopy-style installations for managed code add-ins. If you put all the files in the right place, then your add-in works just fine. Also, its use of commented XML to define the registration settings for add-ins allows the information to be more easily understood and edited than registry keys.

So now, the question is how we can still use Windows Installer (.msi) to deploy an add-in with this new registration method. Here, I will walk you through building a generic custom action to manipulate and XCopy the .addin file along with your add-in assembly that will work for most add-in deployment scenarios.

The .Addin File

The following is an example of a complete .Addin XML file. The .Addin file is usually placed at \Documents and Settings\All Users\My Documents\Visual Studio 2005\Addins or \Documents and Settings\<user name>\My Documents\Visual Studio 2005\Addins. The Assembly node (in bold) specifies the location of the add-in binaries. This field can be set to a local path, a network path, or a valid URL. And, it is where the custom action comes in to update at the time of deployment.

<?xml version="1.0" encoding="UTF-16" standalone="no"?>
<Extensibility 
  xmlns="http://schemas.microsoft.com/AutomationExtensibility">
    <HostApplication>
        <Name>Microsoft Visual Studio Macros</Name>
        <Version>8.0</Version>
    </HostApplication> 
    <HostApplication>
        <Name>Microsoft Visual Studio</Name>
        <Version>8.0</Version>
    </HostApplication>
    <Addin>
        <FriendlyName>My new add-in.</FriendlyName>
        <Description>This add-in does something important.</Description>
        <AboutBoxDetails>Copyright MyCompany 2006.</AboutBoxDetails>
        <AboutIconData>0000 . . . FFFF0000</AboutIconData>
        <Assembly>[Path to add-in]\MyNewAddin.dll</Assembly>
        <FullClassName>MyNewAddin.Connect</FullClassName>
        <LoadBehavior>1</LoadBehavior>
        <CommandPreload>0</CommandPreload>
        <CommandLineSafe>0</CommandLineSafe>
    </Addin>
    <ToolsOptionsPage>
        <Category Name="MyNewAddin">
        <SubCategory Name="General">
            <Assembly>[Path to add-in]\MyNewAddin.dll</Assembly>
            <FullClassName>MyNewAddin.OptionsPage</FullClassName>
        </SubCategory>
        </Category>
    </ToolsOptionsPage>
</Extensibility>

Creating a Custom Action Project

Create a class library project, and add a new item by choosing an Installer class. The newly added class will inherit from the System.Configuration.Install.Installer class, which has methods like Install, Commit, Rollback, and Uninstall that you can override.

namespace AddinCustomAction
{
    using System;
    using System.IO;
    using System.Diagnostics;
    using System.Collections;
    using System.ComponentModel;
    using System.Configuration.Install;
    using System.Xml;
    
    /// <summary>
    /// Custom action for add-in deployment.
    /// </summary>

    [RunInstaller(true)]
    public partial class AddinInstaller : Installer
    {
        /// <summary>
        /// Namespace used in the .addin configuration file.
        /// </summary>         

        private const string ExtNameSpace = 
          "http://schemas.microsoft.com/AutomationExtensibility";
        
        /// <summary>
        /// Constructor. Initializes components.
        /// </summary>

        public AddinInstaller()
            : base()
        {
            InitializeComponent();
        }
        
        /// <summary>
        /// Overrides Installer.Install,
        /// which will be executed during install process.
        /// </summary>
        /// <param name="savedState">The saved state.</param>

        public override void Install(IDictionary savedState)
        {
            // Uncomment the following line, recompile the setup
            // project and run the setup executable if you want
            // to debug into this custom action.

            ////Debugger.Break();

            base.Install(savedState);
            
            // Parameters required to pass in from installer

            string productName = this.Context.Parameters["ProductName"];
            string assemblyName = this.Context.Parameters["AssemblyName"];
            
            // Setup .addin path and assembly path

            string addinTargetPath = Path.Combine(Environment.GetFolderPath(
                   Environment.SpecialFolder.MyDocuments), 
                   @"Visual Studio 2005\Addins");
            string assemblyPath = Path.GetDirectoryName(
                   System.Reflection.Assembly.GetExecutingAssembly().Location);
            string addinControlFileName = assemblyName + ".Addin";
            string addinAssemblyFileName = assemblyName + ".dll";
            
            try
            {
                DirectoryInfo dirInfo = new DirectoryInfo(addinTargetPath);
                if (!dirInfo.Exists)
                {
                    dirInfo.Create();
                }
                
                string sourceFile = Path.Combine(assemblyPath, addinControlFileName);
                XmlDocument doc = new XmlDocument();
                doc.Load(sourceFile);
                XmlNamespaceManager xnm = new XmlNamespaceManager(doc.NameTable);
                xnm.AddNamespace("def", ExtNameSpace);
                
                // Update Addin/Assembly node

                XmlNode node = doc.SelectSingleNode("/def:" + 
                    "Extensibility/def:Addin/def:Assembly", xnm);
                if (node != null)
                {
                    node.InnerText = Path.Combine(assemblyPath, addinAssemblyFileName);
                }
                
                // Update ToolsOptionsPage/Assembly node

                node = doc.SelectSingleNode("/def:Extensibility/def:" + 
                       "ToolsOptionsPage/def:Category/def:SubCategory/def:Assembly", xnm);
                if (node != null)
                {
                    node.InnerText = Path.Combine(assemblyPath, addinAssemblyFileName);
                }
                
                doc.Save(sourceFile);
                
                string targetFile = Path.Combine(addinTargetPath, addinControlFileName);
                File.Copy(sourceFile, targetFile, true);
                
                // Save AddinPath to be used in Uninstall or Rollback

                savedState.Add("AddinPath", targetFile);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }
        
        /// <summary>
        /// Overrides Installer.Rollback, which will be executed during rollback process.
        /// </summary>

        /// <param name="savedState">The saved state.</param>

        public override void Rollback(IDictionary savedState)
        {
            ////Debugger.Break();

            base.Rollback(savedState);
            
            try
            {
                string fileName = (string)savedState["AddinPath"];
                if (File.Exists(fileName))
                {
                    File.Delete(fileName);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }
        
        /// <summary>
        /// Overrides Installer.Uninstall, which will be executed during uninstall process.
        /// </summary>

        /// <param name="savedState">The saved state.</param>

        public override void Uninstall(IDictionary savedState)
        {
            ////Debugger.Break();

            base.Uninstall(savedState);

            try
            {
                string fileName = (string)savedState["AddinPath"];
                if (File.Exists(fileName))
                {
                    File.Delete(fileName);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }
    }
}

Configuring the Setup Project

Add the custom action project's output to the setup project. As shown below, in the Custom Action view, add the custom action primary output to Install, Rollback, and Uninstall.

Specify the CustomActionData in the Install action. Specify AssemblyName as the name of your DLL and ProductName as your product's full name.

If you want to debug your custom action, add the following line inside the method you want to debug in the custom action class:

Debugger.Break();
You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralGreat article
Sasa Popovic
23:58 22 Jun '08  
Saved me some time figuring-out if there is a setup project for VS Add-ins or if I should make a custom one. You even implemented everything so I didn't have to do anything Smile
Thx a lot!


GeneralNice but not necessary
MLansdaal
10:53 28 May '08  
Thank you for the article information about the custom actions for VS addin installers. However, this particular example is misleading.

I have developed two addins and both .AddIn files I have simply placed the non-path qualifed assembly name in the <Assembly></Assembly> node. The .AddIn and .DLL files are stored in the C:\Documents and Settings\[profilename]\My Documents\Visual Studio 2005\AddIns directory and are loaded by VS just fine without the need for a custom action.

I think if you were to install the DLL file in some other location, then you would need to programmatically set the assembly path information as you have shown. I'm not sure why you would want to have the DLL installed somewhere else though.
Generaldeploy msi with VS 2005
dakna
2:29 31 Oct '07  
Hi everybody , I have a problem with msi deployement, when I install msi under administrateur account it ok , I can launch the .exe from desktop shortcut or programm menu , but when I create limited user
and I try to launch .exe from shortcut desktop , it try to launch msi installation and crush with access denied to installastate , I need that all users can launch normally .exe generate by msi package

best regards
GeneralWorks perfectly!
SlickEdit Inc.
7:52 15 Aug '07  
Thanks so much!
GeneralExcellent
Pelotas
12:08 27 Jun '07  
This is exactly what I need. Not only it resolve my problem deploying my add-in but also I learn some useful tips about custom installer action. Thank you.
GeneralCustom Action Execution Trouble
zaac
5:49 13 Apr '07  
Hi,

Thanks a lot for your article. I try to create a setup project with a custom action. I test my custom with installUtil.exe, it works. But when i install my setup builded, a message box appears with the syntax of installUtil. The setup don't manage to execute the action, and it rolls back. It seems to be a wrong call of InstallUtil made by the setup. Do you ever see this strange behavior ?

(sorry for my english)

AnswerRe: Custom Action Execution Trouble
Ting Huang
15:41 13 Apr '07  
This custom action is only for deploying visual studio 2005 add-in. It doesn't apply in your case.
GeneralFormatting
ApoloniaK
22:19 31 Jan '07  
Can you reformat the html of this page please, so that it doesn't need the horizontal scrolling
GeneralWhere is the setup source
jdariasl
5:44 24 Nov '06  
Hi, I want to know if is posible to post the setup source code.
Thanks

Jorge Arias
GeneralHow does one get permission to use this code
HC72
14:57 28 Oct '06  
I see that it has a Copyright with All rights reserved.
Thanks,
David
GeneralRe: How does one get permission to use this code
Ting Huang
17:17 28 Oct '06  
You are allowed to view, modify, and redistribute the source code for either commercial or non-commercial purposes, under the condition that you will keep the copyright statement attached.
GeneralHow can I useThis Add-in
Vishram
19:24 4 Aug '06  
I downloaded an Add-in from - visualstudiohacks.com/classify. After Installing this, It's not showing in VS 2005 Professional Edition. May be you can help me to use this one.
GeneralRe: How can I useThis Add-in [modified]
Abhayc
0:48 24 Aug '06  
add-in from visualstudiohacks.com/classify is for VS2003 and NOT for VS2005. Try to create your own sample VS2005 add-in by using http://msdn2.microsoft.com/en-us/library/80493a3w.aspx
VS2005 requires .Addin XML file to load add-in.


Last Updated 23 Jul 2006 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010