mirror of
				https://github.com/Kopano-dev/kopano-ol-extension.git
				synced 2023-10-10 11:37:40 +00:00 
			
		
		
		
	Fixed double release of item event objects
This commit is contained in:
		@@ -38,14 +38,14 @@ namespace Acacia.Stubs.OutlookWrappers
 | 
				
			|||||||
            if (o == null)
 | 
					            if (o == null)
 | 
				
			||||||
                return null;
 | 
					                return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            IBase wrapper = CreateWrapper(o);
 | 
					            IBase wrapper = CreateWrapper(o, mustRelease);
 | 
				
			||||||
            if (wrapper != null)
 | 
					            if (wrapper != null)
 | 
				
			||||||
                wrapper.MustRelease = mustRelease;
 | 
					                wrapper.MustRelease = mustRelease;
 | 
				
			||||||
            ComRelease.LogWrapper(o, wrapper);
 | 
					            ComRelease.LogWrapper(o, wrapper);
 | 
				
			||||||
            return wrapper;
 | 
					            return wrapper;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static IBase CreateWrapper(object o)
 | 
					        private static IBase CreateWrapper(object o, bool mustRelease)
 | 
				
			||||||
        { 
 | 
					        { 
 | 
				
			||||||
            // TODO: switch on o.Class
 | 
					            // TODO: switch on o.Class
 | 
				
			||||||
            if (o is NSOutlook.MailItem)
 | 
					            if (o is NSOutlook.MailItem)
 | 
				
			||||||
@@ -64,9 +64,11 @@ namespace Acacia.Stubs.OutlookWrappers
 | 
				
			|||||||
                return new TaskItemWrapper((NSOutlook.TaskItem)o);
 | 
					                return new TaskItemWrapper((NSOutlook.TaskItem)o);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // TODO: support others?
 | 
					            // TODO: support others?
 | 
				
			||||||
            // The caller assumes a wrapper will be returned, so any lingering object here will never be released.
 | 
					            if (mustRelease)
 | 
				
			||||||
            // TODO: do this only if caller has mustRelease
 | 
					            {
 | 
				
			||||||
            ComRelease.Release(o);
 | 
					                // The caller assumes a wrapper will be returned, so any lingering object here will never be released.
 | 
				
			||||||
 | 
					                ComRelease.Release(o);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -75,6 +77,7 @@ namespace Acacia.Stubs.OutlookWrappers
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            return (Type)Wrap(o, mustRelease);
 | 
					            return (Type)Wrap(o, mustRelease);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // TODO: are these not the same now? Differ only on wrong type?
 | 
					        // TODO: are these not the same now? Differ only on wrong type?
 | 
				
			||||||
        public static Type WrapOrDefault<Type>(object o, bool mustRelease = true)
 | 
					        public static Type WrapOrDefault<Type>(object o, bool mustRelease = true)
 | 
				
			||||||
        where Type : IBase
 | 
					        where Type : IBase
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,7 +73,7 @@ namespace Acacia.Utils
 | 
				
			|||||||
                Logger.Instance.TraceExtra(typeof(ComRelease), "Releasing object: {0:X} @ {1}", GetObjAddress(o),
 | 
					                Logger.Instance.TraceExtra(typeof(ComRelease), "Releasing object: {0:X} @ {1}", GetObjAddress(o),
 | 
				
			||||||
                                new System.Diagnostics.StackTrace());
 | 
					                                new System.Diagnostics.StackTrace());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Marshal.ReleaseComObject(o);
 | 
					            Marshal.FinalReleaseComObject(o);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static long GetObjAddress(object o)
 | 
					        private static long GetObjAddress(object o)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -208,6 +208,8 @@ namespace Acacia.Utils
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        #region Implementation
 | 
					        #region Implementation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private readonly HashSet<MailEventHooker> _keepAlives = new HashSet<MailEventHooker>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public MailEvents(IAddIn app)
 | 
					        public MailEvents(IAddIn app)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            app.ItemLoad += OnItemLoad;
 | 
					            app.ItemLoad += OnItemLoad;
 | 
				
			||||||
@@ -219,21 +221,25 @@ namespace Acacia.Utils
 | 
				
			|||||||
            NSOutlook.ItemEvents_10_Event hasEvents = item as NSOutlook.ItemEvents_10_Event;
 | 
					            NSOutlook.ItemEvents_10_Event hasEvents = item as NSOutlook.ItemEvents_10_Event;
 | 
				
			||||||
            if (hasEvents != null)
 | 
					            if (hasEvents != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                new MailEventHooker(hasEvents, this);
 | 
					                _keepAlives.Add(new MailEventHooker(item, hasEvents, this));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            else ComRelease.Release(item);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private class MailEventHooker : ComWrapper
 | 
					        private class MailEventHooker : ComWrapper
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            private NSOutlook.ItemEvents_10_Event _item;
 | 
					            private object _item;
 | 
				
			||||||
 | 
					            private NSOutlook.ItemEvents_10_Event _itemEvents;
 | 
				
			||||||
            private readonly MailEvents _events;
 | 
					            private readonly MailEvents _events;
 | 
				
			||||||
 | 
					            // TODO: remove id and debug logging
 | 
				
			||||||
            private int _id;
 | 
					            private int _id;
 | 
				
			||||||
            private static int nextId;
 | 
					            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._id = ++nextId;
 | 
				
			||||||
                this._item = item;
 | 
					                this._item = item;
 | 
				
			||||||
 | 
					                this._itemEvents = itemEvents;
 | 
				
			||||||
                this._events = events;
 | 
					                this._events = events;
 | 
				
			||||||
                HookEvents(true);
 | 
					                HookEvents(true);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -241,57 +247,67 @@ namespace Acacia.Utils
 | 
				
			|||||||
            protected override void DoRelease()
 | 
					            protected override void DoRelease()
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Logger.Instance.Debug(this, "DoRelease: {0}", _id);
 | 
					                Logger.Instance.Debug(this, "DoRelease: {0}", _id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                _events._keepAlives.Remove(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                ComRelease.Release(_item);
 | 
					                ComRelease.Release(_item);
 | 
				
			||||||
                _item = null;
 | 
					                _item = null;
 | 
				
			||||||
 | 
					                ComRelease.Release(_itemEvents);
 | 
				
			||||||
 | 
					                _itemEvents = null;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            private void HookEvents(bool add)
 | 
					            private void HookEvents(bool add)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (add)
 | 
					                if (add)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    _item.BeforeDelete += HandleBeforeDelete;
 | 
					                    _itemEvents.BeforeDelete += HandleBeforeDelete;
 | 
				
			||||||
                    _item.Forward += HandleForward;
 | 
					                    _itemEvents.Forward += HandleForward;
 | 
				
			||||||
                    _item.Read += HandleRead;
 | 
					                    _itemEvents.Read += HandleRead;
 | 
				
			||||||
                    _item.Reply += HandleReply;
 | 
					                    _itemEvents.Reply += HandleReply;
 | 
				
			||||||
                    _item.ReplyAll += HandleReplyAll;
 | 
					                    _itemEvents.ReplyAll += HandleReplyAll;
 | 
				
			||||||
                    _item.Unload += HandleUnload;
 | 
					                    _itemEvents.Unload += HandleUnload;
 | 
				
			||||||
                    _item.Write += HandleWrite;
 | 
					                    _itemEvents.Write += HandleWrite;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    _item.BeforeDelete -= HandleBeforeDelete;
 | 
					                    _itemEvents.BeforeDelete -= HandleBeforeDelete;
 | 
				
			||||||
                    _item.Forward -= HandleForward;
 | 
					                    _itemEvents.Forward -= HandleForward;
 | 
				
			||||||
                    _item.Read -= HandleRead;
 | 
					                    _itemEvents.Read -= HandleRead;
 | 
				
			||||||
                    _item.Reply -= HandleReply;
 | 
					                    _itemEvents.Reply -= HandleReply;
 | 
				
			||||||
                    _item.ReplyAll -= HandleReplyAll;
 | 
					                    _itemEvents.ReplyAll -= HandleReplyAll;
 | 
				
			||||||
                    _item.Unload -= HandleUnload;
 | 
					                    _itemEvents.Unload -= HandleUnload;
 | 
				
			||||||
                    _item.Write -= HandleWrite;
 | 
					                    _itemEvents.Write -= HandleWrite;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            private void HandleBeforeDelete(object item, ref bool cancel)
 | 
					            private void HandleBeforeDelete(object item, ref bool cancel)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					                Logger.Instance.Debug(this, "HandleBeforeDelete: {0}", _id);
 | 
				
			||||||
                _events.OnBeforeDelete(item, ref cancel);
 | 
					                _events.OnBeforeDelete(item, ref cancel);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            private void HandleForward(object response, ref bool 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()
 | 
					            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)
 | 
					            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)
 | 
					            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()
 | 
					            private void HandleUnload()
 | 
				
			||||||
@@ -305,7 +321,7 @@ namespace Acacia.Utils
 | 
				
			|||||||
            private void HandleWrite(ref bool cancel)
 | 
					            private void HandleWrite(ref bool cancel)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Logger.Instance.Debug(this, "HandleWrite: {0}", _id);
 | 
					                Logger.Instance.Debug(this, "HandleWrite: {0}", _id);
 | 
				
			||||||
                _events.OnWrite(_item, ref cancel);
 | 
					                _events.OnWrite(_itemEvents, ref cancel);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user