What is the difference between these methods for 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 document I have tried the following.

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

      

This worked and gave me a DTE2 object.

From there I tried the following this quest I tried the following:

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

      

No luck, null object.

It should be noted that the last question says it is using a namespace Microsoft.VisualStudio.TeamFoundation.Client

. The problem is I can't find it. I even made sure to reference a DLL with the same name. I was able to reference all other namespaces.

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;

      

It worked.

So, while I managed to get DTE2 and the VersionControlExt from it, I feel like I entered the country of the Cargo Cult programmers, and I would rather understand why they were all presented as valid ways to get DTE2 but they all behaved differently.

+3


source to share


1 answer


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

  • For macros, this was the global DTE instance.
  • For add-ins, this was the instance passed in the OnConnection method of the IDTExtensibility2 interface that the add-ins were supposed to implement.
  • For packages used:

    base.GetService (TypeOf (EnvDTE.DTE))

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

but unrelated, these are a couple of issues that happen with packages marked for autoloading:

1) The return value of the DTE will be null if the package is marked as autoloading when VS starts (and not when loaded as needed).



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

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

The wrong way to get a DTE instance from an internal extension is to use COM Automation (via the .NET Framework API) instead of using the Extensibility API (and it's awful that the MSDN docs mention this approach):

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

      

as GetObject (ProgId) in COM Automation (or .NET wrappers like Marshal.GetActiveObject (ProgId)) are used to attach the required ProgId ("VisualStudio.DTE.12.0") to the executable instance and if you have multiple instances to run , your extension may end up getting a link to another instance !.

+5


source







All Articles