Fixed double release of item event objects

This commit is contained in:
Patrick Simpson 2017-02-08 16:03:43 +01:00
parent 58cd79fdb6
commit b4d84ef303
3 changed files with 47 additions and 28 deletions

View File

@ -38,14 +38,14 @@ namespace Acacia.Stubs.OutlookWrappers
if (o == null)
return null;
IBase wrapper = CreateWrapper(o);
IBase wrapper = CreateWrapper(o, mustRelease);
if (wrapper != null)
wrapper.MustRelease = mustRelease;
ComRelease.LogWrapper(o, wrapper);
return wrapper;
}
private static IBase CreateWrapper(object o)
private static IBase CreateWrapper(object o, bool mustRelease)
{
// TODO: switch on o.Class
if (o is NSOutlook.MailItem)
@ -64,9 +64,11 @@ namespace Acacia.Stubs.OutlookWrappers
return new TaskItemWrapper((NSOutlook.TaskItem)o);
// TODO: support others?
// The caller assumes a wrapper will be returned, so any lingering object here will never be released.
// TODO: do this only if caller has mustRelease
ComRelease.Release(o);
if (mustRelease)
{
// The caller assumes a wrapper will be returned, so any lingering object here will never be released.
ComRelease.Release(o);
}
return null;
}
@ -75,6 +77,7 @@ namespace Acacia.Stubs.OutlookWrappers
{
return (Type)Wrap(o, mustRelease);
}
// TODO: are these not the same now? Differ only on wrong type?
public static Type WrapOrDefault<Type>(object o, bool mustRelease = true)
where Type : IBase

View File

@ -73,7 +73,7 @@ namespace Acacia.Utils
Logger.Instance.TraceExtra(typeof(ComRelease), "Releasing object: {0:X} @ {1}", GetObjAddress(o),
new System.Diagnostics.StackTrace());
}
Marshal.ReleaseComObject(o);
Marshal.FinalReleaseComObject(o);
}
private static long GetObjAddress(object o)

View File

@ -208,6 +208,8 @@ namespace Acacia.Utils
#region Implementation
private readonly HashSet<MailEventHooker> _keepAlives = new HashSet<MailEventHooker>();
public MailEvents(IAddIn app)
{
app.ItemLoad += OnItemLoad;
@ -219,21 +221,25 @@ namespace Acacia.Utils
NSOutlook.ItemEvents_10_Event hasEvents = item as NSOutlook.ItemEvents_10_Event;
if (hasEvents != null)
{
new MailEventHooker(hasEvents, this);
_keepAlives.Add(new MailEventHooker(item, hasEvents, this));
}
else ComRelease.Release(item);
}
private class MailEventHooker : ComWrapper
{
private NSOutlook.ItemEvents_10_Event _item;
private object _item;
private NSOutlook.ItemEvents_10_Event _itemEvents;
private readonly MailEvents _events;
// TODO: remove id and debug logging
private int _id;
private static int nextId;
public MailEventHooker(NSOutlook.ItemEvents_10_Event item, MailEvents events)
public MailEventHooker(object item, NSOutlook.ItemEvents_10_Event itemEvents, MailEvents events)
{
this._id = ++nextId;
this._item = item;
this._itemEvents = itemEvents;
this._events = events;
HookEvents(true);
}
@ -241,57 +247,67 @@ namespace Acacia.Utils
protected override void DoRelease()
{
Logger.Instance.Debug(this, "DoRelease: {0}", _id);
_events._keepAlives.Remove(this);
ComRelease.Release(_item);
_item = null;
ComRelease.Release(_itemEvents);
_itemEvents = null;
}
private void HookEvents(bool add)
{
if (add)
{
_item.BeforeDelete += HandleBeforeDelete;
_item.Forward += HandleForward;
_item.Read += HandleRead;
_item.Reply += HandleReply;
_item.ReplyAll += HandleReplyAll;
_item.Unload += HandleUnload;
_item.Write += HandleWrite;
_itemEvents.BeforeDelete += HandleBeforeDelete;
_itemEvents.Forward += HandleForward;
_itemEvents.Read += HandleRead;
_itemEvents.Reply += HandleReply;
_itemEvents.ReplyAll += HandleReplyAll;
_itemEvents.Unload += HandleUnload;
_itemEvents.Write += HandleWrite;
}
else
{
_item.BeforeDelete -= HandleBeforeDelete;
_item.Forward -= HandleForward;
_item.Read -= HandleRead;
_item.Reply -= HandleReply;
_item.ReplyAll -= HandleReplyAll;
_item.Unload -= HandleUnload;
_item.Write -= HandleWrite;
_itemEvents.BeforeDelete -= HandleBeforeDelete;
_itemEvents.Forward -= HandleForward;
_itemEvents.Read -= HandleRead;
_itemEvents.Reply -= HandleReply;
_itemEvents.ReplyAll -= HandleReplyAll;
_itemEvents.Unload -= HandleUnload;
_itemEvents.Write -= HandleWrite;
}
}
private void HandleBeforeDelete(object item, ref bool cancel)
{
Logger.Instance.Debug(this, "HandleBeforeDelete: {0}", _id);
_events.OnBeforeDelete(item, ref cancel);
}
private void HandleForward(object response, ref bool cancel)
{
_events.OnForward(_item as NSOutlook.MailItem, response as NSOutlook.MailItem);
Logger.Instance.Debug(this, "HandleForward: {0}", _id);
_events.OnForward(_itemEvents as NSOutlook.MailItem, response as NSOutlook.MailItem);
}
private void HandleRead()
{
_events.OnRead(_item as NSOutlook.MailItem);
Logger.Instance.Debug(this, "HandleRead: {0}", _id);
_events.OnRead(_itemEvents as NSOutlook.MailItem);
}
private void HandleReply(object response, ref bool cancel)
{
_events.OnReply(_item as NSOutlook.MailItem, response as NSOutlook.MailItem);
Logger.Instance.Debug(this, "HandleReply: {0}", _id);
_events.OnReply(_itemEvents as NSOutlook.MailItem, response as NSOutlook.MailItem);
}
private void HandleReplyAll(object response, ref bool cancel)
{
_events.OnReplyAll(_item as NSOutlook.MailItem, response as NSOutlook.MailItem);
Logger.Instance.Debug(this, "HandleReplyAll: {0}", _id);
_events.OnReplyAll(_itemEvents as NSOutlook.MailItem, response as NSOutlook.MailItem);
}
private void HandleUnload()
@ -305,7 +321,7 @@ namespace Acacia.Utils
private void HandleWrite(ref bool cancel)
{
Logger.Instance.Debug(this, "HandleWrite: {0}", _id);
_events.OnWrite(_item, ref cancel);
_events.OnWrite(_itemEvents, ref cancel);
}
}