Logo
HOWTO: Get loaded add-ins and installed products from a Visual Studio add-in.

Author: Carlos J. Quintero (Microsoft MVP) Applies to: Microsoft Visual Studio 2005
Date: August 2012   Microsoft Visual Studio 2008
      Microsoft Visual Studio 2010
      Microsoft Visual Studio 2012
Introduction

This article explains how to get the list of loaded add-ins and installed Visual Studio products from a Visual Studio add-in. This information is useful to be included in the bug report to be sent to the add-in publisher when an exception happens in the add-in, since some exceptions can happen only when some 3rd party add-in or product is installed.

More information

The list of installed add-ins can be obtained from the automation model using EnvDTE.DTE.AddIns. To know if an add-in is loaded, you can use the Connected property.

The list of installed products can be obtained reading the registry key HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\<version>\InstalledProducts where <version> can be:

  • 8.0 for Visual Studio 2005
  • 9.0 for Visual Studio 2008
  • 10.0 for Visual Studio 2010
  • 11.0 for Visual Studio 2011

Note 1: for Visual Studio 2005 and 2008, if you use the regedit.exe tool to examine visually the installed products on a Windows 64-bit operating system you need to go to the HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\<version> registry key since Visual Studio is a 32-bit application.

Note 2: for Visual Studio 2010 and higher if you use the regedit.exe tool to examine visually the installed products you need to go to the HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\<version>_Config\InstalledProducts registry key. This is because for Visual Studio 2010 and higher, products can be installed:

  • For all-users as in previous versions (using Registry-registration in the HKEY_LOCAL_MACHINE hive, requiring admin rights to install the product).
  • For the current user (using registration through a file on disk, not requiring admin rights to install the product).

And Visual Studio 2010 and higher does the following things:

  • It copies the information from HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\<version> to HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\<version>_Config
  • It generates information in HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\<version>_Config about products registered using a file on disk for the current user.
  • Most notably, it sets a Registry redirection that causes that every attempt from the Visual Studio devenv.exe process (and its extensions, such as add-ins or packages) to read the HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\<version> is actually redirected to HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\<version>_Config. So, programatically the add-in needs to read the HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\<version>\InstalledProducts registry key. Behind the scenes, Visual Studio redirects that read to the HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\<version>_Config registry key.

If you want to get even more low level information such as installed packages (rather than just installed products) you need to read the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\<version>\Packages registry key (which for Visual Studio 2010 and higher is actually redirected to HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\<version>_Config\Packages).

The following sample shows the code of an add-in that shows in the Immediate window information about loaded add-ins and installed products:

Language: VB.NET   Copy Code Copy Code (IE only)
Imports System
Imports Microsoft.VisualStudio.CommandBars
Imports Extensibility
Imports EnvDTE
Imports EnvDTE80

Public Class Connect
   Implements IDTExtensibility2	

   Private _applicationObject As DTE2
   Private _addInInstance As AddIn

   Public Sub OnConnection(ByVal application As Object, ByVal connectMode As ext_ConnectMode, ByVal addInInst As Object, _
      ByRef custom As Array) Implements IDTExtensibility2.OnConnection

      _applicationObject = CType(application, DTE2)
      _addInInstance = CType(addInInst, AddIn)

      Select Case connectMode

         Case ext_ConnectMode.ext_cm_AfterStartup

            ShowInstalledAddInsAndProducts()

         Case ext_ConnectMode.ext_cm_Startup

            ' OnStartupComplete will be called

      End Select

   End Sub

   Public Sub OnDisconnection(ByVal disconnectMode As ext_DisconnectMode, ByRef custom As Array) _
      Implements IDTExtensibility2.OnDisconnection
   End Sub

   Public Sub OnAddInsUpdate(ByRef custom As Array) Implements IDTExtensibility2.OnAddInsUpdate
   End Sub

   Public Sub OnStartupComplete(ByRef custom As Array) Implements IDTExtensibility2.OnStartupComplete

      ShowInstalledAddInsAndProducts()

   End Sub

   Public Sub OnBeginShutdown(ByRef custom As Array) Implements IDTExtensibility2.OnBeginShutdown
   End Sub

   Private Sub ShowInstalledAddInsAndProducts()

      ShowLoadedAddIns()
      ShowInstalledProducts()

   End Sub

   Private Sub ShowLoadedAddIns()

      For Each installedAddIn As AddIn In _applicationObject.AddIns

         If installedAddIn.Connected Then

            Debug.WriteLine("Loaded add-in:")
            Debug.WriteLine("- Name: " & installedAddIn.Name)
            Debug.WriteLine("- ProgId: " & installedAddIn.ProgID)
            Debug.WriteLine("- Description: " & installedAddIn.Description)
            Try
               Debug.WriteLine("- Location: " & installedAddIn.Object.GetType().Assembly.Location)
            Catch ex As Exception
            End Try
            Debug.WriteLine("- Satellite Dll Path: " & installedAddIn.SatelliteDllPath)

         End If

      Next

   End Sub

   Private Sub ShowInstalledProducts()

      Dim registryKey As Microsoft.Win32.RegistryKey = Nothing
      Dim subKeyNames As String()

      Try

         registryKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(_applicationObject.RegistryRoot & "\InstalledProducts", False)

         subKeyNames = registryKey.GetSubKeyNames()

         If Not subKeyNames Is Nothing Then

            For Each subKeyName As String In subKeyNames

               Debug.WriteLine("Installed package:")
               Debug.WriteLine("- Name: " & subKeyName)

            Next

         End If

      Catch ex As Exception

      Finally

         If Not registryKey Is Nothing Then
            registryKey.Close()
         End If

      End Try

   End Sub

End Class
Language: C#   Copy Code Copy Code (IE only)
using System;
using Extensibility;
using EnvDTE;
using EnvDTE80;
using System.Diagnostics;

namespace MyAddIn
{

   public class Connect : IDTExtensibility2
   {
      private DTE2 _applicationObject;
      private AddIn _addInInstance;
      
      public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
      {
         _applicationObject = (DTE2)application;
         _addInInstance = (AddIn)addInInst;

         switch (connectMode)
         {
            case ext_ConnectMode.ext_cm_AfterStartup:
               ShowInstalledAddInsAndProducts();
               break;
            case ext_ConnectMode.ext_cm_Startup:
               // OnStartupComplete will be called
               break;
         }
      }

      public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
      {
      }

      public void OnAddInsUpdate(ref Array custom)
      {
      }

      public void OnStartupComplete(ref Array custom)
      {
         ShowInstalledAddInsAndProducts();
      }

      public void OnBeginShutdown(ref Array custom)
      {
      }

      private void ShowInstalledAddInsAndProducts()
      {
         ShowLoadedAddIns();
         ShowInstalledProducts();
      }

      private void ShowLoadedAddIns()
      {
         foreach (AddIn installedAddIn in _applicationObject.AddIns)
         {
            if (installedAddIn.Connected)
            {
               Debug.WriteLine("Loaded add-in:");
               Debug.WriteLine("- Name: " + installedAddIn.Name);
               Debug.WriteLine("- ProgId: " + installedAddIn.ProgID);
               Debug.WriteLine("- Description: " + installedAddIn.Description);
               try
               {
                  Debug.WriteLine("- Location: " + installedAddIn.Object.GetType().Assembly.Location);
               }
               catch (Exception ex)
               {
               }
               Debug.WriteLine("- Satellite Dll Path: " + installedAddIn.SatelliteDllPath);
            }
         }
      }

      private void ShowInstalledProducts()
      {
         Microsoft.Win32.RegistryKey registryKey = null;
         string[] subKeyNames;

         try
         {
            registryKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(_applicationObject.RegistryRoot + "\\InstalledProducts", false);

            subKeyNames = registryKey.GetSubKeyNames();

            if (subKeyNames != null)
            {
               foreach (string subKeyName in subKeyNames)
               {   
                  Debug.WriteLine("Installed product:");
                  Debug.WriteLine("- Name: " + subKeyName);
               }
            }
         }
         catch (Exception ex)
         {
         }
         finally
         {
            if (registryKey != null)
            {
               registryKey.Close();
            }
         }
      }
   }
}

Related articles


Go back to the 'Resources for Visual Studio .NET extensibility' section for more articles like this


Top