views:

48

answers:

2

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.

+1  A: 

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));
}
JaredPar
I don't have a MEF component though. Any ideas as to why the property never changes? It's a VS VMSDK project.
hb
+2  A: 

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.
Aaron Marten
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!
hb