1

I am converting a VS Addin to a VS Package.

I have this code in my VSIX Package class(that derives from Microsoft.VisualStudio.Shell.Package)

  protected override void Initialize() {
     base.Initialize();

     var dte = this.GetService<DTE>() as DTE2;
     if(dte != null) {
        var x = dte.MainWindow;

However calling dte.MainWindow in this context throws a NullReferenceException.

enter image description here

Something must not be initialized then. When am I supposed to call dte.MainWindow then?

In the VS Addin it was working when dte.MainWindow was called from public void OnStartupComplete(ref Array custom) { in the Connect Addin type.

Patrick from NDepend team
  • 13,237
  • 6
  • 61
  • 92
  • That Debug.Assert() put you to sleep. It does absolutely nothing to tell you something you will not find out very soon anyway. It is harmful, remove it. Clears your mind, you'll look at *dte* now. – Hans Passant Sep 19 '14 at 17:55
  • The question is not related to the Debug.Assert(...) Hans. And btw it tells me something very useful: Thanks to this assert I know dte is not null, hence the NullRefEx comes from something null during the call to get_MainWindow(). – Patrick from NDepend team Sep 19 '14 at 18:01
  • The road to mystic problems is paved with assumptions. What we don't know is whether the _DEBUG conditional is actually defined. Everything says it is not. – Hans Passant Sep 19 '14 at 18:09
  • Hans, the problem doesn't come from the Debug.Assert() and yes the code is compiled in debug mode, and I could have precised this indeed. – Patrick from NDepend team Sep 19 '14 at 18:25
  • Just updated the question to let's focus on the issue itself. – Patrick from NDepend team Sep 19 '14 at 18:27

2 Answers2

1

To be able to call dte.MainWindow I found the option to register to event dte.Events.DTEEvents.OnStartupComplete. As explained here, I need to keep a reference to the DTEEvents object to avoid getting it discarded.

  DTEEvents m_EventsObj;

  protected override void Initialize() {
     base.Initialize();

     var dte = this.GetService<DTE>() as DTE2;
     if(dte != null) {

        m_EventsObj = dte.Events.DTEEvents;
        m_EventsObj.OnStartupComplete += delegate {
            var mainWindow = dte.MainWindow; // <-- it works!!
            ...
         };
Community
  • 1
  • 1
Patrick from NDepend team
  • 13,237
  • 6
  • 61
  • 92
0

I have also seen that issue when DTE is not null but DTE.MainWindow is null if called when initializing my MZ-Tools package. I have pending to reproduce it with a minimal package (a quick attempt a few days ago was not able to reproduce it).

I have also seen an InvalidCastException when getting DTE.MainWindow when terminating the package, which I have also to reproduce:

  private WindowEx GetMainWindowEx()
  {
     EnvDTE.Window mainWindow = null;
     WindowEx mainWindowEx = null;

     try
     {
        mainWindow = m_dte.MainWindow;
     }
     catch (InvalidCastException)
     {
        // This can happen in the case of a package after the IDE is closed that needs to show a MessageBox
     }
     catch (NullReferenceException)
     {
        // This can happen in the case of a package loaded before the IDE is initialized that needs to show a MessageBox
     }

     if (mainWindow != null)
     {
        mainWindowEx = new WindowEx(m_plugIn, mainWindow);
     }
     return mainWindowEx;
  }

In my case I only need the MainWindow to get its handle (hwnd) as parent for message boxes that in very rare cases must be shown during initialization/termination and if it fails I can use null as parent window.

Carlos Quintero
  • 4,300
  • 1
  • 11
  • 18
  • 1
    I'm on the phone, so I can't check myself, but does this happen after VS is no longer in a zombie state? e.g. your own http://www.mztools.com/articles/2013/MZ2013029.aspx – Igal Tabachnik Sep 19 '14 at 21:01