VSIX: Getting DTE object
Asked Answered
F

4

10

My Visual Studio package requires the use of an EnvDTE.DTE variable, but it always gets back as null. After reading up on many hacks, all of them say to use the OnShellPropertyChange() method (IVsShellPropertyEvents), but sometimes it just never fires - as if my extension never finishes loading.

I'm using VS2010 and checking against both VSSPROPID_Zombie and ShellInitialized - no work. :(

Any ideas? This is the code I'm using:

public int OnShellPropertyChange(int propid, object var) {
            if (propid == -9053 || (int) __VSSPROPID.VSSPROPID_Zombie == propid) { // -9053 = ShellInit
                try {
                    if ((bool) var == false) {
                        Dte = GetService(typeof (SDTE)) as DTE;
                        Flow.Dte = Dte;

                        var shellService = GetService(typeof (SVsShell)) as IVsShell;

                        if (shellService != null)
                            ErrorHandler.ThrowOnFailure(shellService.UnadviseShellPropertyChanges(_cookie));

                        _cookie = 0;
                    }
                } catch {

                }
            }

            return VSConstants.S_OK;
        }

EDIT: Under Experimental Instance, it works perfectly and takes about 5 seconds to initialize. However, once deployed as VSIX - it simply doesn't fire.

Formant answered 25/9, 2010 at 3:14 Comment(0)
A
6

I see a couple of problems here:

  • You really should be using __VSSPROPID4.VSSPROPID_ShellInitialized (defined in Microsoft.VisualStudio.Shell.Interop.10.0) instead of -9083 for readability
  • You should be checking for ShellInitialized being set to true (although checking for Zombie going to false is correct)
  • Keep in mind that ShellInitialized will change to true once...on startup of VS. Checking for it is the right approach if your package is registered to auto-load on startup (which may happen before VS is fully ready to go). However, most packages should not auto-load on startup, but rather load on-demand from some user action requiring your package code. You can then check for the DTE service in your package class Initialize method.
Affidavit answered 25/9, 2010 at 17:22 Comment(1)
VSSPROPID4 gave me some ambiguity issues, which is why I went with the integer for now. I'll change the condition and see if it works now - thanks!Formant
R
34

Try the following command:

dte = Package.GetGlobalService(typeof(DTE)) as DTE2;
Rhythmist answered 16/3, 2012 at 9:37 Comment(2)
This one works for me, just have to add a reference to Microsoft.VisualStudio.Shell.dll in the project.Charters
This works for me as well. I'm using in the code behind XAML UI.Endymion
F
7

If you have a MEF component the easiest way to get to a DTE object is as follows

First add a reference to Microsoft.VisualStudio.Shell.Immutable.10. Then add a MEF import for SVsServiceProvider. This object has a GetService method which can be queried for DTE

[ImportingConstructor]
public MyComponent(SVsServiceProvider serviceProvider) {
  _DTE dte = (_DTE)serviceProvider.GetService(typeof(_DTE));
}
Felty answered 25/9, 2010 at 5:15 Comment(1)
I don't have a MEF component though. Any ideas as to why the property never changes? It's a VS VMSDK project.Formant
A
6

I see a couple of problems here:

  • You really should be using __VSSPROPID4.VSSPROPID_ShellInitialized (defined in Microsoft.VisualStudio.Shell.Interop.10.0) instead of -9083 for readability
  • You should be checking for ShellInitialized being set to true (although checking for Zombie going to false is correct)
  • Keep in mind that ShellInitialized will change to true once...on startup of VS. Checking for it is the right approach if your package is registered to auto-load on startup (which may happen before VS is fully ready to go). However, most packages should not auto-load on startup, but rather load on-demand from some user action requiring your package code. You can then check for the DTE service in your package class Initialize method.
Affidavit answered 25/9, 2010 at 17:22 Comment(1)
VSSPROPID4 gave me some ambiguity issues, which is why I went with the integer for now. I'll change the condition and see if it works now - thanks!Formant
C
3

I know you selected an answer already but you did specify that you didnt want to use the MEF so I thought I would post an alternative just for the sake of completeness....;p


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using EnvDTE;
using EnvDTE80;

namespace DTETesting
{
    class Program
    {
        const string ACTIVE_OBJECT = "VisualStudio.DTE.10.0";
        static void Main(string[] args)
        {
            EnvDTE80.DTE2 MyDte;
            MyDte = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject(ACTIVE_OBJECT);
            Console.WriteLine("The Edition is "+MyDte.Edition);
            Console.ReadLine();
        }
    }
}

Circumscissile answered 24/11, 2010 at 13:15 Comment(2)
found this too, msdn.microsoft.com/en-us/library/68shb4dw%28v=VS.100%29.aspxCircumscissile
Beware: if you're running more than one instance of Visual Studio, this will get you one of them, but not necessarily the one you're running in.Vi

© 2022 - 2024 — McMap. All rights reserved.