From ae0b12e08d247543bee948ee9c16bc9a630c8d32 Mon Sep 17 00:00:00 2001 From: comintern Date: Tue, 11 Oct 2016 18:37:51 -0500 Subject: [PATCH 1/2] Release RawFoo event handlers on dispose. --- RetailCoder.VBE/Common/RubberduckHooks.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/RetailCoder.VBE/Common/RubberduckHooks.cs b/RetailCoder.VBE/Common/RubberduckHooks.cs index 0db8dfb8a2..21aa405d9f 100644 --- a/RetailCoder.VBE/Common/RubberduckHooks.cs +++ b/RetailCoder.VBE/Common/RubberduckHooks.cs @@ -22,8 +22,8 @@ public class RubberduckHooks : IRubberduckHooks // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable private readonly User32.WndProc _newWndProc; private RawInput _rawinput; - private IRawDevice _kb; - private IRawDevice _mouse; + private RawKeyboard _kb; + private RawMouse _mouse; private readonly IGeneralConfigService _config; private readonly IEnumerable _commands; private readonly IList _hooks = new List(); @@ -186,6 +186,8 @@ public void Dispose() { Detach(); User32.SetWindowLong(_mainWindowHandle, (int)WindowLongFlags.GWL_WNDPROC, _oldWndProc); + _mouse.RawMouseInputReceived -= Mouse_RawMouseInputReceived; + _kb.RawKeyInputReceived -= Keyboard_RawKeyboardInputReceived; } private IntPtr WindowProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam) From 58f682cd28d65a37693dbd2f4e4a5f190db354dd Mon Sep 17 00:00:00 2001 From: comintern Date: Tue, 11 Oct 2016 21:57:48 -0500 Subject: [PATCH 2/2] Released handle for SubClassingWindow on exit. --- RetailCoder.VBE/Common/WinAPI/RawKeyboard.cs | 10 +++++++++ RetailCoder.VBE/Common/WinAPI/RawMouse.cs | 10 +++++++++ RetailCoder.VBE/Common/WinAPI/User32.cs | 22 ++++++++++++++++++- RetailCoder.VBE/Common/WinAPI/WM.cs | 4 ++++ RetailCoder.VBE/Extension.cs | 17 ++++++++++---- RetailCoder.VBE/UI/DockableWindowHost.cs | 13 +++++++---- .../SafeComWrappers/VBA/VBE.cs | 12 +++++++++- 7 files changed, 78 insertions(+), 10 deletions(-) diff --git a/RetailCoder.VBE/Common/WinAPI/RawKeyboard.cs b/RetailCoder.VBE/Common/WinAPI/RawKeyboard.cs index 911fab4c6f..9aefc93e3d 100644 --- a/RetailCoder.VBE/Common/WinAPI/RawKeyboard.cs +++ b/RetailCoder.VBE/Common/WinAPI/RawKeyboard.cs @@ -80,5 +80,15 @@ private int VirtualKeyCorrection(int virtualKey, bool isE0BitSet, int makeCode, return correctedVKey; } + + ~RawKeyboard() + { + var rid = new RawInputDevice[1]; + rid[0].UsagePage = HidUsagePage.GENERIC; + rid[0].Usage = HidUsage.Mouse; + rid[0].Flags = (RawInputDeviceFlags.REMOVE); + rid[0].Target = IntPtr.Zero; + User32.RegisterRawInputDevices(rid, (uint) rid.Length, (uint) Marshal.SizeOf(rid[0])); + } } } diff --git a/RetailCoder.VBE/Common/WinAPI/RawMouse.cs b/RetailCoder.VBE/Common/WinAPI/RawMouse.cs index ced15ddda4..7e2d3c5a62 100644 --- a/RetailCoder.VBE/Common/WinAPI/RawMouse.cs +++ b/RetailCoder.VBE/Common/WinAPI/RawMouse.cs @@ -35,5 +35,15 @@ public void ProcessRawInput(InputData _rawBuffer) RawMouseInputReceived(this, args); } } + + ~RawMouse() + { + var rid = new RawInputDevice[1]; + rid[0].UsagePage = HidUsagePage.GENERIC; + rid[0].Usage = HidUsage.Mouse; + rid[0].Flags = (RawInputDeviceFlags.REMOVE); + rid[0].Target = IntPtr.Zero; + User32.RegisterRawInputDevices(rid, (uint) rid.Length, (uint) Marshal.SizeOf(rid[0])); + } } } diff --git a/RetailCoder.VBE/Common/WinAPI/User32.cs b/RetailCoder.VBE/Common/WinAPI/User32.cs index 533cc68dea..0f8df6e33a 100644 --- a/RetailCoder.VBE/Common/WinAPI/User32.cs +++ b/RetailCoder.VBE/Common/WinAPI/User32.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.InteropServices; +using System.Text; namespace Rubberduck.Common.WinAPI { @@ -69,7 +70,7 @@ public static class User32 /// If the function succeeds, the return value is the number of characters copied to the buffer, not including the terminating null character. /// If the function fails, the return value is zero. To get extended error information, call GetLastError. [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] - public static extern int GetClassName(IntPtr hWnd, string lpClassName, int nMaxCount); + public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); /// /// Retrieves the identifier of the thread that created the specified window and, optionally, @@ -183,6 +184,10 @@ public static class User32 [DllImport("user32.dll", CharSet = CharSet.Auto)] internal static extern IntPtr SendMessage(IntPtr hWnd, WM msg, IntPtr wParam, IntPtr lParam); + public delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam); + [DllImport("user32.dll")] + public static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam); + /// /// A helper function that returns true when the specified handle is that of the foreground window. /// @@ -198,5 +203,20 @@ public static bool IsVbeWindowActive(IntPtr mainWindowHandle) return (IntPtr)hThread == (IntPtr)vbeThread; } + + public enum WindowType + { + Indeterminate, + VbaWindow, + DesignerWindow + } + + public static WindowType ToWindowType(this IntPtr hwnd) + { + var name = new StringBuilder(128); + GetClassName(hwnd, name, name.Capacity); + WindowType id; + return Enum.TryParse(name.ToString(), out id) ? id : WindowType.Indeterminate; + } } } diff --git a/RetailCoder.VBE/Common/WinAPI/WM.cs b/RetailCoder.VBE/Common/WinAPI/WM.cs index cf3fdbd184..3702961928 100644 --- a/RetailCoder.VBE/Common/WinAPI/WM.cs +++ b/RetailCoder.VBE/Common/WinAPI/WM.cs @@ -926,6 +926,10 @@ public enum WM : uint /// Private message to signal focus set/lost for a DockableWindowHost. Set wParam to the DockableWindowHost hWnd, lParam to zero for lost focus, non-zero for gained focus. /// RUBBERDUCK_CHILD_FOCUS = USER + 0x0F00, + /// + /// Private message to signal focus RD shutdown. No parameters. + /// + RUBBERDUCK_SINKING = USER + 0x0D1E, /// /// The accessibility state has changed. diff --git a/RetailCoder.VBE/Extension.cs b/RetailCoder.VBE/Extension.cs index 31d3b66ba6..1730f6711d 100644 --- a/RetailCoder.VBE/Extension.cs +++ b/RetailCoder.VBE/Extension.cs @@ -1,6 +1,8 @@ -using Extensibility; +using System.Text; +using Extensibility; using Ninject; using Ninject.Extensions.Factory; +using Rubberduck.Common.WinAPI; using Rubberduck.Root; using Rubberduck.UI; using System; @@ -53,7 +55,7 @@ public void OnConnection(object Application, ext_ConnectMode ConnectMode, object { var vbe = (Microsoft.Vbe.Interop.VBE) Application; _ide = new VBEditor.SafeComWrappers.VBA.VBE(vbe); - + var addin = (Microsoft.Vbe.Interop.AddIn)AddInInst; _addin = new VBEditor.SafeComWrappers.VBA.AddIn(addin) { Object = this }; } @@ -104,12 +106,13 @@ public void OnStartupComplete(ref Array custom) public void OnBeginShutdown(ref Array custom) { _isBeginShutdownExecuted = true; + User32.EnumChildWindows(_ide.MainWindow.Handle(), EnumCallback, new IntPtr(0)); ShutdownAddIn(); } // ReSharper disable InconsistentNaming public void OnDisconnection(ext_DisconnectMode RemoveMode, ref Array custom) - { + { switch (RemoveMode) { case ext_DisconnectMode.ext_dm_UserClosed: @@ -213,8 +216,14 @@ private void ShutdownAddIn() { _logger.Error(e); } - + GC.WaitForPendingFinalizers(); _isInitialized = false; } + + private static int EnumCallback(IntPtr hwnd, IntPtr lparam) + { + User32.SendMessage(hwnd, WM.RUBBERDUCK_SINKING, IntPtr.Zero, IntPtr.Zero); + return 1; + } } } diff --git a/RetailCoder.VBE/UI/DockableWindowHost.cs b/RetailCoder.VBE/UI/DockableWindowHost.cs index b505bafce3..cc77e1db5d 100644 --- a/RetailCoder.VBE/UI/DockableWindowHost.cs +++ b/RetailCoder.VBE/UI/DockableWindowHost.cs @@ -133,6 +133,7 @@ public SubClassingWindow(IntPtr handle, IntPtr vbeHwnd) protected override void WndProc(ref Message msg) { + var closing = false; switch ((uint)msg.Msg) { case (uint)WM.SIZE: @@ -145,14 +146,18 @@ protected override void WndProc(ref Message msg) case (uint)WM.KILLFOCUS: User32.SendMessage(_vbeHwnd, WM.RUBBERDUCK_CHILD_FOCUS, Handle, IntPtr.Zero); break; + case (uint)WM.RUBBERDUCK_SINKING: + closing = true; + break; } base.WndProc(ref msg); + if (closing) ReleaseHandle(); } - ~SubClassingWindow() - { - ReleaseHandle(); - } + //~SubClassingWindow() + //{ + // ReleaseHandle(); + //} } } } diff --git a/Rubberduck.VBEEditor/SafeComWrappers/VBA/VBE.cs b/Rubberduck.VBEEditor/SafeComWrappers/VBA/VBE.cs index ac33732f4d..8de6573785 100644 --- a/Rubberduck.VBEEditor/SafeComWrappers/VBA/VBE.cs +++ b/Rubberduck.VBEEditor/SafeComWrappers/VBA/VBE.cs @@ -53,7 +53,17 @@ public ICommandBars CommandBars public IWindow MainWindow { - get { return new Window(IsWrappingNullReference ? null : Target.MainWindow); } + get + { + try + { + return new Window(IsWrappingNullReference ? null : Target.MainWindow); + } + catch (InvalidComObjectException ex) + { + return null; + } + } } public IVBComponent SelectedVBComponent