From 58cd79fdb6a0ecfcc11d181fd237273a16159634 Mon Sep 17 00:00:00 2001 From: Patrick Simpson Date: Wed, 8 Feb 2017 15:40:48 +0100 Subject: [PATCH] First batch of Com verification update --- .../AcaciaZPushPlugin.csproj | 2 + .../Features/DebugSupport/DebugInfo.cs | 6 +- .../DebugSupport/FeatureDebugSupport.cs | 2 - .../AcaciaZPushPlugin/Features/Feature.cs | 8 +- .../Features/FreeBusy/FeatureFreeBusy.cs | 12 +- .../Features/GAB/FeatureGAB.cs | 13 +- .../Features/GAB/GABHandler.cs | 26 ++- .../Features/Notes/FeatureNotes.cs | 5 +- .../OutOfOffice/FeatureOutOfOffice.cs | 1 - .../Features/ReplyFlags/FeatureReplyFlags.cs | 1 - .../FeatureSecondaryContacts.cs | 1 - .../Features/SendAs/FeatureSendAs.cs | 4 +- .../AcaciaZPushPlugin/Stubs/IAddIn.cs | 52 +++++ .../AcaciaZPushPlugin/Stubs/IBase.cs | 16 +- .../Stubs/IDistributionList.cs | 5 + .../AcaciaZPushPlugin/Stubs/IMailItem.cs | 4 +- .../AcaciaZPushPlugin/Stubs/ISearch.cs | 2 +- .../Stubs/OutlookWrappers/AddInWrapper.cs | 188 +++++++++++++++++ .../OutlookWrappers/AddressBookWrapper.cs | 7 +- .../OutlookWrappers/AppointmentItemWrapper.cs | 113 +++++++--- .../Stubs/OutlookWrappers/ComWrapper.cs | 5 +- .../OutlookWrappers/ContactItemWrapper.cs | 110 +++++++--- .../DistributionListWrapper.cs | 159 ++++++++------ .../Stubs/OutlookWrappers/FolderWrapper.cs | 156 ++++++++------ .../Stubs/OutlookWrappers/MailItemWrapper.cs | 198 ++++++++++-------- .../Stubs/OutlookWrappers/Mapping.cs | 80 +++---- .../Stubs/OutlookWrappers/NoteItemWrapper.cs | 106 +++++++--- .../OutlookWrappers/OutlookItemWrapper.cs | 16 +- .../Stubs/OutlookWrappers/OutlookWrapper.cs | 33 +-- .../Stubs/OutlookWrappers/SearchWrapper.cs | 22 +- .../OutlookWrappers/StorageItemWrapper.cs | 101 ++++++--- .../Stubs/OutlookWrappers/StoreWrapper.cs | 23 +- .../Stubs/OutlookWrappers/TaskItemWrapper.cs | 103 ++++++--- .../AcaciaZPushPlugin/ThisAddIn.cs | 97 +-------- .../AcaciaZPushPlugin/UI/GABLookupControl.cs | 32 +-- .../UI/Outlook/OutlookImageList.cs | 3 +- .../AcaciaZPushPlugin/UI/Outlook/OutlookUI.cs | 1 - .../AcaciaZPushPlugin/UI/SettingsDialog.cs | 12 +- .../AcaciaZPushPlugin/UI/SettingsPage.cs | 10 +- .../AcaciaZPushPlugin/Utils/ComRelease.cs | 8 +- .../AcaciaZPushPlugin/Utils/MailEvents.cs | 92 ++++---- .../Utils/OutlookRegistryUtils.cs | 2 +- .../AcaciaZPushPlugin/Utils/Util.cs | 37 +++- .../ZPush/FolderRegistration.cs | 1 - .../AcaciaZPushPlugin/ZPush/ZPushAccount.cs | 14 +- .../AcaciaZPushPlugin/ZPush/ZPushAccounts.cs | 50 +++-- .../AcaciaZPushPlugin/ZPush/ZPushChannel.cs | 1 - .../AcaciaZPushPlugin/ZPush/ZPushChannels.cs | 1 - .../AcaciaZPushPlugin/ZPush/ZPushFolder.cs | 24 +-- .../ZPush/ZPushLocalStore.cs | 26 +-- .../AcaciaZPushPlugin/ZPush/ZPushSync.cs | 5 +- .../AcaciaZPushPlugin/ZPush/ZPushWatcher.cs | 47 +++-- 52 files changed, 1279 insertions(+), 764 deletions(-) create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj index 64518df..702b8e4 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj @@ -279,7 +279,9 @@ + + diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs index 8bbb2c9..cc11799 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs @@ -101,9 +101,9 @@ namespace Acacia.Features.DebugSupport } // Add Add-ins - foreach (COMAddIn addin in ThisAddIn.Instance.Application.COMAddIns) + foreach (KeyValuePair addin in ThisAddIn.Instance.COMAddIns) { - PropertyDescriptor p = new CustomPropertyDescriptor(addin.ProgId, DebugCategory.AddIns, addin.Description); + PropertyDescriptor p = new CustomPropertyDescriptor(addin.Key, DebugCategory.AddIns, addin.Value); properties.Add(p); } } @@ -234,7 +234,7 @@ namespace Acacia.Features.DebugSupport { get { - return ThisAddIn.Instance.Application.Version; + return ThisAddIn.Instance.Version; } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureDebugSupport.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureDebugSupport.cs index 8730652..44315c5 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureDebugSupport.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureDebugSupport.cs @@ -13,8 +13,6 @@ /// along with this program.If not, see. /// /// Consult LICENSE file for details - -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using Acacia.Features.ReplyFlags; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Feature.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Feature.cs index 2460dfc..3d0b1b2 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Feature.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Feature.cs @@ -14,7 +14,6 @@ /// /// Consult LICENSE file for details -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; @@ -58,11 +57,6 @@ namespace Acacia.Features return null; } - protected static Microsoft.Office.Interop.Outlook.Application App - { - get { return ThisAddIn.Instance.Application; } - } - virtual public void GetCapabilities(ZPushCapabilities caps) { caps.Add(Name.ToLower()); @@ -206,7 +200,7 @@ namespace Acacia.Features get { if (_mailEvents == null) - _mailEvents = new MailEvents(App); + _mailEvents = new MailEvents(ThisAddIn.Instance); return _mailEvents; } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FeatureFreeBusy.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FeatureFreeBusy.cs index f9fb908..64ad9fd 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FeatureFreeBusy.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FeatureFreeBusy.cs @@ -190,12 +190,14 @@ namespace Acacia.Features.FreeBusy if (account != null && handler.Contacts != null) { // Look for the email address. If found, use the account associated with the GAB - ISearch search = handler.Contacts.Search(); - search.AddField("urn:schemas:contacts:email1").SetOperation(SearchOperation.Equal, username); - using (IItem result = search.SearchOne()) + using (ISearch search = handler.Contacts.Search()) { - if (result != null) - return account; + search.AddField("urn:schemas:contacts:email1").SetOperation(SearchOperation.Equal, username); + using (IItem result = search.SearchOne()) + { + if (result != null) + return account; + } } } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs index c932342..d644247 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs @@ -14,7 +14,6 @@ /// /// Consult LICENSE file for details -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; @@ -30,6 +29,7 @@ using System.ComponentModel; using System.Windows.Forms; using Acacia.UI; using static Acacia.DebugOptions; +using Microsoft.Office.Interop.Outlook; namespace Acacia.Features.GAB { @@ -233,7 +233,7 @@ namespace Acacia.Features.GAB /// private void DoSuppressEvent(IItem item, ref bool cancel) { - if (item != null) + /*if (item != null) { foreach (Inspector inspector in App.Inspectors) { @@ -248,7 +248,8 @@ namespace Acacia.Features.GAB MessageBoxButtons.OK, MessageBoxIcon.Warning ); - cancel = true; + cancel = true;*/ + // TODO } #endregion @@ -263,7 +264,7 @@ namespace Acacia.Features.GAB BeginProcessing(); // Delete any contacts folders in the local store - using (ZPushLocalStore store = ZPushLocalStore.GetInstance(App)) + using (ZPushLocalStore store = ZPushLocalStore.GetInstance(ThisAddIn.Instance)) { if (store != null) { @@ -353,7 +354,7 @@ namespace Acacia.Features.GAB _store.Dispose(); _store = null; } - _store = ZPushLocalStore.GetInstance(App); + _store = ZPushLocalStore.GetInstance(ThisAddIn.Instance); if (_store == null) return null; @@ -469,7 +470,7 @@ namespace Acacia.Features.GAB _store.Dispose(); _store = null; } - _store = ZPushLocalStore.GetInstance(App); + _store = ZPushLocalStore.GetInstance(ThisAddIn.Instance); if (_store == null) return; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABHandler.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABHandler.cs index 9562b9e..903ea11 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABHandler.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABHandler.cs @@ -262,16 +262,18 @@ namespace Acacia.Features.GAB try { // Delete the old contacts from this chunk - ISearch search = Contacts.Search(); - search.AddField(PROP_SEQUENCE, true).SetOperation(SearchOperation.Equal, index.numberOfChunks); - search.AddField(PROP_CHUNK, true).SetOperation(SearchOperation.Equal, index.chunk); - foreach (IItem oldItem in search.Search()) + using (ISearch search = Contacts.Search()) { - // TODO: Search should handle this, like folder enumeration - using (oldItem) + search.AddField(PROP_SEQUENCE, true).SetOperation(SearchOperation.Equal, index.numberOfChunks); + search.AddField(PROP_CHUNK, true).SetOperation(SearchOperation.Equal, index.chunk); + foreach (IItem oldItem in search.Search()) { - Logger.Instance.Trace(this, "Deleting GAB entry: {0}", oldItem.Subject); - oldItem.Delete(); + // TODO: Search should handle this, like folder enumeration + using (oldItem) + { + Logger.Instance.Trace(this, "Deleting GAB entry: {0}", oldItem.Subject); + oldItem.Delete(); + } } } @@ -616,9 +618,11 @@ namespace Acacia.Features.GAB private IItem FindItemById(string id) { - ISearch search = Contacts.Search(); - search.AddField(PROP_GAB_ID, true).SetOperation(SearchOperation.Equal, id); - return search.SearchOne(); + using (ISearch search = Contacts.Search()) + { + search.AddField(PROP_GAB_ID, true).SetOperation(SearchOperation.Equal, id); + return search.SearchOne(); + } } private void SetItemStandard(IItem item, string id, Dictionary value, ChunkIndex index) diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Notes/FeatureNotes.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Notes/FeatureNotes.cs index a21892b..d481693 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Notes/FeatureNotes.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Notes/FeatureNotes.cs @@ -18,7 +18,6 @@ using Acacia.Stubs; using Acacia.Stubs.OutlookWrappers; using Acacia.Utils; using Acacia.ZPush; -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Drawing; @@ -122,7 +121,7 @@ namespace Acacia.Features.Notes Logger.Instance.Trace(this, "PatchFolder: {0}", folderId); try { - using (IFolder folder = Mapping.GetFolderFromID(folderId)) + using (IFolder folder = ThisAddIn.Instance.GetFolderFromID(folderId)) { if (folder == null) return; @@ -168,7 +167,7 @@ namespace Acacia.Features.Notes Logger.Instance.Trace(this, "UnpatchFolder: {0}", folderId); try { - using (IFolder folder = Mapping.GetFolderFromID(folderId)) + using (IFolder folder = ThisAddIn.Instance.GetFolderFromID(folderId)) { if (folder == null) return; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/FeatureOutOfOffice.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/FeatureOutOfOffice.cs index 409df96..e019b6f 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/FeatureOutOfOffice.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/FeatureOutOfOffice.cs @@ -19,7 +19,6 @@ using Acacia.UI.Outlook; using Acacia.Utils; using Acacia.ZPush; using Acacia.ZPush.Connect; -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/FeatureReplyFlags.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/FeatureReplyFlags.cs index e9c3df8..2e00658 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/FeatureReplyFlags.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/FeatureReplyFlags.cs @@ -22,7 +22,6 @@ using System.Threading.Tasks; using Acacia.Stubs; using Acacia.Utils; using Acacia.ZPush; -using Microsoft.Office.Interop.Outlook; using static Acacia.DebugOptions; namespace Acacia.Features.ReplyFlags diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SecondaryContacts/FeatureSecondaryContacts.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SecondaryContacts/FeatureSecondaryContacts.cs index 4952c4d..f6d9c8c 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SecondaryContacts/FeatureSecondaryContacts.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SecondaryContacts/FeatureSecondaryContacts.cs @@ -18,7 +18,6 @@ using Acacia.Stubs; using Acacia.Stubs.OutlookWrappers; using Acacia.Utils; using Acacia.ZPush; -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Drawing; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs index 0dbedcc..0641b13 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs @@ -22,7 +22,6 @@ using System.Threading.Tasks; using Acacia.Stubs; using Acacia.Utils; using Acacia.ZPush; -using Microsoft.Office.Interop.Outlook; using Acacia.Features.SharedFolders; using Acacia.ZPush.API.SharedFolders; using static Acacia.DebugOptions; @@ -86,7 +85,8 @@ namespace Acacia.Features.SendAs Logger.Instance.Trace(this, "Checking, Shared folder owner: {0}", shared.Store.UserName); // It's a shared folder, use the owner as the sender if possible // TODO: make a wrapper for this - var recip = ThisAddIn.Instance.Application.Session.CreateRecipient(shared.Store.UserName); + // TODO: remove RawApp access + var recip = ThisAddIn.Instance.RawApp.Session.CreateRecipient(shared.Store.UserName); Logger.Instance.Trace(this, "Checking, Shared folder owner recipient: {0}", recip.Name); if (recip != null && recip.Resolve()) { diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs new file mode 100644 index 0000000..5489474 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs @@ -0,0 +1,52 @@ +using Acacia.Features; +using Acacia.UI.Outlook; +using Acacia.ZPush; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using NSOutlook = Microsoft.Office.Interop.Outlook; + +namespace Acacia.Stubs +{ + public interface IAddIn + { + NSOutlook.Application RawApp { get; } // TODO: remove + + ZPushWatcher Watcher { get; } + IEnumerable Features { get; } + IEnumerable> COMAddIns { get; } + string Version { get; } + + IWin32Window Window { get; } + + OutlookUI OutlookUI { get; } + + #region Event handlers + + // TODO: custom event types + event NSOutlook.ApplicationEvents_11_ItemLoadEventHandler ItemLoad; + event NSOutlook.ApplicationEvents_11_ItemSendEventHandler ItemSend; + + #endregion + + /// + /// Sends and receives all accounts. + /// + void SendReceive(); + + /// + /// Restarts the application + /// + void Restart(); + + void InvokeUI(Action action); + + IFolder GetFolderFromID(string folderId); + + FeatureType GetFeature() + where FeatureType : Feature; + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IBase.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IBase.cs index e41772f..3e3cb77 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IBase.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IBase.cs @@ -24,7 +24,7 @@ namespace Acacia.Stubs { public interface IBase : IComWrapper { - #region MAPI properties + #region Properties bool AttrHidden { get; set; } @@ -34,21 +34,31 @@ namespace Acacia.Stubs #endregion + #region Ids and hierarchy + string EntryId { get; } IFolder Parent { get; } string ParentEntryId { get; } IStore Store { get; } /// - /// Quick accessor to Store.Id, to prevent allocation a wrapper for it. + /// Quick accessor to Store.Id, to prevent allocating a wrapper for it. /// string StoreId { get; } + /// - /// Quick accessor to Store.DisplayName, to prevent allocation a wrapper for it. + /// Quick accessor to Store.DisplayName, to prevent allocating a wrapper for it. /// string StoreDisplayName { get; } + + #endregion + + #region Methods + void Delete(); string ToString(); + + #endregion } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IDistributionList.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IDistributionList.cs index 184f5a6..5ce8428 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IDistributionList.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IDistributionList.cs @@ -27,6 +27,11 @@ namespace Acacia.Stubs string DLName { get; set; } string SMTPAddress { get; set; } + /// + /// Adds a member to the distribution list. + /// + /// The item. This is not disposed or released. + /// If the item is not a contact or distribution list void AddMember(IItem item); } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IMailItem.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IMailItem.cs index 355ea10..5fff5dc 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IMailItem.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IMailItem.cs @@ -19,7 +19,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Microsoft.Office.Interop.Outlook; namespace Acacia.Stubs { @@ -34,6 +33,7 @@ namespace Acacia.Stubs string SenderEmailAddress { get; } string SenderName { get; } - void SetSender(AddressEntry addressEntry); + // TODO: make a wrapper for this + void SetSender(Microsoft.Office.Interop.Outlook.AddressEntry addressEntry); } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ISearch.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ISearch.cs index 18d5aef..385b676 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ISearch.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ISearch.cs @@ -53,7 +53,7 @@ namespace Acacia.Stubs ISearchField AddField(string name, bool isUserField = false); } - public interface ISearch : ISearchOperator + public interface ISearch : ISearchOperator, IDisposable where ItemType : IItem { ISearchOperator AddOperator(SearchOperator oper); diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs new file mode 100644 index 0000000..9b81921 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs @@ -0,0 +1,188 @@ +using Acacia.Features; +using Acacia.Native; +using Acacia.UI.Outlook; +using Acacia.Utils; +using Acacia.ZPush; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using NSOutlook = Microsoft.Office.Interop.Outlook; + +namespace Acacia.Stubs.OutlookWrappers +{ + public class AddInWrapper : IAddIn + { + private readonly ThisAddIn _thisAddIn; + private NSOutlook.Application _app; + + public AddInWrapper(ThisAddIn thisAddIn) + { + this._thisAddIn = thisAddIn; + this._app = thisAddIn.Application; + } + + public void SendReceive() + { + NSOutlook.NameSpace session = _app.Session; + try + { + session.SendAndReceive(false); + } + finally + { + ComRelease.Release(session); + } + } + + public void Restart() + { + // Can not use the assembly location, as that is in the GAC + string codeBase = Assembly.GetExecutingAssembly().CodeBase; + UriBuilder uri = new UriBuilder(codeBase); + string path = Uri.UnescapeDataString(uri.Path); + // Create the path to the restarter + path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(path), "OutlookRestarter.exe"); + + // Run that + Process process = new Process(); + process.StartInfo = new ProcessStartInfo(path, Environment.CommandLine); + process.Start(); + + // And close us + _app.Quit(); + } + + public event NSOutlook.ApplicationEvents_11_ItemLoadEventHandler ItemLoad + { + add { _app.ItemLoad += value; } + remove { _app.ItemLoad -= value; } + } + + public event NSOutlook.ApplicationEvents_11_ItemSendEventHandler ItemSend + { + add { _app.ItemSend += value; } + remove { _app.ItemSend -= value; } + } + + public NSOutlook.Application RawApp + { + get + { + return _app; + } + } + + public OutlookUI OutlookUI { get { return _thisAddIn.OutlookUI; } } + + public ZPushWatcher Watcher { get { return _thisAddIn.Watcher; } } + public IEnumerable Features { get { return _thisAddIn.Features; } } + public IEnumerable> COMAddIns + { + get + { + Microsoft.Office.Core.COMAddIns addIns = _app.COMAddIns; + try + { + foreach(Microsoft.Office.Core.COMAddIn comAddin in addIns) + { + try + { + yield return new KeyValuePair(comAddin.ProgId, comAddin.Description); + } + finally + { + ComRelease.Release(comAddin); + } + } + } + finally + { + ComRelease.Release(addIns); + } + } + } + + public string Version + { + get { return _app.Version; } + } + + + public FeatureType GetFeature() + where FeatureType : Feature + { + foreach (Feature feature in Features) + { + if (feature is FeatureType) + return (FeatureType)feature; + } + return default(FeatureType); + } + + + public void InvokeUI(Action action) + { + // [ZP-992] For some reason using the dispatcher causes a deadlock + // since switching to UI-chunked tasks. Running directly works. + action(); + } + + public IFolder GetFolderFromID(string folderId) + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.NameSpace nmspace = com.Add(_app.Session); + NSOutlook.Folder f = (NSOutlook.Folder)nmspace.GetFolderFromID(folderId); + return Mapping.Wrap(f); + } + } + + #region Window handle + + private class WindowHandle : IWin32Window + { + private IntPtr hWnd; + + public WindowHandle(IntPtr hWnd) + { + this.hWnd = hWnd; + } + + public IntPtr Handle + { + get + { + return hWnd; + } + } + } + + public IWin32Window Window + { + get + { + IOleWindow win = _app.ActiveWindow() as IOleWindow; + if (win == null) + return null; + try + { + IntPtr hWnd; + win.GetWindow(out hWnd); + return new WindowHandle(hWnd); + } + finally + { + ComRelease.Release(win); + } + } + } + + #endregion + + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddressBookWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddressBookWrapper.cs index 47a9f3a..ff6a4ce 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddressBookWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddressBookWrapper.cs @@ -15,18 +15,18 @@ /// Consult LICENSE file for details using Acacia.Utils; -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.Stubs.OutlookWrappers { class AddressBookWrapper : FolderWrapper, IAddressBook { - public AddressBookWrapper(Folder folder) + public AddressBookWrapper(NSOutlook.MAPIFolder folder) : base(folder) { @@ -35,10 +35,9 @@ namespace Acacia.Stubs.OutlookWrappers public void Clear() { - foreach(dynamic item in _item.Items) + foreach(dynamic item in _item.Items.RawEnum()) { item.Delete(); - ComRelease.Release(item); } } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AppointmentItemWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AppointmentItemWrapper.cs index 7a3263e..9071f7d 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AppointmentItemWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AppointmentItemWrapper.cs @@ -19,27 +19,21 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Microsoft.Office.Interop.Outlook; using Acacia.Utils; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.Stubs.OutlookWrappers { - class AppointmentItemWrapper : OutlookItemWrapper, IAppointmentItem, IZPushItem + class AppointmentItemWrapper : OutlookItemWrapper, IAppointmentItem, IZPushItem { - internal AppointmentItemWrapper(AppointmentItem item) + internal AppointmentItemWrapper(NSOutlook.AppointmentItem item) : base(item) { } - public override string ToString() { return "Appointment: " + Subject; } - protected override PropertyAccessor GetPropertyAccessor() - { - return _item.PropertyAccessor; - } - - #region Properties + #region IAppointmentItem implementation public DateTime Start { @@ -58,6 +52,29 @@ namespace Acacia.Stubs.OutlookWrappers set { _item.Location = value; } } + #endregion + + #region Wrapper methods + + protected override NSOutlook.UserProperties GetUserProperties() + { + return _item.UserProperties; + } + + protected override NSOutlook.PropertyAccessor GetPropertyAccessor() + { + return _item.PropertyAccessor; + } + + public override string ToString() + { + return "Appointment:" + Subject; + } + + #endregion + + #region IItem implementation + public string Body { get { return _item.Body; } @@ -70,45 +87,75 @@ namespace Acacia.Stubs.OutlookWrappers set { _item.Subject = value; } } - public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } } - // TODO: release needed - public string StoreId { get { return _item.Parent?.Store?.StoreID; } } - public string StoreDisplayName { get { return _item.Parent?.Store?.DisplayName; } } - - #endregion - - #region Methods - - protected override UserProperties GetUserProperties() - { - return _item.UserProperties; - } - - public void Delete() { _item.Delete(); } public void Save() { _item.Save(); } #endregion + #region IBase implementation + + public string EntryId { get { return _item.EntryID; } } + public IFolder Parent { - get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } + get + { + // The wrapper manages the returned folder + return Mapping.Wrap(_item.Parent as NSOutlook.Folder); + } } + public string ParentEntryId { get { - Folder parent = _item.Parent; - try + using (ComRelease com = new ComRelease()) { + NSOutlook.Folder parent = com.Add(_item.Parent); return parent?.EntryID; } - finally - { - ComRelease.Release(parent); - } } } - public string EntryId { get { return _item.EntryID; } } + public IStore Store + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + return StoreWrapper.Wrap(parent?.Store); + } + } + } + + public string StoreId + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + NSOutlook.Store store = com.Add(parent?.Store); + return store.StoreID; + } + } + } + + public string StoreDisplayName + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + NSOutlook.Store store = com.Add(parent?.Store); + return store.StoreID; + } + } + } + + public void Delete() { _item.Delete(); } + + #endregion } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ComWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ComWrapper.cs index e5b150e..61cf8cb 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ComWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ComWrapper.cs @@ -43,9 +43,8 @@ namespace Acacia.Stubs.OutlookWrappers if (!_isDisposed) { Logger.Instance.Warning(this, "Undisposed wrapper: {0}", _createdTrace); - Dispose(); - // Don't count auto disposals - Interlocked.Decrement(ref Statistics.DisposedWrappers); + // Dispose, but don't count auto disposals, so the stats show it. + DoRelease(); } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ContactItemWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ContactItemWrapper.cs index 01db56f..a8617a2 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ContactItemWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ContactItemWrapper.cs @@ -15,30 +15,23 @@ /// Consult LICENSE file for details using Acacia.Utils; -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.Stubs.OutlookWrappers { - class ContactItemWrapper : OutlookItemWrapper, IContactItem + class ContactItemWrapper : OutlookItemWrapper, IContactItem { - internal ContactItemWrapper(ContactItem item) + internal ContactItemWrapper(NSOutlook.ContactItem item) : base(item) { } - protected override PropertyAccessor GetPropertyAccessor() - { - return _item.PropertyAccessor; - } - - public override string ToString() { return "Contact: " + Subject; } - #region IContactItem implementation public string CustomerID @@ -179,6 +172,30 @@ namespace Acacia.Stubs.OutlookWrappers set { _item.Language = value; } } + public void SetPicture(string path) + { + _item.AddPicture(path); + } + + #endregion + + #region Wrapper methods + + protected override NSOutlook.UserProperties GetUserProperties() + { + return _item.UserProperties; + } + + protected override NSOutlook.PropertyAccessor GetPropertyAccessor() + { + return _item.PropertyAccessor; + } + + public override string ToString() + { + return "Contact:" + Subject; + } + #endregion #region IItem implementation @@ -195,49 +212,74 @@ namespace Acacia.Stubs.OutlookWrappers set { _item.Subject = value; } } - public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } } - // TODO: release needed - public string StoreId { get { return _item.Parent?.Store?.StoreID; } } - public string StoreDisplayName { get { return _item.Parent?.Store?.DisplayName; } } - - protected override UserProperties GetUserProperties() - { - return _item.UserProperties; - } - - public void Delete() { _item.Delete(); } public void Save() { _item.Save(); } - public void SetPicture(string path) - { - _item.AddPicture(path); - } - #endregion #region IBase implementation + public string EntryId { get { return _item.EntryID; } } + public IFolder Parent { - get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } + get + { + // The wrapper manages the returned folder + return Mapping.Wrap(_item.Parent as NSOutlook.Folder); + } } + public string ParentEntryId { get { - Folder parent = _item.Parent; - try + using (ComRelease com = new ComRelease()) { + NSOutlook.Folder parent = com.Add(_item.Parent); return parent?.EntryID; } - finally - { - ComRelease.Release(parent); - } } } - public string EntryId { get { return _item.EntryID; } } + public IStore Store + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + return StoreWrapper.Wrap(parent?.Store); + } + } + } + + public string StoreId + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + NSOutlook.Store store = com.Add(parent?.Store); + return store.StoreID; + } + } + } + + public string StoreDisplayName + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + NSOutlook.Store store = com.Add(parent?.Store); + return store.StoreID; + } + } + } + + public void Delete() { _item.Delete(); } #endregion diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/DistributionListWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/DistributionListWrapper.cs index 2754c93..7771581 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/DistributionListWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/DistributionListWrapper.cs @@ -19,47 +19,35 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Microsoft.Office.Interop.Outlook; using Acacia.Utils; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.Stubs.OutlookWrappers { - class DistributionListWrapper : OutlookItemWrapper, IDistributionList + class DistributionListWrapper : OutlookItemWrapper, IDistributionList { - internal DistributionListWrapper(DistListItem item) + internal DistributionListWrapper(NSOutlook.DistListItem item) : base(item) { } - protected override PropertyAccessor GetPropertyAccessor() - { - return _item.PropertyAccessor; - } - - #region Properties + #region IDistributionList implementation public string SMTPAddress { get { - PropertyAccessor props = _item.PropertyAccessor; - try - { - return (string)props.GetProperty(OutlookConstants.PR_EMAIL1EMAILADDRESS); - } - finally - { - ComRelease.Release(props); - } + return (string)GetProperty(OutlookConstants.PR_EMAIL1EMAILADDRESS); } set { - string displayName = DLName + " (" + value + ")"; - byte[] oneOffId = CreateOneOffMemberId(DLName, "SMTP", value); - PropertyAccessor props = _item.PropertyAccessor; - try + using (ComRelease com = new ComRelease()) { + string displayName = DLName + " (" + value + ")"; + byte[] oneOffId = CreateOneOffMemberId(DLName, "SMTP", value); + + NSOutlook.PropertyAccessor props = com.Add(_item.PropertyAccessor); props.SetProperties( new string[] { @@ -79,35 +67,20 @@ namespace Acacia.Stubs.OutlookWrappers } ); } - finally - { - ComRelease.Release(props); - } } } - #endregion - - #region Methods - - protected override UserProperties GetUserProperties() + public string DLName { - return _item.UserProperties; + get { return _item.DLName; } + set { _item.DLName = value; } } - public void Delete() { _item.Delete(); } - public void Save() { _item.Save(); } - public void AddMember(IItem item) { if (item is IContactItem) { - string email = ((IContactItem)item).Email1Address; - Recipient recipient = ThisAddIn.Instance.Application.Session.CreateRecipient(email); - if (recipient.Resolve()) - _item.AddMember(recipient); - else - Logger.Instance.Warning(this, "Unable to resolve recipient: {0}", email); + AddContactMember((IContactItem)item); } else if (item is IDistributionList) { @@ -115,8 +88,19 @@ namespace Acacia.Stubs.OutlookWrappers } else { - Logger.Instance.Warning(this, "Unknown item type when adding to distlist: {0}", item); - } + throw new NotSupportedException("Unknown item type when adding to distlist: " + item.GetType()); + } + } + + private void AddContactMember(IContactItem member) + { + string email = member.Email1Address; + // TODO: remove RawApp, Recipient wrapper + NSOutlook.Recipient recipient = ThisAddIn.Instance.RawApp.Session.CreateRecipient(email); + if (recipient.Resolve()) + _item.AddMember(recipient); + else + Logger.Instance.Warning(this, "Unable to resolve recipient: {0}", email); } private void AddDistributionListMember(IDistributionList member) @@ -124,9 +108,8 @@ namespace Acacia.Stubs.OutlookWrappers // Resolving a distribution list can only be done by name. This fails if the name is in multiple // groups (e.g. 'Germany' and 'Sales Germany' fails to find Germany). Patch the member // tables explicitly. - PropertyAccessor props = _item.PropertyAccessor; - object[] members = props.GetProperty(OutlookConstants.PR_DISTLIST_MEMBERS); - object[] oneOffMembers = props.GetProperty(OutlookConstants.PR_DISTLIST_ONEOFFMEMBERS); + object[] members = (object[])GetProperty(OutlookConstants.PR_DISTLIST_MEMBERS); + object[] oneOffMembers = (object[])GetProperty(OutlookConstants.PR_DISTLIST_ONEOFFMEMBERS); // Create the new member ids byte[] memberId = CreateMemberId(member); @@ -163,7 +146,7 @@ namespace Acacia.Stubs.OutlookWrappers newOneOffMembers[existingIndex] = oneOffMemberId; // Write back - props.SetProperties( + SetProperties( new string[] { OutlookConstants.PR_DISTLIST_MEMBERS, OutlookConstants.PR_DISTLIST_ONEOFFMEMBERS }, new object[] { newMembers, newOneOffMembers } ); @@ -213,14 +196,27 @@ namespace Acacia.Stubs.OutlookWrappers #endregion - public override string ToString() { return "DistributionList: " + DLName; } + #region Wrapper methods - public string DLName + protected override NSOutlook.UserProperties GetUserProperties() { - get { return _item.DLName; } - set { _item.DLName = value; } + return _item.UserProperties; } + protected override NSOutlook.PropertyAccessor GetPropertyAccessor() + { + return _item.PropertyAccessor; + } + + public override string ToString() + { + return "DistributionList: " + DLName; + } + + #endregion + + #region IItem implementation + public string Body { get { return _item.Body; } @@ -233,40 +229,75 @@ namespace Acacia.Stubs.OutlookWrappers set { _item.Subject = value; } } - public IFolder Parent { get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } } + public void Save() { _item.Save(); } + + #endregion + + #region IBase implementation + + public string EntryId { get { return _item.EntryID; } } + + public IFolder Parent + { + get + { + // The wrapper manages the returned folder + return Mapping.Wrap(_item.Parent as NSOutlook.Folder); + } + } + public string ParentEntryId { get { - Folder parent = _item.Parent; - try + using (ComRelease com = new ComRelease()) { + NSOutlook.Folder parent = com.Add(_item.Parent); return parent?.EntryID; } - finally - { - ComRelease.Release(parent); - } } } - public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } } + + public IStore Store + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + return StoreWrapper.Wrap(parent?.Store); + } + } + } + public string StoreId { get { - // TODO: release needed - return _item.Parent?.Store?.StoreID; + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + NSOutlook.Store store = com.Add(parent?.Store); + return store.StoreID; + } } } + public string StoreDisplayName { get { - // TODO: release needed - return _item.Parent?.Store?.DisplayName; + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + NSOutlook.Store store = com.Add(parent?.Store); + return store.StoreID; + } } } - public string EntryId { get { return _item.EntryID; } } + public void Delete() { _item.Delete(); } + + #endregion } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs index 944d122..2361b09 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs @@ -14,7 +14,6 @@ /// /// Consult LICENSE file for details -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; @@ -23,39 +22,41 @@ using System.Threading.Tasks; using System.Collections; using Acacia.Utils; using Acacia.ZPush; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.Stubs.OutlookWrappers { - public class FolderWrapper : OutlookWrapper, IFolder + public class FolderWrapper : OutlookWrapper, IFolder { - public FolderWrapper(Folder folder) + public FolderWrapper(NSOutlook.MAPIFolder folder) : - base(folder) + base((NSOutlook.Folder)folder) { } - protected override PropertyAccessor GetPropertyAccessor() + protected override NSOutlook.PropertyAccessor GetPropertyAccessor() { return _item.PropertyAccessor; } public IFolder Parent { - get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } + get + { + // The wrapper manages the returned folder + return Mapping.Wrap(_item.Parent as NSOutlook.Folder); + } } + public string ParentEntryId { get { - Folder parent = _item.Parent; - try + using (ComRelease com = new ComRelease()) { + NSOutlook.Folder parent = com.Add(_item.Parent); return parent?.EntryID; } - finally - { - ComRelease.Release(parent); - } } } @@ -69,17 +70,20 @@ namespace Acacia.Stubs.OutlookWrappers using (ComRelease com = new ComRelease()) { // The parent of the root item is a session, not null. Hence the explicit type checks. - Folder current = _item; + // _item is managed by this wrapper and does not need to be released. + NSOutlook.Folder current = _item; for (int i = 0; i < depth; ++i) { - object parent = current.Parent; - com.Add(parent); - if (!(parent is Folder)) + object parent = com.Add(current.Parent); + + current = parent as NSOutlook.Folder; + if (current == null) return false; - current = (Folder)parent; } - return !(com.Add(current.Parent) is Folder); + // Check if the remaining parent is a folder + object finalParent = com.Add(current.Parent); + return !(finalParent is NSOutlook.Folder); } } @@ -118,15 +122,18 @@ namespace Acacia.Stubs.OutlookWrappers public ItemType ItemType { get { return (ItemType)(int)_item.DefaultItemType; } } - public class IItemsEnumerator : IEnumerator + #region Enumeration + + public class ItemsEnumerator : ComWrapper, IEnumerator where ItemType : IItem { - private Items _items; + private NSOutlook.Items _items; private IEnumerator _enum; private ItemType _last; - public IItemsEnumerator(Folder _folder, string field, bool descending) + public ItemsEnumerator(NSOutlook.Folder _folder, string field, bool descending) { + // TODO: can _items be released here already? this._items = _folder.Items; if (field != null) { @@ -135,6 +142,23 @@ namespace Acacia.Stubs.OutlookWrappers this._enum = _items.GetEnumerator(); } + protected override void DoRelease() + { + CleanLast(); + if (_enum != null) + { + if (_enum is IDisposable) + ((IDisposable)_enum).Dispose(); + ComRelease.Release(_enum); + _enum = null; + } + if (_items != null) + { + ComRelease.Release(_items); + _items = null; + } + } + public ItemType Current { get @@ -162,23 +186,6 @@ namespace Acacia.Stubs.OutlookWrappers } } - public void Dispose() - { - CleanLast(); - if (_enum != null) - { - if (_enum is IDisposable) - ((IDisposable)_enum).Dispose(); - ComRelease.Release(_enum); - _enum = null; - } - if (_items != null) - { - ComRelease.Release(_items); - _items = null; - } - } - public bool MoveNext() { CleanLast(); @@ -192,14 +199,15 @@ namespace Acacia.Stubs.OutlookWrappers } } - public class IItemsEnumerable : IEnumerable + public class ItemsEnumerable : IEnumerable where ItemType : IItem { - private readonly Folder _folder; + // Managed by the caller, not released here + private readonly NSOutlook.Folder _folder; private readonly string _field; private readonly bool _descending; - public IItemsEnumerable(Folder folder, string field, bool descending) + public ItemsEnumerable(NSOutlook.Folder folder, string field, bool descending) { this._folder = folder; this._field = field; @@ -208,7 +216,7 @@ namespace Acacia.Stubs.OutlookWrappers public IEnumerator GetEnumerator() { - return new IItemsEnumerator(_folder, _field, _descending); + return new ItemsEnumerator(_folder, _field, _descending); } IEnumerator IEnumerable.GetEnumerator() @@ -221,15 +229,17 @@ namespace Acacia.Stubs.OutlookWrappers { get { - return new IItemsEnumerable(_item, null, false); + return new ItemsEnumerable(_item, null, false); } } public IEnumerable ItemsSorted(string field, bool descending) { - return new IItemsEnumerable(_item, field, descending); + return new ItemsEnumerable(_item, field, descending); } + #endregion + public IItem GetItemById(string entryId) { try @@ -274,10 +284,13 @@ namespace Acacia.Stubs.OutlookWrappers return new SearchWrapper(_item.Items); } + #region Subfolders + public IEnumerable GetSubFolders() where FolderType : IFolder { - foreach (MAPIFolder folder in _item.Folders) + // Don't release the items, the wrapper manages them + foreach (NSOutlook.Folder folder in _item.Folders.RawEnum(false)) { yield return WrapFolder(folder); }; @@ -287,14 +300,19 @@ namespace Acacia.Stubs.OutlookWrappers where FolderType : IFolder { // Fetching the folder by name throws an exception if not found, loop and find - // to prevent exceptions in the log - MAPIFolder sub = null; - foreach(MAPIFolder folder in _item.Folders) + // to prevent exceptions in the log. + // Don't release the items in RawEnum, they are release manually or handed to WrapFolders. + NSOutlook.Folder sub = null; + foreach(NSOutlook.Folder folder in _item.Folders.RawEnum(false)) { if (folder.Name == name) { sub = folder; - break; + break; // TODO: does this prevent the rest of the objects from getting released? + } + else + { + ComRelease.Release(folder); } } if (sub == null) @@ -305,46 +323,47 @@ namespace Acacia.Stubs.OutlookWrappers public FolderType CreateFolder(string name) where FolderType : IFolder { - Folders folders = _item.Folders; - try + using (ComRelease com = new ComRelease()) { + NSOutlook.Folders folders = com.Add(_item.Folders); if (typeof(FolderType) == typeof(IFolder)) { return WrapFolder(folders.Add(name)); } else if (typeof(FolderType) == typeof(IAddressBook)) { - MAPIFolder newFolder = folders.Add(name, OlDefaultFolders.olFolderContacts); + NSOutlook.MAPIFolder newFolder = folders.Add(name, NSOutlook.OlDefaultFolders.olFolderContacts); newFolder.ShowAsOutlookAB = true; return WrapFolder(newFolder); } else throw new NotSupportedException(); } - finally - { - ComRelease.Release(folders); - } } - private FolderType WrapFolder(MAPIFolder folder) + private FolderType WrapFolder(NSOutlook.MAPIFolder folder) where FolderType : IFolder { if (typeof(FolderType) == typeof(IFolder)) { - return (FolderType)(IFolder)new FolderWrapper((Folder)folder); + return (FolderType)(IFolder)new FolderWrapper(folder); } else if (typeof(FolderType) == typeof(IAddressBook)) { - return (FolderType)(IFolder)new AddressBookWrapper((Folder)folder); + return (FolderType)(IFolder)new AddressBookWrapper(folder); } else + { + ComRelease.Release(folder); throw new NotSupportedException(); + } } + #endregion + public IStorageItem GetStorageItem(string name) { - StorageItem item = _item.GetStorage(name, OlStorageIdentifierType.olIdentifyBySubject); + NSOutlook.StorageItem item = _item.GetStorage(name, NSOutlook.OlStorageIdentifierType.olIdentifyBySubject); if (item == null) return null; return new StorageItemWrapper(item); @@ -359,16 +378,12 @@ namespace Acacia.Stubs.OutlookWrappers public ItemType Create() where ItemType : IItem { - Items items = _item.Items; - try + using (ComRelease com = new ComRelease()) { + NSOutlook.Items items = com.Add(_item.Items); object item = items.Add(Mapping.OutlookItemType()); return Mapping.Wrap(item); } - finally - { - ComRelease.Release(items); - } } #endregion @@ -415,12 +430,14 @@ namespace Acacia.Stubs.OutlookWrappers _item.BeforeItemMove -= HandleBeforeItemMove; } - private void HandleBeforeItemMove(object item, MAPIFolder target, ref bool cancel) + private void HandleBeforeItemMove(object item, NSOutlook.MAPIFolder target, ref bool cancel) { try { if (_beforeItemMove != null) { + // TODO: there is a tiny potential for a leak here, if there is an exception in the wrap methods. Should + // only happen if Outlook sends the wrong type object though using (IItem itemWrapped = Mapping.Wrap(item)) using (IFolder targetWrapped = Mapping.Wrap(target)) { @@ -430,6 +447,11 @@ namespace Acacia.Stubs.OutlookWrappers } } } + else + { + // TODO: check this + ComRelease.Release(item, target); + } } catch(System.Exception e) { diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/MailItemWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/MailItemWrapper.cs index 10edd5e..be57f96 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/MailItemWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/MailItemWrapper.cs @@ -19,27 +19,95 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Microsoft.Office.Interop.Outlook; using Acacia.Utils; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.Stubs.OutlookWrappers { - class MailItemWrapper : OutlookItemWrapper, IMailItem + class MailItemWrapper : OutlookItemWrapper, IMailItem { - internal MailItemWrapper(MailItem item) + internal MailItemWrapper(NSOutlook.MailItem item) : base(item) { } - protected override PropertyAccessor GetPropertyAccessor() + #region IMailItem implementation + + public DateTime? AttrLastVerbExecutionTime + { + get + { + return GetProperty(OutlookConstants.PR_LAST_VERB_EXECUTION_TIME) as DateTime?; + } + set + { + SetProperty(OutlookConstants.PR_LAST_VERB_EXECUTION_TIME, value); + } + } + + public int AttrLastVerbExecuted + { + get + { + return (int)GetProperty(OutlookConstants.PR_LAST_VERB_EXECUTED); + } + set + { + SetProperty(OutlookConstants.PR_LAST_VERB_EXECUTED, value); + } + } + + public string SenderEmailAddress + { + get + { + using (ComRelease com = new ComRelease()) + { + return com.Add(_item.Sender)?.Address; + } + } + } + + public string SenderName + { + get + { + using (ComRelease com = new ComRelease()) + { + return com.Add(_item.Sender)?.Name; + } + } + } + + + public void SetSender(NSOutlook.AddressEntry addressEntry) + { + _item.Sender = addressEntry; + } + + #endregion + + #region Wrapper methods + + protected override NSOutlook.UserProperties GetUserProperties() + { + return _item.UserProperties; + } + + protected override NSOutlook.PropertyAccessor GetPropertyAccessor() { return _item.PropertyAccessor; } - public override string ToString() { return "Mail: " + Subject; } + public override string ToString() + { + return "Mail:" + Subject; + } - #region Properties + #endregion + + #region IItem implementation public string Body { @@ -53,19 +121,44 @@ namespace Acacia.Stubs.OutlookWrappers set { _item.Subject = value; } } + public void Save() { _item.Save(); } + + #endregion + + #region IBase implementation + + public string EntryId { get { return _item.EntryID; } } + + public IFolder Parent + { + get + { + // The wrapper manages the returned folder + return Mapping.Wrap(_item.Parent as NSOutlook.Folder); + } + } + + public string ParentEntryId + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + return parent?.EntryID; + } + } + } + public IStore Store { get { - Folder parent = (Folder)_item.Parent; - try + using (ComRelease com = new ComRelease()) { + NSOutlook.Folder parent = com.Add(_item.Parent); return StoreWrapper.Wrap(parent?.Store); } - finally - { - ComRelease.Release(parent); - } } } @@ -73,17 +166,11 @@ namespace Acacia.Stubs.OutlookWrappers { get { - Folder parent = (Folder)_item.Parent; - Store store = null; - try + using (ComRelease com = new ComRelease()) { - store = parent?.Store; - return store?.StoreID; - } - finally - { - ComRelease.Release(parent); - ComRelease.Release(store); + NSOutlook.Folder parent = com.Add(_item.Parent); + NSOutlook.Store store = com.Add(parent?.Store); + return store.StoreID; } } } @@ -92,76 +179,17 @@ namespace Acacia.Stubs.OutlookWrappers { get { - Folder parent = (Folder)_item.Parent; - Store store = null; - try + using (ComRelease com = new ComRelease()) { - store = parent?.Store; - return store?.DisplayName; - } - finally - { - ComRelease.Release(parent); - ComRelease.Release(store); + NSOutlook.Folder parent = com.Add(_item.Parent); + NSOutlook.Store store = com.Add(parent?.Store); + return store.StoreID; } } } - public string SenderEmailAddress - { - get - { - // TODO: should Sender be released? - return _item.Sender?.Address; - } - } - - public string SenderName - { - get { return _item.Sender?.Name; } - } - - - public void SetSender(AddressEntry addressEntry) - { - _item.Sender = addressEntry; - } - - - #endregion - - #region Methods - - protected override UserProperties GetUserProperties() - { - return _item.UserProperties; - } - public void Delete() { _item.Delete(); } - public void Save() { _item.Save(); } #endregion - - public IFolder Parent - { - get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } - } - public string ParentEntryId - { - get - { - Folder parent = _item.Parent; - try - { - return parent?.EntryID; - } - finally - { - ComRelease.Release(parent); - } - } - } - - public string EntryId { get { return _item.EntryID; } } } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/Mapping.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/Mapping.cs index 93bcf10..f19bac6 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/Mapping.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/Mapping.cs @@ -15,12 +15,12 @@ /// Consult LICENSE file for details using Acacia.Utils; -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.Stubs.OutlookWrappers { @@ -32,7 +32,8 @@ namespace Acacia.Stubs.OutlookWrappers /// /// The Outlook object. /// The IItem wrapper, or null if the object could not be wrapped - public static IBase Wrap(object o, bool mustRelease = true) + // TODO: made this private to see if it's still used + private static IBase Wrap(object o, bool mustRelease = true) { if (o == null) return null; @@ -47,25 +48,25 @@ namespace Acacia.Stubs.OutlookWrappers private static IBase CreateWrapper(object o) { // TODO: switch on o.Class - if (o is MailItem) - return new MailItemWrapper((MailItem)o); - if (o is AppointmentItem) - return new AppointmentItemWrapper((AppointmentItem)o); - if (o is Folder) - return new FolderWrapper((Folder)o); - if (o is ContactItem) - return new ContactItemWrapper((ContactItem)o); - if (o is DistListItem) - return new DistributionListWrapper((DistListItem)o); - if (o is NoteItem) - return new NoteItemWrapper((NoteItem)o); - if (o is TaskItem) - return new TaskItemWrapper((TaskItem)o); - - // TODO: support this? - if (o is ReportItem) - return null; + if (o is NSOutlook.MailItem) + return new MailItemWrapper((NSOutlook.MailItem)o); + if (o is NSOutlook.AppointmentItem) + return new AppointmentItemWrapper((NSOutlook.AppointmentItem)o); + if (o is NSOutlook.Folder) + return new FolderWrapper((NSOutlook.Folder)o); + if (o is NSOutlook.ContactItem) + return new ContactItemWrapper((NSOutlook.ContactItem)o); + if (o is NSOutlook.DistListItem) + return new DistributionListWrapper((NSOutlook.DistListItem)o); + if (o is NSOutlook.NoteItem) + return new NoteItemWrapper((NSOutlook.NoteItem)o); + if (o is NSOutlook.TaskItem) + 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); return null; } @@ -74,60 +75,45 @@ 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(object o, bool mustRelease = true) where Type : IBase { IBase wrapped = Wrap(o, mustRelease); if (wrapped is Type) return (Type)wrapped; + + // TODO: release if required if (wrapped != null) wrapped.Dispose(); return default(Type); } - public static OlItemType OutlookItemType() + public static NSOutlook.OlItemType OutlookItemType() where ItemType: IItem { Type type = typeof(ItemType); if (type == typeof(IContactItem)) - return OlItemType.olContactItem; + return NSOutlook.OlItemType.olContactItem; if (type == typeof(IDistributionList)) - return OlItemType.olDistributionListItem; + return NSOutlook.OlItemType.olDistributionListItem; throw new NotImplementedException(); // TODO } - public static OlUserPropertyType OutlookPropertyType() + public static NSOutlook.OlUserPropertyType OutlookPropertyType() { Type type = typeof(PropType); if (type == typeof(string)) - return OlUserPropertyType.olText; + return NSOutlook.OlUserPropertyType.olText; if (type == typeof(DateTime)) - return OlUserPropertyType.olDateTime; + return NSOutlook.OlUserPropertyType.olDateTime; if (type == typeof(int)) - return OlUserPropertyType.olInteger; + return NSOutlook.OlUserPropertyType.olInteger; if (type.IsEnum) - return OlUserPropertyType.olInteger; + return NSOutlook.OlUserPropertyType.olInteger; if (type == typeof(string[])) - return OlUserPropertyType.olKeywords; + return NSOutlook.OlUserPropertyType.olKeywords; throw new NotImplementedException(); // TODO } - - - // TODO: this needs to go elsewhere - public static IFolder GetFolderFromID(string folderId) - { - NameSpace nmspace = ThisAddIn.Instance.Application.Session; - try - { - Folder f = (Folder)nmspace.GetFolderFromID(folderId); - return Wrap(f); - } - finally - { - ComRelease.Release(nmspace); - } - } - } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/NoteItemWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/NoteItemWrapper.cs index 0b8a55a..e3ebaa2 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/NoteItemWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/NoteItemWrapper.cs @@ -14,32 +14,44 @@ /// /// Consult LICENSE file for details -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; using Acacia.Utils; using System.Text; using System.Threading.Tasks; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.Stubs.OutlookWrappers { - public class NoteItemWrapper : OutlookItemWrapper, INoteItem + public class NoteItemWrapper : OutlookItemWrapper, INoteItem { - internal NoteItemWrapper(NoteItem item) + internal NoteItemWrapper(NSOutlook.NoteItem item) : base(item) { } - protected override PropertyAccessor GetPropertyAccessor() + #region Wrapper methods + + protected override NSOutlook.UserProperties GetUserProperties() + { + throw new NotSupportedException("NoteItem does not support user properties"); + } + + protected override NSOutlook.PropertyAccessor GetPropertyAccessor() { return _item.PropertyAccessor; } - public override string ToString() { return "Note: " + Subject; } + public override string ToString() + { + return "Note:" + Subject; + } - #region Properties + #endregion + + #region IItem implementation public string Body { @@ -50,49 +62,81 @@ namespace Acacia.Stubs.OutlookWrappers public string Subject { get { return _item.Subject; } - set { throw new NotSupportedException(); } + set + { + throw new NotSupportedException("NoteItem does not support setting body"); + } } - public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } } - // TODO: release needed - public string StoreId { get { return _item.Parent?.Store?.StoreID; } } - public string StoreDisplayName { get { return _item.Parent?.Store?.DisplayName; } } - - #endregion - - #region Methods - - protected override UserProperties GetUserProperties() - { - // Note item doesn't have user properties - throw new NotSupportedException(); - } - - public void Delete() { _item.Delete(); } public void Save() { _item.Save(); } #endregion + #region IBase implementation + + public string EntryId { get { return _item.EntryID; } } + public IFolder Parent { - get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } + get + { + // The wrapper manages the returned folder + return Mapping.Wrap(_item.Parent as NSOutlook.Folder); + } } + public string ParentEntryId { get { - Folder parent = _item.Parent; - try + using (ComRelease com = new ComRelease()) { + NSOutlook.Folder parent = com.Add(_item.Parent); return parent?.EntryID; } - finally - { - ComRelease.Release(parent); - } } } - public string EntryId { get { return _item.EntryID; } } + public IStore Store + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + return StoreWrapper.Wrap(parent?.Store); + } + } + } + + public string StoreId + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + NSOutlook.Store store = com.Add(parent?.Store); + return store.StoreID; + } + } + } + + public string StoreDisplayName + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + NSOutlook.Store store = com.Add(parent?.Store); + return store.StoreID; + } + } + } + + public void Delete() { _item.Delete(); } + + #endregion } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookItemWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookItemWrapper.cs index 683e28c..0e86002 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookItemWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookItemWrapper.cs @@ -1,10 +1,10 @@ using Acacia.Utils; -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.Stubs.OutlookWrappers { @@ -20,8 +20,8 @@ namespace Acacia.Stubs.OutlookWrappers { using (ComRelease com = new ComRelease()) { - UserProperties userProperties = com.Add(GetUserProperties()); - UserProperty prop = com.Add(userProperties.Find(name, true)); + NSOutlook.UserProperties userProperties = com.Add(GetUserProperties()); + NSOutlook.UserProperty prop = com.Add(userProperties.Find(name, true)); if (prop == null) return default(Type); @@ -35,8 +35,8 @@ namespace Acacia.Stubs.OutlookWrappers { using (ComRelease com = new ComRelease()) { - UserProperties userProperties = com.Add(GetUserProperties()); - UserProperty prop = com.Add(userProperties.Find(name, true)); + NSOutlook.UserProperties userProperties = com.Add(GetUserProperties()); + NSOutlook.UserProperty prop = com.Add(userProperties.Find(name, true)); if (prop == null) prop = userProperties.Add(name, Mapping.OutlookPropertyType()); @@ -52,6 +52,10 @@ namespace Acacia.Stubs.OutlookWrappers } } - abstract protected UserProperties GetUserProperties(); + /// + /// Returns the UserProperties associated with the current item. + /// + /// An unwrapped UserProperties object. The caller is responsible for releasing this. + abstract protected NSOutlook.UserProperties GetUserProperties(); } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookWrapper.cs index 86221aa..fe56318 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookWrapper.cs @@ -15,7 +15,6 @@ /// Consult LICENSE file for details using Acacia.Features.DebugSupport; -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; @@ -23,6 +22,7 @@ using Acacia.Utils; using System.Text; using System.Threading; using System.Threading.Tasks; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.Stubs.OutlookWrappers { @@ -70,9 +70,10 @@ namespace Acacia.Stubs.OutlookWrappers #region Properties implementation - private PropertyAccessor _props; + // Assigned in Props, released in DoRelease + private NSOutlook.PropertyAccessor _props; - private PropertyAccessor Props + private NSOutlook.PropertyAccessor Props { get { @@ -88,7 +89,7 @@ namespace Acacia.Stubs.OutlookWrappers /// Returns the wrapped item's property accessor. /// /// The property accessor. The caller is responsible for disposing this. - abstract protected PropertyAccessor GetPropertyAccessor(); + abstract protected NSOutlook.PropertyAccessor GetPropertyAccessor(); #endregion @@ -127,30 +128,6 @@ namespace Acacia.Stubs.OutlookWrappers } } - public DateTime? AttrLastVerbExecutionTime - { - get - { - return Props.GetProperty(OutlookConstants.PR_LAST_VERB_EXECUTION_TIME) as DateTime?; - } - set - { - Props.SetProperty(OutlookConstants.PR_LAST_VERB_EXECUTION_TIME, value); - } - } - - public int AttrLastVerbExecuted - { - get - { - return Props.GetProperty(OutlookConstants.PR_LAST_VERB_EXECUTED); - } - set - { - Props.SetProperty(OutlookConstants.PR_LAST_VERB_EXECUTED, value); - } - } - public object GetProperty(string property) { try diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/SearchWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/SearchWrapper.cs index 440aa03..1e26dae 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/SearchWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/SearchWrapper.cs @@ -19,12 +19,12 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Microsoft.Office.Interop.Outlook; using Acacia.Utils; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.Stubs.OutlookWrappers { - class SearchWrapper : ISearch + class SearchWrapper : ComWrapper, ISearch where ItemType : IItem { private interface SearchTerm @@ -151,13 +151,23 @@ namespace Acacia.Stubs.OutlookWrappers } private readonly List terms = new List(); - private readonly Items _items; + private NSOutlook.Items _items; - public SearchWrapper(Items items) + /// + /// Constructor. + /// + /// The items to search. The new object takes ownership + public SearchWrapper(NSOutlook.Items items) { this._items = items; } + protected override void DoRelease() + { + ComRelease.Release(_items); + _items = null; + } + public ISearchOperator AddOperator(SearchOperator oper) { SearchOperatorImpl so = new SearchOperatorImpl(oper); @@ -176,11 +186,13 @@ namespace Acacia.Stubs.OutlookWrappers { List values = new List(); string filter = MakeFilter(); + object value = _items.Find(filter); while(value != null) { if (values.Count < maxResults) { + // Wrap and add if it returns an object. If not, WrapOrDefault will release it ItemType wrapped = Mapping.WrapOrDefault(value); if (wrapped != null) { @@ -189,6 +201,7 @@ namespace Acacia.Stubs.OutlookWrappers } else { + // Release if not returned. Keep looping to release any others ComRelease.Release(value); } value = _items.FindNext(); @@ -198,6 +211,7 @@ namespace Acacia.Stubs.OutlookWrappers public ItemType SearchOne() { + // Wrap manages com object in value object value = _items.Find(MakeFilter()); if (value == null) return default(ItemType); diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StorageItemWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StorageItemWrapper.cs index c148bf1..e0ea714 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StorageItemWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StorageItemWrapper.cs @@ -15,31 +15,44 @@ /// Consult LICENSE file for details using Acacia.Utils; -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using NSOutlook = Microsoft.Office.Interop.Outlook; + namespace Acacia.Stubs.OutlookWrappers { - public class StorageItemWrapper : OutlookItemWrapper, IStorageItem + public class StorageItemWrapper : OutlookItemWrapper, IStorageItem { - public StorageItemWrapper(StorageItem item) + public StorageItemWrapper(NSOutlook.StorageItem item) : base(item) { } - protected override PropertyAccessor GetPropertyAccessor() + #region Wrapper methods + + protected override NSOutlook.UserProperties GetUserProperties() + { + return _item.UserProperties; + } + + protected override NSOutlook.PropertyAccessor GetPropertyAccessor() { return _item.PropertyAccessor; } - public override string ToString() { return "StorageItem"; } + public override string ToString() + { + return "StorageItem"; + } - #region Properties + #endregion + + #region IItem implementation public string Body { @@ -53,45 +66,75 @@ namespace Acacia.Stubs.OutlookWrappers set { _item.Subject = value; } } - public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } } - // TODO: release needed - public string StoreId { get { return _item.Parent?.Store?.StoreID; } } - public string StoreDisplayName { get { return _item.Parent?.Store?.DisplayName; } } - - #endregion - - #region Methods - - protected override UserProperties GetUserProperties() - { - return _item.UserProperties; - } - - public void Delete() { _item.Delete(); } public void Save() { _item.Save(); } #endregion + #region IBase implementation + + public string EntryId { get { return _item.EntryID; } } + public IFolder Parent { - get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } + get + { + // The wrapper manages the returned folder + return Mapping.Wrap(_item.Parent as NSOutlook.Folder); + } } + public string ParentEntryId { get { - Folder parent = _item.Parent; - try + using (ComRelease com = new ComRelease()) { + NSOutlook.Folder parent = com.Add(_item.Parent); return parent?.EntryID; } - finally - { - ComRelease.Release(parent); - } } } - public string EntryId { get { return _item.EntryID; } } + public IStore Store + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + return StoreWrapper.Wrap(parent?.Store); + } + } + } + + public string StoreId + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + NSOutlook.Store store = com.Add(parent?.Store); + return store.StoreID; + } + } + } + + public string StoreDisplayName + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + NSOutlook.Store store = com.Add(parent?.Store); + return store.StoreID; + } + } + } + + public void Delete() { _item.Delete(); } + + #endregion } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StoreWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StoreWrapper.cs index e17b4c4..30f1241 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StoreWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StoreWrapper.cs @@ -19,21 +19,21 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Microsoft.Office.Interop.Outlook; using Acacia.Utils; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.Stubs.OutlookWrappers { public class StoreWrapper : ComWrapper, IStore { - public static IStore Wrap(Store store) + public static IStore Wrap(NSOutlook.Store store) { return store == null ? null : new StoreWrapper(store); } - private Store _store; + private NSOutlook.Store _store; - private StoreWrapper(Store store) + private StoreWrapper(NSOutlook.Store store) { this._store = store; } @@ -46,21 +46,20 @@ namespace Acacia.Stubs.OutlookWrappers public IFolder GetRootFolder() { - return new FolderWrapper((Folder)_store.GetRootFolder()); + // FolderWrapper manages the returned Folder + return new FolderWrapper((NSOutlook.Folder)_store.GetRootFolder()); } public IItem GetItemFromID(string id) { - NameSpace nmspace = _store.Session; - try - { + using (ComRelease com = new ComRelease()) + { + NSOutlook.NameSpace nmspace = com.Add(_store.Session); + + // Get the item; the wrapper manages it object o = nmspace.GetItemFromID(id); return Mapping.Wrap(o); } - finally - { - ComRelease.Release(nmspace); - } } public string DisplayName { get { return _store.DisplayName; } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/TaskItemWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/TaskItemWrapper.cs index cc05464..833f7a1 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/TaskItemWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/TaskItemWrapper.cs @@ -15,31 +15,44 @@ /// Consult LICENSE file for details using Acacia.Utils; -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using NSOutlook = Microsoft.Office.Interop.Outlook; + namespace Acacia.Stubs.OutlookWrappers { - public class TaskItemWrapper : OutlookItemWrapper, ITaskItem + public class TaskItemWrapper : OutlookItemWrapper, ITaskItem { - internal TaskItemWrapper(TaskItem item) + internal TaskItemWrapper(NSOutlook.TaskItem item) : base(item) { } - protected override PropertyAccessor GetPropertyAccessor() + #region Wrapper methods + + protected override NSOutlook.UserProperties GetUserProperties() + { + return _item.UserProperties; + } + + protected override NSOutlook.PropertyAccessor GetPropertyAccessor() { return _item.PropertyAccessor; } - public override string ToString() { return "Task: " + Subject; } + public override string ToString() + { + return "Task:" + Subject; + } - #region Properties + #endregion + + #region IItem implementation public string Body { @@ -50,48 +63,78 @@ namespace Acacia.Stubs.OutlookWrappers public string Subject { get { return _item.Subject; } - set { throw new NotSupportedException(); } + set { _item.Subject = value; } } - public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } } - // TODO: release needed - public string StoreId { get { return _item.Parent?.Store?.StoreID; } } - public string StoreDisplayName { get { return _item.Parent?.Store?.DisplayName; } } - - #endregion - - #region Methods - - protected override UserProperties GetUserProperties() - { - return _item.UserProperties; - } - - public void Delete() { _item.Delete(); } public void Save() { _item.Save(); } #endregion + #region IBase implementation + + public string EntryId { get { return _item.EntryID; } } + public IFolder Parent { - get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } + get + { + // The wrapper manages the returned folder + return Mapping.Wrap(_item.Parent as NSOutlook.Folder); + } } + public string ParentEntryId { get { - Folder parent = _item.Parent; - try + using (ComRelease com = new ComRelease()) { + NSOutlook.Folder parent = com.Add(_item.Parent); return parent?.EntryID; } - finally - { - ComRelease.Release(parent); - } } } - public string EntryId { get { return _item.EntryID; } } + public IStore Store + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + return StoreWrapper.Wrap(parent?.Store); + } + } + } + + public string StoreId + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + NSOutlook.Store store = com.Add(parent?.Store); + return store.StoreID; + } + } + } + + public string StoreDisplayName + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.Folder parent = com.Add(_item.Parent); + NSOutlook.Store store = com.Add(parent?.Store); + return store.StoreID; + } + } + } + + public void Delete() { _item.Delete(); } + + #endregion } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.cs index 640a8f0..c1fb633 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.cs @@ -19,8 +19,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Linq; -using Outlook = Microsoft.Office.Interop.Outlook; -using Office = Microsoft.Office.Core; using Acacia.Features; using System.Threading; using System.Windows.Forms; @@ -33,27 +31,22 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Reflection; using Acacia.Native; +using Acacia.Stubs; +using Acacia.Stubs.OutlookWrappers; namespace Acacia { public partial class ThisAddIn { - - public static ThisAddIn Instance + public static IAddIn Instance { get; private set; } + // TODO: remove? private Control _dispatcher; - public void InvokeUI(Action action) - { - // [ZP-992] For some reason using the dispatcher causes a deadlock - // since switching to UI-chunked tasks. Running directly works. - action(); - } - #region Features /// @@ -73,17 +66,6 @@ namespace Acacia private set; } - public FeatureType GetFeature() - where FeatureType : Feature - { - foreach(Feature feature in Features) - { - if (feature is FeatureType) - return (FeatureType)feature; - } - return default(FeatureType); - } - #region Startup / Shutdown private void ThisAddIn_Startup(object sender, System.EventArgs args) @@ -104,10 +86,10 @@ namespace Acacia return; } - Instance = this; + Instance = new AddInWrapper(this); // Set the culture info from Outlook's language setting rather than the OS setting - int lcid = Application.LanguageSettings.get_LanguageID(Office.MsoAppLanguageID.msoLanguageIDUI); + int lcid = Application.LanguageSettings.get_LanguageID(Microsoft.Office.Core.MsoAppLanguageID.msoLanguageIDUI); Thread.CurrentThread.CurrentUICulture = new CultureInfo(lcid); // Create a dispatcher @@ -122,7 +104,7 @@ namespace Acacia } // Create the watcher - Watcher = new ZPushWatcher(Application); + Watcher = new ZPushWatcher(Instance); OutlookUI.Watcher = Watcher; // Allow to features to register whatever they need @@ -176,6 +158,7 @@ namespace Acacia { try { + // TODO: is any management of Pages needed here? Pages.Add(new SettingsPage(Features.ToArray()), Properties.Resources.ThisAddIn_Title); } catch(System.Exception e) @@ -192,35 +175,6 @@ namespace Acacia #endregion - #region Misc helpers - - public void SendReceive() - { - Outlook.NameSpace session = Application.Session; - session.SendAndReceive(false); - ComRelease.Release(session); - } - - public void Restart() - { - // Can not use the assembly location, as that is in the GAC - string codeBase = Assembly.GetExecutingAssembly().CodeBase; - UriBuilder uri = new UriBuilder(codeBase); - string path = Uri.UnescapeDataString(uri.Path); - // Create the path to the restarter - path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(path), "OutlookRestarter.exe"); - - // Run that - Process process = new Process(); - process.StartInfo = new ProcessStartInfo(path, Environment.CommandLine); - process.Start(); - - // And close us - Application.Quit(); - } - - #endregion - #region Ribbons private OutlookUI _outlookUI; @@ -245,41 +199,6 @@ namespace Acacia } } - #region Window handle - - private class WindowHandle : IWin32Window - { - private IntPtr hWnd; - - public WindowHandle(IntPtr hWnd) - { - this.hWnd = hWnd; - } - - public IntPtr Handle - { - get - { - return hWnd; - } - } - } - - public IWin32Window Window - { - get - { - var win = Application.ActiveWindow() as IOleWindow; - if (win == null) - return null; - IntPtr hWnd; - win.GetWindow(out hWnd); - return new WindowHandle(hWnd); - } - } - - #endregion - protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject() { return OutlookUI; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs index 17dc99a..5088051 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs @@ -224,23 +224,25 @@ namespace Acacia.UI public List Lookup(string text, int max) { // Begin GAB lookup, search on full name or username - ISearch search = _gab.Contacts.Search(); - ISearchOperator oper = search.AddOperator(SearchOperator.Or); - oper.AddField("urn:schemas:contacts:cn").SetOperation(SearchOperation.Like, text + "%"); - oper.AddField("urn:schemas:contacts:customerid").SetOperation(SearchOperation.Like, text + "%"); - - // Fetch the results up to the limit. - // TODO: make limit a property - List users = new List(); - foreach (IContactItem result in search.Search(max)) + using (ISearch search = _gab.Contacts.Search()) { - using (result) - { - users.Add(new GABUser(result.FullName, result.CustomerID)); - } - } + ISearchOperator oper = search.AddOperator(SearchOperator.Or); + oper.AddField("urn:schemas:contacts:cn").SetOperation(SearchOperation.Like, text + "%"); + oper.AddField("urn:schemas:contacts:customerid").SetOperation(SearchOperation.Like, text + "%"); - return users; + // Fetch the results up to the limit. + // TODO: make limit a property + List users = new List(); + foreach (IContactItem result in search.Search(max)) + { + using (result) + { + users.Add(new GABUser(result.FullName, result.CustomerID)); + } + } + + return users; + } } public GABUser LookupExact(string username) diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookImageList.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookImageList.cs index 2347e02..048d413 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookImageList.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookImageList.cs @@ -128,7 +128,8 @@ namespace Acacia.UI.Outlook Images.ColorDepth = ColorDepth.Depth32Bit; Images.ImageSize = new Size(16, 16); - CommandBars cmdBars = ThisAddIn.Instance.Application.ActiveWindow().CommandBars; + // TODO: memory management + CommandBars cmdBars = ThisAddIn.Instance.RawApp.ActiveWindow().CommandBars; foreach (string id in icons) { IPictureDisp pict = cmdBars.GetImageMso(id, Images.ImageSize.Width, Images.ImageSize.Height); diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookUI.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookUI.cs index f889750..1f88a94 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookUI.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookUI.cs @@ -14,7 +14,6 @@ /// /// Consult LICENSE file for details -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Drawing; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.cs index 0e8d30f..68bc4a9 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.cs @@ -23,7 +23,6 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; -using Microsoft.Office.Interop.Outlook; namespace Acacia.UI { @@ -48,19 +47,20 @@ namespace Acacia.UI { get { - return ThisAddIn.Instance.Application; + return null; + // TODO return ThisAddIn.Instance.Application; } } - public OlObjectClass Class + public Microsoft.Office.Interop.Outlook.OlObjectClass Class { get { - return OlObjectClass.olApplication; + return Microsoft.Office.Interop.Outlook.OlObjectClass.olApplication; } } - public NameSpace Session + public Microsoft.Office.Interop.Outlook.NameSpace Session { get { @@ -68,7 +68,7 @@ namespace Acacia.UI } } - dynamic PropertyPageSite.Parent + dynamic Microsoft.Office.Interop.Outlook.PropertyPageSite.Parent { get { diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.cs index 7a128af..e921a73 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.cs @@ -25,11 +25,12 @@ using System.Threading.Tasks; using System.Windows.Forms; using System.Runtime.InteropServices; using Acacia.Features; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.UI { [ComVisible(true)] - public partial class SettingsPage : UserControl, Microsoft.Office.Interop.Outlook.PropertyPage + public partial class SettingsPage : UserControl, NSOutlook.PropertyPage { private readonly Dictionary _featuresDirty = new Dictionary(); @@ -78,8 +79,8 @@ namespace Acacia.UI Dirty = _featuresDirty.Values.Aggregate((a, b) => a | b); } - private Microsoft.Office.Interop.Outlook.PropertyPageSite _propertyPageSite; - public Microsoft.Office.Interop.Outlook.PropertyPageSite PropertyPageSite + private NSOutlook.PropertyPageSite _propertyPageSite; + public NSOutlook.PropertyPageSite PropertyPageSite { get { @@ -96,7 +97,8 @@ namespace Acacia.UI System.Reflection.MethodInfo methodInfo = oleObjectType.GetMethod("GetClientSite"); Object propertyPageSite = methodInfo.Invoke(this, null); - _propertyPageSite = (Microsoft.Office.Interop.Outlook.PropertyPageSite)propertyPageSite; + // TODO: does this need to be released? + _propertyPageSite = (NSOutlook.PropertyPageSite)propertyPageSite; } return _propertyPageSite; } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ComRelease.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ComRelease.cs index b20488d..5d089ab 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ComRelease.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ComRelease.cs @@ -55,6 +55,12 @@ namespace Acacia.Utils } } + public static void Release(params object[] objs) + { + foreach (object o in objs) + Release(o); + } + public static void Release(object o) { if (!Enabled) @@ -67,7 +73,7 @@ namespace Acacia.Utils Logger.Instance.TraceExtra(typeof(ComRelease), "Releasing object: {0:X} @ {1}", GetObjAddress(o), new System.Diagnostics.StackTrace()); } - Marshal.FinalReleaseComObject(o); + Marshal.ReleaseComObject(o); } private static long GetObjAddress(object o) diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/MailEvents.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/MailEvents.cs index 2008541..d2c6d5e 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/MailEvents.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/MailEvents.cs @@ -14,7 +14,6 @@ /// /// Consult LICENSE file for details -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; @@ -22,6 +21,7 @@ using System.Text; using System.Threading.Tasks; using Acacia.Stubs; using Acacia.Stubs.OutlookWrappers; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.Utils { @@ -47,8 +47,10 @@ namespace Acacia.Utils public event MailResponseEventHandler Respond; public event MailResponseEventHandler Reply; - private void OnReply(MailItem mail, MailItem response) + private void OnReply(NSOutlook.MailItem mail, NSOutlook.MailItem response) { + // TODO: check release of first item + // TODO: release if not sending event try { if ((Reply != null || Respond != null) && mail != null) @@ -70,8 +72,10 @@ namespace Acacia.Utils } public event MailResponseEventHandler ReplyAll; - private void OnReplyAll(MailItem mail, MailItem response) + private void OnReplyAll(NSOutlook.MailItem mail, NSOutlook.MailItem response) { + // TODO: check release of first item + // TODO: release if not sending event try { if ((ReplyAll != null || Respond != null) && mail != null) @@ -93,8 +97,10 @@ namespace Acacia.Utils } public event MailResponseEventHandler Forward; - private void OnForward(MailItem mail, MailItem response) + private void OnForward(NSOutlook.MailItem mail, NSOutlook.MailItem response) { + // TODO: check release of first item + // TODO: release if not sending event try { if ((Forward != null || Respond != null) && mail != null) @@ -116,8 +122,10 @@ namespace Acacia.Utils } public event MailEventHandler Read; - private void OnRead(MailItem mail) + private void OnRead(NSOutlook.MailItem mail) { + // TODO: check release of first item + // TODO: release if not sending event try { if (Read != null && mail != null) @@ -180,6 +188,7 @@ namespace Acacia.Utils { try { + // TODO: release item if event not sent if (ItemSend != null && item != null) { using (IMailItem wrapped = Mapping.WrapOrDefault(item, false)) @@ -199,93 +208,104 @@ namespace Acacia.Utils #region Implementation - public MailEvents(Application app) + public MailEvents(IAddIn app) { app.ItemLoad += OnItemLoad; app.ItemSend += OnItemSend; } - void OnItemLoad(object item) + private void OnItemLoad(object item) { - ItemEvents_10_Event hasEvents = item as ItemEvents_10_Event; + NSOutlook.ItemEvents_10_Event hasEvents = item as NSOutlook.ItemEvents_10_Event; if (hasEvents != null) { new MailEventHooker(hasEvents, this); } } - private class MailEventHooker + private class MailEventHooker : ComWrapper { - private readonly ItemEvents_10_Event item; - private readonly MailEvents events; + private NSOutlook.ItemEvents_10_Event _item; + private readonly MailEvents _events; + private int _id; + private static int nextId; - public MailEventHooker(ItemEvents_10_Event item, MailEvents events) + public MailEventHooker(NSOutlook.ItemEvents_10_Event item, MailEvents events) { - this.item = item; - this.events = events; + this._id = ++nextId; + this._item = item; + this._events = events; HookEvents(true); } + protected override void DoRelease() + { + Logger.Instance.Debug(this, "DoRelease: {0}", _id); + ComRelease.Release(_item); + _item = null; + } + private void HookEvents(bool add) { - ItemEvents_10_Event events = this.item; - if (add) { - events.BeforeDelete += HandleBeforeDelete; - events.Forward += HandleForward; - events.Read += HandleRead; - events.Reply += HandleReply; - events.ReplyAll += HandleReplyAll; - events.Unload += HandleUnload; - events.Write += HandleWrite; + _item.BeforeDelete += HandleBeforeDelete; + _item.Forward += HandleForward; + _item.Read += HandleRead; + _item.Reply += HandleReply; + _item.ReplyAll += HandleReplyAll; + _item.Unload += HandleUnload; + _item.Write += HandleWrite; } else { - events.BeforeDelete -= HandleBeforeDelete; - events.Forward -= HandleForward; - events.Read -= HandleRead; - events.Reply -= HandleReply; - events.ReplyAll -= HandleReplyAll; - events.Unload -= HandleUnload; - events.Write -= HandleWrite; + _item.BeforeDelete -= HandleBeforeDelete; + _item.Forward -= HandleForward; + _item.Read -= HandleRead; + _item.Reply -= HandleReply; + _item.ReplyAll -= HandleReplyAll; + _item.Unload -= HandleUnload; + _item.Write -= HandleWrite; } } private void HandleBeforeDelete(object item, ref bool cancel) { - events.OnBeforeDelete(item, ref cancel); + _events.OnBeforeDelete(item, ref cancel); } private void HandleForward(object response, ref bool cancel) { - events.OnForward(item as MailItem, response as MailItem); + _events.OnForward(_item as NSOutlook.MailItem, response as NSOutlook.MailItem); } private void HandleRead() { - events.OnRead(item as MailItem); + _events.OnRead(_item as NSOutlook.MailItem); } private void HandleReply(object response, ref bool cancel) { - events.OnReply(item as MailItem, response as MailItem); + _events.OnReply(_item as NSOutlook.MailItem, response as NSOutlook.MailItem); } private void HandleReplyAll(object response, ref bool cancel) { - events.OnReplyAll(item as MailItem, response as MailItem); + _events.OnReplyAll(_item as NSOutlook.MailItem, response as NSOutlook.MailItem); } private void HandleUnload() { + Logger.Instance.Debug(this, "HandleUnload: {0}", _id); // All events must be unhooked on unload, otherwise a resource leak is created. HookEvents(false); + Dispose(); } private void HandleWrite(ref bool cancel) { - events.OnWrite(item, ref cancel); + Logger.Instance.Debug(this, "HandleWrite: {0}", _id); + _events.OnWrite(_item, ref cancel); } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/OutlookRegistryUtils.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/OutlookRegistryUtils.cs index 4d61861..4a7110a 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/OutlookRegistryUtils.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/OutlookRegistryUtils.cs @@ -29,7 +29,7 @@ namespace Acacia.Utils public static RegistryKey OpenOutlookKey(string suffix = null, RegistryKeyPermissionCheck permissions = RegistryKeyPermissionCheck.Default) { // Determine the base path - string[] versionParts = ThisAddIn.Instance.Application.Version.Split('.'); + string[] versionParts = ThisAddIn.Instance.Version.Split('.'); string versionString = versionParts[0] + "." + versionParts[1]; string baseKeyPath = string.Format(OutlookConstants.REG_KEY_BASE, versionString); return RegistryUtil.OpenKeyImpl(baseKeyPath, suffix, false, permissions); diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Util.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Util.cs index e565bda..0803c1a 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Util.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Util.cs @@ -15,8 +15,8 @@ /// Consult LICENSE file for details using Acacia.ZPush; -using Microsoft.Office.Interop.Outlook; using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -44,5 +44,40 @@ namespace Acacia.Utils return a.Equals(b); } + + public static IEnumerable RawEnum(this IEnumerable source, bool releaseItems = true) + { + foreach (T item in source) + { + try + { + yield return item; + } + finally + { + if (releaseItems) + ComRelease.Release(item); + } + } + ComRelease.Release(source); + } + + // TODO: check this + public static IEnumerable RawEnum(this IEnumerable source, bool releaseItems = true) + { + foreach (object item in source) + { + try + { + yield return item; + } + finally + { + if (releaseItems) + ComRelease.Release(item); + } + } + ComRelease.Release(source); + } } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/FolderRegistration.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/FolderRegistration.cs index 402b985..d3f6938 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/FolderRegistration.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/FolderRegistration.cs @@ -16,7 +16,6 @@ using Acacia.Features; using Acacia.Stubs; -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs index d3c89c9..6f4d531 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs @@ -17,7 +17,6 @@ using Acacia.Stubs; using Acacia.Utils; using Acacia.ZPush.Connect; -using Microsoft.Office.Interop.Outlook; using Microsoft.Win32; using System; using System.Collections.Concurrent; @@ -28,6 +27,7 @@ using System.Security; using System.Text; using System.Threading; using System.Threading.Tasks; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.ZPush { @@ -37,14 +37,16 @@ namespace Acacia.ZPush #region Miscellaneous private readonly string _regPath; - private readonly Store _store; + + // TODO: this should probably be wrapped. Make ZPushAccount ComWrapper? + private readonly NSOutlook.Store _store; /// /// Constructor. /// /// They registry key containing the account settings. /// The store this account represents. - internal ZPushAccount(string regPath, Store store) + internal ZPushAccount(string regPath, NSOutlook.Store store) { this._regPath = regPath; this._store = store; @@ -72,7 +74,8 @@ namespace Acacia.ZPush /// public void SendReceive() { - ThisAddIn.Instance.SendReceive(); + // TODO: ThisAddIn.Instance.SendReceive(); + throw new NotImplementedException(); } #endregion @@ -80,7 +83,8 @@ namespace Acacia.ZPush #region Properties [Browsable(false)] - public Store Store + // TODO: remove this + public NSOutlook.Store Store { get { diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccounts.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccounts.cs index d563775..60a6d7d 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccounts.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccounts.cs @@ -16,13 +16,13 @@ using Acacia.Stubs; using Acacia.Utils; -using Microsoft.Office.Interop.Outlook; using Microsoft.Win32; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.ZPush { @@ -33,9 +33,10 @@ namespace Acacia.ZPush public class ZPushAccounts { private readonly ZPushWatcher _watcher; - private readonly Application _app; - private readonly NameSpace _session; - private readonly Stores _stores; + // TODO: wrap these + private readonly NSOutlook.Application _app; + private readonly NSOutlook.NameSpace _session; + private readonly NSOutlook.Stores _stores; /// /// ZPushAccounts indexed by SMTPAddress. Null values are not allowed. @@ -48,7 +49,7 @@ namespace Acacia.ZPush /// private readonly Dictionary _accountsByStoreId = new Dictionary(); - public ZPushAccounts(ZPushWatcher watcher, Application app) + public ZPushAccounts(ZPushWatcher watcher, NSOutlook.Application app) { this._watcher = watcher; this._app = app; @@ -66,7 +67,7 @@ namespace Acacia.ZPush { // Process existing accounts using (ComRelease com = new ComRelease()) - foreach (Account account in com.Add(_session.Accounts)) + foreach (NSOutlook.Account account in com.Add(_session.Accounts)) { Tasks.Task(null, "AccountCheck", () => { @@ -113,7 +114,7 @@ namespace Acacia.ZPush { // Collect all the store ids HashSet stores = new HashSet(); - foreach (Store store in _stores) + foreach (NSOutlook.Store store in _stores) { try { @@ -184,22 +185,18 @@ namespace Acacia.ZPush return null; } - public ZPushAccount GetAccount(MAPIFolder folder) + public ZPushAccount GetAccount(NSOutlook.MAPIFolder folder) { - ZPushAccount zpush = null; - Store store = folder.Store; - try + using (ComRelease com = new ComRelease()) { + ZPushAccount zpush = null; + NSOutlook.Store store = com.Add(folder.Store); string storeId = store?.StoreID; if (storeId == null) return null; _accountsByStoreId.TryGetValue(storeId, out zpush); return zpush; } - finally - { - ComRelease.Release(store); - } } public ZPushAccount GetAccount(string smtpAddress) @@ -214,12 +211,12 @@ namespace Acacia.ZPush /// /// The account. This function will release the handle /// The ZPushAccount, or null if not a ZPush account. - private ZPushAccount GetAccount(Account account) + private ZPushAccount GetAccount(NSOutlook.Account account) { try { // Only EAS accounts can be zpush accounts - if (account.AccountType != OlAccountType.olEas) + if (account.AccountType != NSOutlook.OlAccountType.olEas) return null; // Check for a cached value @@ -239,14 +236,14 @@ namespace Acacia.ZPush /// /// Event handler for Stores.StoreAdded event. /// - internal void StoreAdded(Store s) + private void StoreAdded(NSOutlook.Store s) { try { using (ComRelease com = new ComRelease()) { Logger.Instance.Trace(this, "StoreAdded: {0}", s.StoreID); - foreach (Store store in com.Add(com.Add(_app.Session).Stores)) + foreach (NSOutlook.Store store in com.Add(com.Add(_app.Session).Stores)) { if (!_accountsByStoreId.ContainsKey(store.StoreID)) { @@ -287,11 +284,12 @@ namespace Acacia.ZPush /// /// Creates the ZPushAccount for the account, from the registry values. /// - /// The account. + /// The account. The caller is responsible for releasing this. /// The associated ZPushAccount /// If the registry key cannot be found - private ZPushAccount CreateFromRegistry(Account account) + private ZPushAccount CreateFromRegistry(NSOutlook.Account account) { + // TODO: check that caller releases account everywhere using (ComRelease com = new ComRelease()) using (RegistryKey baseKey = FindRegistryKey(account)) { @@ -302,7 +300,7 @@ namespace Acacia.ZPush string storeId = ZPushAccount.GetStoreId(baseKey.Name); // Find the store - Store store = _app.Session.GetStoreFromID(storeId); + NSOutlook.Store store = _app.Session.GetStoreFromID(storeId); // Done, create and register ZPushAccount zpush = new ZPushAccount(baseKey.Name, store); @@ -316,7 +314,7 @@ namespace Acacia.ZPush /// /// The store /// The ZPushAccount, or null if no account is associated with the store - private ZPushAccount TryCreateFromRegistry(Store store) + private ZPushAccount TryCreateFromRegistry(NSOutlook.Store store) { using (RegistryKey baseKey = FindRegistryKey(store)) { @@ -330,7 +328,7 @@ namespace Acacia.ZPush private RegistryKey OpenBaseKey() { - NameSpace session = _app.Session; + NSOutlook.NameSpace session = _app.Session; string path = string.Format(OutlookConstants.REG_SUBKEY_ACCOUNTS, session.CurrentProfileName); ComRelease.Release(session); return OutlookRegistryUtils.OpenOutlookKey(path); @@ -340,7 +338,7 @@ namespace Acacia.ZPush /// Finds the registry key for the account. /// /// The registry key, or null if it cannot be found - private RegistryKey FindRegistryKey(Account account) + private RegistryKey FindRegistryKey(NSOutlook.Account account) { // Find the registry key by email adddress using (RegistryKey key = OpenBaseKey()) @@ -365,7 +363,7 @@ namespace Acacia.ZPush /// Finds the registry key for the account associated with the store. /// /// The registry key, or null if it cannot be found - private RegistryKey FindRegistryKey(Store store) + private RegistryKey FindRegistryKey(NSOutlook.Store store) { // Find the registry key by store id using (RegistryKey key = OpenBaseKey()) diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannel.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannel.cs index b129e74..f78a25f 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannel.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannel.cs @@ -14,7 +14,6 @@ /// /// Consult LICENSE file for details -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannels.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannels.cs index 07684b2..0372ec0 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannels.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannels.cs @@ -14,7 +14,6 @@ /// /// Consult LICENSE file for details -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushFolder.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushFolder.cs index fb340f0..23eed64 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushFolder.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushFolder.cs @@ -16,20 +16,20 @@ using Acacia.Stubs; using Acacia.Stubs.OutlookWrappers; -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.Linq; using Acacia.Utils; using System.Text; using System.Threading.Tasks; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.ZPush { public class ZPushFolder : FolderWrapper { - private readonly Items _items; - private readonly Folders _subFolders; + private readonly NSOutlook.Items _items; + private readonly NSOutlook.Folders _subFolders; private ZPushFolder _parent; private readonly ZPushWatcher _watcher; private List _itemsWatchers = new List(); @@ -39,14 +39,14 @@ namespace Acacia.ZPush /// protected readonly Dictionary _children = new Dictionary(); - internal ZPushFolder(ZPushWatcher watcher, Folder folder) + internal ZPushFolder(ZPushWatcher watcher, NSOutlook.Folder folder) : this(watcher, null, folder) { Initialise(); } - private ZPushFolder(ZPushWatcher watcher, ZPushFolder parent, Folder folder) + private ZPushFolder(ZPushWatcher watcher, ZPushFolder parent, NSOutlook.Folder folder) : base(folder) { @@ -66,7 +66,7 @@ namespace Acacia.ZPush _watcher.OnFolderDiscovered(this); // Recurse the children - foreach (Folder subfolder in this._subFolders) + foreach (NSOutlook.Folder subfolder in this._subFolders) { Tasks.Task(null, "WatchChild", () => WatchChild(subfolder)); } @@ -140,7 +140,7 @@ namespace Acacia.ZPush /// Watches the child folder. /// /// The child folder. Ownership will be taken. - private void WatchChild(Folder child) + private void WatchChild(NSOutlook.Folder child) { if (!_children.ContainsKey(child.EntryID)) { @@ -167,12 +167,12 @@ namespace Acacia.ZPush #region Event handlers - private void SubFolders_FolderAdd(MAPIFolder folder) + private void SubFolders_FolderAdd(NSOutlook.MAPIFolder folder) { try { Logger.Instance.Debug(this, "Folder added in {0}: {1}", this._item.Name, folder.Name); - WatchChild((Folder)folder); + WatchChild((NSOutlook.Folder)folder); } catch (System.Exception e) { Logger.Instance.Error(this, "Exception in SubFolders_FolderAdd: {0}: {1}", Name, e); } } @@ -187,7 +187,7 @@ namespace Acacia.ZPush // but that doesn't fire if a folder was removed on the server. // Hence, fetch all the remaining folder ids, and remove any folder that no longer exists. HashSet remaining = new HashSet(); - foreach (Folder child in _subFolders) + foreach (NSOutlook.Folder child in _subFolders) { try { @@ -219,7 +219,7 @@ namespace Acacia.ZPush catch (System.Exception e) { Logger.Instance.Error(this, "Exception in SubFolders_FolderRemove: {0}: {1}", Name, e); } } - private void SubFolders_FolderChange(MAPIFolder folder) + private void SubFolders_FolderChange(NSOutlook.MAPIFolder folder) { try { @@ -236,7 +236,7 @@ namespace Acacia.ZPush // Create it now // This will send a discover notification if required, which is just as good as a change notification Logger.Instance.Debug(this, "Folder change on unreported folder in {0}: {1}, {2}, {3}", this._item.Name, folder.Name, folder.EntryID, folder.Store.DisplayName); - WatchChild((Folder)folder); + WatchChild((NSOutlook.Folder)folder); } } catch (System.Exception e) { Logger.Instance.Error(this, "Exception in SubFolders_FolderChange: {0}: {1}", Name, e); } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs index 7674a63..faa31f2 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs @@ -17,13 +17,13 @@ using Acacia.Stubs; using Acacia.Stubs.OutlookWrappers; using Acacia.Utils; -using Microsoft.Office.Interop.Outlook; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.ZPush { @@ -33,7 +33,7 @@ namespace Acacia.ZPush /// TODO: merge with Store where possible public class ZPushLocalStore : ComWrapper { - private Store _store; + private NSOutlook.Store _store; public IFolder RootFolder { @@ -45,7 +45,7 @@ namespace Acacia.ZPush public string StoreId { get { return _store.StoreID; } } - private ZPushLocalStore(Store store) + private ZPushLocalStore(NSOutlook.Store store) { this._store = store; HideAllFolders(); @@ -69,7 +69,7 @@ namespace Acacia.ZPush // Hide the folders that are not custom folders using (ComRelease com = new ComRelease()) { - foreach (Folder sub in com.Add(com.Add(_store.GetRootFolder()).Folders)) + foreach (NSOutlook.Folder sub in com.Add(com.Add(_store.GetRootFolder()).Folders)) { using (IFolder wrapped = Mapping.Wrap(sub)) { @@ -80,7 +80,7 @@ namespace Acacia.ZPush } } - public static ZPushLocalStore GetInstance(Application App) + public static ZPushLocalStore GetInstance(IAddIn addIn) { try { @@ -94,7 +94,7 @@ namespace Acacia.ZPush Logger.Instance.Debug(typeof(ZPushLocalStore), "Opening store with prefix {0}", prefix); // See if a store with this prefix exists - Store store = FindInstance(App, prefix); + NSOutlook.Store store = FindInstance(addIn, prefix); if (store != null) return new ZPushLocalStore(store); @@ -114,8 +114,8 @@ namespace Acacia.ZPush // Path found, create the store Logger.Instance.Info(typeof(ZPushLocalStore), "Creating new store: {0}", path); - App.Session.AddStore(path); - store = App.Session.Stores[App.Session.Stores.Count]; + addIn.RawApp.Session.AddStore(path); + store = addIn.RawApp.Session.Stores[addIn.RawApp.Session.Stores.Count]; Logger.Instance.Debug(typeof(ZPushLocalStore), "Created new store: {0}", store.FilePath); // Set the display name @@ -134,9 +134,9 @@ namespace Acacia.ZPush } } - private static Store FindInstance(Application app, string prefix) + private static NSOutlook.Store FindInstance(IAddIn addIn, string prefix) { - foreach (Store store in app.Session.Stores) + foreach (NSOutlook.Store store in addIn.RawApp.Session.Stores) { if (store.IsDataFileStore && store.FilePath.StartsWith(prefix)) { @@ -151,17 +151,17 @@ namespace Acacia.ZPush { using (ComRelease com = new ComRelease()) { - MAPIFolder f = _store.GetDefaultFolder(OlDefaultFolders.olFolderDeletedItems); + NSOutlook.MAPIFolder f = _store.GetDefaultFolder(NSOutlook.OlDefaultFolders.olFolderDeletedItems); if (f != null) { com.Add(f); // Normal enumeration fails when deleting. Do it like this. - Folders folders = com.Add(f.Folders); + NSOutlook.Folders folders = com.Add(f.Folders); for (int i = folders.Count; i > 0; --i) com.Add(folders[i]).Delete(); - Items items = com.Add(f.Items); + NSOutlook.Items items = com.Add(f.Items); for (int i = items.Count; i > 0; --i) com.Add(items[i]).Delete(); } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushSync.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushSync.cs index 5dabaa0..dadfb89 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushSync.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushSync.cs @@ -23,6 +23,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.ZPush { @@ -76,7 +77,7 @@ namespace Acacia.ZPush #region Setup - private readonly Microsoft.Office.Interop.Outlook.SyncObject _syncObject; + private readonly NSOutlook.SyncObject _syncObject; private readonly Timer _timer; private ZPushWatcher _watcher; private bool _started; @@ -85,7 +86,7 @@ namespace Acacia.ZPush public readonly bool Enabled; public readonly TimeSpan Period; - public ZPushSync(ZPushWatcher watcher, Microsoft.Office.Interop.Outlook.Application app) + public ZPushSync(ZPushWatcher watcher, NSOutlook.Application app) { // Get the settings Enabled = GlobalOptions.INSTANCE.ZPushSync; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushWatcher.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushWatcher.cs index dc536c5..c4c6588 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushWatcher.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushWatcher.cs @@ -19,7 +19,6 @@ using Acacia.Stubs; using Acacia.Stubs.OutlookWrappers; using Acacia.Utils; using Acacia.ZPush.Connect; -using Microsoft.Office.Interop.Outlook; using Microsoft.Win32; using System; using System.Collections.Generic; @@ -27,6 +26,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.ZPush { @@ -37,22 +37,22 @@ namespace Acacia.ZPush /// public class ZPushWatcher { - private readonly Application _app; + private readonly NSOutlook.Application _app; public readonly ZPushAccounts Accounts; public readonly ZPushSync Sync; - private Explorer _explorer; + private NSOutlook.Explorer _explorer; #region Setup - public ZPushWatcher(Application app) + public ZPushWatcher(IAddIn addIn) { - this._app = app; - Sync = new ZPushSync(this, app); - Accounts = new ZPushAccounts(this, app); + this._app = addIn.RawApp; + Sync = new ZPushSync(this, _app); + Accounts = new ZPushAccounts(this, _app); // Need to keep a link to keep receiving events - _explorer = app.ActiveExplorer(); + _explorer = _app.ActiveExplorer(); _explorer.SelectionChange += Explorer_SelectionChange; } @@ -164,6 +164,7 @@ namespace Acacia.ZPush } else { + // TODO ThisAddIn.Instance.InvokeUI(() => { Logger.Instance.Warning(this, "Password not available for account: {0}", account); @@ -206,7 +207,7 @@ namespace Acacia.ZPush { if (ActiveFolderChange != null) { - MAPIFolder active = _explorer.CurrentFolder; + NSOutlook.MAPIFolder active = _explorer.CurrentFolder; if (active != null) { using (IFolder folder = Mapping.Wrap(active)) @@ -237,7 +238,7 @@ namespace Acacia.ZPush if (_explorer.CurrentFolder == null) return null; - MAPIFolder folder = _explorer.CurrentFolder; + NSOutlook.MAPIFolder folder = _explorer.CurrentFolder; try { return Accounts.GetAccount(folder); @@ -276,7 +277,7 @@ namespace Acacia.ZPush private void HandleFolderWatchers(ZPushAccount account) { // We need to keep the object alive to keep receiving events - _rootFolder = new ZPushFolder(this, (Folder)account.Store.GetRootFolder()); + _rootFolder = new ZPushFolder(this, (NSOutlook.Folder)account.Store.GetRootFolder()); } public void WatchFolder(FolderRegistration folder, FolderEventHandler handler, FolderEventHandler changedHandler = null) @@ -341,12 +342,12 @@ namespace Acacia.ZPush watcher.OnChanged(folder); } - internal bool ShouldFolderBeWatched(ZPushFolder parent, Folder child) + internal bool ShouldFolderBeWatched(ZPushFolder parent, NSOutlook.Folder child) { if (parent.IsAtDepth(0)) { // Special mail folders cause issues, they are disallowed - if (child.DefaultItemType != OlItemType.olMailItem) + if (child.DefaultItemType != NSOutlook.OlItemType.olMailItem) return true; return !IsBlackListedMailFolder(child); @@ -354,23 +355,23 @@ namespace Acacia.ZPush return true; } - private static readonly OlDefaultFolders[] BLACKLISTED_MAIL_FOLDERS = + private static readonly NSOutlook.OlDefaultFolders[] BLACKLISTED_MAIL_FOLDERS = { - OlDefaultFolders.olFolderOutbox, - OlDefaultFolders.olFolderDrafts, - OlDefaultFolders.olFolderConflicts, - OlDefaultFolders.olFolderSyncIssues, - OlDefaultFolders.olFolderRssFeeds, - OlDefaultFolders.olFolderManagedEmail + NSOutlook.OlDefaultFolders.olFolderOutbox, + NSOutlook.OlDefaultFolders.olFolderDrafts, + NSOutlook.OlDefaultFolders.olFolderConflicts, + NSOutlook.OlDefaultFolders.olFolderSyncIssues, + NSOutlook.OlDefaultFolders.olFolderRssFeeds, + NSOutlook.OlDefaultFolders.olFolderManagedEmail }; - private static bool IsBlackListedMailFolder(Folder folder) + private static bool IsBlackListedMailFolder(NSOutlook.Folder folder) { string entryId = folder.EntryID; using (ComRelease com = new ComRelease()) { - Store store = com.Add(folder.Store); - foreach(OlDefaultFolders defaultFolder in BLACKLISTED_MAIL_FOLDERS) + NSOutlook.Store store = com.Add(folder.Store); + foreach(NSOutlook.OlDefaultFolders defaultFolder in BLACKLISTED_MAIL_FOLDERS) { try {