kopano-ol-extension/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs

371 lines
11 KiB
C#

/// Copyright 2017 Kopano b.v.
///
/// This program is free software: you can redistribute it and/or modify
/// it under the terms of the GNU Affero General Public License, version 3,
/// as published by the Free Software Foundation.
///
/// This program is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
/// GNU Affero General Public License for more details.
///
/// You should have received a copy of the GNU Affero General Public License
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
///
/// Consult LICENSE file for details
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;
using System.Threading.Tasks;
using System.Windows.Forms;
using NSOutlook = Microsoft.Office.Interop.Outlook;
using System.Drawing;
namespace Acacia.Stubs.OutlookWrappers
{
class AddInWrapper : IAddIn
{
private readonly NSOutlook.Application _app;
private readonly ThisAddIn _thisAddIn;
private readonly StoresWrapper _stores;
private readonly SynchronizationContext _sync;
public AddInWrapper(ThisAddIn thisAddIn)
{
this._thisAddIn = thisAddIn;
this._app = thisAddIn.Application;
NSOutlook.NameSpace session = _app.Session;
try
{
this._stores = new StoresWrapper(session.Stores);
}
finally
{
ComRelease.Release(session);
}
// The synchronization context is needed to allow background tasks to jump back to the UI thread.
// It's null in older versions of .Net, this fixes that
if (SynchronizationContext.Current == null)
{
SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
}
_sync = SynchronizationContext.Current;
}
public ISignatures GetSignatures()
{
return new SignaturesWrapper();
}
public bool IsOffline
{
get
{
NSOutlook.NameSpace session = _app.Session;
try
{
return session.Offline;
}
finally
{
ComRelease.Release(session);
}
}
}
public string ProfileName
{
get
{
NSOutlook.NameSpace session = _app.Session;
try
{
return session.CurrentProfileName;
}
finally
{
ComRelease.Release(session);
}
}
}
public void InUI(Action action, bool synchronous = true)
{
if (synchronous)
{
Exception x = null;
_sync.Send((_) =>
{
try
{
action();
}
catch (Exception e)
{
x = e;
}
}, null);
if (x != null)
{
Logger.Instance.Trace(this, "Rethrowing exception from UI send: {0}", x);
throw x;
}
}
else
{
_sync.Post((_) =>
{
try
{
action();
}
catch (Exception e)
{
Logger.Instance.Error(this, "Unhandled exception in UI post: {0}", e);
}
}, null);
}
}
public void SendReceive(IAccount account, AcaciaTask after)
{
if (after != null)
{
Watcher.Sync.AddEndTaskOnce(after);
}
// TODO: send/receive specific account
NSOutlook.NameSpace session = _app.Session;
try
{
session.SendAndReceive(false);
}
finally
{
ComRelease.Release(session);
}
}
public void Start()
{
_stores.Start();
}
public IRestarter Restarter()
{
return new Restarter(this);
}
public void Quit(bool closeWindows)
{
if (closeWindows)
{
List<Form> openForms = new List<Form>();
foreach (Form f in Application.OpenForms)
openForms.Add(f);
foreach (Form f in openForms)
f.Close();
}
_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 ISyncObject GetSyncObject()
{
using (ComRelease com = new ComRelease())
{
NSOutlook.NameSpace session = com.Add(_app.Session);
NSOutlook.SyncObjects syncObjects = com.Add(session.SyncObjects);
return new SyncObjectWrapper(syncObjects.AppFolders);
}
}
#region UI
public OutlookUI OutlookUI { get { return _thisAddIn.OutlookUI; } }
public IExplorer GetActiveExplorer()
{
NSOutlook.Explorer explorer = _app.ActiveExplorer();
if (explorer == null)
return null;
return new ExplorerWrapper(explorer);
}
public IInspectors GetInspectors()
{
return new InspectorsWrapper(_app.Inspectors);
}
#region Window handle
/// <summary>
/// Simple IWin32Window wrapper for a native handle. NativeWindow sometimes refuses to handle
/// these (FromHandle returns null), so use a simple wrapper.
/// </summary>
private class WindowHandle : ISystemWindow
{
private IntPtr hWnd;
public WindowHandle(IntPtr hWnd)
{
this.hWnd = hWnd;
}
public Rectangle Bounds
{
get
{
return User32.GetWindowRect(hWnd);
}
}
public IntPtr Handle
{
get
{
return hWnd;
}
}
}
public ISystemWindow 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
#endregion
public ZPushWatcher Watcher { get { return _thisAddIn.Watcher; } }
public MailEvents MailEvents { get { return _thisAddIn.MailEvents; } }
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 string VersionMajor
{
get { return _app.Version.Split('.')[0]; }
}
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);
}
}
public IRecipient ResolveRecipient(string name)
{
using (ComRelease com = new ComRelease())
{
NSOutlook.NameSpace session = com.Add(_app.Session);
// Add recipient, unlock after Resolve (which might throw) to wrap
NSOutlook.Recipient recipient = com.Add(session.CreateRecipient(name));
if (recipient == null)
return null;
IRecipient wrapped = Mapping.Wrap(com.Remove(recipient));
wrapped.Resolve();
return wrapped;
}
}
public IStores Stores
{
get { return _stores; }
}
}
}