Logo
HOWTO: Get a Visual Studio service from an add-in

Author: Carlos J. Quintero (Microsoft MVP) Applies to: Microsoft Visual Studio .NET 2002
Date: February 2007   Microsoft Visual Studio .NET 2003
Updated: October 2012   Microsoft Visual Studio 2005
      Microsoft Visual Studio 2008
      Microsoft Visual Studio 2010
      Microsoft Visual Studio 2012

Introduction

There are two main forms of extensibility for Visual Studio: add-ins and VS packages:

  • Add-ins are a high-level form of extensibility, based on the object model provided by EnvDTE.dll (and other DLLs as explained in the article INFO: Assemblies used in Visual Studio Extensibility)
  • VS packages are a low-level form of extensibility based on the Visual Studio SDK. Visual Studio works with registered packages, which provide services to the IDE.

While the extensibility model for add-ins (EnvDTE) is powerful enough for most add-ins, sometimes you need some functionality only available from Visual Studio services. Fortunately you don't need to convert your add-in to a Visual Studio package to get that functionality. This article explains how to get it.

More Information

Several objects provided by the extensibility model for add-ins, such as EnvDTE.DTE, are service providers and implement the Microsoft.VisualStudio.OLE.Interop.IServiceProvider (OLE) interface (do not confuse it with the System.IServiceProvider interface of the .NET Framework) and its QueryService method. You can get the definition of this interface in your source code by the following ways:

  • For Visual Studio .NET 2002/2003, the Microsoft.VisualStudio.OLE.Interop.dll assembly is supplied with Visual Studio Industry Partner Program (VSIP) SDK 2003 Extras, which in turn requires Visual Studio Industry Partner Program (VSIP) SDK 2003. Once installed, the required assembly is located at the folder:

    C:\Program Files\VSIP 7.1\EnvSDK\common\VSIA

    This DLL is redistributable using the MSI package C:\Program Files\VSIP 7.1\EnvSDK\VSIP Interop Assembly Redist.msi (which includes two other assemblies), but as long as you keep it private for your add-in, you don't need to redistribute the other two assemblies.
  • For Visual Studio 2005 and higher, the Microsoft.VisualStudio.OLE.Interop.dll assembly is supplied through two ways:
    • With Visual Studio SDK. For example, for the VS 2005 SDK, once installed, the required assembly is located at the folder:

      C:\Program Files\Visual Studio 2005 SDK\<year.month>\VisualStudioIntegration\Common\Assemblies
    • Since Visual Studio 2005 and higher installs it in the GAC, you can get it from there (more simple than installing the SDK). See the article HOWTO: Reference a Visual Studio assembly in the GAC from an add-in. The subfolder is "GAC\Microsoft.VisualStudio.OLE.Interop\7.1.40304.0__b03f5f7f11d50a3a"

    In both cases you don't need to redistribute the assembly since it is installed in the GAC by Visual Studio 2005 and higher.
  • If you don't want to reference that assembly at all in your add-in, you can declare it in your own source code:

    Language: VB.NET   Copy Code Copy Code (IE only)
    Imports System.Runtime.InteropServices
    
    <ComImport(), Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)> _
    Friend Interface IServiceProvider
    
       <PreserveSig()> _
       Function QueryService(<InAttribute()> ByRef guidService As Guid, <InAttribute()> ByRef riid As Guid, _
          <Out()> ByRef ppvObject As IntPtr) As Integer
    
    End Interface
    
    Language: C#   Copy Code Copy Code (IE only)
    using System.Runtime.InteropServices;
    
    [ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IServiceProvider
    {
        [PreserveSig]
        int QueryService([In] ref Guid guidService, [In] ref Guid riid, out IntPtr ppvObject);
    }
    

Services are identified either by a GUID or by a type, so you can use the following helper functions to get a service from an object that implements the IServiceProvider:

Language: VB.NET   Copy Code Copy Code (IE only)
Public Function GetService(ByVal serviceProvider As Object, ByVal type As System.Type) As Object
   Return GetService(serviceProvider, type.GUID)
End Function

Public Function GetService(ByVal serviceProvider As Object, ByVal guid As System.Guid) As Object

   Dim objService As Object = Nothing
   Dim objIServiceProvider As Microsoft.VisualStudio.OLE.Interop.IServiceProvider
   Dim objIntPtr As IntPtr
   Dim hr As Integer
   Dim objSIDGuid As Guid
   Dim objIIDGuid As Guid

   objSIDGuid = guid
   objIIDGuid = objSIDGuid
   
   objIServiceProvider = CType(serviceProvider, Microsoft.VisualStudio.OLE.Interop.IServiceProvider)

   hr = objIServiceProvider.QueryService(objSIDGuid, objIIDGuid, objIntPtr)

   If hr <> 0 Then
      System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(hr)
   ElseIf Not objIntPtr.Equals(IntPtr.Zero) Then
      objService = System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(objIntPtr)
      System.Runtime.InteropServices.Marshal.Release(objIntPtr)
   End If

   Return objService

End Function
Language: C#   Copy Code Copy Code (IE only)
public object GetService(object serviceProvider, System.Type type)
{
   return GetService(serviceProvider, type.GUID);
}

public object GetService(object serviceProvider, System.Guid guid)
{
   object objService = null;
   IServiceProvider objIServiceProvider = null;
   IntPtr objIntPtr;
   int hr = 0;
   Guid objSIDGuid;
   Guid objIIDGuid;
 
   objSIDGuid = guid;
   objIIDGuid = objSIDGuid;
 
   objIServiceProvider = (IServiceProvider)serviceProvider;
 
   hr = objIServiceProvider.QueryService(ref objSIDGuid, ref objIIDGuid, out objIntPtr);
   if (hr != 0)
   {
      System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(hr);
   }
   else if (!objIntPtr.Equals(IntPtr.Zero))
   {
      objService = System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(objIntPtr);
      System.Runtime.InteropServices.Marshal.Release(objIntPtr);
   }
   return objService;
}

Since the service is returned as Object, you will likely need to cast it to the actual service, so you will need to reference the assembly containing the service (see the article above).

The following sample shows how to enumerate the data connections of the Server Explorer using the Microsoft.VisualStudio.Data.Interop.IVsDataConnectionsService service from an add-in for Visual Studio 2005 or higher (you need to add a reference to the Microsoft.VisualStudio.Data.Interop.dll assembly, in the subfolder "Microsoft Visual Studio <version>\Common7\IDE"). The _applicationObject is the EnvDTE.DTE instance:

Language: VB.NET   Copy Code Copy Code (IE only)
Dim objService As Object
Dim objIVsDataConnectionsService As Microsoft.VisualStudio.Data.Interop.IVsDataConnectionsService
Dim iConnectionIndex As Integer
Dim sConnectionName As String

objService = GetService(_applicationObject, _
   GetType(Microsoft.VisualStudio.Data.Interop.IVsDataConnectionsService))

objIVsDataConnectionsService = CType(objService, _
   Microsoft.VisualStudio.Data.Interop.IVsDataConnectionsService)

For iConnectionIndex = 0 To objIVsDataConnectionsService.Count - 1
   sConnectionName = objIVsDataConnectionsService.GetConnectionName(iConnectionIndex)
   System.Windows.Forms.MessageBox.Show(sConnectionName)
Next
Language: C#   Copy Code Copy Code (IE only)
object objService = null;
Microsoft.VisualStudio.Data.Interop.IVsDataConnectionsService objIVsDataConnectionsService = null;
int iConnectionIndex = 0;
string sConnectionName = null;

objService = GetService(_applicationObject, typeof(Microsoft.VisualStudio.Data.Interop.IVsDataConnectionsService));

objIVsDataConnectionsService = (Microsoft.VisualStudio.Data.Interop.IVsDataConnectionsService) objService;

for (iConnectionIndex = 0; iConnectionIndex <= objIVsDataConnectionsService.Count - 1; iConnectionIndex++) {
   sConnectionName = objIVsDataConnectionsService.GetConnectionName(iConnectionIndex);
   System.Windows.Forms.MessageBox.Show(sConnectionName);
}

Related articles


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


Top