First batch of Com verification update

This commit is contained in:
Patrick Simpson 2017-02-08 15:40:48 +01:00
parent ac56b301b4
commit a450f6e616
52 changed files with 1279 additions and 764 deletions

View File

@ -279,7 +279,9 @@
<Compile Include="Native\MAPI.cs" />
<Compile Include="Native\IOleWindow.cs" />
<Compile Include="OutlookConstants.cs" />
<Compile Include="Stubs\IAddIn.cs" />
<Compile Include="Stubs\IComWrapper.cs" />
<Compile Include="Stubs\OutlookWrappers\AddInWrapper.cs" />
<Compile Include="Stubs\OutlookWrappers\OutlookItemWrapper.cs" />
<Compile Include="UI\Outlook\OutlookImageList.cs" />
<Compile Include="UI\Outlook\RibbonToggleButton.cs" />

View File

@ -101,9 +101,9 @@ namespace Acacia.Features.DebugSupport
}
// Add Add-ins
foreach (COMAddIn addin in ThisAddIn.Instance.Application.COMAddIns)
foreach (KeyValuePair<string,string> addin in ThisAddIn.Instance.COMAddIns)
{
PropertyDescriptor p = new CustomPropertyDescriptor<string, DebugInfo>(addin.ProgId, DebugCategory.AddIns, addin.Description);
PropertyDescriptor p = new CustomPropertyDescriptor<string, DebugInfo>(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;
}
}

View File

@ -13,8 +13,6 @@
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
///
/// Consult LICENSE file for details
using Microsoft.Office.Interop.Outlook;
using System;
using System.Collections.Generic;
using Acacia.Features.ReplyFlags;

View File

@ -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;
}
}

View File

@ -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<IContactItem> search = handler.Contacts.Search<IContactItem>();
search.AddField("urn:schemas:contacts:email1").SetOperation(SearchOperation.Equal, username);
using (IItem result = search.SearchOne())
using (ISearch<IContactItem> search = handler.Contacts.Search<IContactItem>())
{
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;
}
}
}
}

View File

@ -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
/// <param name="cancel"></param>
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;

View File

@ -262,16 +262,18 @@ namespace Acacia.Features.GAB
try
{
// Delete the old contacts from this chunk
ISearch<IItem> search = Contacts.Search<IItem>();
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<IItem> search = Contacts.Search<IItem>())
{
// 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<IItem> search = Contacts.Search<IItem>();
search.AddField(PROP_GAB_ID, true).SetOperation(SearchOperation.Equal, id);
return search.SearchOne();
using (ISearch<IItem> search = Contacts.Search<IItem>())
{
search.AddField(PROP_GAB_ID, true).SetOperation(SearchOperation.Equal, id);
return search.SearchOne();
}
}
private void SetItemStandard(IItem item, string id, Dictionary<string, object> value, ChunkIndex index)

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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())
{

View File

@ -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<Feature> Features { get; }
IEnumerable<KeyValuePair<string,string>> 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
/// <summary>
/// Sends and receives all accounts.
/// </summary>
void SendReceive();
/// <summary>
/// Restarts the application
/// </summary>
void Restart();
void InvokeUI(Action action);
IFolder GetFolderFromID(string folderId);
FeatureType GetFeature<FeatureType>()
where FeatureType : Feature;
}
}

View File

@ -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; }
/// <summary>
/// Quick accessor to Store.Id, to prevent allocation a wrapper for it.
/// Quick accessor to Store.Id, to prevent allocating a wrapper for it.
/// </summary>
string StoreId { get; }
/// <summary>
/// Quick accessor to Store.DisplayName, to prevent allocation a wrapper for it.
/// Quick accessor to Store.DisplayName, to prevent allocating a wrapper for it.
/// </summary>
string StoreDisplayName { get; }
#endregion
#region Methods
void Delete();
string ToString();
#endregion
}
}

View File

@ -27,6 +27,11 @@ namespace Acacia.Stubs
string DLName { get; set; }
string SMTPAddress { get; set; }
/// <summary>
/// Adds a member to the distribution list.
/// </summary>
/// <param name="item">The item. This is not disposed or released.</param>
/// <exception cref="NotSupportedException">If the item is not a contact or distribution list</exception>
void AddMember(IItem item);
}
}

View File

@ -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);
}
}

View File

@ -53,7 +53,7 @@ namespace Acacia.Stubs
ISearchField AddField(string name, bool isUserField = false);
}
public interface ISearch<ItemType> : ISearchOperator
public interface ISearch<ItemType> : ISearchOperator, IDisposable
where ItemType : IItem
{
ISearchOperator AddOperator(SearchOperator oper);

View File

@ -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<Feature> Features { get { return _thisAddIn.Features; } }
public IEnumerable<KeyValuePair<string, string>> COMAddIns
{
get
{
Microsoft.Office.Core.COMAddIns addIns = _app.COMAddIns;
try
{
foreach(Microsoft.Office.Core.COMAddIn comAddin in addIns)
{
try
{
yield return new KeyValuePair<string, string>(comAddin.ProgId, comAddin.Description);
}
finally
{
ComRelease.Release(comAddin);
}
}
}
finally
{
ComRelease.Release(addIns);
}
}
}
public string Version
{
get { return _app.Version; }
}
public FeatureType GetFeature<FeatureType>()
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<IFolder>(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
}
}

View File

@ -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);
}
}
}

View File

@ -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<AppointmentItem>, IAppointmentItem, IZPushItem
class AppointmentItemWrapper : OutlookItemWrapper<NSOutlook.AppointmentItem>, 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<IFolder>(_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
}
}

View File

@ -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();
}
}

View File

@ -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<ContactItem>, IContactItem
class ContactItemWrapper : OutlookItemWrapper<NSOutlook.ContactItem>, 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<IFolder>(_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

View File

@ -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<DistListItem>, IDistributionList
class DistributionListWrapper : OutlookItemWrapper<NSOutlook.DistListItem>, 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<IFolder>(_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
}
}

View File

@ -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<Folder>, IFolder
public class FolderWrapper : OutlookWrapper<NSOutlook.Folder>, 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<IFolder>(_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<ItemType> : IEnumerator<ItemType>
#region Enumeration
public class ItemsEnumerator<ItemType> : ComWrapper, IEnumerator<ItemType>
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<ItemType> : IEnumerable<ItemType>
public class ItemsEnumerable<ItemType> : IEnumerable<ItemType>
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<ItemType> GetEnumerator()
{
return new IItemsEnumerator<ItemType>(_folder, _field, _descending);
return new ItemsEnumerator<ItemType>(_folder, _field, _descending);
}
IEnumerator IEnumerable.GetEnumerator()
@ -221,15 +229,17 @@ namespace Acacia.Stubs.OutlookWrappers
{
get
{
return new IItemsEnumerable<IItem>(_item, null, false);
return new ItemsEnumerable<IItem>(_item, null, false);
}
}
public IEnumerable<IItem> ItemsSorted(string field, bool descending)
{
return new IItemsEnumerable<IItem>(_item, field, descending);
return new ItemsEnumerable<IItem>(_item, field, descending);
}
#endregion
public IItem GetItemById(string entryId)
{
try
@ -274,10 +284,13 @@ namespace Acacia.Stubs.OutlookWrappers
return new SearchWrapper<ItemType>(_item.Items);
}
#region Subfolders
public IEnumerable<FolderType> GetSubFolders<FolderType>()
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<FolderType>(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<FolderType>(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<FolderType>(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<FolderType>(newFolder);
}
else
throw new NotSupportedException();
}
finally
{
ComRelease.Release(folders);
}
}
private FolderType WrapFolder<FolderType>(MAPIFolder folder)
private FolderType WrapFolder<FolderType>(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<ItemType>()
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<ItemType>());
return Mapping.Wrap<ItemType>(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<IItem>(item))
using (IFolder targetWrapped = Mapping.Wrap<IFolder>(target))
{
@ -430,6 +447,11 @@ namespace Acacia.Stubs.OutlookWrappers
}
}
}
else
{
// TODO: check this
ComRelease.Release(item, target);
}
}
catch(System.Exception e)
{

View File

@ -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<MailItem>, IMailItem
class MailItemWrapper : OutlookItemWrapper<NSOutlook.MailItem>, 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<IFolder>(_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; } }
}
}

View File

@ -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
/// </summary>
/// <param name="o">The Outlook object.</param>
/// <returns>The IItem wrapper, or null if the object could not be wrapped</returns>
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<Type>(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<ItemType>()
public static NSOutlook.OlItemType OutlookItemType<ItemType>()
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<PropType>()
public static NSOutlook.OlUserPropertyType OutlookPropertyType<PropType>()
{
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<IFolder>(f);
}
finally
{
ComRelease.Release(nmspace);
}
}
}
}

View File

@ -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<NoteItem>, INoteItem
public class NoteItemWrapper : OutlookItemWrapper<NSOutlook.NoteItem>, 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<IFolder>(_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
}
}

View File

@ -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<Type>());
@ -52,6 +52,10 @@ namespace Acacia.Stubs.OutlookWrappers
}
}
abstract protected UserProperties GetUserProperties();
/// <summary>
/// Returns the UserProperties associated with the current item.
/// </summary>
/// <returns>An unwrapped UserProperties object. The caller is responsible for releasing this.</returns>
abstract protected NSOutlook.UserProperties GetUserProperties();
}
}

View File

@ -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.
/// </summary>
/// <returns>The property accessor. The caller is responsible for disposing this.</returns>
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

View File

@ -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<ItemType> : ISearch<ItemType>
class SearchWrapper<ItemType> : ComWrapper, ISearch<ItemType>
where ItemType : IItem
{
private interface SearchTerm
@ -151,13 +151,23 @@ namespace Acacia.Stubs.OutlookWrappers
}
private readonly List<SearchTerm> terms = new List<SearchTerm>();
private readonly Items _items;
private NSOutlook.Items _items;
public SearchWrapper(Items items)
/// <summary>
/// Constructor.
/// </summary>
/// <param name="items">The items to search. The new object takes ownership</param>
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<ItemType> values = new List<ItemType>();
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<ItemType>(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);

View File

@ -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<StorageItem>, IStorageItem
public class StorageItemWrapper : OutlookItemWrapper<NSOutlook.StorageItem>, 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<IFolder>(_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
}
}

View File

@ -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<IItem>(o);
}
finally
{
ComRelease.Release(nmspace);
}
}
public string DisplayName { get { return _store.DisplayName; } }

View File

@ -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<TaskItem>, ITaskItem
public class TaskItemWrapper : OutlookItemWrapper<NSOutlook.TaskItem>, 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<IFolder>(_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
}
}

View File

@ -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
/// <summary>
@ -73,17 +66,6 @@ namespace Acacia
private set;
}
public FeatureType GetFeature<FeatureType>()
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;

View File

@ -224,23 +224,25 @@ namespace Acacia.UI
public List<GABUser> Lookup(string text, int max)
{
// Begin GAB lookup, search on full name or username
ISearch<IContactItem> search = _gab.Contacts.Search<IContactItem>();
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<GABUser> users = new List<GABUser>();
foreach (IContactItem result in search.Search(max))
using (ISearch<IContactItem> search = _gab.Contacts.Search<IContactItem>())
{
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<GABUser> users = new List<GABUser>();
foreach (IContactItem result in search.Search(max))
{
using (result)
{
users.Add(new GABUser(result.FullName, result.CustomerID));
}
}
return users;
}
}
public GABUser LookupExact(string username)

View File

@ -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);

View File

@ -14,7 +14,6 @@
///
/// Consult LICENSE file for details
using Microsoft.Office.Interop.Outlook;
using System;
using System.Collections.Generic;
using System.Drawing;

View File

@ -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
{

View File

@ -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<FeatureSettings, bool> _featuresDirty = new Dictionary<FeatureSettings, bool>();
@ -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;
}

View File

@ -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)

View File

@ -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<IMailItem>(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);
}
}

View File

@ -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);

View File

@ -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<T> RawEnum<T>(this IEnumerable<T> 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);
}
}
}

View File

@ -16,7 +16,6 @@
using Acacia.Features;
using Acacia.Stubs;
using Microsoft.Office.Interop.Outlook;
using System;
using System.Collections.Generic;
using System.Linq;

View File

@ -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;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="regPath">They registry key containing the account settings.</param>
/// <param name="store">The store this account represents.</param>
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
/// </summary>
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
{

View File

@ -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;
/// <summary>
/// ZPushAccounts indexed by SMTPAddress. Null values are not allowed.
@ -48,7 +49,7 @@ namespace Acacia.ZPush
/// </summary>
private readonly Dictionary<string, ZPushAccount> _accountsByStoreId = new Dictionary<string, ZPushAccount>();
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<string> stores = new HashSet<string>();
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
/// </summary>
/// <param name="account">The account. This function will release the handle</param>
/// <returns>The ZPushAccount, or null if not a ZPush account.</returns>
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
/// <summary>
/// Event handler for Stores.StoreAdded event.
/// </summary>
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
/// <summary>
/// Creates the ZPushAccount for the account, from the registry values.
/// </summary>
/// <param name="account">The account.</param>
/// <param name="account">The account. The caller is responsible for releasing this.</param>
/// <returns>The associated ZPushAccount</returns>
/// <exception cref="Exception">If the registry key cannot be found</exception>
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
/// </summary>
/// <param name="store">The store</param>
/// <returns>The ZPushAccount, or null if no account is associated with the store</returns>
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.
/// </summary>
/// <returns>The registry key, or null if it cannot be found</returns>
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.
/// </summary>
/// <returns>The registry key, or null if it cannot be found</returns>
private RegistryKey FindRegistryKey(Store store)
private RegistryKey FindRegistryKey(NSOutlook.Store store)
{
// Find the registry key by store id
using (RegistryKey key = OpenBaseKey())

View File

@ -14,7 +14,6 @@
///
/// Consult LICENSE file for details
using Microsoft.Office.Interop.Outlook;
using System;
using System.Collections.Generic;
using System.Linq;

View File

@ -14,7 +14,6 @@
///
/// Consult LICENSE file for details
using Microsoft.Office.Interop.Outlook;
using System;
using System.Collections.Generic;
using System.Linq;

View File

@ -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<ItemsWatcher> _itemsWatchers = new List<ItemsWatcher>();
@ -39,14 +39,14 @@ namespace Acacia.ZPush
/// </summary>
protected readonly Dictionary<string, ZPushFolder> _children = new Dictionary<string, ZPushFolder>();
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.
/// </summary>
/// <param name="child">The child folder. Ownership will be taken.</param>
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<string> remaining = new HashSet<string>();
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); }

View File

@ -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<IFolder>(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();
}

View File

@ -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;

View File

@ -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
/// </summary>
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<IFolder>(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
{