diff --git a/trunk/ProcessHacker/Components/TaskbarLib/Interop/COMTypes.cs b/trunk/ProcessHacker/Components/TaskbarLib/Interop/COMTypes.cs
new file mode 100644
index 000000000..347d0241f
--- /dev/null
+++ b/trunk/ProcessHacker/Components/TaskbarLib/Interop/COMTypes.cs
@@ -0,0 +1,197 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Runtime.CompilerServices;
+
+namespace TaskbarLib.Interop
+{
+ #region "Interface Classes"
+
+ [ComImportAttribute()]
+ [GuidAttribute("86C14003-4D6B-4EF3-A7B4-0506663B2E68")]
+ [ClassInterfaceAttribute(ClassInterfaceType.None)]
+ internal class CApplicationDestinations { }
+
+ [ComImportAttribute()]
+ [GuidAttribute("86BEC222-30F2-47E0-9F25-60D11CD75C28")]
+ [ClassInterfaceAttribute(ClassInterfaceType.None)]
+ internal class CApplicationDocumentLists { }
+
+ [ComImportAttribute()]
+ [GuidAttribute("56FDF344-FD6D-11d0-958A-006097C9A090")]
+ [ClassInterfaceAttribute(ClassInterfaceType.None)]
+ internal class CTaskbarList { }
+
+ [ComImportAttribute()]
+ [GuidAttribute("00021401-0000-0000-C000-000000000046")]
+ [ClassInterfaceAttribute(ClassInterfaceType.None)]
+ internal class CShellLink { }
+
+ [ComImportAttribute()]
+ [GuidAttribute("77F10CF0-3DB5-4966-B520-B7C54FD35ED6")]
+ [ClassInterfaceAttribute(ClassInterfaceType.None)]
+ internal class CDestinationList { }
+
+ [ComImportAttribute()]
+ [GuidAttribute("2D3468C1-36A7-43B6-AC24-D3F02FD9607A")]
+ [ClassInterfaceAttribute(ClassInterfaceType.None)]
+ internal class CEnumerableObjectCollection { }
+
+ #endregion
+
+ [ComImportAttribute()]
+ [GuidAttribute("92CA9DCD-5622-4BBA-A805-5E9F541BD8C9")]
+ [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IObjectArray
+ {
+ void GetCount(out uint cObjects);
+ void GetAt(uint iIndex, ref Guid riid, [Out(), MarshalAs(UnmanagedType.Interface)] out object ppvObject);
+ }
+
+ [ComImportAttribute()]
+ [GuidAttribute(SafeNativeMethods.IID_IObjectCollection)]
+ [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IObjectCollection
+ {
+ // IObjectArray
+ [PreserveSig]
+ void GetCount(out uint cObjects);
+ [PreserveSig]
+ void GetAt(uint iIndex, ref Guid riid, [Out(), MarshalAs(UnmanagedType.Interface)] out object ppvObject);
+
+ // IObjectCollection
+ void AddObject([MarshalAs(UnmanagedType.Interface)] object pvObject);
+ void AddFromArray([MarshalAs(UnmanagedType.Interface)] IObjectArray poaSource);
+ void RemoveObject(uint uiIndex);
+ void Clear();
+ }
+
+ [ComImportAttribute()]
+ [GuidAttribute("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99")]
+ [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IPropertyStore
+ {
+ void GetCount(out UInt32 cProps);
+ void GetAt(UInt32 iProp, [MarshalAs(UnmanagedType.Struct)] out PropertyKey pkey);
+ void GetValue([In, MarshalAs(UnmanagedType.Struct)] ref PropertyKey pkey, [Out(), MarshalAs(UnmanagedType.Struct)] out PropVariant pv);
+ void SetValue([In, MarshalAs(UnmanagedType.Struct)] ref PropertyKey pkey, [In, MarshalAs(UnmanagedType.Struct)] ref PropVariant pv);
+ void Commit();
+ }
+
+ [ComImportAttribute()]
+ [GuidAttribute("6332DEBF-87B5-4670-90C0-5E57B408A49E")]
+ [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface ICustomDestinationList
+ {
+ void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID);
+ void BeginList(out uint cMaxSlots, ref Guid riid, [Out(), MarshalAs(UnmanagedType.Interface)] out object ppvObject);
+ void AppendCategory([MarshalAs(UnmanagedType.LPWStr)] string pszCategory, [MarshalAs(UnmanagedType.Interface)] IObjectArray poa);
+ void AppendKnownCategory([MarshalAs(UnmanagedType.I4)] KNOWNDESTCATEGORY category);
+ void AddUserTasks([MarshalAs(UnmanagedType.Interface)] IObjectArray poa);
+ void CommitList();
+ void GetRemovedDestinations(ref Guid riid, [Out(), MarshalAs(UnmanagedType.Interface)] out object ppvObject);
+ void DeleteList([MarshalAs(UnmanagedType.LPWStr)] string pszAppID);
+ void AbortList();
+ }
+
+ [ComImportAttribute()]
+ [GuidAttribute("12337D35-94C6-48A0-BCE7-6A9C69D4D600")]
+ [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IApplicationDestinations
+ {
+ void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID);
+ void RemoveDestination([MarshalAs(UnmanagedType.Interface)] object pvObject);
+ void RemoveAllDestinations();
+ }
+
+ [ComImportAttribute()]
+ [GuidAttribute("3C594F9F-9F30-47A1-979A-C9E83D3D0A06")]
+ [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IApplicationDocumentLists
+ {
+ void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID);
+ void GetList([MarshalAs(UnmanagedType.I4)] APPDOCLISTTYPE listtype, uint cItemsDesired, ref Guid riid, [Out(), MarshalAs(UnmanagedType.Interface)] out object ppvObject);
+ }
+
+ [ComImportAttribute()]
+ [GuidAttribute("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf")]
+ [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface ITaskbarList3
+ {
+ // ITaskbarList
+ [PreserveSig]
+ void HrInit();
+ [PreserveSig]
+ void AddTab(IntPtr hwnd);
+ [PreserveSig]
+ void DeleteTab(IntPtr hwnd);
+ [PreserveSig]
+ void ActivateTab(IntPtr hwnd);
+ [PreserveSig]
+ void SetActiveAlt(IntPtr hwnd);
+
+ // ITaskbarList2
+ [PreserveSig]
+ void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen);
+
+ // ITaskbarList3
+ void SetProgressValue(IntPtr hwnd, UInt64 ullCompleted, UInt64 ullTotal);
+ void SetProgressState(IntPtr hwnd, TBPFLAG tbpFlags);
+ void RegisterTab(IntPtr hwndTab, IntPtr hwndMDI);
+ void UnregisterTab(IntPtr hwndTab);
+ void SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore);
+ void SetTabActive(IntPtr hwndTab, IntPtr hwndMDI, TBATFLAG tbatFlags);
+ void ThumbBarAddButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray)] THUMBBUTTON[] pButtons);
+ void ThumbBarUpdateButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray)] THUMBBUTTON[] pButtons);
+ void ThumbBarSetImageList(IntPtr hwnd, IntPtr himl);
+ void SetOverlayIcon(IntPtr hwnd, IntPtr hIcon, [MarshalAs(UnmanagedType.LPWStr)] string pszDescription);
+ void SetThumbnailTooltip(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszTip);
+ void SetThumbnailClip(IntPtr hwnd, /*[MarshalAs(UnmanagedType.LPStruct)]*/ ref RECT prcClip);
+ }
+
+ [ComImportAttribute()]
+ [GuidAttribute("43826D1E-E718-42EE-BC55-A1E261C37BFE")]
+ [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IShellItem
+ {
+ [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+ void BindToHandler([In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid bhid, [In] ref Guid riid, out IntPtr ppv);
+
+ [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+ void GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
+
+ [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+ void GetDisplayName([In] SIGDN sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName);
+
+ [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+ void GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs);
+
+ [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+ void Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder);
+ }
+
+ [ComImportAttribute()]
+ [GuidAttribute("000214F9-0000-0000-C000-000000000046")]
+ [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IShellLinkW
+ {
+ void GetPath([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, IntPtr pfd, uint fFlags);
+ void GetIDList(out IntPtr ppidl);
+ void SetIDList(IntPtr pidl);
+ void GetDescription([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxName);
+ void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
+ void GetWorkingDirectory([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
+ void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
+ void GetArguments([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
+ void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
+ void GetHotKey(out short wHotKey);
+ void SetHotKey(short wHotKey);
+ void GetShowCmd(out uint iShowCmd);
+ void SetShowCmd(uint iShowCmd);
+ void GetIconLocation([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int iIcon);
+ void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
+ void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved);
+ void Resolve(IntPtr hwnd, uint fFlags);
+ void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
+ }
+}
\ No newline at end of file
diff --git a/trunk/ProcessHacker/Components/TaskbarLib/Interop/Interop.cs b/trunk/ProcessHacker/Components/TaskbarLib/Interop/Interop.cs
new file mode 100644
index 000000000..f5519a790
--- /dev/null
+++ b/trunk/ProcessHacker/Components/TaskbarLib/Interop/Interop.cs
@@ -0,0 +1,290 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Text;
+
+namespace TaskbarLib.Interop
+{
+ [Flags]
+ internal enum KNOWNDESTCATEGORY
+ {
+ KDC_FREQUENT = 1,
+ KDC_RECENT
+ }
+ [Flags]
+ internal enum APPDOCLISTTYPE
+ {
+ ADLT_RECENT = 0,
+ ADLT_FREQUENT
+ }
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct RECT
+ {
+ public int left;
+ public int top;
+ public int right;
+ public int bottom;
+
+ public RECT(int left, int top, int right, int bottom)
+ {
+ this.left = left;
+ this.top = top;
+ this.right = right;
+ this.bottom = bottom;
+ }
+ }
+ [Flags]
+ internal enum TBPFLAG
+ {
+ TBPF_NOPROGRESS = 0,
+ TBPF_INDETERMINATE = 0x1,
+ TBPF_NORMAL = 0x2,
+ TBPF_ERROR = 0x4,
+ TBPF_PAUSED = 0x8
+ }
+ [Flags]
+ internal enum TBATFLAG
+ {
+ TBATF_USEMDITHUMBNAIL = 0x1,
+ TBATF_USEMDILIVEPREVIEW = 0x2
+ }
+ [Flags]
+ internal enum THBMASK
+ {
+ THB_BITMAP = 0x1,
+ THB_ICON = 0x2,
+ THB_TOOLTIP = 0x4,
+ THB_FLAGS = 0x8
+ }
+ [Flags]
+ internal enum THBFLAGS
+ {
+ THBF_ENABLED = 0,
+ THBF_DISABLED = 0x1,
+ THBF_DISMISSONCLICK = 0x2,
+ THBF_NOBACKGROUND = 0x4,
+ THBF_HIDDEN = 0x8
+ }
+ [Flags]
+ internal enum SIGDN : uint
+ {
+ SIGDN_NORMALDISPLAY = 0x00000000, // SHGDN_NORMAL
+ SIGDN_PARENTRELATIVEPARSING = 0x80018001, // SHGDN_INFOLDER | SHGDN_FORPARSING
+ SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, // SHGDN_FORPARSING
+ SIGDN_PARENTRELATIVEEDITING = 0x80031001, // SHGDN_INFOLDER | SHGDN_FOREDITING
+ SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, // SHGDN_FORPARSING | SHGDN_FORADDRESSBAR
+ SIGDN_FILESYSPATH = 0x80058000, // SHGDN_FORPARSING
+ SIGDN_URL = 0x80068000, // SHGDN_FORPARSING
+ SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001, // SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR
+ SIGDN_PARENTRELATIVE = 0x80080001 // SHGDN_INFOLDER
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct POINT
+ {
+ internal int X;
+ internal int Y;
+
+ internal POINT(int x, int y)
+ {
+ this.X = x;
+ this.Y = y;
+ }
+ }
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ internal struct THUMBBUTTON
+ {
+ [MarshalAs(UnmanagedType.U4)]
+ public THBMASK dwMask;
+ public uint iId;
+ public uint iBitmap;
+ public IntPtr hIcon;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
+ public string szTip;
+ [MarshalAs(UnmanagedType.U4)]
+ public THBFLAGS dwFlags;
+ }
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ internal struct PropertyKey
+ {
+ public Guid fmtid;
+ public uint pid;
+
+ public PropertyKey(Guid fmtid, uint pid)
+ {
+ this.fmtid = fmtid;
+ this.pid = pid;
+ }
+
+ public static PropertyKey PKEY_Title = new PropertyKey(new Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9"), 2);
+ public static PropertyKey PKEY_AppUserModel_ID = new PropertyKey(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 5);
+ public static PropertyKey PKEY_AppUserModel_IsDestListSeparator = new PropertyKey(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 6);
+ public static PropertyKey PKEY_AppUserModel_RelaunchCommand = new PropertyKey(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 2);
+ public static PropertyKey PKEY_AppUserModel_RelaunchDisplayNameResource = new PropertyKey(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 4);
+ public static PropertyKey PKEY_AppUserModel_RelaunchIconResource = new PropertyKey(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 3);
+ }
+ [StructLayout(LayoutKind.Explicit)]
+ internal struct CALPWSTR
+ {
+ [FieldOffset(0)]
+ internal uint cElems;
+ [FieldOffset(4)]
+ internal IntPtr pElems;
+ }
+ [StructLayout(LayoutKind.Explicit)]
+ internal struct PropVariant
+ {
+ [FieldOffset(0)]
+ private ushort vt;
+ [FieldOffset(8)]
+ private IntPtr pointerValue;
+ [FieldOffset(8)]
+ private byte byteValue;
+ [FieldOffset(8)]
+ private long longValue;
+ [FieldOffset(8)]
+ private short boolValue;
+ [MarshalAs(UnmanagedType.Struct)]
+ [FieldOffset(8)]
+ private CALPWSTR calpwstr;
+
+ [DllImport("ole32.dll")]
+ private static extern int PropVariantClear(ref PropVariant pvar);
+
+ public VarEnum VarType
+ {
+ get { return (VarEnum)vt; }
+ }
+
+ public void SetValue(String val)
+ {
+ this.Clear();
+ this.vt = (ushort)VarEnum.VT_LPWSTR;
+ this.pointerValue = Marshal.StringToCoTaskMemUni(val);
+ }
+ public void SetValue(bool val)
+ {
+ this.Clear();
+ this.vt = (ushort)VarEnum.VT_BOOL;
+ this.boolValue = val ? (short)-1 : (short)0;
+ }
+
+ public string GetValue()
+ {
+ return Marshal.PtrToStringUni(this.pointerValue);
+ }
+
+ public void Clear()
+ {
+ PropVariantClear(ref this);
+ }
+ }
+
+ [SuppressUnmanagedCodeSecurity]
+ internal static class SafeNativeMethods
+ {
+ //Obviously, these GUIDs shouldn't be modified. The reason they
+ //are not readonly is that they are passed with 'ref' to various
+ //native methods.
+ public static Guid IID_IObjectArray = new Guid("92CA9DCD-5622-4BBA-A805-5E9F541BD8C9");
+ public const string IID_IObjectCollection = "5632B1A4-E38A-400A-928A-D4CD63230295";
+ public static Guid IID_IPropertyStore = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
+ public static Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
+
+ public const int DWM_SIT_DISPLAYFRAME = 0x00000001;
+
+ public const int DWMWA_FORCE_ICONIC_REPRESENTATION = 7;
+ public const int DWMWA_HAS_ICONIC_BITMAP = 10;
+
+ public const int WM_COMMAND = 0x111;
+ public const int WM_SYSCOMMAND = 0x112;
+ public const int WM_DWMSENDICONICTHUMBNAIL = 0x0323;
+ public const int WM_DWMSENDICONICLIVEPREVIEWBITMAP = 0x0326;
+ public const int WM_CLOSE = 0x0010;
+ public const int WM_ACTIVATE = 0x0006;
+
+ public const int WA_ACTIVE = 1;
+ public const int WA_CLICKACTIVE = 2;
+
+ public const int SC_CLOSE = 0xF060;
+
+ public const int MSGFLT_ADD = 1;
+ public const int MSGFLT_REMOVE = 2;
+
+ // Thumbbutton WM_COMMAND notification
+ public const uint THBN_CLICKED = 0x1800;
+ }
+ [SuppressUnmanagedCodeSecurity]
+ internal static class UnsafeNativeMethods
+ {
+ [DllImport("shell32.dll")]
+ public static extern int SHGetPropertyStoreForWindow(IntPtr hwnd, ref Guid iid /*IID_IPropertyStore*/, [Out(), MarshalAs(UnmanagedType.Interface)] out IPropertyStore propertyStore);
+ [DllImport("dwmapi.dll")]
+ public static extern int DwmSetIconicThumbnail(IntPtr hwnd, IntPtr hbitmap, uint flags);
+ [DllImport("dwmapi.dll")]
+ public static extern int DwmSetIconicLivePreviewBitmap(IntPtr hwnd, IntPtr hbitmap, ref POINT ptClient, uint flags);
+ [DllImport("dwmapi.dll")]
+ public static extern int DwmSetIconicLivePreviewBitmap(IntPtr hwnd, IntPtr hbitmap, IntPtr ptClient, uint flags);
+ [DllImport("dwmApi.dll")]
+ internal static extern int DwmSetWindowAttribute(IntPtr hwnd, uint dwAttributeToSet, IntPtr pvAttributeValue, uint cbAttribute);
+ [DllImport("dwmApi.dll")]
+ internal static extern int DwmSetWindowAttribute(IntPtr hwnd, uint dwAttributeToSet, ref int pvAttributeValue, uint cbAttribute);
+ [DllImport("dwmapi.dll")]
+ public static extern int DwmInvalidateIconicBitmaps(IntPtr hwnd);
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool ChangeWindowMessageFilter(uint message, uint flags);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ internal static extern uint RegisterWindowMessage(string lpString);
+
+ public static readonly uint WM_TaskbarButtonCreated = RegisterWindowMessage("TaskbarButtonCreated");
+
+ [DllImport("shell32.dll")]
+ public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
+ [DllImport("shell32.dll")]
+ public static extern void GetCurrentProcessExplicitAppUserModelID([Out(), MarshalAs(UnmanagedType.LPWStr)] out string AppID);
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetWindowRect(IntPtr hwnd, ref RECT rect);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetClientRect(IntPtr hwnd, ref RECT rect);
+ public static bool GetClientSize(IntPtr hwnd, out System.Drawing.Size size)
+ {
+ RECT rect = new RECT();
+ if (!GetClientRect(hwnd, ref rect))
+ {
+ size = new System.Drawing.Size(-1, -1);
+ return false;
+ }
+ size = new System.Drawing.Size(rect.right, rect.bottom);
+ return true;
+ }
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool ShowWindow(IntPtr hwnd, int cmd);
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int X, int Y, int cx, int cy, uint flags);
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool ClientToScreen(IntPtr hwnd, ref POINT point);
+ [DllImport("user32.dll")]
+ public static extern int GetWindowText(IntPtr hwnd, StringBuilder str, int maxCount);
+ [DllImport("gdi32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool BitBlt (IntPtr hDestDC, int destX, int destY, int width, int height, IntPtr hSrcDC, int srcX, int srcY, uint operation);
+ [DllImport("gdi32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool StretchBlt(IntPtr hDestDC, int destX, int destY, int destWidth, int destHeight, IntPtr hSrcDC, int srcX, int srcY, int srcWidth, int srcHeight, uint operation);
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetWindowDC(IntPtr hwnd);
+ [DllImport("user32.dll")]
+ public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
+ [DllImport("Shell32", CharSet = CharSet.Auto, SetLastError = true)]
+ internal static extern uint SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string path, /* The following parameter is not used - binding context. */ IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem shellItem);
+ }
+}
\ No newline at end of file
diff --git a/trunk/ProcessHacker/Components/TaskbarLib/JumpLists/JumpListImpl.cs b/trunk/ProcessHacker/Components/TaskbarLib/JumpLists/JumpListImpl.cs
new file mode 100644
index 000000000..fb9678c6b
--- /dev/null
+++ b/trunk/ProcessHacker/Components/TaskbarLib/JumpLists/JumpListImpl.cs
@@ -0,0 +1,411 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using TaskbarLib.Interop;
+
+namespace TaskbarLib.DesktopIntegration
+{
+ ///
+ /// A collection of categorized jump list destinations.
+ ///
+ internal sealed class JumpListDestinations
+ {
+ //TODO: This is highly inefficient, but we want to maintain
+ //insertion order when adding the categories because the bottom
+ //categories are first to be truncated if screen estate is low.
+ private SortedDictionary> _categorizedDestinations =
+ new SortedDictionary>();
+
+ public void AddDestination(IJumpListDestination destination)
+ {
+ List destinations =
+ _categorizedDestinations.Values.FirstOrDefault(
+ list => list.First().Category == destination.Category);
+ if (destinations == null)
+ {
+ destinations = new List();
+ _categorizedDestinations.Add(
+ _categorizedDestinations.Keys.LastOrDefault() + 1, destinations);
+ }
+
+ destinations.Add(destination);
+ }
+
+ public void DeleteDestination(IJumpListDestination destination)
+ {
+ List destinations =
+ _categorizedDestinations.Values.First(
+ list => list.First().Category == destination.Category);
+ IJumpListDestination toDelete = destinations.Find(
+ d => d.Path == destination.Path && d.Category == destination.Category && d.Title == destination.Title);
+ if (toDelete != null)
+ destinations.Remove(toDelete);
+ }
+
+ internal void RefreshDestinations(ICustomDestinationList destinationList)
+ {
+ if (_categorizedDestinations.Count == 0)
+ return;
+
+ foreach (int key in _categorizedDestinations.Keys)
+ {
+ IObjectCollection categoryContents =
+ (IObjectCollection)new CEnumerableObjectCollection();
+ var destinations = _categorizedDestinations[key];
+ foreach (IJumpListDestination destination in destinations)
+ {
+ categoryContents.AddObject(destination.GetShellRepresentation());
+ }
+ destinationList.AppendCategory(
+ destinations.First().Category,
+ (IObjectArray)categoryContents);
+ }
+ }
+
+ public IEnumerable Categories
+ {
+ get
+ {
+ return
+ (from d in _categorizedDestinations.Keys
+ select _categorizedDestinations[d].First().Category);
+ }
+ }
+ public IEnumerable GetDestinationsByCategory(
+ string category)
+ {
+ return
+ (from k in _categorizedDestinations.Keys
+ let d = _categorizedDestinations[k]
+ where d.First().Category == category
+ select d).Single();
+ }
+
+ public void Clear()
+ {
+ _categorizedDestinations.Clear();
+ }
+ }
+
+ ///
+ /// A collection of jump list tasks.
+ ///
+ internal sealed class JumpListTasks
+ {
+ private List _tasks = new List();
+
+ public void AddTask(IJumpListTask task)
+ {
+ _tasks.Add(task);
+ }
+ public void DeleteTask(IJumpListTask task)
+ {
+ IJumpListTask toDelete = _tasks.Find(t => t.Path == task.Path && t.Arguments == task.Arguments);
+ if (toDelete != null)
+ _tasks.Remove(toDelete);
+ }
+
+ internal void RefreshTasks(ICustomDestinationList destinationList)
+ {
+ if (_tasks.Count == 0)
+ return;
+
+ IObjectCollection taskCollection =
+ (IObjectCollection)new CEnumerableObjectCollection();
+ foreach (IJumpListTask task in _tasks)
+ {
+ taskCollection.AddObject(task.GetShellRepresentation());
+ }
+ destinationList.AddUserTasks((IObjectArray)taskCollection);
+ }
+
+ public IEnumerable Tasks
+ {
+ get { return _tasks; }
+ }
+
+ public void Clear()
+ {
+ _tasks.Clear();
+ }
+ }
+
+ ///
+ /// Represents a shell object that can be inserted to an application's
+ /// jump list.
+ ///
+ public interface IJumpListShellObject
+ {
+ ///
+ /// Gets or sets the object's title.
+ ///
+ string Title { get; }
+ ///
+ /// Gets or sets the object's path.
+ ///
+ string Path { get; }
+
+ ///
+ /// Gets the shell representation of an object, such as
+ /// IShellLink or IShellItem.
+ ///
+ ///
+ object GetShellRepresentation();
+ }
+
+ ///
+ /// Represents a jump list destination.
+ ///
+ public interface IJumpListDestination : IJumpListShellObject
+ {
+ ///
+ /// Gets or sets the destination's category.
+ ///
+ string Category { get; }
+ }
+ ///
+ /// Represents a jump list task.
+ ///
+ public interface IJumpListTask : IJumpListShellObject
+ {
+ ///
+ /// Gets or sets the task's command line arguments.
+ ///
+ string Arguments { get; }
+ }
+
+ ///
+ /// Flags controlling the appearance of a window.
+ ///
+ public enum WindowShowCommand : uint
+ {
+ ///
+ /// Hides the window and activates another window.
+ ///
+ Hide = 0,
+ ///
+ /// Activates and displays the window (including restoring
+ /// it to its original size and position).
+ ///
+ Normal = 1,
+ ///
+ /// Minimizes the window.
+ ///
+ Minimized = 2,
+ ///
+ /// Maximizes the window.
+ ///
+ Maximized = 3,
+ ///
+ /// Similar to , except that the window
+ /// is not activated.
+ ///
+ ShowNoActivate = 4,
+ ///
+ /// Activates the window and displays it in its current size
+ /// and position.
+ ///
+ Show = 5,
+ ///
+ /// Minimizes the window and activates the next top-level window.
+ ///
+ Minimize = 6,
+ ///
+ /// Minimizes the window and does not activate it.
+ ///
+ ShowMinimizedNoActivate = 7,
+ ///
+ /// Similar to , except that the window is not
+ /// activated.
+ ///
+ ShowNA = 8,
+ ///
+ /// Activates and displays the window, restoring it to its original
+ /// size and position.
+ ///
+ Restore = 9,
+ ///
+ /// Sets the show state based on the initial value specified when
+ /// the process was created.
+ ///
+ Default = 10,
+ ///
+ /// Minimizes a window, even if the thread owning the window is not
+ /// responding. Use this only to minimize windows from a different
+ /// thread.
+ ///
+ ForceMinimize = 11
+ }
+
+ ///
+ /// Represents a separator in the task area of the jump list.
+ /// There is no need to set any properties on this class.
+ ///
+ public sealed class Separator : IJumpListTask
+ {
+ string IJumpListTask.Arguments
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ string IJumpListShellObject.Title
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ string IJumpListShellObject.Path
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ object IJumpListShellObject.GetShellRepresentation()
+ {
+ ShellLink shellLink = new ShellLink
+ {
+ IsSeparator = true
+ };
+ return shellLink.GetShellRepresentation();
+ }
+ }
+
+ ///
+ /// Represents a shell link (IShellLink) object.
+ ///
+ public sealed class ShellLink : IJumpListTask, IJumpListDestination
+ {
+ ///
+ /// Gets or sets the object's title.
+ ///
+ public string Title { get; set; }
+ ///
+ /// Gets or sets the object's category.
+ ///
+ public string Category { get; set; }
+
+ ///
+ /// Gets or sets the object's path.
+ ///
+ public string Path { get; set; }
+ ///
+ /// Gets or sets the location of the object's icon.
+ ///
+ public string IconLocation { get; set; }
+ ///
+ /// Gets or sets the index of the object's icon in the specified
+ /// icon's location ().
+ ///
+ public int IconIndex { get; set; }
+ ///
+ /// Gets or sets the object's arguments (passed to the command
+ /// line).
+ ///
+ public string Arguments { get; set; }
+ ///
+ /// Gets or sets the object's working directory.
+ ///
+ public string WorkingDirectory { get; set; }
+
+ ///
+ /// Gets or sets the show command of the launched application.
+ ///
+ public WindowShowCommand ShowCommand { get; set; }
+
+ ///
+ /// Gets or sets a flag indicating that the shell link
+ /// is a menu separator. If this flag is set, all other
+ /// properties are ignored.
+ ///
+ internal bool IsSeparator { get; set; }
+
+ ///
+ /// Gets the shell IShellLink representation
+ /// of the object.
+ ///
+ /// An IShellLink up-cast to object.
+ public object GetShellRepresentation()
+ {
+ IShellLinkW shellLink = (IShellLinkW)new CShellLink();
+
+ IPropertyStore propertyStore = (IPropertyStore)shellLink;
+ PropVariant propVariant = new PropVariant();
+
+ if (IsSeparator)
+ {
+ propVariant.SetValue(true);
+ propertyStore.SetValue(ref PropertyKey.PKEY_AppUserModel_IsDestListSeparator, ref propVariant);
+ propVariant.Clear();
+ }
+ else
+ {
+ shellLink.SetPath(Path);
+
+ if (!String.IsNullOrEmpty(IconLocation))
+ shellLink.SetIconLocation(IconLocation, IconIndex);
+ if (!String.IsNullOrEmpty(Arguments))
+ shellLink.SetArguments(Arguments);
+ if (!String.IsNullOrEmpty(WorkingDirectory))
+ shellLink.SetWorkingDirectory(WorkingDirectory);
+ shellLink.SetShowCmd((uint)ShowCommand);
+
+ propVariant.SetValue(Title);
+ propertyStore.SetValue(ref PropertyKey.PKEY_Title, ref propVariant);
+ propVariant.Clear();
+ }
+
+ propertyStore.Commit();
+
+ return shellLink;
+ }
+ }
+
+ ///
+ /// Represents a IShellItem object.
+ ///
+ public sealed class ShellItem : IJumpListDestination
+ {
+ string IJumpListShellObject.Title { get { return null; } }
+
+ ///
+ /// Gets or sets the object's category.
+ ///
+ public string Category { get; set; }
+
+ ///
+ /// Gets or sets the object's path.
+ ///
+ public string Path { get; set; }
+
+ ///
+ /// Gets the shell IShellItem representation
+ /// of the object.
+ ///
+ /// An IShellItem up-cast to object.
+ public object GetShellRepresentation()
+ {
+ return null;// GetShellItemFromPath(Path);
+
+ //Note: this will only work if there is a file association
+ //for the extension we're trying to register to our program.
+ }
+
+ internal static IShellItem GetShellItemFromPath(string path)
+ {
+ if (String.IsNullOrEmpty(path))
+ throw new ArgumentNullException(
+ "path", "Shell item cannot be generated from null or empty path.");
+
+ IShellItem resultItem = default(IShellItem);
+ //Guid shellItemGuid = new Guid(IIDGuid.IShellItem);
+ //uint result = SHCreateItemFromParsingName(
+ // path,
+ // IntPtr.Zero,
+ // ref shellItemGuid,
+ // out resultItem);
+ //// Throw if an error occurred.
+ //System.Runtime.InteropServices.Marshal.ThrowExceptionForHR((int)result);
+ return resultItem;
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/trunk/ProcessHacker/Components/TaskbarLib/JumpLists/JumpListManager.cs b/trunk/ProcessHacker/Components/TaskbarLib/JumpLists/JumpListManager.cs
new file mode 100644
index 000000000..cf0d629c2
--- /dev/null
+++ b/trunk/ProcessHacker/Components/TaskbarLib/JumpLists/JumpListManager.cs
@@ -0,0 +1,528 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using Microsoft.Win32;
+using TaskbarLib.Interop;
+using System.Runtime.CompilerServices;
+using TaskbarLib.DesktopIntegration;
+
+namespace TaskbarLib.DesktopIntegration
+{
+ ///
+ /// Provides services to manage taskbar jump lists, including
+ /// custom destinations and custom tasks.
+ ///
+ ///
+ /// This class mostly borrows the Windows Shell's concepts where
+ /// jump lists are concerned including:
+ /// Application destinations - Destinations added to the application's
+ /// recent and frequent categories by the shell or by the application.
+ /// Custom destinations - Destinations added to the application's
+ /// jump list in other categories by the application.
+ /// Tasks - Tasks added to the application's jump list.
+ /// The methods of this class are not thread-safe.
+ ///
+ public sealed class JumpListManager : IDisposable
+ {
+ #region Members
+
+ string _appId;
+ JumpListDestinations _destinations;
+ JumpListTasks _tasks;
+
+ ICustomDestinationList _customDestinationList;
+ uint _maxSlotsInList;
+
+ ApplicationDestinationType _enabledAutoDestinationType = ApplicationDestinationType.Recent;
+
+ EventHandler _displaySettingsChangeHandler;
+
+ #endregion
+
+ ///
+ /// Initializes a new instance of the jump list manager
+ /// with the specified application id.
+ ///
+ /// The application id.
+ public JumpListManager(string appId)
+ {
+ _appId = appId;
+ _destinations = new JumpListDestinations();
+ _tasks = new JumpListTasks();
+
+ _customDestinationList = (ICustomDestinationList)new CDestinationList();
+ if (String.IsNullOrEmpty(_appId))
+ {
+ _appId = Windows7Taskbar.GetCurrentProcessAppId();
+ }
+ if (!String.IsNullOrEmpty(_appId))
+ {
+ _customDestinationList.SetAppID(_appId);
+ }
+
+ _displaySettingsChangeHandler = delegate
+ {
+ RefreshMaxSlots();
+ };
+ SystemEvents.DisplaySettingsChanged +=
+ _displaySettingsChangeHandler;
+ }
+
+ ///
+ /// Initializes a new instance of the jump list manager
+ /// with the specified window handle.
+ ///
+ /// The window handle.
+ public JumpListManager(IntPtr hwnd)
+ : this(Windows7Taskbar.GetWindowAppId(hwnd))
+ {
+ }
+
+ ///
+ /// Adds a task to the application's jump list.
+ ///
+ /// An object implementing ,
+ /// such as .
+ public void AddUserTask(IJumpListTask task)
+ {
+ _tasks.AddTask(task);
+ }
+
+ ///
+ /// Retrieves the tasks currently present in the application's
+ /// jump list. If the tasks are modified through the use of this
+ /// property, the method must be called to
+ /// repopulate the application's jump list.
+ ///
+ public IEnumerable Tasks
+ {
+ get { return _tasks.Tasks; }
+ }
+
+ ///
+ /// Deletes the specified task from the application's jump list.
+ ///
+ /// The task to delete.
+ public void DeleteTask(IJumpListTask task)
+ {
+ _tasks.DeleteTask(task);
+ }
+
+ ///
+ /// Deletes all the tasks from the application's jump list.
+ ///
+ public void ClearTasks()
+ {
+ _tasks.Clear();
+ }
+
+ ///
+ /// Adds a custom destination to the application's jump list.
+ ///
+ /// An object implementing
+ /// such as
+ /// or .
+ public void AddCustomDestination(IJumpListDestination destination)
+ {
+ _destinations.AddDestination(destination);
+ }
+
+ ///
+ /// Deletes the specified custom destination from the application's
+ /// jump list.
+ ///
+ /// The destination to delete.
+ public void DeleteCustomDestination(IJumpListDestination destination)
+ {
+ _destinations.DeleteDestination(destination);
+ }
+
+ ///
+ /// The currently enabled automatic application destination type.
+ /// The supported values are the values of the
+ /// enumeration.
+ /// Only of the values can be set at any given time.
+ ///
+ public ApplicationDestinationType EnabledAutoDestinationType
+ {
+ get
+ {
+ return _enabledAutoDestinationType;
+ }
+ set
+ {
+ if (_enabledAutoDestinationType == value)
+ return;
+
+ _enabledAutoDestinationType = value;
+ }
+ }
+
+ ///
+ /// Removes all destinations from the application's jump list.
+ ///
+ public void ClearAllDestinations()
+ {
+ ClearApplicationDestinations();
+ ClearCustomDestinations();
+ }
+
+ ///
+ /// Removes all application destinations (such as frequent and recent)
+ /// from the application's jump list.
+ ///
+ public void ClearApplicationDestinations()
+ {
+ IApplicationDestinations destinations = (IApplicationDestinations)
+ new CApplicationDestinations();
+ if (!String.IsNullOrEmpty(_appId))
+ {
+ destinations.SetAppID(_appId);
+ }
+ try
+ {
+ //This does not remove pinned items.
+ destinations.RemoveAllDestinations();
+ }
+ catch (System.IO.FileNotFoundException)
+ {//There are no destinations. That's cool.
+ }
+ }
+
+ ///
+ /// Retrieves all application destinations belonging to the specified
+ /// application destination type.
+ ///
+ /// The application destination type.
+ /// A copy of the application destinations belonging to
+ /// the specified type; modifying the returned objects has no effect
+ /// on the application's destination list.
+ public IEnumerable GetApplicationDestinations(ApplicationDestinationType type)
+ {
+ if (type == ApplicationDestinationType.NONE)
+ throw new ArgumentException("type can't be NONE");
+
+ IApplicationDocumentLists destinations = (IApplicationDocumentLists)new CApplicationDocumentLists();
+ Guid iidObjectArray = typeof(IObjectArray).GUID;
+ object obj;
+
+ destinations.GetList((APPDOCLISTTYPE)type, 100, ref iidObjectArray, out obj);
+
+ List returnValue = new List();
+
+ Guid iidShellItem = typeof(IShellItem).GUID;
+ Guid iidShellLink = typeof(IShellLinkW).GUID;
+ IObjectArray array = (IObjectArray)obj;
+ uint count;
+ array.GetCount(out count);
+ for (uint i = 0; i < count; ++i)
+ {
+ try
+ {
+ array.GetAt(i, ref iidShellItem, out obj);
+ }
+ catch (Exception)//Wrong type
+ {
+ }
+ if (obj == null)
+ {
+ array.GetAt(i, ref iidShellLink, out obj);
+ //This shouldn't fail since if it's not IShellItem
+ //then it must be IShellLink.
+
+ IShellLinkW link = (IShellLinkW)obj;
+ ShellLink wrapper = new ShellLink();
+
+ StringBuilder sb = new StringBuilder(256);
+ link.GetPath(sb, sb.Capacity, IntPtr.Zero, 2);
+ wrapper.Path = sb.ToString();
+
+ link.GetArguments(sb, sb.Capacity);
+ wrapper.Arguments = sb.ToString();
+
+ int iconId;
+ link.GetIconLocation(sb, sb.Capacity, out iconId);
+ wrapper.IconIndex = iconId;
+ wrapper.IconLocation = sb.ToString();
+
+ uint showCmd;
+ link.GetShowCmd(out showCmd);
+ wrapper.ShowCommand = (WindowShowCommand)showCmd;
+
+ link.GetWorkingDirectory(sb, sb.Capacity);
+ wrapper.WorkingDirectory = sb.ToString();
+
+ returnValue.Add(wrapper);
+ }
+ else //It's an IShellItem.
+ {
+ IShellItem item = (IShellItem)obj;
+ ShellItem wrapper = new ShellItem();
+
+ string path;
+ item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out path);
+ wrapper.Path = path;
+
+ //Title and Category are irrelevant here, because it's
+ //an IShellItem. The user might want to see them, but he's
+ //free to go to the IShellItem and look at its property store.
+
+ returnValue.Add(wrapper);
+ }
+ }
+
+ return returnValue;
+ }
+
+ ///
+ /// Deletes the specified application destination from the application's
+ /// jump list.
+ ///
+ /// The application destination.
+ public void DeleteApplicationDestination(IJumpListDestination destination)
+ {
+ IApplicationDestinations destinations = (IApplicationDestinations)
+ new CApplicationDestinations();
+ if (!String.IsNullOrEmpty(_appId))
+ {
+ destinations.SetAppID(_appId);
+ }
+
+ destinations.RemoveDestination(destination.GetShellRepresentation());
+ }
+
+ ///
+ /// Deletes all custom destinations from the application's jump list.
+ ///
+ public void ClearCustomDestinations()
+ {
+ try
+ {
+ _customDestinationList.DeleteList(_appId);
+ }
+ catch (FileNotFoundException)
+ {//Means the list is empty, that's cool.
+ }
+
+ _destinations.Clear();
+ }
+
+ ///
+ /// Repopulates the application's jump list.
+ /// Use this method after all current changes to
+ /// the application's jump list have been introduced,
+ /// and you want the list to be refreshed.
+ ///
+ /// true if the list was refreshed; false
+ /// if the operation was cancelled. The operation might have
+ /// been cancelled if the event
+ /// handler instructed us to cancel the operation.
+ ///
+ /// If the user removed items from the jump list between the
+ /// last refresh operation and this one, then the
+ /// event will be invoked.
+ /// If the event handler for this event instructed us to cancel
+ /// the operation, then the current transaction is aborted,
+ /// no items are added, and this method returns false.
+ /// Check the return value to determine whether the jump list
+ /// needs to be changed and the operation attempted again.
+ ///
+ public bool Refresh()
+ {
+ if (!BeginList())
+ return false; //Operation was cancelled
+
+ _tasks.RefreshTasks(_customDestinationList);
+ _destinations.RefreshDestinations(_customDestinationList);
+
+ switch (EnabledAutoDestinationType)
+ {
+ case ApplicationDestinationType.Frequent:
+ _customDestinationList.AppendKnownCategory(KNOWNDESTCATEGORY.KDC_FREQUENT);
+ break;
+ case ApplicationDestinationType.Recent:
+ _customDestinationList.AppendKnownCategory(KNOWNDESTCATEGORY.KDC_RECENT);
+ break;
+ }
+
+ CommitList();
+ return true;
+ }
+
+ ///
+ /// Returns the maximum number of items to be placed
+ /// in the application's jump list. This number depends
+ /// on factors such as the display resolution or monitor
+ /// change - do not assume it is always constant.
+ ///
+ public uint MaximumSlotsInList
+ {
+ get
+ {
+ if (_maxSlotsInList == 0)
+ {
+ RefreshMaxSlots();
+ }
+ return _maxSlotsInList;
+ }
+ }
+
+ ///
+ /// Cleans the resources associated with this jump list.
+ ///
+ public void Dispose()
+ {
+ SystemEvents.DisplaySettingsChanged -=
+ _displaySettingsChangeHandler;
+ if (_customDestinationList != null)
+ Marshal.ReleaseComObject(_customDestinationList);
+ }
+
+ ///
+ /// Register to this event to receive notifications when custom
+ /// destinations are being removed from your jump list by the user.
+ /// If you do not register to this event, you will not be able
+ /// to refresh the list. Additionally, if you attempt to add
+ /// items to the list which have been previously removed by the user,
+ /// the next refresh will fail to add your category.
+ ///
+ public event EventHandler UserRemovedItems;
+
+ #region Implementation
+
+ private void RefreshMaxSlots()
+ {
+ object obj;
+ _customDestinationList.BeginList(out _maxSlotsInList, ref SafeNativeMethods.IID_IObjectArray, out obj);
+ _customDestinationList.AbortList();
+ }
+
+ private bool BeginList()
+ {
+ if (UserRemovedItems == null)
+ {
+ throw new InvalidOperationException("You must register for the JumpListManager.UserRemovedItems event before adding any items");
+ }
+
+ object obj;
+ _customDestinationList.BeginList(out _maxSlotsInList, ref SafeNativeMethods.IID_IObjectArray, out obj);
+
+ IObjectArray removedItems = (IObjectArray)obj;
+ uint count;
+ removedItems.GetCount(out count);
+ if (count == 0)
+ return true;
+
+ string[] removedItemsArr = new string[count];
+ for (uint i = 0; i < count; ++i)
+ {
+ object item;
+ removedItems.GetAt(i, ref SafeNativeMethods.IID_IUnknown, out item);
+
+ try
+ {
+ IShellLinkW shellLink = (IShellLinkW)item;
+ if (shellLink != null)
+ {
+ StringBuilder sb = new StringBuilder(256);
+ shellLink.GetPath(sb, sb.Capacity, IntPtr.Zero, 2);
+ removedItemsArr[i] = sb.ToString();
+ }
+ continue;
+ }
+ catch (InvalidCastException) //It's not a ShellLink
+ { }
+
+ try
+ {
+ IShellItem shellItem = (IShellItem)item;
+ if (shellItem != null)
+ {
+ string path;
+ shellItem.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out path);
+ removedItemsArr[i] = path;
+ }
+ }
+ catch (InvalidCastException)
+ {
+ //It's neither a shell link nor a shell item.
+ //This is impossible.
+ Debug.Assert(false,
+ "List of removed items contains something that is neither a shell item nor a shell link");
+ }
+ }
+
+ UserRemovedItemsEventArgs args = new UserRemovedItemsEventArgs(removedItemsArr);
+ UserRemovedItems(this, args);
+ if (args.CancelCurrentOperation)
+ {
+ _customDestinationList.AbortList();
+ }
+ return !args.CancelCurrentOperation;
+ }
+
+ private void CommitList()
+ {
+ _customDestinationList.CommitList();
+ }
+
+ #endregion
+ }
+
+ ///
+ /// The application destination type.
+ ///
+ public enum ApplicationDestinationType
+ {
+ ///
+ /// No application destination type is selected.
+ ///
+ NONE = -1,
+ ///
+ /// Destinations used recently.
+ ///
+ Recent = 0,
+ ///
+ /// Destinations used frequently.
+ ///
+ Frequent
+ }
+
+ ///
+ /// The event arguments for the event that occurs
+ /// when the user removes items from the application's
+ /// jump list.
+ ///
+ public class UserRemovedItemsEventArgs : EventArgs
+ {
+ readonly string[] _removedItems;
+
+ internal UserRemovedItemsEventArgs(string[] removedItems)
+ {
+ _removedItems = removedItems;
+ }
+
+ ///
+ /// The collection of removed items. Each item is the path.
+ ///
+ public string[] RemovedItems
+ {
+ get
+ {
+ return _removedItems;
+ }
+ }
+
+ ///
+ /// Set to true if the current operation
+ /// should be cancelled. Should be used by the application
+ /// if because of the items the user has removed
+ /// there is no real work to do with the jump list.
+ ///
+ public bool CancelCurrentOperation { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/trunk/ProcessHacker/Components/TaskbarLib/ThumbnailButtons/ThumbButton.cs b/trunk/ProcessHacker/Components/TaskbarLib/ThumbnailButtons/ThumbButton.cs
new file mode 100644
index 000000000..221420a7e
--- /dev/null
+++ b/trunk/ProcessHacker/Components/TaskbarLib/ThumbnailButtons/ThumbButton.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Drawing;
+using TaskbarLib.Interop;
+
+namespace TaskbarLib.DesktopIntegration
+{
+ ///
+ /// Represents a taskbar thumbnail button in the thumbnail toolbar.
+ ///
+ public sealed class ThumbButton
+ {
+ private ThumbButtonManager _manager;
+
+ internal ThumbButton(ThumbButtonManager manager, uint id, Icon icon, string tooltip)
+ {
+ _manager = manager;
+
+ Id = id;
+ Icon = icon;
+ Tooltip = tooltip;
+ }
+
+ ///
+ /// The event that occurs when the taskbar thumbnail button
+ /// is clicked.
+ ///
+ public event EventHandler Clicked;
+
+ ///
+ /// Gets or sets thumbnail button's id.
+ ///
+ public uint Id { get; set; }
+
+ ///
+ /// Gets or sets the thumbnail button's icon.
+ ///
+ public Icon Icon { get; set; }
+
+ ///
+ /// Gets or sets the thumbnail button's tooltip.
+ ///
+ public string Tooltip { get; set; }
+
+ internal THBFLAGS Flags { get; set; }
+
+ internal THUMBBUTTON Win32ThumbButton
+ {
+ get
+ {
+ THUMBBUTTON win32ThumbButton = new THUMBBUTTON();
+ win32ThumbButton.iId = Id;
+ win32ThumbButton.szTip = Tooltip;
+ win32ThumbButton.hIcon = Icon.Handle;
+ win32ThumbButton.dwFlags = Flags;
+
+ win32ThumbButton.dwMask = THBMASK.THB_FLAGS;
+ if (Tooltip != null)
+ win32ThumbButton.dwMask |= THBMASK.THB_TOOLTIP;
+ if (Icon != null)
+ win32ThumbButton.dwMask |= THBMASK.THB_ICON;
+
+ return win32ThumbButton;
+ }
+ }
+
+ ///
+ /// Gets or sets the thumbnail button's visibility.
+ ///
+ public bool Visible
+ {
+ get
+ {
+ return (this.Flags & THBFLAGS.THBF_HIDDEN) == 0;
+ }
+ set
+ {
+ if (value)
+ {
+ this.Flags &= ~(THBFLAGS.THBF_HIDDEN);
+ }
+ else
+ {
+ this.Flags |= THBFLAGS.THBF_HIDDEN;
+ }
+ _manager.RefreshThumbButtons();
+ }
+ }
+
+ ///
+ /// Gets or sets the thumbnail button's enabled state.
+ ///
+ public bool Enabled
+ {
+ get
+ {
+ return (this.Flags & THBFLAGS.THBF_DISABLED) == 0;
+ }
+ set
+ {
+ if (value)
+ {
+ this.Flags &= ~(THBFLAGS.THBF_DISABLED);
+ }
+ else
+ {
+ this.Flags |= THBFLAGS.THBF_DISABLED;
+ }
+ _manager.RefreshThumbButtons();
+ }
+ }
+
+ internal void FireClick()
+ {
+ if (Clicked != null)
+ Clicked(this, EventArgs.Empty);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/trunk/ProcessHacker/Components/TaskbarLib/ThumbnailButtons/ThumbButtonManager.cs b/trunk/ProcessHacker/Components/TaskbarLib/ThumbnailButtons/ThumbButtonManager.cs
new file mode 100644
index 000000000..9a71231bc
--- /dev/null
+++ b/trunk/ProcessHacker/Components/TaskbarLib/ThumbnailButtons/ThumbButtonManager.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Windows.Forms;
+using TaskbarLib.Interop;
+using System.Collections;
+
+namespace TaskbarLib.DesktopIntegration
+{
+ ///
+ /// Manages a set of taskbar thumbnail buttons in an application.
+ ///
+ public sealed class ThumbButtonManager
+ {
+ ///
+ /// Initializes a new manager with the specified window handle.
+ ///
+ /// The window handle.
+ public ThumbButtonManager(IntPtr hwnd)
+ {
+ _hwnd = hwnd;
+ }
+
+ ///
+ /// Creates a new taskbar thumbnail button.
+ ///
+ /// The button's id.
+ /// The button's icon.
+ /// The button's tooltip.
+ /// An object of type
+ /// representing the newly created thumbnail button.
+ public ThumbButton CreateThumbButton(uint id, Icon icon, string tooltip)
+ {
+ return new ThumbButton(this, id, icon, tooltip);
+ }
+
+ ///
+ /// Dispatches a Windows message to the thumbnail button event
+ /// handlers if appropriate.
+ ///
+ ///
+ /// This method is intended for infrastructure use only.
+ ///
+ /// The message.
+ public void DispatchMessage(ref Message message)
+ {
+ UInt64 wparam = (UInt64)message.WParam.ToInt64();
+ UInt32 wparam32 = (UInt32) (wparam & 0xffffffff); //Clear top 32 bits
+
+ if (message.Msg == SafeNativeMethods.WM_COMMAND && (wparam32 >> 16 == SafeNativeMethods.THBN_CLICKED))
+ {
+ uint id = wparam32 & 0xffff; //Bottom 16 bits
+ _thumbButtons[id].FireClick();
+ }
+ }
+
+ ///
+ /// Adds the specified taskbar thumbnail buttons to the application's
+ /// thumbnail toolbar.
+ ///
+ ///
+ /// Thumbnail buttons can only be added once - after being added,
+ /// they cannot be removed or deleted. However, they can be shown,
+ /// hidden, enabled and disabled.
+ ///
+ /// The buttons to add.
+ public void AddThumbButtons(params ThumbButton[] buttons)
+ {
+ Array.ForEach(buttons, b => _thumbButtons.Add(b.Id, b));
+
+ RefreshThumbButtons();
+ }
+
+ ///
+ /// Gets a specific thumbnail button by its id.
+ ///
+ /// The thumbnail button's id.
+ /// An object of type
+ /// with the specified id.
+ public ThumbButton this[uint id]
+ {
+ get
+ {
+ return _thumbButtons[id];
+ }
+ }
+
+ #region Implementation
+
+ private bool _buttonsLoaded;
+ internal void RefreshThumbButtons()
+ {
+ THUMBBUTTON[] win32Buttons = (from thumbButton in _thumbButtons.Values select thumbButton.Win32ThumbButton).ToArray();
+
+ if (_buttonsLoaded)
+ {
+ Windows7Taskbar.TaskbarList.ThumbBarUpdateButtons(_hwnd, (uint)win32Buttons.Length, win32Buttons);
+ }
+ else //First time
+ {
+ Windows7Taskbar.TaskbarList.ThumbBarAddButtons(_hwnd, (uint)win32Buttons.Length, win32Buttons);
+ _buttonsLoaded = true;
+ }
+ }
+
+ private Dictionary _thumbButtons = new Dictionary();
+ private IntPtr _hwnd;
+
+ #endregion
+ }
+
+}
\ No newline at end of file
diff --git a/trunk/ProcessHacker/Components/TaskbarLib/Windows7Taskbar.cs b/trunk/ProcessHacker/Components/TaskbarLib/Windows7Taskbar.cs
new file mode 100644
index 000000000..b9dd2ee4f
--- /dev/null
+++ b/trunk/ProcessHacker/Components/TaskbarLib/Windows7Taskbar.cs
@@ -0,0 +1,316 @@
+using System;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using TaskbarLib.Interop;
+
+namespace TaskbarLib.DesktopIntegration
+{
+ ///
+ /// The primary coordinator of the Windows 7 taskbar-related activities.
+ /// For additional functionality, see the JumpListManager
+ /// and ThumbButtonManager classes.
+ ///
+ public static class Windows7Taskbar
+ {
+ #region Infrastructure
+
+ ///
+ /// The WM_TaskbarButtonCreated message number.
+ ///
+ public static uint TaskbarButtonCreatedMessage
+ {
+ get { return UnsafeNativeMethods.WM_TaskbarButtonCreated; }
+ }
+
+ // Use thread static to work around COM threading issues.
+ [ThreadStatic]
+ private static ITaskbarList3 _taskbarList;
+ internal static ITaskbarList3 TaskbarList
+ {
+ get
+ {
+ if (_taskbarList == null)
+ {
+ _taskbarList = (ITaskbarList3)new CTaskbarList();
+ _taskbarList.HrInit();
+ }
+ return _taskbarList;
+ }
+ }
+
+ private static IPropertyStore InternalGetWindowPropertyStore(IntPtr hwnd)
+ {
+ IPropertyStore propStore;
+ int rc = UnsafeNativeMethods.SHGetPropertyStoreForWindow(hwnd, ref SafeNativeMethods.IID_IPropertyStore, out propStore);
+ if (rc != 0)
+ throw Marshal.GetExceptionForHR(rc);
+
+ return propStore;
+ }
+
+ private static void InternalEnableCustomWindowPreview(IntPtr hwnd, bool enable)
+ {
+ int t = enable ? 1 : 0;
+
+ int rc;
+ rc = UnsafeNativeMethods.DwmSetWindowAttribute(hwnd, SafeNativeMethods.DWMWA_HAS_ICONIC_BITMAP, ref t, 4);
+ if (rc != 0)
+ throw Marshal.GetExceptionForHR(rc);
+
+ rc = UnsafeNativeMethods.DwmSetWindowAttribute(hwnd, SafeNativeMethods.DWMWA_FORCE_ICONIC_REPRESENTATION, ref t, 4);
+ if (rc != 0)
+ throw Marshal.GetExceptionForHR(rc);
+ }
+
+ #endregion
+
+ #region Application Id
+
+ ///
+ /// Gets a window's application id by its window handle.
+ ///
+ /// The window handle.
+ /// The application id of that window.
+ public static string GetWindowAppId(IntPtr hwnd)
+ {
+ IPropertyStore propStore = InternalGetWindowPropertyStore(hwnd);
+
+ PropVariant pv;
+ propStore.GetValue(ref PropertyKey.PKEY_AppUserModel_ID, out pv);
+
+ Marshal.ReleaseComObject(propStore);
+
+ return pv.GetValue();
+ }
+
+ ///
+ /// Sets the window's application id by its window handle.
+ ///
+ /// The window handle.
+ /// The application id.
+ public static void SetWindowAppId(IntPtr hwnd, string appId)
+ {
+ IPropertyStore propStore = InternalGetWindowPropertyStore(hwnd);
+
+ PropVariant pv = new PropVariant();
+ pv.SetValue(appId);
+ propStore.SetValue(ref PropertyKey.PKEY_AppUserModel_ID, ref pv);
+
+ Marshal.ReleaseComObject(propStore);
+ }
+
+ ///
+ /// Sets the current process' explicit application user model id.
+ ///
+ /// The application id.
+ public static void SetCurrentProcessAppId(string appId)
+ {
+ UnsafeNativeMethods.SetCurrentProcessExplicitAppUserModelID(appId);
+ }
+
+ ///
+ /// Gets the current process' explicit application user model id.
+ ///
+ /// The application id.
+ public static string GetCurrentProcessAppId()
+ {
+ string appId;
+ UnsafeNativeMethods.GetCurrentProcessExplicitAppUserModelID(out appId);
+ return appId;
+ }
+
+ #endregion
+
+ #region DWM Iconic Thumbnail and Peek Bitmap
+
+ ///
+ /// Indicates that the specified window requests the DWM
+ /// to demand live preview (thumbnail and peek) mode when necessary
+ /// instead of relying on default preview.
+ ///
+ /// The window handle.
+ public static void EnableCustomWindowPreview(IntPtr hwnd)
+ {
+ InternalEnableCustomWindowPreview(hwnd, true);
+ }
+
+ ///
+ /// Indicates that the specified window does not require the DWM
+ /// to demand live preview (thumbnail and peek) mode when necessary,
+ /// i.e. this window relies on default preview.
+ ///
+ /// The window handle.
+ public static void DisableCustomWindowPreview(IntPtr hwnd)
+ {
+ InternalEnableCustomWindowPreview(hwnd, false);
+ }
+
+ ///
+ /// Sets the specified iconic thumbnail for the specified window.
+ /// This is typically done in response to a DWM message.
+ ///
+ /// The window handle.
+ /// The thumbnail bitmap.
+ public static void SetIconicThumbnail(IntPtr hwnd, Bitmap bitmap)
+ {
+ int rc = UnsafeNativeMethods.DwmSetIconicThumbnail(hwnd, bitmap.GetHbitmap(), SafeNativeMethods.DWM_SIT_DISPLAYFRAME);
+ if (rc != 0)
+ throw Marshal.GetExceptionForHR(rc);
+ }
+
+ ///
+ /// Sets the specified peek (live preview) bitmap for the specified
+ /// window. This is typically done in response to a DWM message.
+ ///
+ /// The window handle.
+ /// The thumbnail bitmap.
+ /// Whether to display a standard window
+ /// frame around the bitmap.
+ public static void SetPeekBitmap(IntPtr hwnd, Bitmap bitmap, bool displayFrame)
+ {
+ int rc = UnsafeNativeMethods.DwmSetIconicLivePreviewBitmap(hwnd, bitmap.GetHbitmap(), IntPtr.Zero, displayFrame ? SafeNativeMethods.DWM_SIT_DISPLAYFRAME : (uint)0);
+
+ if (rc != 0)
+ throw Marshal.GetExceptionForHR(rc);
+ }
+
+ ///
+ /// Sets the specified peek (live preview) bitmap for the specified
+ /// window. This is typically done in response to a DWM message.
+ ///
+ /// The window handle.
+ /// The thumbnail bitmap.
+ /// The client area offset at which to display
+ /// the specified bitmap. The rest of the parent window will be
+ /// displayed as "remembered" by the DWM.
+ /// Whether to display a standard window
+ /// frame around the bitmap.
+ public static void SetPeekBitmap(IntPtr hwnd, Bitmap bitmap, Point offset, bool displayFrame)
+ {
+ var nativePoint = new POINT(offset.X, offset.Y);
+ int rc = UnsafeNativeMethods.DwmSetIconicLivePreviewBitmap(hwnd, bitmap.GetHbitmap(), ref nativePoint, displayFrame ? SafeNativeMethods.DWM_SIT_DISPLAYFRAME : (uint)0);
+ if (rc != 0)
+ throw Marshal.GetExceptionForHR(rc);
+ }
+
+ #endregion
+
+ #region Taskbar Overlay Icon
+
+ ///
+ /// Draws the specified overlay icon on the specified window's
+ /// taskbar button.
+ ///
+ /// The window handle.
+ /// The overlay icon.
+ /// The overlay icon description.
+ public static void SetTaskbarOverlayIcon(IntPtr hwnd, Icon icon, string description)
+ {
+ TaskbarList.SetOverlayIcon(
+ hwnd,
+ icon == null ? IntPtr.Zero : icon.Handle,
+ description);
+ }
+
+ #endregion
+
+ #region Taskbar Progress Bar
+
+ ///
+ /// Represents the thumbnail progress bar state.
+ ///
+ public enum ThumbnailProgressState
+ {
+ ///
+ /// No progress is displayed.
+ ///
+ NoProgress = 0,
+ ///
+ /// The progress is indeterminate (marquee).
+ ///
+ Indeterminate = 0x1,
+ ///
+ /// Normal progress is displayed.
+ ///
+ Normal = 0x2,
+ ///
+ /// An error occurred (red).
+ ///
+ Error = 0x4,
+ ///
+ /// The operation is paused (yellow).
+ ///
+ Paused = 0x8
+ }
+
+ ///
+ /// Sets the progress state of the specified window's
+ /// taskbar button.
+ ///
+ /// The window handle.
+ /// The progress state.
+ public static void SetProgressState(IntPtr hwnd, ThumbnailProgressState state)
+ {
+ TaskbarList.SetProgressState(hwnd, (TBPFLAG)state);
+ }
+ ///
+ /// Sets the progress value of the specified window's
+ /// taskbar button.
+ ///
+ /// The window handle.
+ /// The current value.
+ /// The maximum value.
+ public static void SetProgressValue(IntPtr hwnd, ulong current, ulong maximum)
+ {
+ TaskbarList.SetProgressValue(hwnd, current, maximum);
+ }
+
+ #endregion
+
+ #region Taskbar Thumbnails
+
+ ///
+ /// Specifies that only a portion of the window's client area
+ /// should be used in the window's thumbnail.
+ ///
+ /// The window.
+ /// The rectangle that specifies the clipped region.
+ public static void SetThumbnailClip(IntPtr hwnd, Rectangle clipRect)
+ {
+ RECT rect = new RECT(clipRect.Left, clipRect.Top, clipRect.Right, clipRect.Bottom);
+ TaskbarList.SetThumbnailClip(hwnd, ref rect);
+ }
+
+ ///
+ /// Sets the specified window's thumbnail tooltip.
+ ///
+ /// The window.
+ /// The tooltip text.
+ public static void SetThumbnailTooltip(IntPtr hwnd, string tooltip)
+ {
+ TaskbarList.SetThumbnailTooltip(hwnd, tooltip);
+ }
+
+ #endregion
+
+ #region Miscellaneous
+
+ ///
+ /// Specifies that the taskbar- and DWM-related windows messages should
+ /// pass through the Windows UIPI mechanism even if the process is
+ /// running elevated. Calling this method is not required unless the
+ /// process is running elevated.
+ ///
+ public static void AllowTaskbarWindowMessagesThroughUipi()
+ {
+ UnsafeNativeMethods.ChangeWindowMessageFilter(UnsafeNativeMethods.WM_TaskbarButtonCreated, SafeNativeMethods.MSGFLT_ADD);
+ UnsafeNativeMethods.ChangeWindowMessageFilter(SafeNativeMethods.WM_DWMSENDICONICTHUMBNAIL, SafeNativeMethods.MSGFLT_ADD);
+ UnsafeNativeMethods.ChangeWindowMessageFilter(SafeNativeMethods.WM_DWMSENDICONICLIVEPREVIEWBITMAP, SafeNativeMethods.MSGFLT_ADD);
+ UnsafeNativeMethods.ChangeWindowMessageFilter(SafeNativeMethods.WM_COMMAND, SafeNativeMethods.MSGFLT_ADD);
+ UnsafeNativeMethods.ChangeWindowMessageFilter(SafeNativeMethods.WM_SYSCOMMAND, SafeNativeMethods.MSGFLT_ADD);
+ UnsafeNativeMethods.ChangeWindowMessageFilter(SafeNativeMethods.WM_ACTIVATE, SafeNativeMethods.MSGFLT_ADD);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/trunk/ProcessHacker/Components/TaskbarLib/WindowsFormsExtensions.cs b/trunk/ProcessHacker/Components/TaskbarLib/WindowsFormsExtensions.cs
new file mode 100644
index 000000000..e53b30f90
--- /dev/null
+++ b/trunk/ProcessHacker/Components/TaskbarLib/WindowsFormsExtensions.cs
@@ -0,0 +1,189 @@
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace TaskbarLib.DesktopIntegration.WindowsForms
+{
+ ///
+ /// Contains extension methods for easier Windows Forms interop.
+ ///
+ public static class WindowsFormsExtensions
+ {
+ ///
+ /// Sets this form's application id.
+ ///
+ /// The form.
+ /// The application id.
+ public static void SetAppId(this Form form, string appId)
+ {
+ Windows7Taskbar.SetWindowAppId(form.Handle, appId);
+ }
+
+ ///
+ /// Gets this form's application id.
+ ///
+ /// The form.
+ /// The form's application id.
+ public static string GetAppId(this Form form)
+ {
+ return Windows7Taskbar.GetWindowAppId(form.Handle);
+ }
+
+ ///
+ /// Enables custom window preview on this form, meaning that
+ /// the DWM will send messages when a live thumbnail preview
+ /// or a live peek will be necessary.
+ ///
+ /// The form.
+ public static void EnableCustomWindowPreview(this Form form)
+ {
+ Windows7Taskbar.EnableCustomWindowPreview(form.Handle);
+ }
+
+ ///
+ /// Disables custom window preview on this form, meaning that
+ /// the DWM will not send messages when a live thumbnail preview
+ /// or a live peek will be necessary, but instead rely on its
+ /// default rendering.
+ ///
+ /// The form.
+ public static void DisableCustomWindowPreview(this Form form)
+ {
+ Windows7Taskbar.DisableCustomWindowPreview(form.Handle);
+ }
+
+ ///
+ /// Sets this form's iconic thumbnail to the specified bitmap.
+ ///
+ /// The form.
+ /// The bitmap.
+ public static void SetIconicThumbnail(this Form form, Bitmap bitmap)
+ {
+ Windows7Taskbar.SetIconicThumbnail(form.Handle, bitmap);
+ }
+
+ ///
+ /// Sets this form's peek (live preview) bitmap.
+ ///
+ /// The form.
+ /// The bitmap.
+ /// Whether to display a standard window
+ /// frame around the bitmap.
+ public static void SetPeekBitmap(this Form form, Bitmap bitmap, bool displayFrame)
+ {
+ Windows7Taskbar.SetPeekBitmap(form.Handle, bitmap, displayFrame);
+ }
+
+ ///
+ /// Draws the specified overlay icon over this form's taskbar button.
+ ///
+ /// The form.
+ /// The overlay icon.
+ /// The overlay icon's description.
+ public static void SetTaskbarOverlayIcon(this Form form, Icon icon, string description)
+ {
+ Windows7Taskbar.SetTaskbarOverlayIcon(form.Handle, icon, description);
+ }
+
+ ///
+ /// Sets the progress bar in the containing form's taskbar button
+ /// to this progress bar's progress.
+ ///
+ /// The progress bar.
+ public static void SetTaskbarProgress(ProgressBar progressBar)
+ {
+ Form form = (Form)progressBar.TopLevelControl;
+
+ //Approximation:
+ ulong maximum = (ulong)(progressBar.Maximum - progressBar.Minimum);
+ ulong progress = (ulong)(progressBar.Value - progressBar.Minimum);
+
+ Windows7Taskbar.SetProgressState(form.Handle, Windows7Taskbar.ThumbnailProgressState.Normal);
+ Windows7Taskbar.SetProgressValue(form.Handle, progress, maximum);
+ }
+
+ ///
+ /// Sets the progress bar in the containing form's taskbar button
+ /// to this toolstrip progress bar's progress.
+ ///
+ /// The progress bar.
+ public static void SetTaskbarProgress(ToolStripProgressBar progressBar)
+ {
+ Form form = (Form)progressBar.Control.TopLevelControl;
+
+ //Approximation:
+ ulong maximum = (ulong)(progressBar.Maximum - progressBar.Minimum);
+ ulong progress = (ulong)(progressBar.Value - progressBar.Minimum);
+
+ Windows7Taskbar.SetProgressState(form.Handle, Windows7Taskbar.ThumbnailProgressState.Normal);
+ Windows7Taskbar.SetProgressValue(form.Handle, progress, maximum);
+ }
+
+ ///
+ /// Sets the progress bar of this form's taskbar button to the
+ /// specified percentage.
+ ///
+ /// The form.
+ /// The progress percentage.
+ public static void SetTaskbarProgress(this Form form, float percent)
+ {
+ Windows7Taskbar.SetProgressState(form.Handle, Windows7Taskbar.ThumbnailProgressState.Normal);
+ Windows7Taskbar.SetProgressValue(form.Handle, (ulong)percent, 100);
+ }
+
+ ///
+ /// Sets the progress bar of this form's taskbar button to the
+ /// specified state.
+ ///
+ /// The form.
+ /// The taskbar progress state.
+ public static void SetTaskbarProgressState(this Form form, Windows7Taskbar.ThumbnailProgressState state)
+ {
+ Windows7Taskbar.SetProgressState(form.Handle, state);
+ }
+
+ ///
+ /// Creates a taskbar thumbnail button manager for this form.
+ ///
+ /// The form.
+ /// An object of type
+ /// that can be used to add and manage thumbnail toolbar buttons.
+ public static ThumbButtonManager CreateThumbButtonManager(this Form form)
+ {
+ return new ThumbButtonManager(form.Handle);
+ }
+
+ ///
+ /// Creates a jump list manager for this form.
+ ///
+ /// The form.
+ /// An object of type
+ /// that can be used to manage the application's jump list.
+ public static JumpListManager CreateJumpListManager(this Form form)
+ {
+ return new JumpListManager(form.Handle);
+ }
+
+ ///
+ /// Specifies that only a portion of the form's client area
+ /// should be used in the form's thumbnail.
+ ///
+ /// The form.
+ /// The rectangle that specifies the clipped region.
+ public static void SetThumbnailClip(this Form form, Rectangle clipRect)
+ {
+ Windows7Taskbar.SetThumbnailClip(form.Handle, clipRect);
+ }
+
+ ///
+ /// Sets the specified form's thumbnail tooltip.
+ ///
+ /// The form.
+ /// The tooltip text.
+ public static void SetThumbnailTooltip(this Form form, string tooltip)
+ {
+ Windows7Taskbar.SetThumbnailTooltip(form.Handle, tooltip);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/trunk/ProcessHacker/ProcessHacker.csproj b/trunk/ProcessHacker/ProcessHacker.csproj
index 3819feca8..e2b133ae1 100644
--- a/trunk/ProcessHacker/ProcessHacker.csproj
+++ b/trunk/ProcessHacker/ProcessHacker.csproj
@@ -416,6 +416,14 @@
Component
+
+
+
+
+
+
+
+
UserControl