Logo
HOWTO: Get an EnvDTE.DTE instance from a Visual Studio package

Author: Carlos J. Quintero (Microsoft MVP) Applies to: Microsoft Visual Studio 2010
Date: July 2013   Microsoft Visual Studio 2012
       
Introduction

Visual Studio packages can use the automation model (EnvDTE, EnvDTE80) used by Visual Studio macros and add-ins. In fact, the EnvDTE*.* references are added by default to Visual Studio package projects. This article provides the sample code to get an instance of the EnvDTE.DTE root of the automation model.

More Information

While Visual Studio macros have a global instance of EnvDTE.DTE named DTE and Visual Studio add-ins receive the EnvDTE.DTE instance in the OnConnection method, VS packages can get the EnvDTE.DTE (or EnvDTE80.DTE2) interface of the Microsoft.VisualStudio.Shell.Interop.SDTE service (like they get any other service).

However, if a package is marked to load on startup it is possible that the IDE is not yet fully initialized (it is in a "zombie" state), and in such case the service is null yet. As a workaround, the package can detect when the IDE exits the "zombie" state as shown in the next sample code:

Language: C#   Copy Code Copy Code (IE only)
using System;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;

namespace Company.VSPackage1
{
   [PackageRegistration(UseManagedResourcesOnly = true)]
   [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
   [Guid(GuidList.guidVSPackage1PkgString)]
   [ProvideAutoLoad(Microsoft.VisualStudio.VSConstants.UICONTEXT.NoSolution_string)]
   public sealed class VSPackage1Package : Package
   {
      private EnvDTE80.DTE2 dte;
      private DteInitializer dteInitializer;

      public VSPackage1Package()
      {
      }

      protected override void Initialize()
      {
         base.Initialize();

         InitializeDTE();
      }

      private void InitializeDTE()
      {
         IVsShell shellService;

         this.dte = this.GetService(typeof(Microsoft.VisualStudio.Shell.Interop.SDTE)) as EnvDTE80.DTE2;

         if (this.dte == null) // The IDE is not yet fully initialized
         {
            shellService = this.GetService(typeof(SVsShell)) as IVsShell;
            this.dteInitializer = new DteInitializer(shellService, this.InitializeDTE);
         }
         else
         {
            this.dteInitializer = null;
         }
      }
   }

   internal class DteInitializer: IVsShellPropertyEvents
   {
      private IVsShell shellService;
      private uint cookie;
      private Action callback;

      internal DteInitializer(IVsShell shellService, Action callback)
      {
         int hr;

         this.shellService = shellService;
         this.callback = callback;

         // Set an event handler to detect when the IDE is fully initialized
         hr = this.shellService.AdviseShellPropertyChanges(this, out this.cookie);

         Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(hr);
      }

      int IVsShellPropertyEvents.OnShellPropertyChange(int propid, object var)
      {
         int hr;
         bool isZombie;

         if (propid == (int)__VSSPROPID.VSSPROPID_Zombie)
         {
            isZombie = (bool)var;

            if (!isZombie)
            {
               // Release the event handler to detect when the IDE is fully initialized
               hr = this.shellService.UnadviseShellPropertyChanges(this.cookie);

               Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(hr);

               this.cookie = 0;

               this.callback();
            }
         }
         return VSConstants.S_OK;
      }
   }
}


Go to the 'Visual Studio Extensibility (VSX)' web site for more articles like this (Articles section)


Top