Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the current EnvDTE or IServiceProvider when NOT coding an Addin

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.)

like image 896
Vaccano Avatar asked Jun 02 '12 17:06

Vaccano


2 Answers

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.

like image 149
Quickhorn Avatar answered Oct 13 '22 09:10

Quickhorn


You need an IServiceProvider and then you can call its GetService method.
dte = (DTE)serviceProvider.GetService(typeof(DTE));

So the question is how to get a reference to the IServiceProvider interface.

If you are creating a VsPackage with a tool window (that inherits from ToolWindowPane), for example, then the ToolWindow class itself implements IServiceProvider. In such case when you want to use IServiceProvider in your WPF control, you create its instance on your tool window constructor and simply pass this as an argument to your control's constructor.

[Guid("f716c629-b8e3-4ab2-8dbd-8edd67165609")]
public class MyToolWindow : ToolWindowPane
{
    /// <summary>
    /// Standard constructor for the tool window.
    /// </summary>
    public MyToolWindow() :
        base(null)
    {
        ...
        // This is the user control hosted by the tool window
        base.Content = new MyControl(this);
    }

Your control's constructor gets IServiceProvider as an argument:

public MyControl(IServiceProvider _serviceProvider)
like image 32
Amir Gonnen Avatar answered Oct 13 '22 08:10

Amir Gonnen