Getting the current EnvDTE or IServiceProvider when NOT coding an Addin

Vaccano picture Vaccano · Jun 2, 2012 · Viewed 7.8k times · Source

I am coding up some design time code. I want to use this snippet: (Found here)

var dte = (EnvDTE.DTE) GetService(typeof(EnvDTE.DTE));
if (dte != null)
{
    var solution = dte.Solution;
    if (solution != null)
    {
        string baseDir = Path.GetDirectoryName(solution.FullName);
    }
}

Problem is that this does not compile. (GetService is not a known method call) I tried adding Microsoft.VisualStudio.Shell (and Microsoft.VisualStudio.Shell.10.0) but it did not help.

In looking around on the internet I found that you need a IServiceProvider to call this.

But all the examples that show how to get an IServiceProvider use a EnvDTE.

So, to get the current EnvDTE I need IServiceProvider. But to get an IServiceProvider I need an EnvDTE. (There is a hole in my bucket...)

So, here is my question:

In a normal WPF Application, how can I get the current instance of EnvDTE?

NOTE: I am not looking for any old instance of EnvDTE. I need the one for my current Visual Studio instance (I run 3-4 instances of Visual Studio at a time.)

Answer

Quickhorn picture Quickhorn · Jun 12, 2012

This question has the answer to which you're looking.

Get the reference of the DTE2 object in Visual C# 2010

Specifically

https://stackoverflow.com/a/4724924/858142

Here is the code:

Usings:

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using EnvDTE;
using Process = System.Diagnostics.Process;

Method:

[DllImport("ole32.dll")]
private static extern void CreateBindCtx(int reserved, out IBindCtx ppbc);
[DllImport("ole32.dll")]
private static extern void GetRunningObjectTable(int reserved,
                                                 out IRunningObjectTable prot);
internal static DTE GetCurrent()
{
   //rot entry for visual studio running under current process.
   string rotEntry = String.Format("!VisualStudio.DTE.10.0:{0}",
                                    Process.GetCurrentProcess().Id);
   IRunningObjectTable rot;
   GetRunningObjectTable(0, out rot);
   IEnumMoniker enumMoniker;
   rot.EnumRunning(out enumMoniker);
   enumMoniker.Reset();
   IntPtr fetched = IntPtr.Zero;
   IMoniker[] moniker = new IMoniker[1];
   while (enumMoniker.Next(1, moniker, fetched) == 0)
   {
       IBindCtx bindCtx;
       CreateBindCtx(0, out bindCtx);
       string displayName;
       moniker[0].GetDisplayName(bindCtx, null, out displayName);
       if (displayName == rotEntry)
       {
           object comObject;
           rot.GetObject(moniker[0], out comObject);
           return (DTE)comObject;
       }
   }
   return null;
}

As the other answer indicates, this does not work while debugging.