Skip to content

Commit 789cee5

Browse files
committed
Explicitly clear event delegates, more "sane" check COM object checking.
1 parent f040a16 commit 789cee5

File tree

3 files changed

+82
-10
lines changed

3 files changed

+82
-10
lines changed

Rubberduck.VBEEditor/Events/VBENativeServices.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Linq;
3-
using System.Runtime.CompilerServices;
43
using System.Text;
54
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
65
using Rubberduck.VBEditor.WindowsApi;
@@ -40,6 +39,10 @@ public static void UnhookEvents()
4039
{
4140
lock (ThreadLock)
4241
{
42+
SelectionChanged = delegate { };
43+
IntelliSenseChanged = delegate { };
44+
KeyDown = delegate { };
45+
WindowFocusChange = delegate { };
4346
User32.UnhookWinEvent(_eventHandle);
4447
Subclasses.Dispose();
4548
VBEEvents.Terminate();
@@ -92,7 +95,7 @@ public static void VbeEventCallback(IntPtr hWinEventHook, uint eventType, IntPtr
9295
else if (windowType == WindowType.CodePane && idObject == (int)ObjId.Caret &&
9396
(eventType == (uint)WinEvent.ObjectLocationChange || eventType == (uint)WinEvent.ObjectCreate))
9497
{
95-
OnSelectionChanged(hwnd);
98+
OnSelectionChanged(hwnd);
9699
}
97100
else if (SubclassManager.IsSubclassable(windowType) && (idObject == (int)ObjId.Window && eventType == (uint)WinEvent.ObjectCreate) ||
98101
!Subclasses.IsSubclassed(hwnd))

Rubberduck.VBEEditor/WindowsApi/NativeMethods.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@ public static class NativeMethods
5959
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
6060
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
6161

62+
/// <summary>
63+
/// Forces the specified region to repaint.
64+
/// </summary>
65+
/// <param name="hWnd">The window to redraw</param>
66+
/// <param name="lprcUpdate">The update region. Ignored if hrgnUpdate is not null.</param>
67+
/// <param name="hrgnUpdate">Handle to an update region. Defaults to the entire window if null and lprcUpdate is null</param>
68+
/// <param name="flags">Redraw flags.</param>
69+
/// <returns></returns>
70+
[DllImport("user32.dll")]
71+
public static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, RedrawWindowFlags flags);
72+
6273
/// <summary> Gets window caption text by handle. </summary>
6374
///
6475
/// <param name="windowHandle"> Handle of the window to be activated. </param>
@@ -101,4 +112,58 @@ public static void EnumChildWindows(IntPtr parentWindowHandle, EnumChildWindowsD
101112
}
102113
}
103114
}
115+
116+
[Flags]
117+
public enum RedrawWindowFlags : uint
118+
{
119+
/// <summary>
120+
/// Invalidates the rectangle or region that you specify in lprcUpdate or hrgnUpdate.
121+
/// You can set only one of these parameters to a non-NULL value. If both are NULL, RDW_INVALIDATE invalidates the entire window.
122+
/// </summary>
123+
Invalidate = 0x1,
124+
125+
/// <summary>Causes the OS to post a WM_PAINT message to the window regardless of whether a portion of the window is invalid.</summary>
126+
InternalPaint = 0x2,
127+
128+
/// <summary>
129+
/// Causes the window to receive a WM_ERASEBKGND message when the window is repainted.
130+
/// Specify this value in combination with the RDW_INVALIDATE value; otherwise, RDW_ERASE has no effect.
131+
/// </summary>
132+
Erase = 0x4,
133+
134+
/// <summary>
135+
/// Validates the rectangle or region that you specify in lprcUpdate or hrgnUpdate.
136+
/// You can set only one of these parameters to a non-NULL value. If both are NULL, RDW_VALIDATE validates the entire window.
137+
/// This value does not affect internal WM_PAINT messages.
138+
/// </summary>
139+
Validate = 0x8,
140+
141+
NoInternalPaint = 0x10,
142+
143+
/// <summary>Suppresses any pending WM_ERASEBKGND messages.</summary>
144+
NoErase = 0x20,
145+
146+
/// <summary>Excludes child windows, if any, from the repainting operation.</summary>
147+
NoChildren = 0x40,
148+
149+
/// <summary>Includes child windows, if any, in the repainting operation.</summary>
150+
AllChildren = 0x80,
151+
152+
/// <summary>
153+
/// Causes the affected windows, which you specify by setting the RDW_ALLCHILDREN and RDW_NOCHILDREN values, to receive
154+
/// WM_ERASEBKGND and WM_PAINT messages before the RedrawWindow returns, if necessary.
155+
/// </summary>
156+
UpdateNow = 0x100,
157+
158+
/// <summary>
159+
/// Causes the affected windows, which you specify by setting the RDW_ALLCHILDREN and RDW_NOCHILDREN values, to receive WM_ERASEBKGND
160+
/// messages before RedrawWindow returns, if necessary.
161+
/// The affected windows receive WM_PAINT messages at the ordinary time.
162+
/// </summary>
163+
EraseNow = 0x200,
164+
165+
Frame = 0x400,
166+
167+
NoFrame = 0x800
168+
}
104169
}

Rubberduck.VBEEditor/WindowsApi/VbeAttachableSubclass.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,24 @@ public bool HasValidVbeObject
4747

4848
try
4949
{
50-
if (Marshal.GetIUnknownForObject(_target.Target) != IntPtr.Zero)
50+
var unmanaged = Marshal.GetIUnknownForObject(_target.Target);
51+
if (unmanaged != IntPtr.Zero)
5152
{
53+
try
54+
{
55+
Marshal.Release(unmanaged);
56+
}
57+
catch (COMException)
58+
{
59+
// this should be "safe" to hold the reference - it's not like it should go anywhere now... :-/
60+
SubclassLogger.Warn($"{ GetType().Name } failed to dispose of a held { typeof(T).Name } reference.");
61+
}
5262
return true;
5363
}
54-
55-
_target.Dispose();
56-
_target = default;
5764
}
58-
catch
65+
catch (COMException)
5966
{
60-
// All paths leading to here mean that we need to ditch the held reference, and there
61-
// isn't jack all that we can do about it.
6267
_target = default;
63-
SubclassLogger.Warn($"{ GetType().Name } failed to dispose of a held { typeof(T).Name } reference.");
6468
}
6569
return false;
6670
}

0 commit comments

Comments
 (0)