KnowDotNet NetRefactor

Deploying VS2005 Add-In

.Addin File Must Be Updated During Installation

by Les Smith
Print this Article Discuss in Forums

How do I install a VS2005 Add-in?  I can't get the add-in to show up in the Add-In Manager list box.  It was stated from the outset that VS2005 add-ins would have some of the "Com" ness removed and that registration of an add-in would not be the same as it was in earlier versions.  At first, that sounds good, because some of the registry convolution might be done away with, great!

What they failed to say was that deployment of the add-in would be left totally up to the developer.  In the first place, the Add-in Wizard does not create a setup project as the earlier versions did.  So you have to add your own Setup project, and get the dependencies.

The next problem, and the one about which this article is written, is that the new methodology replaces registration with an XML file that describes the original add-in manager fields and points to the assembly for the add-in.  The wizard does build that file, but it does not provide a way to deploy the file to the proper directory so the add-in manager will see it.  So you are left with two issues here.  First, you must modify the .Addin file to point to where your add-in was installed, which can be anywhere the user chooses.  Secondly, the file must then be copied to the proper directory, see
Add-In Registration.

The code shown below will do these two processes for you.  You can compile this code into a form-less windows application, build the executable and add it to your Custom Actions in the Setup project for your add-in.  Once you have added the custom action, set the Arguments property of the custom action to the name of your add-in (no .dll extension).

In the addin project, for which you are running this custom action, you must do a couple of things.  First, add a custom action, pointing to the executable created by the code for this article.  Secondly, enter the name of the addin in the parameter property of the custom action.  Do not put the ".dll", as the code shown below will do that for you.  Putting the name of the addin in its deployment setup allows you to use the code for this article in any addin without recompiling it.

To be fair, I got my start on this code from the following DEVX Link.  But I had to make some changes to get it to work and simply made an executable instead of using a
System.Configuration.Install.Installer Class as did the referenced article.  Although the DEVX version was probably more academically pleasing, you know me by now, I just like to keep it simple and easy to debug and understand.  You should find that the code works without changes.

Imports System.IO
Module Module1
  
''' <summary>
  
''' Get the .addin file from the install directory
   ''' Update the assembly element to point to the install directory
   ''' and save the updated file.  Then copy to the user documents folder
   ''' where the addin manager will see it.
   ''' </summary>
   ''' <remarks></remarks>
   Public Sub Main()
      
Dim addinName As String
      Dim asm As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly
      
Dim fileName As String = My.Computer.FileSystem.SpecialDirectories.Desktop
      
Dim fInfo As FileInfo
      
Dim dirInfo As DirectoryInfo
      
Dim doc As New System.Xml.XmlDocument()
      
Dim Node As System.Xml.XmlNode
      
Dim FoundIt As Boolean = False
      Dim szStage As String = ""
      Dim FolderPath As String = ""

      addinName = Environment.CommandLine.Trim
      
' in this implementation, addinName in commandline cannot have a space in it
      addinName = addinName.Substring(addinName.LastIndexOf(" ") + 1).Trim

      FolderPath = Path.Combine(
My.Computer.FileSystem.SpecialDirectories.MyDocuments, "Visual Studio 2005\Addins")
      dirInfo =
New System.IO.DirectoryInfo(FolderPath)

      
If Not dirInfo.Exists Then
         dirInfo.Create()
      
End If
      Dim assemblyPathandName As String = Path.Combine(Path.GetDirectoryName(asm.Location), addinName & ".DLL")

      
' get directory name of install directory
      Filename = Path.Combine(Path.GetDirectoryName(Asm.Location), addinName + ".Addin")
      fInfo =
New System.IO.FileInfo(fileName)

      
If Not fInfo.Exists Then
         Throw New Exception("File '" + fileName + _
            
"' is not found. Installation will be aborted or not complete")
      
Else
         ' Load the .Addin file into XML document
         Try
            doc.Load(fInfo.FullName)

            
' search for the assembly element which points to the addin dll
            Dim found As Boolean = False
            For Each Node In doc.Item("Extensibility").Item("Addin")
              
If Node.Name = "Assembly" Then
                  ' Change the Assembly to point to where the Addin is installed
                  Node.InnerText = assemblyPathandName
                  found =
True
                  Exit For
               End If
            Next Node

            
If Not found Then
               Throw New Exception("XML File is missing the Assembley Element, " & _
                  
"installation is not complete")
            
End If

            ' Save the updated xml .addin File
            doc.Save(fInfo.FullName)

            
' Copy the file to the target path
            Dim destFile As String = Path.Combine(FolderPath, addinName + ".Addin")
            fInfo.CopyTo(Path.Combine(FolderPath, destFile),
True)
        
Catch ex As Exception
            
Throw New Exception("Failure to process file '" + _
               fInfo.FullName +
"'. Error= " & ex.ToString + _
              
". Installation will be aborted or not complete")
        
End Try
      End If
   End Sub
End
Module


Typically, the user will install your addin in the default location desginated in you setup project.  That path has to be modified in the .Addin XML file.  The .Addin file is included in your deployment package and must be moved to a path that generally looks like this.

  
C:\Documents and Settings\Les Smith\My Documents\Visual Studio 2005\Addins

The .Addin file will have a format similiar to the following and you will note that the Assembly element of the file has been modified to reflect the actual installation folder for the addin.

<?xml version="1.0" encoding="UTF-16" standalone="no"?>
<Extensibility xmlns="http://schemas.microsoft.com/AutomationExtensibility">
  <HostApplication>
    <Name>Microsoft Visual Studio</Name>
    <Version>8.0</Version>
  </HostApplication>
  <Addin>
    <FriendlyName>NetRefactor2005 </FriendlyName>
    <Description>Refactoring and Class Organizing for C# and VB.NET.</Description>
    <Assembly>
C:\Program Files\KnowDotNet\NetRefactor2005\NetRefactor2005.DLL</Assembly>
    <FullClassName>NetRefactor2005.Connect</FullClassName>
    <LoadBehavior>1</LoadBehavior>
    <CommandPreload>0</CommandPreload>
    <CommandLineSafe>0</CommandLineSafe>
  </Addin>
</Extensibility>

One final thing that you need to do; set the InstallerClass property of the Custom Action exe to False.

Ask a Question, or give your feedback on my articles or products by clicking on My Blog.



Writing Add-Ins for Visual Studio .NET
Writing Add-ins for Visual Studio .NET
by Les Smith
Apress Publishing