Skip to content

Commit 31be1b5

Browse files
committed
Assert more control over tearing down the toolwindows.
1 parent 732da4e commit 31be1b5

File tree

7 files changed

+54
-68
lines changed

7 files changed

+54
-68
lines changed

RetailCoder.VBE/App.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Rubberduck.UI;
88
using Rubberduck.UI.Command.MenuItems;
99
using System;
10+
using System.Diagnostics;
1011
using System.Globalization;
1112
using System.Windows.Forms;
1213
using Rubberduck.Inspections.Resources;
@@ -129,6 +130,7 @@ public void Shutdown()
129130
{
130131
try
131132
{
133+
Debug.WriteLine("App calling Hooks.Detach.");
132134
_hooks.Detach();
133135
}
134136
catch

RetailCoder.VBE/Extension.cs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
using System.Runtime.InteropServices;
1515
using System.Windows.Forms;
1616
using System.Windows.Threading;
17+
using Microsoft.Vbe.Interop;
1718
using Ninject.Extensions.Interception;
1819
using NLog;
1920
using Rubberduck.Settings;
2021
using Rubberduck.SettingsProvider;
2122
using Rubberduck.VBEditor.Events;
23+
using Rubberduck.VBEditor.SafeComWrappers;
2224
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
2325

2426
namespace Rubberduck
@@ -52,13 +54,13 @@ public void OnConnection(object Application, ext_ConnectMode ConnectMode, object
5254
{
5355
try
5456
{
55-
if (Application is Microsoft.Vbe.Interop.VBE)
57+
if (Application is VBE)
5658
{
57-
var vbe = (Microsoft.Vbe.Interop.VBE) Application;
59+
var vbe = (VBE) Application;
5860
_ide = new VBEditor.SafeComWrappers.VBA.VBE(vbe);
5961
VBENativeServices.HookEvents(_ide);
6062

61-
var addin = (Microsoft.Vbe.Interop.AddIn)AddInInst;
63+
var addin = (AddIn)AddInInst;
6264
_addin = new VBEditor.SafeComWrappers.VBA.AddIn(addin) { Object = this };
6365
}
6466
else if (Application is Microsoft.VB6.Interop.VBIDE.VBE)
@@ -221,35 +223,31 @@ private void Startup()
221223

222224
private void ShutdownAddIn()
223225
{
226+
Debug.WriteLine("Extension unhooking VBENativeServices events.");
224227
VBENativeServices.UnhookEvents();
225228

226229
var currentDomain = AppDomain.CurrentDomain;
227230
currentDomain.AssemblyResolve -= LoadFromSameFolder;
228-
231+
Debug.WriteLine("Extension broadcasting shutdown.");
229232
User32.EnumChildWindows(_ide.MainWindow.Handle(), EnumCallback, new IntPtr(0));
230233

234+
Debug.WriteLine("Extension calling ReleaseDockableHosts.");
235+
VBEditor.SafeComWrappers.VBA.Windows.ReleaseDockableHosts();
236+
231237
if (_app != null)
232238
{
239+
Debug.WriteLine("Extension calling App.Shutdown.");
233240
_app.Shutdown();
234241
_app = null;
235242
}
236243

237244
if (_kernel != null)
238245
{
246+
Debug.WriteLine("Extension calling Kernel.Dispose.");
239247
_kernel.Dispose();
240248
_kernel = null;
241249
}
242250

243-
//try
244-
//{
245-
// _ide.Release();
246-
//}
247-
//catch (Exception e)
248-
//{
249-
// _logger.Error(e);
250-
//}
251-
252-
GC.WaitForPendingFinalizers();
253251
_isInitialized = false;
254252
}
255253

RetailCoder.VBE/UI/Controls/SearchResultPresenterInstanceManager.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public SearchResultPresenterInstanceManager(IVBE vbe, IAddIn addin)
2222
private SearchResultsDockablePresenter _presenter;
2323
public SearchResultsDockablePresenter Presenter(ISearchResultsWindowViewModel viewModel)
2424
{
25-
if (_presenter == null || _presenter.IsDisposed)
25+
if (_presenter == null)
2626
{
2727
if (_view.ViewModel == null)
2828
{
@@ -54,13 +54,6 @@ private void Dispose(bool disposing)
5454
{
5555
_view.ViewModel.LastTabClosed -= viewModel_LastTabClosed;
5656
}
57-
58-
if (_presenter != null)
59-
{
60-
_presenter.Dispose();
61-
_presenter = null;
62-
}
63-
6457
_disposed = true;
6558
}
6659
}

RetailCoder.VBE/UI/DockableToolwindowPresenter.cs

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics;
23
using System.Runtime.InteropServices;
34
using System.Windows.Forms;
45
using NLog;
@@ -19,7 +20,7 @@ public interface IDockablePresenter : IPresenter
1920
UserControl UserControl { get; }
2021
}
2122

22-
public abstract class DockableToolwindowPresenter : IDockablePresenter, IDisposable
23+
public abstract class DockableToolwindowPresenter : IDockablePresenter
2324
{
2425
private readonly IAddIn _addin;
2526
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
@@ -109,36 +110,9 @@ public void Hide()
109110
_window.IsVisible = false;
110111
}
111112

112-
private bool _disposed;
113-
public void Dispose()
114-
{
115-
Dispose(true);
116-
GC.SuppressFinalize(this);
117-
}
118-
119113
~DockableToolwindowPresenter()
120114
{
121-
Dispose(false);
122-
}
123-
124-
public bool IsDisposed { get { return _disposed; } }
125-
protected virtual void Dispose(bool disposing)
126-
{
127-
if (_disposed)
128-
{
129-
return;
130-
}
131-
if (disposing && _window != null)
132-
{
133-
// cleanup unmanaged resource wrappers
134-
_window.Close();
135-
//_window.Release(true);
136-
}
137-
if (!disposing)
138-
{
139-
return;
140-
}
141-
_disposed = true;
115+
Debug.WriteLine("DockableToolwindowPresenter finalized.");
142116
}
143117
}
144118
}

RetailCoder.VBE/UI/DockableWindowHost.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.ComponentModel;
3+
using System.Diagnostics;
34
using System.Drawing;
45
using System.Runtime.InteropServices;
56
using System.Windows.Forms;
@@ -85,8 +86,8 @@ private void OnCallBackEvent(object sender, SubClassingWindowEventArgs e)
8586
}
8687
else
8788
{
89+
Debug.WriteLine("DockableWindowHost removed event handler.");
8890
_subClassingWindow.CallBackEvent -= OnCallBackEvent;
89-
_subClassingWindow.Dispose();
9091
}
9192
}
9293

@@ -146,11 +147,26 @@ protected override void DefWndProc(ref Message m)
146147
//See the comment in the ctor for why we have to listen for this.
147148
if (m.Msg == (int) WM.DESTROY)
148149
{
150+
Debug.WriteLine("DockableWindowHost received WM.DESTROY.");
149151
_thisHandle.Free();
150152
}
151153
base.DefWndProc(ref m);
152154
}
153155

156+
//override
157+
158+
public void Release()
159+
{
160+
Debug.WriteLine("DockableWindowHost release called.");
161+
_subClassingWindow.Dispose();
162+
}
163+
164+
protected override void DestroyHandle()
165+
{
166+
Debug.WriteLine("DockableWindowHost DestroyHandle called.");
167+
base.DestroyHandle();
168+
}
169+
154170
[ComVisible(false)]
155171
public class ParentWindow : SubclassingWindow
156172
{

Rubberduck.VBEEditor/SafeComWrappers/VBA/Windows.cs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,26 @@ public IWindow this[object index]
3232
get { return new Window(IsWrappingNullReference ? null : Target.Item(index)); }
3333
}
3434

35+
36+
private static readonly Dictionary<VB.Window, object> _dockableHosts = new Dictionary<VB.Window, object>();
37+
3538
public ToolWindowInfo CreateToolWindow(IAddIn addInInst, string progId, string caption, string guidPosition)
3639
{
3740
if (IsWrappingNullReference) return new ToolWindowInfo(null, null);
3841
object control = null;
39-
var window = new Window(Target.CreateToolWindow((VB.AddIn)addInInst.Target, progId, caption, guidPosition, ref control));
40-
return new ToolWindowInfo(window, control);
42+
var window = Target.CreateToolWindow((VB.AddIn)addInInst.Target, progId, caption, guidPosition, ref control);
43+
_dockableHosts.Add(window, control);
44+
return new ToolWindowInfo(new Window(window), control);
45+
}
46+
47+
public static void ReleaseDockableHosts()
48+
{
49+
foreach (var item in _dockableHosts)
50+
{
51+
item.Key.Close();
52+
dynamic host = item.Value;
53+
host.Release();
54+
}
4155
}
4256

4357
IEnumerator IEnumerable.GetEnumerator()
@@ -52,18 +66,6 @@ IEnumerator<IWindow> IEnumerable<IWindow>.GetEnumerator()
5266
: new ComWrapperEnumerator<IWindow>(Target, o => new Window((VB.Window) o));
5367
}
5468

55-
//public override void Release(bool final = false)
56-
//{
57-
// if (!IsWrappingNullReference)
58-
// {
59-
// for (var i = 1; i <= Count; i++)
60-
// {
61-
// this[i].Release();
62-
// }
63-
// base.Release(final);
64-
// }
65-
//}
66-
6769
public override bool Equals(ISafeComWrapper<VB.Windows> other)
6870
{
6971
return IsEqualIfNull(other) || (other != null && ReferenceEquals(other.Target, Target));

Rubberduck.VBEEditor/WindowsApi/SubclassingWindow.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ private void AssignHandle()
5555
{
5656
throw new Exception("SetWindowSubClass Failed");
5757
}
58+
Debug.WriteLine("SubclassingWindow.AssignHandle called for hWnd " + Hwnd);
5859
//DO NOT REMOVE THIS CALL. Dockable windows are instantiated by the VBE, not directly by RD. On top of that,
5960
//since we have to inherit from UserControl we don't have to keep handling window messages until the VBE gets
6061
//around to destroying the control's host or it results in an access violation when the base class is disposed.
@@ -72,7 +73,7 @@ private void ReleaseHandle()
7273
{
7374
return;
7475
}
75-
76+
Debug.WriteLine("SubclassingWindow.ReleaseHandle called for hWnd " + Hwnd);
7677
var result = RemoveWindowSubclass(_hwnd, _wndProc, _subclassId);
7778
if (result != 1)
7879
{
@@ -91,7 +92,7 @@ public virtual int SubClassProc(IntPtr hWnd, IntPtr msg, IntPtr wParam, IntPtr l
9192
}
9293

9394
if ((uint)msg == (uint)WM.RUBBERDUCK_SINKING || (uint)msg == (uint)WM.DESTROY)
94-
{
95+
{
9596
ReleaseHandle();
9697
}
9798
return DefSubclassProc(hWnd, msg, wParam, lParam);

0 commit comments

Comments
 (0)