Skip to content

Commit 008da37

Browse files
authored
Merge pull request #3615 from MDoerner/ShutdownIsuueAgain
COM Release for menu items and command bar
2 parents de3de3f + 25ba064 commit 008da37

File tree

8 files changed

+98
-40
lines changed

8 files changed

+98
-40
lines changed

RetailCoder.VBE/UI/Command/MenuItems/CommandBars/AppCommandBarBase.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,12 +173,13 @@ public void RemoveCommandBar()
173173
Logger.Debug("Removing commandbar.");
174174
RemoveChildren();
175175
Item?.Delete();
176+
Item?.Release();
176177
Item = null;
177178
Parent = null;
178179
}
179180
catch (COMException exception)
180181
{
181-
Logger.Error(exception, "COM exception while trying to delee the commandbar");
182+
Logger.Error(exception, "COM exception while trying to delete the commandbar");
182183
}
183184
}
184185

@@ -198,6 +199,7 @@ private void RemoveChildren()
198199
button.Click -= child_Click;
199200
}
200201
button.Delete();
202+
button.Release();
201203
}
202204
}
203205
catch (COMException exception)

RetailCoder.VBE/UI/Command/MenuItems/ParentMenus/ParentMenuItemBase.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Diagnostics;
43
using System.Globalization;
54
using System.Linq;
65
using Rubberduck.Parsing.VBA;
@@ -93,6 +92,7 @@ public void RemoveMenu()
9392
Logger.Debug($"Removing menu {_key}.");
9493
RemoveChildren();
9594
Item?.Delete();
95+
Item?.Release();
9696
Item = null;
9797
}
9898

@@ -106,6 +106,7 @@ private void RemoveChildren()
106106
{
107107
child.Click -= child_Click;
108108
child.Delete();
109+
child.Release();
109110
}
110111
}
111112

RetailCoder.VBE/UI/DockableWindowHost.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,16 @@ protected override void DefWndProc(ref Message m)
145145
if (m.Msg == (int) WM.DESTROY)
146146
{
147147
Debug.WriteLine("DockableWindowHost received WM.DESTROY.");
148+
try
149+
{
150+
_subClassingWindow.CallBackEvent -= OnCallBackEvent;
151+
}
152+
catch(Exception)
153+
{
154+
Debug.WriteLine("Failed to unsubscribe event handler from the parent subclassing window of a DockableWindowHost on WM_DESTROY. It might have been unsubscribed already.");
155+
//We cannot really do anything here. This is only a safeguard to guarantee that the event gets unsubscribed. If it does not work, it might be gone already.
156+
}
157+
148158
_thisHandle.Free();
149159
}
150160
base.DefWndProc(ref m);
@@ -200,6 +210,7 @@ public override int SubClassProc(IntPtr hWnd, IntPtr msg, IntPtr wParam, IntPtr
200210
case (uint)WM.KILLFOCUS:
201211
if (!_closing) User32.SendMessage(_vbeHwnd, WM.RUBBERDUCK_CHILD_FOCUS, Hwnd, IntPtr.Zero);
202212
break;
213+
case (uint)WM.DESTROY:
203214
case (uint)WM.RUBBERDUCK_SINKING:
204215
OnCallBackEvent(new SubClassingWindowEventArgs(lParam) { Closing = true });
205216
_closing = true;

Rubberduck.VBEEditor/Rubberduck.VBEditor.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@
109109
<HintPath>..\libs\Microsoft.Vbe.Interop.Forms.dll</HintPath>
110110
<Private>True</Private>
111111
</Reference>
112+
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
113+
<HintPath>..\packages\NLog.4.0.1\lib\net45\NLog.dll</HintPath>
114+
</Reference>
112115
<Reference Include="office">
113116
<HintPath>..\libs\Office.dll</HintPath>
114117
<EmbedInteropTypes>False</EmbedInteropTypes>

Rubberduck.VBEEditor/SafeComWrappers/Abstract/ISafeComWrapper.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ namespace Rubberduck.VBEditor.SafeComWrappers.Abstract
22
{
33
public interface ISafeComWrapper : INullObjectWrapper
44
{
5-
//void Release(bool final = false);
5+
void Release(bool final = false);
6+
bool HasBeenReleased { get; }
67
}
78

89
public interface ISafeComWrapper<out T> : ISafeComWrapper

Rubberduck.VBEEditor/SafeComWrappers/Office.Core/CommandBar.cs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
1+
using System.Runtime.InteropServices;
2+
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
23
using Rubberduck.VBEditor.SafeComWrappers.MSForms;
34
using Rubberduck.VBEditor.SafeComWrappers.Office.Core.Abstract;
45

56
namespace Rubberduck.VBEditor.SafeComWrappers.Office.Core
67
{
78
public class CommandBar : SafeComWrapper<Microsoft.Office.Core.CommandBar>, ICommandBar
89
{
9-
public CommandBar(Microsoft.Office.Core.CommandBar target)
10+
public CommandBar(Microsoft.Office.Core.CommandBar target)
1011
: base(target)
1112
{
1213
}
@@ -69,12 +70,12 @@ public string Name
6970

7071
public CommandBarPosition Position
7172
{
72-
get => IsWrappingNullReference ? 0 : (CommandBarPosition)Target.Position;
73+
get => IsWrappingNullReference ? 0 : (CommandBarPosition) Target.Position;
7374
set
7475
{
7576
if (!IsWrappingNullReference)
7677
{
77-
Target.Position = (Microsoft.Office.Core.MsoBarPosition)value;
78+
Target.Position = (Microsoft.Office.Core.MsoBarPosition) value;
7879
}
7980
}
8081
}
@@ -91,7 +92,7 @@ public int Top
9192
}
9293
}
9394

94-
public CommandBarType Type => IsWrappingNullReference ? 0 : (CommandBarType)Target.Type;
95+
public CommandBarType Type => IsWrappingNullReference ? 0 : (CommandBarType) Target.Type;
9596

9697
public bool IsVisible
9798
{
@@ -126,7 +127,7 @@ public ICommandBarControl FindControl(ControlType type, int id)
126127
{
127128
return new CommandBarControl(IsWrappingNullReference ? null : Target.FindControl(type, id));
128129
}
129-
130+
130131
public void Delete()
131132
{
132133
if (!IsWrappingNullReference)
@@ -146,13 +147,13 @@ public void Delete()
146147

147148
public override bool Equals(ISafeComWrapper<Microsoft.Office.Core.CommandBar> other)
148149
{
149-
return IsEqualIfNull(other) ||
150-
(other != null
151-
&& (int)other.Target.Type == (int)Type
152-
&& other.Target.Id == Id
153-
&& other.Target.Index == Index
154-
&& other.Target.BuiltIn == IsBuiltIn
155-
&& ReferenceEquals(other.Target.Parent, Target.Parent));
150+
return IsEqualIfNull(other) ||
151+
(other != null
152+
&& (int) other.Target.Type == (int) Type
153+
&& other.Target.Id == Id
154+
&& other.Target.Index == Index
155+
&& other.Target.BuiltIn == IsBuiltIn
156+
&& ReferenceEquals(other.Target.Parent, Target.Parent));
156157
}
157158

158159
public bool Equals(ICommandBar other)

Rubberduck.VBEEditor/SafeComWrappers/SafeComWrapper.cs

Lines changed: 62 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,78 @@
1+
using System.Runtime.InteropServices;
12
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
3+
using NLog;
24

35
namespace Rubberduck.VBEditor.SafeComWrappers
46
{
57
public abstract class SafeComWrapper<T> : ISafeComWrapper<T>
68
where T : class
79
{
10+
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
11+
812
protected SafeComWrapper(T target)
913
{
1014
Target = target;
1115
}
1216

13-
//private bool _isReleased;
14-
//public virtual void Release(bool final = false)
15-
//{
16-
// if (IsWrappingNullReference || _isReleased || !Marshal.IsComObject(Target))
17-
// {
18-
// _isReleased = true;
19-
// return;
20-
// }
17+
private int? _rcwReferenceCount;
18+
public virtual void Release(bool final = false)
19+
{
20+
if (HasBeenReleased)
21+
{
22+
_logger.Warn($"Tried to release already released COM wrapper of type {this.GetType()}.");
23+
return;
24+
}
25+
if (IsWrappingNullReference)
26+
{
27+
_rcwReferenceCount = 0;
28+
_logger.Warn($"Tried to release a COM wrapper of type {this.GetType()} wrapping a null reference.");
29+
return;
30+
}
31+
32+
if (!Marshal.IsComObject(Target))
33+
{
34+
_rcwReferenceCount = 0;
35+
_logger.Warn($"Tried to release a COM wrapper of type {this.GetType()} whose target is not a COM object.");
36+
return;
37+
}
38+
39+
try
40+
{
41+
if (final)
42+
{
43+
_rcwReferenceCount = Marshal.FinalReleaseComObject(Target);
44+
if (HasBeenReleased)
45+
{
46+
_logger.Trace($"Final released COM wrapper of type {this.GetType()}.");
47+
}
48+
else
49+
{
50+
_logger.Warn($"Final released COM wrapper of type {this.GetType()} did not release the wrapper: remaining reference count is {_rcwReferenceCount}.");
51+
}
52+
}
53+
else
54+
{
55+
_rcwReferenceCount = Marshal.ReleaseComObject(Target);
56+
_logger.Trace($"Released COM wrapper of type {this.GetType()} with remaining reference count {_rcwReferenceCount}.");
57+
}
58+
}
59+
catch(COMException exception)
60+
{
61+
var logMessage = $"Failed to release COM wrapper of type {this.GetType()}.";
62+
if (_rcwReferenceCount.HasValue)
63+
{
64+
logMessage = logMessage + $"The previous reference count has been {_rcwReferenceCount}.";
65+
}
66+
else
67+
{
68+
logMessage = logMessage + "There has not yet been an attempt to release the COM wrapper.";
69+
}
70+
71+
_logger.Warn(exception, logMessage);
72+
}
73+
}
2174

22-
// try
23-
// {
24-
// if (final)
25-
// {
26-
// Marshal.FinalReleaseComObject(Target);
27-
// }
28-
// else
29-
// {
30-
// Marshal.ReleaseComObject(Target);
31-
// }
32-
// }
33-
// finally
34-
// {
35-
// _isReleased = true;
36-
// }
37-
//}
75+
public bool HasBeenReleased => _rcwReferenceCount == 0;
3876

3977
public bool IsWrappingNullReference => Target == null;
4078
object INullObjectWrapper.Target => Target;

Rubberduck.VBEEditor/packages.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<packages>
3+
<package id="NLog" version="4.0.1" targetFramework="net45" />
34
<package id="System.ValueTuple" version="4.4.0" targetFramework="net45" />
45
</packages>

0 commit comments

Comments
 (0)