diff --git a/Rubberduck.VBEEditor/Events/VBENativeServices.cs b/Rubberduck.VBEEditor/Events/VBENativeServices.cs index 2391e5c652..a3e75fcaa2 100644 --- a/Rubberduck.VBEEditor/Events/VBENativeServices.cs +++ b/Rubberduck.VBEEditor/Events/VBENativeServices.cs @@ -73,10 +73,13 @@ public static void VbeEventCallback(IntPtr hWinEventHook, uint eventType, IntPtr { OnSelectionChanged(hwnd); } - else if (idObject == (int)ObjId.Window && - (eventType == (uint)WinEvent.ObjectCreate || eventType == (uint)WinEvent.ObjectDestroy) && - hwnd.ToWindowType() != WindowType.Indeterminate) + else if (idObject == (int)ObjId.Window && (eventType == (uint)WinEvent.ObjectCreate || eventType == (uint)WinEvent.ObjectDestroy)) { + var type = hwnd.ToWindowType(); + if (type != WindowType.DesignerWindow && type != WindowType.VbaWindow) + { + return; + } if (eventType == (uint) WinEvent.ObjectCreate) { AttachWindow(hwnd); @@ -90,7 +93,7 @@ public static void VbeEventCallback(IntPtr hWinEventHook, uint eventType, IntPtr { //Test to see if it was a selection change in the project window. var parent = User32.GetParent(hwnd); - if (parent != IntPtr.Zero && parent.ToWindowType() == WindowType.Project) + if (parent != IntPtr.Zero && parent.ToWindowType() == WindowType.Project && hwnd == User32.GetFocus()) { FocusDispatcher(_vbe, new WindowChangedEventArgs(parent, null, null, FocusType.ChildFocus)); } diff --git a/Rubberduck.VBEEditor/WindowsApi/SubclassingWindow.cs b/Rubberduck.VBEEditor/WindowsApi/SubclassingWindow.cs index e1072b2e29..6cec5a9b79 100644 --- a/Rubberduck.VBEEditor/WindowsApi/SubclassingWindow.cs +++ b/Rubberduck.VBEEditor/WindowsApi/SubclassingWindow.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Concurrent; using System.Diagnostics; using System.Runtime.InteropServices; using Rubberduck.Common.WinAPI; @@ -12,6 +11,7 @@ public abstract class SubclassingWindow : IDisposable private readonly IntPtr _hwnd; private readonly SubClassCallback _wndProc; private bool _listening; + private GCHandle _thisHandle; private readonly object _subclassLock = new object(); @@ -43,7 +43,7 @@ protected SubclassingWindow(IntPtr subclassId, IntPtr hWnd) public void Dispose() { ReleaseHandle(); - GC.SuppressFinalize(this); + //GC.SuppressFinalize(this); } private void AssignHandle() @@ -55,6 +55,11 @@ private void AssignHandle() { throw new Exception("SetWindowSubClass Failed"); } + //DO NOT REMOVE THIS CALL. Dockable windows are instantiated by the VBE, not directly by RD. On top of that, + //since we have to inherit from UserControl we don't have to keep handling window messages until the VBE gets + //around to destroying the control's host or it results in an access violation when the base class is disposed. + //We need to manually call base.Dispose() ONLY in response to a WM_DESTROY message. + _thisHandle = GCHandle.Alloc(this, GCHandleType.Normal); _listening = true; } } @@ -85,10 +90,10 @@ public virtual int SubClassProc(IntPtr hWnd, IntPtr msg, IntPtr wParam, IntPtr l } Debug.Assert(IsWindow(_hwnd)); - //TODO: This should change to WM.DESTROY once subclassing\hooking consolidation is complete. - if ((uint)msg == (uint)WM.RUBBERDUCK_SINKING) + if ((uint)msg == (uint)WM.RUBBERDUCK_SINKING || (uint)msg == (uint)WM.DESTROY) { ReleaseHandle(); + _thisHandle.Free(); } return DefSubclassProc(hWnd, msg, wParam, lParam); } diff --git a/Rubberduck.VBEEditor/WindowsApi/User32.cs b/Rubberduck.VBEEditor/WindowsApi/User32.cs index 9b182a2d70..b45ae3537a 100644 --- a/Rubberduck.VBEEditor/WindowsApi/User32.cs +++ b/Rubberduck.VBEEditor/WindowsApi/User32.cs @@ -56,6 +56,12 @@ public static class User32 [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow(); + [DllImport("user32.dll")] + public static extern IntPtr GetActiveWindow(); + + [DllImport("user32.dll")] + public static extern IntPtr GetFocus(); + /// /// Gets the underlying class name for a window handle. /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms633582(v=vs.85).aspx