diff --git a/src/HandyControl.sln b/src/HandyControl.sln
index 36dc8888..39a603b4 100644
--- a/src/HandyControl.sln
+++ b/src/HandyControl.sln
@@ -23,11 +23,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HandyControlDemo_Net_40", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HandyControlDemo_Code", "Shared\HandyControlDemo_Code\HandyControlDemo_Code.csproj", "{D8A4748C-0500-4F63-BC47-3506658C68F7}"
EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.Windows.Shell", "Shared\Microsoft.Windows.Shell\Microsoft.Windows.Shell.shproj", "{BBE51380-8B21-49FF-9CFC-B29447A40999}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
Shared\HandyControl_Shared\HandyControl_Shared.projitems*{32204503-2ef0-4681-ae13-aa1feb6c658a}*SharedItemsImports = 5
+ Shared\Microsoft.Windows.Shell\Microsoft.Windows.Shell.projitems*{32204503-2ef0-4681-ae13-aa1feb6c658a}*SharedItemsImports = 5
Shared\HandyControlDemo_Shared\HandyControlDemo_Shared.projitems*{9a7b52e6-94bb-4e7e-bb6a-7cf6761b79a7}*SharedItemsImports = 5
Shared\HandyControl_Shared\HandyControl_Shared.projitems*{aac11083-faca-405d-9197-5c1212d65656}*SharedItemsImports = 13
+ Shared\Microsoft.Windows.Shell\Microsoft.Windows.Shell.projitems*{bbe51380-8b21-49ff-9cfc-b29447a40999}*SharedItemsImports = 13
Shared\HandyControlDemo_Shared\HandyControlDemo_Shared.projitems*{c4694269-c9b8-45d5-87f8-d0088c532510}*SharedItemsImports = 13
Shared\HandyControlDemo_Shared\HandyControlDemo_Shared.projitems*{d8ae88f8-c36b-4d10-a7f9-22ffcfba5231}*SharedItemsImports = 5
Shared\HandyControl_Shared\HandyControl_Shared.projitems*{dc966e3d-bcff-4652-98cf-070e5494749a}*SharedItemsImports = 5
@@ -83,6 +87,7 @@ Global
{32204503-2EF0-4681-AE13-AA1FEB6C658A} = {35E3F9C0-8924-4536-BE09-F3761FDBF066}
{D8AE88F8-C36B-4D10-A7F9-22FFCFBA5231} = {35E3F9C0-8924-4536-BE09-F3761FDBF066}
{D8A4748C-0500-4F63-BC47-3506658C68F7} = {0938270D-E9F0-489B-AF9E-5C5AD7C69897}
+ {BBE51380-8B21-49FF-9CFC-B29447A40999} = {0938270D-E9F0-489B-AF9E-5C5AD7C69897}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D4636382-1A18-4079-A3E7-054DD970F179}
diff --git a/src/Net_40/HandyControl_Net_40/HandyControl_Net_40.csproj b/src/Net_40/HandyControl_Net_40/HandyControl_Net_40.csproj
index fe610463..9b433da3 100644
--- a/src/Net_40/HandyControl_Net_40/HandyControl_Net_40.csproj
+++ b/src/Net_40/HandyControl_Net_40/HandyControl_Net_40.csproj
@@ -13,11 +13,6 @@
bin\$(Configuration)\$(TargetFramework)\HandyControl.xml
-
-
- 3.0.1
-
-
Properties\Langs\Lang.Designer.cs
@@ -74,6 +69,7 @@
+
Resources\dropper.cur
diff --git a/src/Net_40/HandyControl_Net_40/Themes/Styles/MessageBox.xaml b/src/Net_40/HandyControl_Net_40/Themes/Styles/MessageBox.xaml
index 35de3ab3..a907896e 100644
--- a/src/Net_40/HandyControl_Net_40/Themes/Styles/MessageBox.xaml
+++ b/src/Net_40/HandyControl_Net_40/Themes/Styles/MessageBox.xaml
@@ -1,8 +1,8 @@
@@ -104,4 +104,4 @@
-
\ No newline at end of file
+
diff --git a/src/Net_40/HandyControl_Net_40/Themes/Styles/Window.xaml b/src/Net_40/HandyControl_Net_40/Themes/Styles/Window.xaml
index ee60d042..4f5346e3 100644
--- a/src/Net_40/HandyControl_Net_40/Themes/Styles/Window.xaml
+++ b/src/Net_40/HandyControl_Net_40/Themes/Styles/Window.xaml
@@ -1,8 +1,8 @@
-
@@ -241,4 +241,4 @@
-
\ No newline at end of file
+
diff --git a/src/Net_40/HandyControl_Net_40/Themes/Theme.xaml b/src/Net_40/HandyControl_Net_40/Themes/Theme.xaml
index 040196e7..d1b8d608 100644
--- a/src/Net_40/HandyControl_Net_40/Themes/Theme.xaml
+++ b/src/Net_40/HandyControl_Net_40/Themes/Theme.xaml
@@ -1,4 +1,4 @@
-
+
diff --git a/src/Shared/HandyControl_Shared/Properties/AssemblyInfo.cs b/src/Shared/HandyControl_Shared/Properties/AssemblyInfo.cs
index b4e566f8..a74a8f4b 100644
--- a/src/Shared/HandyControl_Shared/Properties/AssemblyInfo.cs
+++ b/src/Shared/HandyControl_Shared/Properties/AssemblyInfo.cs
@@ -12,4 +12,5 @@
[assembly: XmlnsDefinition("https://handyorg.github.io/handycontrol", "HandyControl.Data")]
[assembly: XmlnsDefinition("https://handyorg.github.io/handycontrol", "HandyControl.Properties.Langs")]
[assembly: XmlnsDefinition("https://handyorg.github.io/handycontrol", "HandyControl.Themes")]
+[assembly: XmlnsDefinition("https://handyorg.github.io/handycontrol", "Microsoft.Windows.Shell")]
[assembly: XmlnsPrefix("https://handyorg.github.io/handycontrol", "hc")]
diff --git a/src/Shared/Microsoft.Windows.Shell/JumpItem.cs b/src/Shared/Microsoft.Windows.Shell/JumpItem.cs
new file mode 100644
index 00000000..2733344e
--- /dev/null
+++ b/src/Shared/Microsoft.Windows.Shell/JumpItem.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Microsoft.Windows.Shell
+{
+ public abstract class JumpItem
+ {
+ internal JumpItem()
+ {
+ }
+
+ public string CustomCategory { get; set; }
+ }
+}
diff --git a/src/Shared/Microsoft.Windows.Shell/JumpItemRejectionReason.cs b/src/Shared/Microsoft.Windows.Shell/JumpItemRejectionReason.cs
new file mode 100644
index 00000000..75fa583b
--- /dev/null
+++ b/src/Shared/Microsoft.Windows.Shell/JumpItemRejectionReason.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Microsoft.Windows.Shell
+{
+ public enum JumpItemRejectionReason
+ {
+ None,
+ InvalidItem,
+ NoRegisteredHandler,
+ RemovedByUser
+ }
+}
diff --git a/src/Shared/Microsoft.Windows.Shell/JumpItemsRejectedEventArgs.cs b/src/Shared/Microsoft.Windows.Shell/JumpItemsRejectedEventArgs.cs
new file mode 100644
index 00000000..ba9d9097
--- /dev/null
+++ b/src/Shared/Microsoft.Windows.Shell/JumpItemsRejectedEventArgs.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+
+namespace Microsoft.Windows.Shell
+{
+ public sealed class JumpItemsRejectedEventArgs : EventArgs
+ {
+ public JumpItemsRejectedEventArgs() : this(null, null)
+ {
+ }
+
+ public JumpItemsRejectedEventArgs(IList rejectedItems, IList reasons)
+ {
+ if ((rejectedItems == null && reasons != null) || (reasons == null && rejectedItems != null) || (rejectedItems != null && reasons != null && rejectedItems.Count != reasons.Count))
+ {
+ throw new ArgumentException("The counts of rejected items doesn't match the count of reasons.");
+ }
+ if (rejectedItems != null)
+ {
+ this.RejectedItems = new List(rejectedItems).AsReadOnly();
+ this.RejectionReasons = new List(reasons).AsReadOnly();
+ return;
+ }
+ this.RejectedItems = new List().AsReadOnly();
+ this.RejectionReasons = new List().AsReadOnly();
+ }
+
+ public IList RejectedItems { get; private set; }
+
+ public IList RejectionReasons { get; private set; }
+ }
+}
diff --git a/src/Shared/Microsoft.Windows.Shell/JumpItemsRemovedEventArgs.cs b/src/Shared/Microsoft.Windows.Shell/JumpItemsRemovedEventArgs.cs
new file mode 100644
index 00000000..ddfdb0b0
--- /dev/null
+++ b/src/Shared/Microsoft.Windows.Shell/JumpItemsRemovedEventArgs.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+
+namespace Microsoft.Windows.Shell
+{
+ public sealed class JumpItemsRemovedEventArgs : EventArgs
+ {
+ public JumpItemsRemovedEventArgs() : this(null)
+ {
+ }
+
+ public JumpItemsRemovedEventArgs(IList removedItems)
+ {
+ if (removedItems != null)
+ {
+ this.RemovedItems = new List(removedItems).AsReadOnly();
+ return;
+ }
+ this.RemovedItems = new List().AsReadOnly();
+ }
+
+ public IList RemovedItems { get; private set; }
+ }
+}
diff --git a/src/Shared/Microsoft.Windows.Shell/JumpList.cs b/src/Shared/Microsoft.Windows.Shell/JumpList.cs
new file mode 100644
index 00000000..66ed6964
--- /dev/null
+++ b/src/Shared/Microsoft.Windows.Shell/JumpList.cs
@@ -0,0 +1,750 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using System.Windows;
+using System.Windows.Markup;
+using Standard;
+
+namespace Microsoft.Windows.Shell
+{
+ [ContentProperty("JumpItems")]
+ public sealed class JumpList : ISupportInitialize
+ {
+ public static void AddToRecentCategory(string itemPath)
+ {
+ Verify.FileExists(itemPath, "itemPath");
+ itemPath = Path.GetFullPath(itemPath);
+ NativeMethods.SHAddToRecentDocs(itemPath);
+ }
+
+ [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")]
+ public static void AddToRecentCategory(JumpPath jumpPath)
+ {
+ Verify.IsNotNull(jumpPath, "jumpPath");
+ JumpList.AddToRecentCategory(jumpPath.Path);
+ }
+
+ public static void AddToRecentCategory(JumpTask jumpTask)
+ {
+ Verify.IsNotNull(jumpTask, "jumpTask");
+ if (Utility.IsOSWindows7OrNewer)
+ {
+ IShellLinkW shellLinkW = JumpList.CreateLinkFromJumpTask(jumpTask, false);
+ try
+ {
+ if (shellLinkW != null)
+ {
+ NativeMethods.SHAddToRecentDocs(shellLinkW);
+ }
+ }
+ finally
+ {
+ Utility.SafeRelease(ref shellLinkW);
+ }
+ }
+ }
+
+ public static void SetJumpList(Application application, JumpList value)
+ {
+ Verify.IsNotNull(application, "application");
+ lock (JumpList.s_lock)
+ {
+ JumpList jumpList;
+ if (JumpList.s_applicationMap.TryGetValue(application, out jumpList) && jumpList != null)
+ {
+ jumpList._application = null;
+ }
+ JumpList.s_applicationMap[application] = value;
+ if (value != null)
+ {
+ value._application = application;
+ }
+ }
+ if (value != null)
+ {
+ value.ApplyFromApplication();
+ }
+ }
+
+ public static JumpList GetJumpList(Application application)
+ {
+ Verify.IsNotNull(application, "application");
+ JumpList result;
+ JumpList.s_applicationMap.TryGetValue(application, out result);
+ return result;
+ }
+
+ public JumpList() : this(null, false, false)
+ {
+ this._initializing = null;
+ }
+
+ public JumpList(IEnumerable items, bool showFrequent, bool showRecent)
+ {
+ if (items != null)
+ {
+ this._jumpItems = new List(items);
+ }
+ else
+ {
+ this._jumpItems = new List();
+ }
+ this.ShowFrequentCategory = showFrequent;
+ this.ShowRecentCategory = showRecent;
+ this._initializing = new bool?(false);
+ }
+
+ public bool ShowFrequentCategory { get; set; }
+
+ public bool ShowRecentCategory { get; set; }
+
+ [SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")]
+ public List JumpItems
+ {
+ get
+ {
+ return this._jumpItems;
+ }
+ }
+
+ private bool _IsUnmodified
+ {
+ get
+ {
+ return this._initializing == null && this.JumpItems.Count == 0 && !this.ShowRecentCategory && !this.ShowFrequentCategory;
+ }
+ }
+
+ [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "BeginInit")]
+ public void BeginInit()
+ {
+ if (!this._IsUnmodified)
+ {
+ throw new InvalidOperationException("Calls to BeginInit cannot be nested.");
+ }
+ this._initializing = new bool?(true);
+ }
+
+ [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "EndInit")]
+ [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "BeginInit")]
+ public void EndInit()
+ {
+ if (this._initializing != true)
+ {
+ throw new NotSupportedException("Can't call EndInit without first calling BeginInit.");
+ }
+ this._initializing = new bool?(false);
+ this.ApplyFromApplication();
+ }
+
+ private static string _RuntimeId
+ {
+ get
+ {
+ string result;
+ HRESULT hrLeft = NativeMethods.GetCurrentProcessExplicitAppUserModelID(out result);
+ if (hrLeft == HRESULT.E_FAIL)
+ {
+ hrLeft = HRESULT.S_OK;
+ result = null;
+ }
+ hrLeft.ThrowIfFailed();
+ return result;
+ }
+ }
+
+ [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "JumpList")]
+ [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "EndInit")]
+ public void Apply()
+ {
+ if (this._initializing == true)
+ {
+ throw new InvalidOperationException("The JumpList can't be applied until EndInit has been called.");
+ }
+ this._initializing = new bool?(false);
+ this._ApplyList();
+ }
+
+ private void ApplyFromApplication()
+ {
+ if (this._initializing != true && !this._IsUnmodified)
+ {
+ this._initializing = new bool?(false);
+ }
+ if (this._application == Application.Current && this._initializing == false)
+ {
+ this._ApplyList();
+ }
+ }
+
+ [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.Verify.IsApartmentState(System.Threading.ApartmentState,System.String)")]
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
+ [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "JumpLists")]
+ private void _ApplyList()
+ {
+ Verify.IsApartmentState(ApartmentState.STA, "JumpLists can only be effected on STA threads.");
+ if (!Utility.IsOSWindows7OrNewer)
+ {
+ this.RejectEverything();
+ return;
+ }
+ List jumpItems;
+ List list;
+ List list2;
+ try
+ {
+ this._BuildShellLists(out jumpItems, out list, out list2);
+ }
+ catch (Exception)
+ {
+ this.RejectEverything();
+ return;
+ }
+ this._jumpItems = jumpItems;
+ EventHandler jumpItemsRejected = this.JumpItemsRejected;
+ EventHandler jumpItemsRemovedByUser = this.JumpItemsRemovedByUser;
+ if (list.Count > 0 && jumpItemsRejected != null)
+ {
+ List list3 = new List(list.Count);
+ List list4 = new List(list.Count);
+ foreach (JumpList._RejectedJumpItemPair rejectedJumpItemPair in list)
+ {
+ list3.Add(rejectedJumpItemPair.JumpItem);
+ list4.Add(rejectedJumpItemPair.Reason);
+ }
+ jumpItemsRejected(this, new JumpItemsRejectedEventArgs(list3, list4));
+ }
+ if (list2.Count > 0 && jumpItemsRemovedByUser != null)
+ {
+ List list5 = new List(list2.Count);
+ foreach (JumpList._ShellObjectPair shellObjectPair in list2)
+ {
+ if (shellObjectPair.JumpItem != null)
+ {
+ list5.Add(shellObjectPair.JumpItem);
+ }
+ }
+ if (list5.Count > 0)
+ {
+ jumpItemsRemovedByUser(this, new JumpItemsRemovedEventArgs(list5));
+ }
+ }
+ }
+
+ private void _BuildShellLists(out List successList, out List rejectedList, out List removedList)
+ {
+ List> list = null;
+ removedList = null;
+ ICustomDestinationList customDestinationList = CLSID.CoCreateInstance("77f10cf0-3db5-4966-b520-b7c54fd35ed6");
+ try
+ {
+ string runtimeId = JumpList._RuntimeId;
+ if (!string.IsNullOrEmpty(runtimeId))
+ {
+ customDestinationList.SetAppID(runtimeId);
+ }
+ Guid guid = new Guid("92CA9DCD-5622-4bba-A805-5E9F541BD8C9");
+ uint num;
+ IObjectArray shellObjects = (IObjectArray)customDestinationList.BeginList(out num, ref guid);
+ removedList = JumpList.GenerateJumpItems(shellObjects);
+ successList = new List(this.JumpItems.Count);
+ rejectedList = new List(this.JumpItems.Count);
+ list = new List>
+ {
+ new List()
+ };
+ foreach (JumpItem jumpItem in this.JumpItems)
+ {
+ if (jumpItem == null)
+ {
+ rejectedList.Add(new JumpList._RejectedJumpItemPair
+ {
+ JumpItem = jumpItem,
+ Reason = JumpItemRejectionReason.InvalidItem
+ });
+ }
+ else
+ {
+ object obj = null;
+ try
+ {
+ obj = JumpList.GetShellObjectForJumpItem(jumpItem);
+ if (obj == null)
+ {
+ rejectedList.Add(new JumpList._RejectedJumpItemPair
+ {
+ Reason = JumpItemRejectionReason.InvalidItem,
+ JumpItem = jumpItem
+ });
+ }
+ else if (JumpList.ListContainsShellObject(removedList, obj))
+ {
+ rejectedList.Add(new JumpList._RejectedJumpItemPair
+ {
+ Reason = JumpItemRejectionReason.RemovedByUser,
+ JumpItem = jumpItem
+ });
+ }
+ else
+ {
+ JumpList._ShellObjectPair item = new JumpList._ShellObjectPair
+ {
+ JumpItem = jumpItem,
+ ShellObject = obj
+ };
+ if (string.IsNullOrEmpty(jumpItem.CustomCategory))
+ {
+ list[0].Add(item);
+ }
+ else
+ {
+ bool flag = false;
+ foreach (List list2 in list)
+ {
+ if (list2.Count > 0 && list2[0].JumpItem.CustomCategory == jumpItem.CustomCategory)
+ {
+ list2.Add(item);
+ flag = true;
+ break;
+ }
+ }
+ if (!flag)
+ {
+ list.Add(new List
+ {
+ item
+ });
+ }
+ }
+ obj = null;
+ }
+ }
+ finally
+ {
+ Utility.SafeRelease