From 0eb4412ed481bd0f9de147667ab3fc32b2151a9d Mon Sep 17 00:00:00 2001 From: Patrick Simpson Date: Fri, 10 Feb 2017 11:01:19 +0100 Subject: [PATCH] Cleaned up OutlookImageList --- .../AcaciaZPushPlugin.csproj | 6 + .../AcaciaZPushPlugin/Stubs/IAddIn.cs | 7 +- .../AcaciaZPushPlugin/Stubs/ICommandBars.cs | 24 ++++ .../AcaciaZPushPlugin/Stubs/IExplorer.cs | 17 +++ .../AcaciaZPushPlugin/Stubs/IOutlookWindow.cs | 12 ++ .../Stubs/OutlookWrappers/AddInWrapper.cs | 96 +++++++++------- .../OutlookWrappers/CommandBarsWrapper.cs | 59 ++++++++++ .../Stubs/OutlookWrappers/ExplorerWrapper.cs | 31 ++++++ .../Stubs/OutlookWrappers/OutlookWrapper.cs | 4 - .../UI/Outlook/OutlookImageList.cs | 104 ++---------------- .../AcaciaZPushPlugin/Utils/ImageUtils.cs | 47 ++++++++ .../ZPush/ZPushLocalStore.cs | 9 +- 12 files changed, 272 insertions(+), 144 deletions(-) create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ICommandBars.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IExplorer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IOutlookWindow.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/CommandBarsWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ExplorerWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ImageUtils.cs diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj index ed0c59b..d0a457b 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj @@ -281,10 +281,15 @@ + + + + + @@ -293,6 +298,7 @@ + diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs index 4a07b11..21ffdf2 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs @@ -22,9 +22,14 @@ namespace Acacia.Stubs IEnumerable> COMAddIns { get; } string Version { get; } - IWin32Window Window { get; } + #region UI OutlookUI OutlookUI { get; } + IWin32Window Window { get; } + IExplorer GetActiveExplorer(); + + #endregion + #region Event handlers diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ICommandBars.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ICommandBars.cs new file mode 100644 index 0000000..e6faa24 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ICommandBars.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + public interface IMSOCommand + { + Bitmap GetImage(Size imageSize); + } + + public interface ICommandBars : IComWrapper + { + /// + /// Returns the command with the specified id. + /// + /// The id. + /// The command, or null if it does not exist. + IMSOCommand GetMso(string id); + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IExplorer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IExplorer.cs new file mode 100644 index 0000000..e4b4474 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IExplorer.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + public interface IExplorer : IOutlookWindow + { + /// + /// Returns the command bars. + /// + /// The command bars. The caller is responsible for disposing. + ICommandBars GetCommandBars(); + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IOutlookWindow.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IOutlookWindow.cs new file mode 100644 index 0000000..3181e84 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IOutlookWindow.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + public interface IOutlookWindow : IComWrapper + { + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs index ebad830..2e75aed 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs @@ -82,8 +82,62 @@ namespace Acacia.Stubs.OutlookWrappers } } + #region UI + public OutlookUI OutlookUI { get { return _thisAddIn.OutlookUI; } } + public IExplorer GetActiveExplorer() + { + using (ComRelease com = new ComRelease()) + { + return new ExplorerWrapper(com.Add(_thisAddIn.Application).ActiveExplorer()); + } + } + + #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 + + #endregion + public ZPushWatcher Watcher { get { return _thisAddIn.Watcher; } } public MailEvents MailEvents { get { return _thisAddIn.MailEvents; } } public IEnumerable Features { get { return _thisAddIn.Features; } } @@ -148,48 +202,6 @@ namespace Acacia.Stubs.OutlookWrappers } } - #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 - public IRecipient ResolveRecipient(string name) { diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/CommandBarsWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/CommandBarsWrapper.cs new file mode 100644 index 0000000..492ffd2 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/CommandBarsWrapper.cs @@ -0,0 +1,59 @@ +using Acacia.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NSOffice = Microsoft.Office.Core; +using System.Drawing; +using stdole; + +namespace Acacia.Stubs.OutlookWrappers +{ + class CommandBarsWrapper : ComWrapper, ICommandBars + { + private class MSOCommand : IMSOCommand + { + private readonly CommandBarsWrapper _commands; + private readonly string _id; + + public MSOCommand(CommandBarsWrapper commands, string id) + { + this._commands = commands; + this._id = id; + } + + public Bitmap GetImage(Size imageSize) + { + IPictureDisp pict = _commands._item.GetImageMso(_id, imageSize.Width, imageSize.Height); + try + { + return ImageUtils.GetBitmapFromHBitmap(new IntPtr(pict.Handle)); + } + finally + { + ComRelease.Release(pict); + } + } + } + + private NSOffice.CommandBars _item; + + public CommandBarsWrapper(NSOffice.CommandBars item) + { + this._item = item; + } + + public IMSOCommand GetMso(string id) + { + return new MSOCommand(this, id); + } + + // TODO: make TypedComWrapper + protected override void DoRelease() + { + ComRelease.Release(_item); + _item = null; + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ExplorerWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ExplorerWrapper.cs new file mode 100644 index 0000000..c02ca0f --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ExplorerWrapper.cs @@ -0,0 +1,31 @@ +using Acacia.Utils; +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 ExplorerWrapper : ComWrapper, IExplorer + { + private NSOutlook.Explorer _item; + + public ExplorerWrapper(NSOutlook.Explorer item) + { + this._item = item; + } + + protected override void DoRelease() + { + ComRelease.Release(_item); + _item = null; + } + + public ICommandBars GetCommandBars() + { + return new CommandBarsWrapper(_item.CommandBars); + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookWrapper.cs index fe56318..c444b3d 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookWrapper.cs @@ -44,10 +44,6 @@ namespace Acacia.Stubs.OutlookWrappers this._item = item; } - ~OutlookWrapper() - { - } - protected override void DoRelease() { if (_props != null) diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookImageList.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookImageList.cs index 048d413..0f4afbc 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookImageList.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookImageList.cs @@ -1,4 +1,7 @@ -/// Copyright 2016 Kopano b.v. + +using Acacia.Stubs; +using Acacia.Utils; +/// Copyright 2016 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, @@ -13,7 +16,6 @@ /// along with this program.If not, see. /// /// Consult LICENSE file for details - using Microsoft.Office.Core; using stdole; using System; @@ -35,93 +37,6 @@ namespace Acacia.UI.Outlook { public ImageList Images { get; private set; } - [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)] - public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count); - - private Bitmap GetBitmapFromHBitmap2(IntPtr nativeHBitmap) - { - - Bitmap bmp = Bitmap.FromHbitmap(nativeHBitmap); - if (Bitmap.GetPixelFormatSize(bmp.PixelFormat) < 32) - return bmp; - - // Special handling is required to convert a bitmap with alpha channel, FromHBitmap doesn't - // set the correct pixel format - Rectangle bmBounds = new Rectangle(0, 0, bmp.Width, bmp.Height); - BitmapData bmpData = bmp.LockBits(bmBounds, ImageLockMode.ReadOnly, bmp.PixelFormat); - Bitmap bmp2 = new Bitmap(bmpData.Width, bmpData.Height, PixelFormat.Format32bppArgb); - BitmapData bmpData2 = bmp2.LockBits(bmBounds, ImageLockMode.WriteOnly, bmp2.PixelFormat); - try - { - for (int y = 0; y < bmp.Height; ++y) - { - IntPtr target = bmpData2.Scan0 + bmpData2.Stride * y; - IntPtr source = bmpData.Scan0 + bmpData.Stride * y; - CopyMemory(target, source, (uint)Math.Abs(bmpData2.Stride)); - } - } - finally - { - bmp2.UnlockBits(bmpData2); - bmp.UnlockBits(bmpData); - } - return bmp2; - } - - private static Bitmap GetBitmapFromHBitmap(IntPtr nativeHBitmap) - { - Bitmap bmp = Bitmap.FromHbitmap(nativeHBitmap); - - if (Bitmap.GetPixelFormatSize(bmp.PixelFormat) < 32) - return bmp; - - BitmapData bmpData; - - if (IsAlphaBitmap(bmp, out bmpData)) - return GetlAlphaBitmapFromBitmapData(bmpData); - - return bmp; - } - - private static Bitmap GetlAlphaBitmapFromBitmapData(BitmapData bmpData) - { - return new Bitmap( - bmpData.Width, - bmpData.Height, - bmpData.Stride, - PixelFormat.Format32bppArgb, - bmpData.Scan0); - } - - private static bool IsAlphaBitmap(Bitmap bmp, out BitmapData bmpData) - { - Rectangle bmBounds = new Rectangle(0, 0, bmp.Width, bmp.Height); - - bmpData = bmp.LockBits(bmBounds, ImageLockMode.ReadOnly, bmp.PixelFormat); - - try - { - for (int y = 0; y <= bmpData.Height - 1; y++) - { - for (int x = 0; x <= bmpData.Width - 1; x++) - { - Color pixelColor = Color.FromArgb( - Marshal.ReadInt32(bmpData.Scan0, (bmpData.Stride * y) + (4 * x))); - - if (pixelColor.A > 0 & pixelColor.A < 255) - { - return true; - } - } - } - } - finally - { - bmp.UnlockBits(bmpData); - } - - return false; - } public OutlookImageList(params string[] icons) { Images = new ImageList(); @@ -129,12 +44,13 @@ namespace Acacia.UI.Outlook Images.ImageSize = new Size(16, 16); // TODO: memory management - CommandBars cmdBars = ThisAddIn.Instance.RawApp.ActiveWindow().CommandBars; - foreach (string id in icons) + using (IExplorer explorer = ThisAddIn.Instance.GetActiveExplorer()) + using (ICommandBars cmdBars = explorer.GetCommandBars()) { - IPictureDisp pict = cmdBars.GetImageMso(id, Images.ImageSize.Width, Images.ImageSize.Height); - var img = GetBitmapFromHBitmap2(new IntPtr(pict.Handle)); - Images.Images.Add(img); + foreach (string id in icons) + { + Images.Images.Add(cmdBars.GetMso(id).GetImage(Images.ImageSize)); + } } } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ImageUtils.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ImageUtils.cs new file mode 100644 index 0000000..6a7d5c5 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ImageUtils.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Utils +{ + public static class ImageUtils + { + [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)] + private static extern void CopyMemory(IntPtr dest, IntPtr src, uint count); + + public static Bitmap GetBitmapFromHBitmap(IntPtr nativeHBitmap) + { + + Bitmap bmp = Bitmap.FromHbitmap(nativeHBitmap); + if (Bitmap.GetPixelFormatSize(bmp.PixelFormat) < 32) + return bmp; + + // Special handling is required to convert a bitmap with alpha channel, FromHBitmap doesn't + // set the correct pixel format + Rectangle bmBounds = new Rectangle(0, 0, bmp.Width, bmp.Height); + BitmapData bmpData = bmp.LockBits(bmBounds, ImageLockMode.ReadOnly, bmp.PixelFormat); + Bitmap bmp2 = new Bitmap(bmpData.Width, bmpData.Height, PixelFormat.Format32bppArgb); + BitmapData bmpData2 = bmp2.LockBits(bmBounds, ImageLockMode.WriteOnly, bmp2.PixelFormat); + try + { + for (int y = 0; y < bmp.Height; ++y) + { + IntPtr target = bmpData2.Scan0 + bmpData2.Stride * y; + IntPtr source = bmpData.Scan0 + bmpData.Stride * y; + CopyMemory(target, source, (uint)Math.Abs(bmpData2.Stride)); + } + } + finally + { + bmp2.UnlockBits(bmpData2); + bmp.UnlockBits(bmpData); + } + return bmp2; + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs index 643b266..8341a04 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs @@ -134,11 +134,14 @@ namespace Acacia.ZPush if (GlobalOptions.INSTANCE.LocalFolders_Hide) { // Hide the folders that are not custom folders - using (ComRelease com = new ComRelease()) + using (IFolder root = store.GetRootFolder()) { - foreach(IFolder sub in store.GetRootFolder().GetSubFolders()) + foreach(IFolder sub in root.GetSubFolders()) { - sub.AttrHidden = !IsCustomFolder(sub); + using (sub) + { + sub.AttrHidden = !IsCustomFolder(sub); + } } } }