Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between these methods of getting DTE2 (Visual Studio 2013)

Based on this question I've tried the following:

EnvDTE80.DTE2 dte = ServiceProvider.GlobalProvider.GetService(typeof(EnvDTE80.DTE2)) as EnvDTE80.DTE2;

No luck, null object.

But based on this MSDN doc I tried the following.

EnvDTE80.DTE2 dte = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.12.0");

That worked and gave me the DTE2 object.

From there, I tried the following this questin I've tried the following:

VersionControlExt vce = dte.GetObject("Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExt") as VersionControlExt;

No luck, null object.

One thing to note, is per that last question, it says to use Microsoft.VisualStudio.TeamFoundation.Client namespace. The problem is, I can't find it. I've even made sure to reference the dll by the same name. I was able to reference all the other name spaces.

Finally, I tried the following from teamfoundation.blogspot.

EnvDTE.IVsExtensibility extensibility = GetService(typeof(EnvDTE.IVsExtensibility)) as EnvDTE.IVsExtensibility;
EnvDTE80.DTE2 dte = extensibility.GetGlobalsObject(null).DTE as EnvDTE80.DTE2;
//Followed by this to get the Version
VersionControlExt vce = dte.GetObject("Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExt") as VersionControlExt;

This worked.

So, while I've managed to get the DTE2 and from it the VersionControlExt, I feel I've entered the land of Cargo Cult programmers and would much prefer to understand why these were all posed as valid ways to get the DTE2 but they all behaved differently.

like image 741
Lawtonfogle Avatar asked Dec 12 '14 16:12

Lawtonfogle


1 Answers

The correct way to get the DTE instance from within an extension is to use the way provided by the extensibility API for that extension.

  • For macros it was the global DTE instance.
  • For add-ins it was the instance passed in the OnConnection method of the IDTExtensibility2 interface that add-ins had to implement.
  • For packages it is using:

    base.GetService(typeof(EnvDTE.DTE))

(notice that "base" refers to the MPF Package class so you are using the extensibility API. You are using also the extensibility API if you use the global provider as in your post)

but unrelated to that, is this couple of issues that happen with packages marked to autoload:

1) The returned DTE value will be null when the package is marked to autoload when VS is launched (rather than loading when required)

2) DTE is not null, but some property such as DTE.MainWindow is still null because the VS instance is not fully initialized yet.

To prevent those two cases you must subscribe to a notification that the VS IDE is fully initialized and not in a zombie state. See the horrible hack that you have to use: HOWTO: Get an EnvDTE.DTE instance from a Visual Studio package.

The incorrect way of getting the DTE instance from within an extension is to use COM automation (through the .NET Framework API) instead of using the extensibility API (and it is horrible that the MSDN docs mention this approach):

EnvDTE80.DTE2 dte = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.12.0");

because GetObject(ProgId) in COM automation (or .NET wrappers such as Marshal.GetActiveObject(ProgId)) are used to attach to a running instance of the required ProgId ("VisualStudio.DTE.12.0") and if you have have more than one running instance your extension could end getting a reference to the other instance!.

like image 59
Carlos Quintero Avatar answered Nov 15 '22 04:11

Carlos Quintero