瀏覽代碼

一次大更新

蓝点lilac 4 年之前
父節點
當前提交
04f33e0b84
共有 73 個文件被更改,包括 2696 次插入1345 次删除
  1. 2 2
      ContextMenuManager.sln
  2. 1 1
      ContextMenuManager/App.config
  3. 147 0
      ContextMenuManager/AppConfig.cs
  4. 28 14
      ContextMenuManager/AppImage.cs
  5. 40 8
      ContextMenuManager/AppString.cs
  6. 21 15
      ContextMenuManager/BulePointLilac.Controls/InputDialog.cs
  7. 1 1
      ContextMenuManager/BulePointLilac.Controls/MyListBox.cs
  8. 2 2
      ContextMenuManager/BulePointLilac.Controls/MySideBar.cs
  9. 1 0
      ContextMenuManager/BulePointLilac.Controls/MyStatusBar.cs
  10. 2 4
      ContextMenuManager/BulePointLilac.Controls/MyToolBar.cs
  11. 1 1
      ContextMenuManager/BulePointLilac.Controls/MyToolTip.cs
  12. 7 0
      ContextMenuManager/BulePointLilac.Methods/ControlExtension.cs
  13. 24 0
      ContextMenuManager/BulePointLilac.Methods/DirectoryEx.cs
  14. 0 78
      ContextMenuManager/BulePointLilac.Methods/IniFileHelper.cs
  15. 4 2
      ContextMenuManager/BulePointLilac.Methods/IniReader.cs
  16. 146 0
      ContextMenuManager/BulePointLilac.Methods/IniWriter.cs
  17. 7 20
      ContextMenuManager/BulePointLilac.Methods/ObjectPath.cs
  18. 47 22
      ContextMenuManager/BulePointLilac.Methods/RegistryEx.cs
  19. 32 30
      ContextMenuManager/BulePointLilac.Methods/WindowsOsVersion.cs
  20. 28 16
      ContextMenuManager/ContextMenuManager.csproj
  21. 167 60
      ContextMenuManager/Controls/AboutApp.cs
  22. 2 2
      ContextMenuManager/Controls/AddGuidDicDialog.cs
  23. 107 0
      ContextMenuManager/Controls/CommandDialog.cs
  24. 1 0
      ContextMenuManager/Controls/EnhanceMenusItem.cs
  25. 90 87
      ContextMenuManager/Controls/EnhanceMenusList.cs
  26. 10 7
      ContextMenuManager/Controls/ExplorerRestarter.cs
  27. 2 0
      ContextMenuManager/Controls/GuidBlockedItem.cs
  28. 10 3
      ContextMenuManager/Controls/GuidBlockedList.cs
  29. 0 1
      ContextMenuManager/Controls/Interfaces/IBtnMoveUpDownItem.cs
  30. 25 1
      ContextMenuManager/Controls/Interfaces/IFoldGroupItem.cs
  31. 19 0
      ContextMenuManager/Controls/Interfaces/ITsiDeleteItem.cs
  32. 42 0
      ContextMenuManager/Controls/Interfaces/ITsiRegExportItem.cs
  33. 1 3
      ContextMenuManager/Controls/Interfaces/ITsiTextItem.cs
  34. 98 0
      ContextMenuManager/Controls/LockNewItem.cs
  35. 4 2
      ContextMenuManager/Controls/NewItem.cs
  36. 25 7
      ContextMenuManager/Controls/NewItemForm.cs
  37. 5 4
      ContextMenuManager/Controls/NewOpenWithDialog.cs
  38. 22 20
      ContextMenuManager/Controls/NewSendToDialog.cs
  39. 20 11
      ContextMenuManager/Controls/NewShellDialog.cs
  40. 6 2
      ContextMenuManager/Controls/OpenWithItem.cs
  41. 3 4
      ContextMenuManager/Controls/OpenWithList.cs
  42. 3 2
      ContextMenuManager/Controls/RegRuleItem.cs
  43. 74 22
      ContextMenuManager/Controls/SendToItem.cs
  44. 25 20
      ContextMenuManager/Controls/SendToList.cs
  45. 31 21
      ContextMenuManager/Controls/ShellExItem.cs
  46. 174 44
      ContextMenuManager/Controls/ShellItem.cs
  47. 45 40
      ContextMenuManager/Controls/ShellList.cs
  48. 31 33
      ContextMenuManager/Controls/ShellNewItem.cs
  49. 90 11
      ContextMenuManager/Controls/ShellNewList.cs
  50. 85 78
      ContextMenuManager/Controls/ShellStoreDialog.cs
  51. 326 182
      ContextMenuManager/Controls/ShellSubMenuDialog.cs
  52. 0 57
      ContextMenuManager/Controls/SubMenuModeForm.cs
  53. 61 49
      ContextMenuManager/Controls/ThirdRulesList.cs
  54. 2 1
      ContextMenuManager/Controls/WinXItem.cs
  55. 4 11
      ContextMenuManager/Controls/WinXList.cs
  56. 24 9
      ContextMenuManager/GuidInfo.cs
  57. 65 27
      ContextMenuManager/MainForm.cs
  58. 7 81
      ContextMenuManager/Program.cs
  59. 2 2
      ContextMenuManager/Properties/AssemblyInfo.cs
  60. 34 31
      ContextMenuManager/Properties/Resources.Designer.cs
  61. 9 9
      ContextMenuManager/Properties/Resources.resx
  62. 二進制
      ContextMenuManager/Properties/Resources/Images/Refresh.png
  63. 二進制
      ContextMenuManager/Properties/Resources/Images/SeparatorItem.png
  64. 41 19
      ContextMenuManager/Properties/Resources/Texts/AppLanguageDic.ini
  65. 15 24
      ContextMenuManager/Properties/Resources/Texts/EnhanceMenusDic.xml
  66. 207 101
      ContextMenuManager/Properties/Resources/Texts/GuidInfosDic.ini
  67. 37 11
      ContextMenuManager/Properties/Resources/Texts/ThirdRulesDic.xml
  68. 19 8
      ContextMenuManager/Updater.cs
  69. 41 0
      Donate.md
  70. 2 2
      README.md
  71. 1 1
      Update.ini
  72. 0 0
      languages/ja-JP.ini
  73. 41 19
      languages/zh-CN.ini

+ 2 - 2
ContextMenuManager.sln

@@ -1,7 +1,7 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29911.84
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.1267
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ContextMenuManager", "ContextMenuManager\ContextMenuManager.csproj", "{EF7E60E9-3565-42BA-AFB3-7FE73A1B011C}"
 EndProject

+ 1 - 1
ContextMenuManager/App.config

@@ -2,7 +2,7 @@
 <configuration>
   <startup>
     
-  <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup>
+  <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup>
   <runtime>
     <legacyCorruptedStateExceptionsPolicy enabled="true"/>
     <EnableWindowsFormsHighDpiAutoResizing enabled="true"/>

+ 147 - 0
ContextMenuManager/AppConfig.cs

@@ -0,0 +1,147 @@
+using System;
+using System.Globalization;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+using BulePointLilac.Methods;
+
+namespace ContextMenuManager
+{
+    static class AppConfig
+    {
+        static AppConfig()
+        {
+            CreateDirs();
+            DeleteOldFiles();
+        }
+
+        [DllImport("kernel32.dll")]
+        private static extern ushort GetUserDefaultUILanguage();
+
+        public static readonly string AppConfigDir = $@"{Application.StartupPath}\Config";
+        public static readonly string AppDataConfigDir = Environment.ExpandEnvironmentVariables(@"%AppData%\ContextMenuManager\Config");
+        public static readonly string ConfigDir = Directory.Exists(AppConfigDir) ? AppConfigDir : AppDataConfigDir;
+        public static readonly bool SaveToAppDir = ConfigDir == AppConfigDir;
+        public static string ConfigIni = $@"{ConfigDir}\Config.ini";
+        public static string BackupDir = $@"{ConfigDir}\Backup";
+        public static string LangsDir = $@"{ConfigDir}\Languages";
+        public static string DicsDir = $@"{ConfigDir}\Dictionaries";
+        public static string WebDicsDir = $@"{DicsDir}\Web";
+        public static string UserDicsDir = $@"{DicsDir}\User";
+        public static string WebGuidInfosDic = $@"{WebDicsDir}\{GUIDINFOSDICINI}";
+        public static string UserGuidInfosDic = $@"{UserDicsDir}\{GUIDINFOSDICINI}";
+        public static string WebThirdRulesDic = $@"{WebDicsDir}\{ThIRDRULESDICXML}";
+        public static string UserThirdRulesDic = $@"{UserDicsDir}\{ThIRDRULESDICXML}";
+        public static string WebEnhanceMenusDic = $@"{WebDicsDir}\{ENHANCEMENUSICXML}";
+        public static string UserEnhanceMenusDic = $@"{UserDicsDir}\{ENHANCEMENUSICXML}";
+
+        public const string ZH_CNINI = "zh-CN.ini";
+        public const string GUIDINFOSDICINI = "GuidInfosDic.ini";
+        public const string ThIRDRULESDICXML = "ThirdRulesDic.xml";
+        public const string ENHANCEMENUSICXML = "EnhanceMenusDic.xml";
+
+        private static IniReader ConfigReader => new IniReader(ConfigIni);
+        private static IniWriter ConfigWriter => new IniWriter(ConfigIni);
+
+        public static DateTime LastCheckUpdateTime
+        {
+            get
+            {
+                try
+                {
+                    string time = ConfigReader.GetValue("General", "LastCheckUpdateTime");
+                    //二进制数据时间不会受系统时间格式影响
+                    return DateTime.FromBinary(Convert.ToInt64(time));
+                }
+                catch
+                {
+                    //将上次检测更新时间推前到两个月前
+                    return DateTime.Today.AddMonths(-2);
+                }
+            }
+            set
+            {
+                ConfigWriter.SetValue("General", "LastCheckUpdateTime", value.ToBinary().ToString());
+            }
+        }
+
+        public static string LanguageIniPath
+        {
+            get
+            {
+                string language = ConfigReader.GetValue("General", "Language");
+                DirectoryInfo di = new DirectoryInfo(LangsDir);
+                if(language == string.Empty && di.Exists)
+                {
+                    string sysLanguageName = new CultureInfo(GetUserDefaultUILanguage()).Name;
+                    foreach(FileInfo fi in di.GetFiles())
+                    {
+                        string name = Path.GetFileNameWithoutExtension(fi.Name);
+                        //如果为空,则赋值为系统显示语言文件名文件(存在时)
+                        if(name.Equals(sysLanguageName, StringComparison.OrdinalIgnoreCase))
+                        {
+                            language = fi.FullName; break;
+                        }
+                    }
+                }
+                else if(!File.Exists(language)) language = string.Empty;
+                return language;
+            }
+            set
+            {
+                ConfigWriter.SetValue("General", "Language", value);
+            }
+        }
+
+        public static bool AutoBackup
+        {
+            get => ConfigReader.GetValue("General", "AutoBackup") != "0";
+            set => ConfigWriter.SetValue("General", "AutoBackup", (value ? 1 : 0).ToString());
+        }
+
+        public static bool ProtectOpenItem
+        {
+            get => ConfigReader.GetValue("General", "ProtectOpenItem") != "0";
+            set => ConfigWriter.SetValue("General", "ProtectOpenItem", (value ? 1 : 0).ToString());
+        }
+
+        private static void CreateDirs()
+        {
+            foreach(string dirPath in new[] { ConfigDir, BackupDir, LangsDir, DicsDir, WebDicsDir, UserDicsDir })
+            {
+                Directory.CreateDirectory(dirPath);
+            }
+        }
+
+        private static void DeleteOldFiles()
+        {
+            DirectoryInfo configDi = new DirectoryInfo(ConfigDir);
+            foreach(DirectoryInfo di in configDi.GetDirectories())
+            {
+                bool isOther = true;
+                foreach(string path in new[] { BackupDir, LangsDir, DicsDir })
+                {
+                    if(di.FullName.Equals(path, StringComparison.OrdinalIgnoreCase))
+                    {
+                        isOther = false;
+                        break;
+                    }
+                }
+                if(isOther) Directory.Delete(di.FullName);
+            }
+            foreach(FileInfo fi in configDi.GetFiles())
+            {
+                bool isOther = true;
+                foreach(string path in new[] { ConfigIni })
+                {
+                    if(fi.FullName.Equals(path, StringComparison.OrdinalIgnoreCase))
+                    {
+                        isOther = false;
+                        break;
+                    }
+                }
+                if(isOther) File.Delete(fi.FullName);
+            }
+        }
+    }
+}

+ 28 - 14
ContextMenuManager/AppImage.cs

@@ -13,6 +13,8 @@ namespace ContextMenuManager
         public static readonly Image Type = Resources.Type.ResizeImage(Scale);
         ///<summary>五角星图标</summary>
         public static readonly Image Star = Resources.Star.ResizeImage(Scale);
+        ///<summary>刷新图标</summary>
+        public static readonly Image Refresh = Resources.Refresh.ResizeImage(Scale);
         ///<summary>关于问号图标</summary>
         public static readonly Image About = Resources.About.ResizeImage(Scale);
         ///<summary>设置按钮图标</summary>
@@ -27,8 +29,6 @@ namespace ContextMenuManager
         public static readonly Image Delete = Resources.Delete.ResizeImage(Scale);
         ///<summary>添加图标</summary>
         public static readonly Image AddNewItem = Resources.Add.ResizeImage(Scale);
-        ///<summary>添加常用菜单项图标</summary>
-        public static readonly Image AddCommon = Resources.AddCommon.ResizeImage(Scale);
         ///<summary>添加已有项目图标</summary>
         public static readonly Image AddExisting = Resources.AddExisting.ResizeImage(Scale);
         ///<summary>添加分割线图标</summary>
@@ -52,24 +52,38 @@ namespace ContextMenuManager
         ///<summary>dll文件默认图标</summary>
         public static readonly Image DllDefaultIcon = ResourceIcon.GetExtensionIcon(".dll").ToBitmap();
         ///<summary>资源不存在图标</summary>
-        public static readonly Image NotFound = ResourceIcon.GetIcon("imageres.dll", 2).ToBitmap();
+        public static readonly Image NotFound = ResourceIcon.GetIcon("imageres.dll", -2).ToBitmap();
         ///<summary>管理员小盾牌</summary>
-        public static readonly Image Shield = ResourceIcon.GetIcon("imageres.dll", 73).ToBitmap();
+        public static readonly Image Shield = ResourceIcon.GetIcon("imageres.dll", -78).ToBitmap();
         ///<summary>资源管理器图标</summary>
         public static readonly Image Explorer = ResourceIcon.GetIcon("explorer.exe", 0).ToBitmap();
         ///<summary>命令提示符图标</summary>
         public static readonly Image Cmd= ResourceIcon.GetIcon("cmd.exe", 0).ToBitmap();
-        ///<summary>刷新图标</summary>
-        public static readonly Image Refresh = ResourceIcon.GetIcon("shell32.dll", 238).ToBitmap();
-        ///<summary>自定义文件夹图标</summary>
-        public static readonly Image CustomFolder = ResourceIcon.GetIcon("imageres.dll", 3).ToBitmap();
+        ///<summary>重启Explorer图标</summary>
+        public static readonly Image RestartExplorer = ResourceIcon.GetIcon("shell32.dll", 238).ToBitmap();
         ///<summary>网络驱动器图标</summary>
-        public static readonly Image NetworkDrive = ResourceIcon.GetIcon("imageres.dll", 28).ToBitmap();
-        ///<summary>回收站属性图标</summary>
-        public static readonly Image RecycleBinProperties = ResourceIcon.GetIcon("shell32.dll", -254).ToBitmap();
-        ///<summary>磁盘图标</summary>
-        public static readonly Image Drive = ResourceIcon.GetIcon("imageres.dll", 27).ToBitmap();
+        public static readonly Image NetworkDrive = ResourceIcon.GetIcon("imageres.dll", -33).ToBitmap();
         ///<summary>发送到图标</summary>
-        public static readonly Image SendTo = ResourceIcon.GetIcon("imageres.dll", 176).ToBitmap();
+        public static readonly Image SendTo = ResourceIcon.GetIcon("imageres.dll", -185).ToBitmap();
+        ///<summary>回收站图标</summary>
+        public static readonly Image RecycleBin = ResourceIcon.GetIcon("imageres.dll", -55).ToBitmap();
+        ///<summary>此电脑图标</summary>
+        public static readonly Image Computer = ResourceIcon.GetIcon("imageres.dll", -109).ToBitmap();
+        ///<summary>磁盘图标</summary>
+        public static readonly Image Drive = ResourceIcon.GetIcon("imageres.dll", -30).ToBitmap();
+        ///<summary>文件图标</summary>
+        public static readonly Image File = ResourceIcon.GetIcon("imageres.dll", -19).ToBitmap();
+        ///<summary>文件夹图标</summary>
+        public static readonly Image Folder = ResourceIcon.GetIcon("imageres.dll", -3).ToBitmap();
+        ///<summary>目录图标</summary>
+        public static readonly Image Directory = ResourceIcon.GetIcon("imageres.dll", -162).ToBitmap();
+        ///<summary目录背景图标</summary>
+        public static readonly Image Background = ResourceIcon.GetIcon("imageres.dll", 0).ToBitmap();
+        ///<summary>桌面图标</summary>
+        public static readonly Image Desktop = ResourceIcon.GetIcon("imageres.dll", -183).ToBitmap();
+        ///<summary>所有对象图标</summary>
+        public static readonly Image AllObjects = ResourceIcon.GetIcon("imageres.dll", -117).ToBitmap();
+        ///<summary>锁定图标</summary>
+        public static readonly Image Lock = ResourceIcon.GetIcon("imageres.dll", -59).ToBitmap();
     }
 }

+ 40 - 8
ContextMenuManager/AppString.cs

@@ -5,7 +5,7 @@ namespace ContextMenuManager
 {
     public static class AppString
     {
-        public static IniReader UserLanguage = new IniReader(Program.LanguageFilePath);
+        public static IniReader UserLanguage = new IniReader(AppConfig.LanguageIniPath);
         private static readonly IniReader DefaultLanguage = new IniReader(new StringBuilder(Properties.Resources.AppLanguageDic));
 
 
@@ -31,6 +31,7 @@ namespace ContextMenuManager
             public static string Home => GetValue("Home");
             public static string Type => GetValue("Type");
             public static string Rule => GetValue("Rule");
+            public static string Refresh => GetValue("Refresh");
             public static string About => GetValue("About");
         }
 
@@ -64,8 +65,11 @@ namespace ContextMenuManager
             public static string AudioDirectory => GetValue("AudioDirectory");
             public static string UnknownType => GetValue("UnknownType");
             public static string CustomType => GetValue("CustomType");
-            public static string GuidBlocked => GetValue("GuidBlocked");
+            public static string EnhanceMenu => GetValue("EnhanceMenu");
             public static string ThirdRules => GetValue("ThirdRules");
+            public static string GuidBlocked => GetValue("GuidBlocked");
+            public static string PublicReferences => GetValue("PublicReferences");
+            public static string AppSetting => GetValue("AppSetting");
             public static string AboutApp => GetValue("AboutApp");
             public static string Dictionaries => GetValue("Dictionaries");
             public static string AppLanguage => GetValue("AppLanguage");
@@ -102,8 +106,10 @@ namespace ContextMenuManager
             public static string AudioDirectory => GetValue("AudioDirectory");
             public static string UnknownType => GetValue("UnknownType");
             public static string CustomType => GetValue("CustomType");
-            public static string GuidBlocked => GetValue("GuidBlocked");
+            public static string EnhanceMenu => GetValue("EnhanceMenu");
             public static string ThirdRules => GetValue("ThirdRules");
+            public static string GuidBlocked => GetValue("GuidBlocked");
+            public static string PublicReferences => GetValue("PublicReferences");
         }
 
         /// <summary>菜单</summary>
@@ -115,6 +121,7 @@ namespace ContextMenuManager
             public static string ChangeIcon => GetValue("ChangeIcon");
             public static string AddIcon => GetValue("AddIcon");
             public static string DeleteIcon => GetValue("DeleteIcon");
+            public static string ShieldIcon => GetValue("ShieldIcon");
             public static string ItemPosition => GetValue("ItemPosition");
             public static string SetDefault => GetValue("SetDefault");
             public static string SetTop => GetValue("SetTop");
@@ -123,13 +130,13 @@ namespace ContextMenuManager
             public static string OnlyWithShift => GetValue("OnlyWithShift");
             public static string OnlyInExplorer => GetValue("OnlyInExplorer");
             public static string NoWorkingDirectory => GetValue("NoWorkingDirectory");
-            public static string ShowSeparator => GetValue("ShowSeparator");
             public static string Details => GetValue("Details");
             public static string WebSearch => GetValue("WebSearch");
             public static string ChangeCommand => GetValue("ChangeCommand");
             public static string FileProperties => GetValue("FileProperties");
             public static string FileLocation => GetValue("FileLocation");
             public static string RegistryLocation => GetValue("RegistryLocation");
+            public static string ExportRegistry => GetValue("ExportRegistry");
             public static string Delete => GetValue("Delete");
             public static string DeleteReference => GetValue("DeleteReference");
             public static string HandleGuid => GetValue("HandleGuid");
@@ -148,6 +155,7 @@ namespace ContextMenuManager
             public static string Open => GetValue("Open");
             public static string Edit => GetValue("Edit");
             public static string Explore => GetValue("Explore");
+            public static string ExploreOld => GetValue("ExploreOld");
             public static string Play => GetValue("Play");
             public static string Print => GetValue("Print");
             public static string Find => GetValue("Find");
@@ -166,6 +174,7 @@ namespace ContextMenuManager
             public static string EditSubItems => GetValue("EditSubItems");
             public static string InvalidItem => GetValue("InvalidItem");
             public static string Separator => GetValue("Separator");
+            public static string LockNewMenu => GetValue("LockNewMenu");
         }
 
         public static class Dialog
@@ -180,17 +189,21 @@ namespace ContextMenuManager
             public static string NewOpenWithItem => GetValue("NewOpenWithItem");
             public static string ItemText => GetValue("ItemText");
             public static string ItemCommand => GetValue("ItemCommand");
+            public static string CommandArguments => GetValue("CommandArguments");
             public static string ItemName => GetValue("ItemName");
             public static string ItemIcon => GetValue("ItemIcon");
             public static string SingleMenu => GetValue("SingleMenu");
             public static string MultiMenu => GetValue("MultiMenu");
+            public static string Public => GetValue("Public");
+            public static string Private => GetValue("Private");
             public static string InputGuid => GetValue("InputGuid");
             public static string AddGuidDic => GetValue("AddGuidDic");
             public static string DeleteGuidDic => GetValue("DeleteGuidDic");
             public static string SelectExtension => GetValue("SelectExtension");
             public static string CheckReference => GetValue("CheckReference");
-            public static string CheckCommon => GetValue("CheckCommon");
+            public static string CheckCopy => GetValue("CheckCopy");
             public static string SelectSubMenuMode => GetValue("SelectSubMenuMode");
+            public static string RegistryFile => GetValue("RegistryFile");
         }
 
         /// <summary>消息框</summary>
@@ -206,6 +219,8 @@ namespace ContextMenuManager
             public static string ConfirmDelete => GetValue("ConfirmDelete");
             public static string ConfirmDeleteReferenced => GetValue("ConfirmDeleteReferenced");
             public static string CannotAddNewItem => GetValue("CannotAddNewItem");
+            public static string VistaUnsupportedMulti => GetValue("VistaUnsupportedMulti");
+            public static string CannotHideSubItem => GetValue("CannotHideSubItem");
             public static string UnsupportedFilename => GetValue("UnsupportedFilename");
             public static string UnsupportedExtension => GetValue("UnsupportedExtension");
             public static string CannotChangePath => GetValue("CannotChangePath");
@@ -216,7 +231,9 @@ namespace ContextMenuManager
             public static string PromptIsOpenItem => GetValue("PromptIsOpenItem");
             public static string RestartApp => GetValue("RestartApp");
             public static string UpdateApp => GetValue("UpdateApp");
-            public static string FileOrFolderNotExists => GetValue("FileOrFolderNotExists");
+            public static string FileNotExists => GetValue("FileNotExists");
+            public static string FolderNotExists => GetValue("FolderNotExists");
+            public static string NoUpdateDetected => GetValue("NoUpdateDetected");
         }
 
         /// <summary>其他文本</summary>
@@ -235,6 +252,16 @@ namespace ContextMenuManager
             public static string AboutApp => GetValue("AboutApp");
             public static string Dictionaries => GetValue("Dictionaries");
             public static string Donate => GetValue("Donate");
+            public static string DonationList => GetValue("DonationList");
+            public static string ConfigFile => GetValue("ConfigFile");
+            public static string SaveToAppData => GetValue("SaveToAppData");
+            public static string SaveToAppDir => GetValue("SaveToAppDir");
+            public static string OpenConfigDir => GetValue("OpenConfigDir");
+            public static string AutoBackup => GetValue("AutoBackup");
+            public static string OpenBackupDir => GetValue("OpenBackupDir");
+            public static string CheckUpdate => GetValue("CheckUpdate");
+            public static string ImmediatelyCheckUpdate => GetValue("ImmediatelyCheckUpdate");
+            public static string ProtectOpenItem => GetValue("ProtectOpenItem");
         }
 
         /// <summary>提示文本</summary>
@@ -249,9 +276,14 @@ namespace ContextMenuManager
             public static string InvalidItem => GetValue("InvalidItem");
             public static string AddSeparator => GetValue("AddSeparator");
             public static string Separator => GetValue("Separator");
-            public static string AddExistingItems => GetValue("AddExistingItems");
-            public static string AddCommonItems => GetValue("AddCommonItems");
+            public static string AddReference => GetValue("AddReference");
+            public static string AddFromParentMenu => GetValue("AddFromParentMenu");
             public static string DeleteGuidDic => GetValue("DeleteGuidDic");
+            public static string LockNewMenu => GetValue("LockNewMenu");
+            public static string CheckUpdate => GetValue("CheckUpdate");
+            public static string LastCheckUpdateTime => GetValue("LastCheckUpdateTime");
+            public static string OpenLanguagesDir => GetValue("OpenLanguagesDir");
+            public static string OpenDictionariesDir => GetValue("OpenDictionariesDir");
         }
     }
 }

+ 21 - 15
ContextMenuManager/BulePointLilac.Controls/InputDialog.cs

@@ -20,9 +20,9 @@ namespace BulePointLilac.Controls
         {
             using(InputBox frm = new InputBox { Text = Title, Size = LastSize })
             {
-                frm.TxtInput.Text = this.Text;
+                frm.InputedText = this.Text;
                 bool flag = frm.ShowDialog() == DialogResult.OK;
-                this.Text = flag ? frm.TxtInput.Text : null;
+                this.Text = flag ? frm.InputedText : null;
                 LastSize = frm.Size;
                 return flag;
             }
@@ -32,32 +32,38 @@ namespace BulePointLilac.Controls
         {
             public InputBox()
             {
-                this.AcceptButton = BtnOk;
-                this.CancelButton = BtnCancel;
+                this.AcceptButton = btnOk;
+                this.CancelButton = btnCancel;
                 this.Font = SystemFonts.MessageBoxFont;
                 this.SizeGripStyle = SizeGripStyle.Hide;
                 this.StartPosition = FormStartPosition.CenterParent;
                 this.MinimumSize = this.Size = new Size(400, 150).DpiZoom();
                 this.MaximizeBox = MinimizeBox = ShowIcon = ShowInTaskbar = false;
-                this.Controls.AddRange(new Control[] { TxtInput, BtnOk, BtnCancel });
-                TxtInput.CanResizeFont();
+                this.Controls.AddRange(new Control[] { txtInput, btnOk, btnCancel });
+                txtInput.CanResizeFont();
                 InitializeComponents();
             }
 
-            public readonly TextBox TxtInput = new TextBox
+            public string InputedText
+            {
+                get => txtInput.Text;
+                set => txtInput.Text = value;
+            }
+
+            readonly TextBox txtInput = new TextBox
             {
                 Font = new Font(SystemFonts.MenuFont.FontFamily, 11F),
                 ScrollBars = ScrollBars.Vertical,
                 Multiline = true
             };
-            readonly Button BtnOk = new Button
+            readonly Button btnOk = new Button
             {
                 Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
                 DialogResult = DialogResult.OK,
                 Text = AppString.Dialog.Ok,
                 AutoSize = true
             };
-            readonly Button BtnCancel = new Button
+            readonly Button btnCancel = new Button
             {
                 Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
                 DialogResult = DialogResult.Cancel,
@@ -68,17 +74,17 @@ namespace BulePointLilac.Controls
             protected override void OnResize(EventArgs e)
             {
                 base.OnResize(e);
-                TxtInput.Width = BtnCancel.Right - TxtInput.Left;
-                TxtInput.Height = BtnCancel.Top - 2 * TxtInput.Top;
+                txtInput.Width = btnCancel.Right - txtInput.Left;
+                txtInput.Height = btnCancel.Top - 2 * txtInput.Top;
             }
 
             private void InitializeComponents()
             {
                 int a = 20.DpiZoom();
-                TxtInput.Location = new Point(a, a);
-                BtnCancel.Top = BtnOk.Top = this.ClientSize.Height - BtnOk.Height - a;
-                BtnCancel.Left = this.ClientSize.Width - BtnCancel.Width - a;
-                BtnOk.Left = BtnCancel.Left - BtnOk.Width - a;
+                txtInput.Location = new Point(a, a);
+                btnCancel.Top = btnOk.Top = this.ClientSize.Height - btnOk.Height - a;
+                btnCancel.Left = this.ClientSize.Width - btnCancel.Width - a;
+                btnOk.Left = btnCancel.Left - btnOk.Width - a;
                 this.OnResize(null);
             }
         }

+ 1 - 1
ContextMenuManager/BulePointLilac.Controls/MyListBox.cs

@@ -23,7 +23,6 @@ namespace BulePointLilac.Controls
 
     public class MyList : FlowLayoutPanel
     {
-
         public MyListBox Owner
         {
             get => (MyListBox)this.Parent;
@@ -64,6 +63,7 @@ namespace BulePointLilac.Controls
 
         public void AddItem(MyListItem item)
         {
+            if(item.Parent == this) return;
             item.Parent = this;
             item.Width = Owner.Width - item.Margin.Horizontal;
             Owner.Resize += (sender, e) => item.Width = Owner.Width - item.Margin.Horizontal;

+ 2 - 2
ContextMenuManager/BulePointLilac.Controls/MySideBar.cs

@@ -146,13 +146,13 @@ namespace BulePointLilac.Controls
                 new SolidBrush(ctr.ForeColor),
                 new PointF(HorizontalSpace, VerticalSpace));
         }
-        
+
         /// <summary>显示选中的项目</summary>
         private void ShowItem(Panel panel, MouseEventArgs e)
         {
             if(itemNames == null) return;
             int index = (e.Y - TopSpace) / ItemHeight;
-            if(index >= itemNames.Length || string.IsNullOrEmpty(itemNames[index]) || index == SelectIndex)
+            if(index >= itemNames.Length || index < 0 || string.IsNullOrEmpty(itemNames[index]) || index == SelectIndex)
             {
                 this.Cursor = Cursors.Default;
                 HoverIndex = SelectIndex;

+ 1 - 0
ContextMenuManager/BulePointLilac.Controls/MyStatusBar.cs

@@ -11,6 +11,7 @@ namespace BulePointLilac.Controls
 
         public MyStatusBar()
         {
+            this.Text = DefaultText;
             this.Height = 30.DpiZoom();
             this.Dock = DockStyle.Bottom;
             this.Font = SystemFonts.StatusFont;

+ 2 - 4
ContextMenuManager/BulePointLilac.Controls/MyToolBar.cs

@@ -43,11 +43,11 @@ namespace BulePointLilac.Controls
             button.Margin = new Padding(12.DpiZoom(), 4.DpiZoom(), 0, 0);
             button.MouseDown += (sender, e) =>
             {
-                if(e.Button == MouseButtons.Left) SelectedButton = button;
+                if(e.Button == MouseButtons.Left) { SelectedButton = button; button.Cursor = Cursors.Default; }
             };
             button.MouseEnter += (sender, e) =>
             {
-                if(button != SelectedButton) button.Opacity = 0.2F;
+                if(button != SelectedButton) { button.Opacity = 0.2F; button.Cursor = Cursors.Hand; }
             };
             button.MouseLeave += (sender, e) =>
             {
@@ -93,8 +93,6 @@ namespace BulePointLilac.Controls
             ForeColor = Color.White
         };
 
-        private static Label LblText = new Label();
-
         public Image Image
         {
             get => picImage.Image;

+ 1 - 1
ContextMenuManager/BulePointLilac.Controls/MyToolTip.cs

@@ -13,7 +13,7 @@ namespace BulePointLilac.Controls
             ctr.Disposed += (sender, e) => toolTip.Dispose();
         }
 
-        public static void SetToolTip(ToolStripMenuItem item, string tip)
+        public static void SetToolTip(ToolStripItem item, string tip)
         {
             //必须先设置item的Owner
             item.Owner.ShowItemToolTips = true;

+ 7 - 0
ContextMenuManager/BulePointLilac.Methods/ControlExtension.cs

@@ -44,5 +44,12 @@ namespace BulePointLilac.Methods
             if(enabled) { SetWindowLong(ctr.Handle, GWL_STYLE, (~WS_DISABLED) & GetWindowLong(ctr.Handle, GWL_STYLE)); }
             else { SetWindowLong(ctr.Handle, GWL_STYLE, WS_DISABLED | GetWindowLong(ctr.Handle, GWL_STYLE)); }
         }
+
+        public static void SetNoClickEvent(this Control ctr)
+        {
+            Cursor cursor = ctr.Cursor;
+            ctr.MouseDown += (sender, e) => ctr.Cursor = Cursors.No;
+            ctr.MouseUp += (sender, e) => ctr.Cursor = cursor;
+        }
     }
 }

+ 24 - 0
ContextMenuManager/BulePointLilac.Methods/DirectoryEx.cs

@@ -0,0 +1,24 @@
+using System.IO;
+
+namespace BulePointLilac.Methods
+{
+    public static class DirectoryEx
+    {
+        public static void CopyTo(string srcDirPath, string dstDirPath)
+        {
+            DirectoryInfo srcDi = new DirectoryInfo(srcDirPath);
+            DirectoryInfo dstDi = new DirectoryInfo(dstDirPath);
+            dstDi.Create();
+            foreach(FileInfo srcFi in srcDi.GetFiles())
+            {
+                string dstFilePath = $@"{dstDirPath}\{srcFi.Name}";
+                srcFi.CopyTo(dstFilePath, true);
+            }
+            foreach(DirectoryInfo srcSubDi in srcDi.GetDirectories())
+            {
+                DirectoryInfo dstSubDi = dstDi.CreateSubdirectory(srcSubDi.Name);
+                CopyTo(srcSubDi.FullName, dstSubDi.FullName);
+            }
+        }
+    }
+}

+ 0 - 78
ContextMenuManager/BulePointLilac.Methods/IniFileHelper.cs

@@ -1,78 +0,0 @@
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Text;
-
-namespace BulePointLilac.Methods
-{
-    public class IniFileHelper
-    {
-        [DllImport("kernel32", CharSet = CharSet.Unicode, BestFitMapping = false, SetLastError = false, ThrowOnUnmappableChar = true)]
-        private static extern bool WritePrivateProfileString(string section, string key, string value, string filePath);
-
-        [DllImport("kernel32", CharSet = CharSet.Unicode, BestFitMapping = false, SetLastError = false, ThrowOnUnmappableChar = true)]
-        private static extern int GetPrivateProfileString(string section, string key, string defVal, StringBuilder retVal, int size, string filePath);
-
-        public IniFileHelper(string filePath) { this.FilePath = filePath; }
-
-        public string FilePath { get; private set; }
-
-        public string GetValue(string section, string key)
-        {
-            StringBuilder retVal = new StringBuilder(255);
-            GetPrivateProfileString(section, key, "", retVal, 255, this.FilePath);
-            return retVal.ToString();
-        }
-
-        public void SetValue(string section, string key, string value)
-        {
-            WritePrivateProfileString(section, key, value, this.FilePath);
-        }
-
-        public void DeleteKey(string section, string key)
-        {
-            SetValue(section, key, null);
-        }
-
-        public void DeleteSection(string section)
-        {
-            SetValue(section, null, null);
-        }
-
-        public bool KeyExists(string section, string key)
-        {
-            return GetValue(section, key) != string.Empty;
-        }
-
-        public bool TryGetValue(string section, string key, out string value)
-        {
-            value = GetValue(section, key);
-            return value != string.Empty;
-        }
-    }
-
-    public static class DesktopIniHelper
-    {
-        public const string LocalizedFileNames = "LocalizedFileNames";
-
-        public static void SetLocalizedFileName(string filePath, string name)
-        {
-            string fileName = Path.GetFileName(filePath);
-            string iniPath = $@"{Path.GetDirectoryName(filePath)}\desktop.ini";
-            IniFileHelper helper = new IniFileHelper(iniPath);
-            helper.SetValue(LocalizedFileNames, fileName, name);
-        }
-
-        public static string GetLocalizedFileName(string filePath)
-        {
-            string fileName = Path.GetFileName(filePath);
-            string iniPath = $@"{Path.GetDirectoryName(filePath)}\desktop.ini";
-            IniFileHelper helper = new IniFileHelper(iniPath);
-            return helper.GetValue(LocalizedFileNames, fileName);
-        }
-
-        public static void DeleteLocalizedFileName(string filePath)
-        {
-            SetLocalizedFileName(filePath, null);
-        }
-    }
-}

+ 4 - 2
ContextMenuManager/BulePointLilac.Methods/IniReader.cs

@@ -6,7 +6,7 @@ using System.Text;
 
 namespace BulePointLilac.Methods
 {
-    public class IniReader
+    public sealed class IniReader
     {
         public IniReader(StringBuilder sb)
         {
@@ -22,11 +22,13 @@ namespace BulePointLilac.Methods
             if(!File.Exists(filePath)) return;
             List<string> lines = new List<string>();
             using(StreamReader reader = new StreamReader(filePath, EncodingType.GetType(filePath)))
+            {
                 while(!reader.EndOfStream)
                 {
                     string line = reader.ReadLine().Trim();
                     if(line != string.Empty) lines.Add(line);
                 }
+            }
             ReadLines(lines);
         }
 
@@ -36,7 +38,7 @@ namespace BulePointLilac.Methods
         private void ReadLines(List<string> lines)
         {
             lines.RemoveAll(
-                line => line.StartsWith(";")//移除注释
+                line => line.StartsWith(";") || line.StartsWith("#")//移除注释
                 || (!line.StartsWith("[") && !line.Contains("=")));//移除非section行且非key行
 
             if(lines.Count == 0) return;

+ 146 - 0
ContextMenuManager/BulePointLilac.Methods/IniWriter.cs

@@ -0,0 +1,146 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace BulePointLilac.Methods
+{
+    public sealed class IniWriter
+    {
+        public IniWriter() { }
+
+        public IniWriter(string filePath)
+        {
+            this.FilePath = filePath;
+            if(File.Exists(FilePath)) this.Encoding = EncodingType.GetType(FilePath);
+        }
+
+        public string FilePath { get; set; }
+        public Encoding Encoding { get; set; } = Encoding.UTF8;
+        public bool DeleteFileWhenEmpty { get; set; }
+
+        private List<string> GetLines()
+        {
+            List<string> lines = new List<string>();
+            if(!File.Exists(FilePath)) return lines;
+            using(StreamReader reader = new StreamReader(FilePath, Encoding))
+            {
+                while(!reader.EndOfStream)
+                {
+                    lines.Add(reader.ReadLine().Trim());
+                }
+            }
+            return lines;
+        }
+
+        public void SetValue(string section, string key, string value)
+        {
+            if(section == null) return;
+            List<string> lines = GetLines();
+            string sectionLine = $"[{section}]";
+            string keyLine = $"{key}={value}";
+            int sectionRow = -1, keyRow = -1;//先假设不存在目标section和目标key
+            int nextSectionRow = -1;//下一个section的行数
+            for(int i = 0; i < lines.Count; i++)
+            {
+                if(lines[i].StartsWith(sectionLine, StringComparison.OrdinalIgnoreCase))
+                {
+                    sectionRow = i; break;//得到目标section所在行
+                }
+            }
+            if(sectionRow >= 0)//如果目标section存在
+            {
+                for(int i = sectionRow + 1; i < lines.Count; i++)
+                {
+                    if(lines[i].StartsWith("["))
+                    {
+                        nextSectionRow = i; break;//读取到下一个section
+                    }
+                    if(key != null && keyRow == -1)
+                    {
+                        int index = lines[i].IndexOf('=');
+                        if(index < 0) continue;
+                        string str = lines[i].Substring(0, index).TrimEnd();
+                        if(str.Equals(key, StringComparison.OrdinalIgnoreCase))
+                        {
+                            keyRow = i; continue;//得到目标key行
+                        }
+                    }
+                }
+            }
+
+            if(sectionRow == -1)
+            {
+                if(key != null && value != null)
+                {
+                    if(lines.Count > 0) lines.Add(string.Empty);//添加空行
+                    //目标section不存在则添加到最后
+                    lines.Add(sectionLine);
+                    lines.Add(keyLine);
+                }
+            }
+            else
+            {
+                if(keyRow == -1)
+                {
+                    if(key != null)
+                    {
+                        //存在下一个section时插入到其上方
+                        if(nextSectionRow != -1)
+                        {
+                            //目标section存在但目标key不存在
+                            keyRow = nextSectionRow;
+                            lines.Insert(keyRow, keyLine);
+                        }
+                        else
+                        {
+                            //不存在下一个section则添加到最后
+                            lines.Add(keyLine);
+                        }
+                    }
+                    else
+                    {
+                        //key为null则删除整个section
+                        int count;
+                        if(nextSectionRow == -1) count = lines.Count - sectionRow;
+                        else count = nextSectionRow - sectionRow;
+                        lines.RemoveRange(sectionRow, count);
+                    }
+                }
+                else
+                {
+                    if(value != null)
+                    {
+                        //目标section和目标key都存在
+                        lines[keyRow] = keyLine;
+                    }
+                    else
+                    {
+                        //赋值为null则删除key
+                        lines.RemoveAt(keyRow);
+                    }
+                }
+            }
+
+            if(DeleteFileWhenEmpty && lines.Count == 0 && File.Exists(FilePath))
+            {
+                File.Delete(FilePath);
+            }
+            else
+            {
+                Directory.CreateDirectory(Path.GetDirectoryName(FilePath));
+                File.WriteAllLines(FilePath, lines, Encoding);
+            }
+        }
+
+        public void DeleteKey(string section, string key)
+        {
+            SetValue(section, key, null);
+        }
+
+        public void DeleteSection(string section)
+        {
+            SetValue(section, null, null);
+        }
+    }
+}

+ 7 - 20
ContextMenuManager/BulePointLilac.Methods/ObjectPath.cs

@@ -31,6 +31,11 @@ namespace BulePointLilac.Methods
         public static bool GetFullFilePath(string fileName, out string fullPath)
         {
             fullPath = null;
+            if(File.Exists(fileName))
+            {
+                fullPath = fileName;
+                return true;
+            }
             foreach(string name in new[] { fileName, $"{fileName}.exe" })
             {
                 foreach(string dir in EnvironmentDirectorys)
@@ -50,19 +55,9 @@ namespace BulePointLilac.Methods
         /// <returns>成功提取返回现有文件路径,否则返回值为null</returns>
         public static string ExtractFilePath(string command)
         {
-            return ExtractFilePath(command, out _);
-        }
-
-        /// <param name="shortPath">文件短路径</param>
-        public static string ExtractFilePath(string command, out string shortPath)
-        {
-            shortPath = null;
             if(command.IsNullOrWhiteSpace()) return null;
             command = Environment.ExpandEnvironmentVariables(command).Replace(@"\\", @"\");
-            if(File.Exists(command)) {
-                shortPath = command;
-                return command;
-            }
+            if(File.Exists(command)) return command;
 
             string[] strs = Array.FindAll(command.Split(IllegalChars), str
                 => IgnoreCommandParts.Any(part => !part.Equals(str.Trim()))).Reverse().ToArray();
@@ -76,15 +71,7 @@ namespace BulePointLilac.Methods
                     if(path1.Contains(",")) paths.Add(path1.Substring(0, path1.LastIndexOf(',')));
                     foreach(string path in paths)
                     {
-                        if(File.Exists(path)) {
-                            shortPath = path;
-                            return path;
-                        }
-                        if(GetFullFilePath(path, out string fullPath))
-                        {
-                            shortPath = path;
-                            return fullPath;
-                        }
+                        if(GetFullFilePath(path, out string fullPath)) return fullPath;
                     }
                     index = path1.LastIndexOf(' ');
                 } while(index != -1);

+ 47 - 22
ContextMenuManager/BulePointLilac.Methods/RegistryEx.cs

@@ -1,12 +1,54 @@
 using Microsoft.Win32;
 using System;
+using System.Diagnostics;
+using System.IO;
 using System.Security.AccessControl;
 
 namespace BulePointLilac.Methods
 {
-
     public static class RegistryEx
     {
+        public static void CopyTo(this RegistryKey srcKey, RegistryKey dstKey)
+        {
+            foreach(string name in srcKey.GetValueNames())
+            {
+                dstKey.SetValue(name, srcKey.GetValue(name), srcKey.GetValueKind(name));
+            }
+            foreach(string name in srcKey.GetSubKeyNames())
+            {
+                using(RegistryKey srcSubKey = srcKey.OpenSubKey(name))
+                using(RegistryKey dstSubKey = dstKey.CreateSubKey(name, true))
+                    srcSubKey.CopyTo(dstSubKey);
+            }
+        }
+
+        public static void CopyTo(string srcPath, string dstPath)
+        {
+            using(RegistryKey srcKey = GetRegistryKey(srcPath))
+            using(RegistryKey dstKey = GetRegistryKey(dstPath, true, true))
+            {
+                CopyTo(srcKey, dstKey);
+            }
+        }
+
+        public static void MoveTo(this RegistryKey srcKey, RegistryKey dstKey)
+        {
+            CopyTo(srcKey, dstKey);
+            DeleteKeyTree(srcKey.Name);
+        }
+
+        public static void MoveTo(string srcPath, string dstPath)
+        {
+            CopyTo(srcPath, dstPath);
+            DeleteKeyTree(srcPath);
+        }
+
+        public static RegistryKey CreateSubKey(this RegistryKey key, string subKeyName, bool writable)
+        {
+            key.CreateSubKey(subKeyName).Close();
+            RegTrustedInstaller.TakeRegTreeOwnerShip($@"{key.Name}\{subKeyName}");
+            return key.OpenSubKey(subKeyName, writable);
+        }
 
         /// <summary>获取指定路径注册表项的上一级路径</summary>
         public static string GetParentPath(string regPath) => regPath.Substring(0, regPath.LastIndexOf('\\'));
@@ -96,29 +138,12 @@ namespace BulePointLilac.Methods
             GetRootAndSubRegPath(regPath, out RegistryKey root, out string keyPath);
             using(root) return root.OpenSubKey(keyPath, check, rights);
         }
-    }
-
-    public static class RegistryKeyExtension
-    {
-        public static void CopyTo(this RegistryKey srcKey, RegistryKey dstKey)
-        {
-            foreach(string name in srcKey.GetValueNames())
-            {
-                dstKey.SetValue(name, srcKey.GetValue(name), srcKey.GetValueKind(name));
-            }
-            foreach(string name in srcKey.GetSubKeyNames())
-            {
-                using(RegistryKey srcSubKey = srcKey.OpenSubKey(name))
-                using(RegistryKey dstSubKey = dstKey.CreateSubKey(name, true))
-                    srcSubKey.CopyTo(dstSubKey);
-            }
-        }
 
-        public static RegistryKey CreateSubKey(this RegistryKey key, string subKeyName, bool writable)
+        public static void Export(string regPath, string filePath)
         {
-            key.CreateSubKey(subKeyName).Close();
-            RegTrustedInstaller.TakeRegTreeOwnerShip($@"{key.Name}\{subKeyName}");
-            return key.OpenSubKey(subKeyName, writable);
+            if(File.Exists(filePath)) File.Delete(filePath);
+            Process process = Process.Start("regedit.exe", $" /e \"{filePath}\" \"{regPath}\"");
+            process.WaitForExit();
         }
     }
 }

+ 32 - 30
ContextMenuManager/BulePointLilac.Methods/WindowsOsVersion.cs

@@ -6,7 +6,7 @@ namespace BulePointLilac.Methods
     public static class WindowsOsVersion
     {
         public static readonly Version OsVersion = Environment.OSVersion.Version;
-        private static readonly float ShortVersion = OsVersion.Major + OsVersion.Minor / 10;
+        private static readonly float ShortVersion = OsVersion.Major + OsVersion.Minor / 10F;
 
         private const float Win10 = 10.0F;
         private const float Win8_1 = 6.3F;
@@ -14,34 +14,36 @@ namespace BulePointLilac.Methods
         private const float Win7 = 6.1F;
         private const float Vista = 6.0F;
 
-        public static bool IsEqual10 = ShortVersion == Win10;
-        public static bool IsAfter10 = ShortVersion > Win10;
-        public static bool IsBefore10 = ShortVersion < Win10;
-        public static bool ISAfterOrEqual10 = ShortVersion >= Win10;
-        public static bool ISBeforeOrEqual10 = ShortVersion <= Win10;
-
-        public static bool IsEqual8_1 = ShortVersion == Win8_1;
-        public static bool IsAfter8_1 = ShortVersion > Win8_1;
-        public static bool IsBefore8_1 = ShortVersion < Win8_1;
-        public static bool ISAfterOrEqual8_1 = ShortVersion >= Win8_1;
-        public static bool ISBeforeOrEqual8_1 = ShortVersion <= Win8_1;
-        
-        public static bool IsEqual8 = ShortVersion == Win8;
-        public static bool IsAfter8 = ShortVersion > Win8;
-        public static bool IsBefore8 = ShortVersion < Win8;
-        public static bool ISAfterOrEqual8 = ShortVersion >= Win8;
-        public static bool ISBeforeOrEqual8 = ShortVersion <= Win8;
-        
-        public static bool IsEqual7 = ShortVersion == Win7;
-        public static bool IsAfter7 = ShortVersion > Win7;
-        public static bool IsBefore7 = ShortVersion < Win7;
-        public static bool ISAfterOrEqual7 = ShortVersion >= Win7;
-        public static bool ISBeforeOrEqual7 = ShortVersion <= Win7;
-
-        public static bool IsEqualVista = ShortVersion == Vista;
-        public static bool IsAfterVista = ShortVersion > Vista;
-        public static bool IsBeforeVista = ShortVersion < Vista;
-        public static bool ISAfterOrEqualVista = ShortVersion >= Vista;
-        public static bool ISBeforeOrEqualVista = ShortVersion <= Vista;
+        public static readonly bool IsEqual10 = ShortVersion == Win10;
+        public static readonly bool IsAfter10 = ShortVersion > Win10;
+        public static readonly bool IsBefore10 = ShortVersion < Win10;
+        public static readonly bool ISAfterOrEqual10 = ShortVersion >= Win10;
+        public static readonly bool ISBeforeOrEqual10 = ShortVersion <= Win10;
+
+        public static readonly bool IsEqual8_1 = ShortVersion == Win8_1;
+        public static readonly bool IsAfter8_1 = ShortVersion > Win8_1;
+        public static readonly bool IsBefore8_1 = ShortVersion < Win8_1;
+        public static readonly bool ISAfterOrEqual8_1 = ShortVersion >= Win8_1;
+        public static readonly bool ISBeforeOrEqual8_1 = ShortVersion <= Win8_1;
+
+        public static readonly bool IsEqual8 = ShortVersion == Win8;
+        public static readonly bool IsAfter8 = ShortVersion > Win8;
+        public static readonly bool IsBefore8 = ShortVersion < Win8;
+        public static readonly bool ISAfterOrEqual8 = ShortVersion >= Win8;
+        public static readonly bool ISBeforeOrEqual8 = ShortVersion <= Win8;
+
+        public static readonly bool IsEqual7 = ShortVersion == Win7;
+        public static readonly bool IsAfter7 = ShortVersion > Win7;
+        public static readonly bool IsBefore7 = ShortVersion < Win7;
+        public static readonly bool ISAfterOrEqual7 = ShortVersion >= Win7;
+        public static readonly bool ISBeforeOrEqual7 = ShortVersion <= Win7;
+
+        public static readonly bool IsEqualVista = ShortVersion == Vista;
+        public static readonly bool IsAfterVista = ShortVersion > Vista;
+        public static readonly bool IsBeforeVista = ShortVersion < Vista;
+        public static readonly bool ISAfterOrEqualVista = ShortVersion >= Vista;
+        public static readonly bool ISBeforeOrEqualVista = ShortVersion <= Vista;
+
+        public static readonly bool IsAfterOrEqualWin10_1703 = OsVersion.CompareTo(new Version(10, 0, 15063)) >= 0;
     }
 }

+ 28 - 16
ContextMenuManager/ContextMenuManager.csproj

@@ -8,9 +8,9 @@
     <OutputType>WinExe</OutputType>
     <RootNamespace>ContextMenuManager</RootNamespace>
     <AssemblyName>ContextMenuManager</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
     <FileAlignment>512</FileAlignment>
-    <AutoGenerateBindingRedirects>false</AutoGenerateBindingRedirects>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
     <Deterministic>true</Deterministic>
     <IsWebBootstrapper>false</IsWebBootstrapper>
     <TargetFrameworkProfile />
@@ -109,37 +109,50 @@
     <Reference Include="System.Xml.Linq" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="AppConfig.cs" />
     <Compile Include="BulePointLilac.Controls\MyToolTip.cs" />
+    <Compile Include="BulePointLilac.Controls\ReadOnlyRichTextBox.cs">
+      <SubType>Component</SubType>
+    </Compile>
     <Compile Include="BulePointLilac.Controls\ResizbleForm.cs">
       <SubType>Form</SubType>
     </Compile>
     <Compile Include="BulePointLilac.Controls\MyToolBar.cs">
       <SubType>Component</SubType>
     </Compile>
+    <Compile Include="BulePointLilac.Methods\DirectoryEx.cs" />
     <Compile Include="BulePointLilac.Methods\GuidEx.cs" />
-    <Compile Include="BulePointLilac.Methods\IniFileHelper.cs" />
     <Compile Include="BulePointLilac.Methods\IniReader.cs" />
+    <Compile Include="BulePointLilac.Methods\IniWriter.cs" />
     <Compile Include="BulePointLilac.Methods\MessageBoxEx.cs" />
     <Compile Include="BulePointLilac.Methods\RichTextBoxExtension.cs" />
     <Compile Include="BulePointLilac.Methods\StringExtension.cs" />
+    <Compile Include="BulePointLilac.Methods\TextBoxExtension.cs" />
+    <Compile Include="BulePointLilac.Methods\WindowsOsVersion.cs" />
     <Compile Include="BulePointLilac.Methods\WshShortcut.cs" />
-    <Compile Include="Controls\AddCommonButton.cs">
+    <Compile Include="Controls\AddGuidDicDialog.cs">
       <SubType>Component</SubType>
     </Compile>
-    <Compile Include="Controls\AddGuidDicDialog.cs">
+    <Compile Include="Controls\CommandDialog.cs">
       <SubType>Component</SubType>
     </Compile>
-    <Compile Include="Controls\SelectItemsForm.cs">
-      <SubType>Form</SubType>
+    <Compile Include="Controls\EnhanceMenusItem.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Controls\EnhanceMenusList.cs">
+      <SubType>Component</SubType>
     </Compile>
     <Compile Include="Controls\Interfaces\IBtnMoveUpDownItem.cs">
       <SubType>Component</SubType>
     </Compile>
-    <Compile Include="Controls\SpecialItems\SkypeShareItem.cs">
+    <Compile Include="Controls\Interfaces\ITsiRegExportItem.cs">
       <SubType>Component</SubType>
     </Compile>
-    <Compile Include="Controls\SubMenuModeForm.cs">
-      <SubType>Form</SubType>
+    <Compile Include="Controls\LockNewItem.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Controls\SpecialItems\SkypeShareItem.cs">
+      <SubType>Component</SubType>
     </Compile>
     <Compile Include="Controls\ShellStoreDialog.cs">
       <SubType>Component</SubType>
@@ -186,9 +199,6 @@
     <Compile Include="Controls\NewItemForm.cs">
       <SubType>Form</SubType>
     </Compile>
-    <Compile Include="Controls\ShellCommonDialog.cs">
-      <SubType>Component</SubType>
-    </Compile>
     <Compile Include="Controls\AboutApp.cs">
       <SubType>Component</SubType>
     </Compile>
@@ -331,10 +341,10 @@
   </ItemGroup>
   <ItemGroup>
     <Content Include="Properties\AppIcon.ico" />
-    <Content Include="Properties\Resources\Texts\ShellCommonDic.xml" />
+    <Content Include="Properties\Resources\Images\Refresh.png" />
+    <Content Include="Properties\Resources\Texts\EnhanceMenusDic.xml" />
     <Content Include="Properties\Resources\Images\About.png" />
     <Content Include="Properties\Resources\Images\Add.png" />
-    <Content Include="Properties\Resources\Images\AddCommon.png" />
     <Content Include="Properties\Resources\Images\AddExisting.png" />
     <Content Include="Properties\Resources\Images\AddSeparator.png" />
     <Content Include="Properties\Resources\Images\CustomType.png" />
@@ -367,6 +377,8 @@
     </PreBuildEvent>
   </PropertyGroup>
   <PropertyGroup>
-    <PostBuildEvent>Xcopy $(ProjectDir)\Properties\Resources\Texts\AppLanguageDic.ini $(SolutionDir)\languages\zh-CN.ini /y</PostBuildEvent>
+    <PostBuildEvent>xcopy $(ProjectDir)\Properties\Resources\Texts\AppLanguageDic.ini $(SolutionDir)\languages\zh-CN.ini /y
+mkdir $(TargetDir)\config\languages
+xcopy $(SolutionDir)\languages $(TargetDir)\config\languages /y</PostBuildEvent>
   </PropertyGroup>
 </Project>

+ 167 - 60
ContextMenuManager/Controls/AboutApp.cs

@@ -1,4 +1,5 @@
-using BulePointLilac.Methods;
+using BulePointLilac.Controls;
+using BulePointLilac.Methods;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -13,20 +14,29 @@ namespace ContextMenuManager.Controls
 {
     sealed class DonateBox : Panel
     {
+        private const string DonateListUrl = "https://github.com/BluePointLilac/ContextMenuManager/blob/master/Donate.md";
+
         public DonateBox()
         {
             this.Dock = DockStyle.Fill;
             this.BackColor = Color.White;
-            this.Controls.AddRange(new Control[] { lblInfo, picQR });
+            this.Font = new Font(SystemFonts.MenuFont.FontFamily, 10F);
+            this.Controls.AddRange(new Control[] { lblInfo, picQR, llbDonationList });
+            llbDonationList.LinkClicked += (sender, e) => Process.Start(DonateListUrl);
         }
 
         readonly Label lblInfo = new Label
         {
-            Font = new Font(SystemFonts.MenuFont.FontFamily, 10F),
             Text = AppString.Other.Donate,
             AutoSize = true
         };
 
+        readonly LinkLabel llbDonationList = new LinkLabel
+        {
+            Text = AppString.Other.DonationList,
+            AutoSize = true
+        };
+
         readonly PictureBox picQR = new PictureBox
         {
             Image = Properties.Resources.Donate,
@@ -36,41 +46,14 @@ namespace ContextMenuManager.Controls
 
         protected override void OnResize(EventArgs e)
         {
+            int a = 60.DpiZoom();
             base.OnResize(e);
             picQR.Left = (this.Width - picQR.Width) / 2;
             lblInfo.Left = (this.Width - lblInfo.Width) / 2;
-            picQR.Top = (this.Height - picQR.Height + lblInfo.Height) / 2;
-            lblInfo.Top = picQR.Top - lblInfo.Height * 2;
-        }
-    }
-
-    sealed class AboutAppBox : RichTextBox
-    {
-        public AboutAppBox()
-        {
-            this.ReadOnly = true;
-            this.Dock = DockStyle.Fill;
-            this.BackColor = Color.White;
-            this.BorderStyle = BorderStyle.None;
-            this.ForeColor = Color.FromArgb(60, 60, 60);
-            this.Font = new Font(SystemFonts.MenuFont.FontFamily, 11F);
-        }
-
-        const int WM_SETFOCUS = 0x0007;
-        const int WM_KILLFOCUS = 0x0008;
-        protected override void WndProc(ref Message m)
-        {
-            switch(m.Msg)
-            {
-                case WM_SETFOCUS:
-                    m.Msg = WM_KILLFOCUS; break;
-            }
-            base.WndProc(ref m);
-        }
-
-        protected override void OnLinkClicked(LinkClickedEventArgs e)
-        {
-            base.OnLinkClicked(e); Process.Start(e.LinkText);
+            llbDonationList.Left = (this.Width - llbDonationList.Width) / 2;
+            lblInfo.Top = a;
+            picQR.Top = lblInfo.Bottom + a;
+            llbDonationList.Top = picQR.Bottom + a;
         }
     }
 
@@ -80,15 +63,19 @@ namespace ContextMenuManager.Controls
         {
             this.Dock = DockStyle.Fill;
             this.Controls.AddRange(pages);
-            this.Font = new Font(SystemFonts.MenuFont.FontFamily, 11F);
+            this.Font = new Font(SystemFonts.MenuFont.FontFamily, 10F);
             cms.Items.AddRange(items);
             for(int i = 0; i < 5; i++)
             {
-                boxs[i] = new AboutAppBox { Parent = pages[i] };
+                boxs[i] = new ReadOnlyRichTextBox { Parent = pages[i] };
                 if(i > 0) boxs[i].ContextMenuStrip = cms;
             }
             items[0].Click += (sender, e) => EditText();
             items[2].Click += (sender, e) => SaveFile();
+            boxs[0].Controls.Add(btnOpenDir);
+            btnOpenDir.Top = boxs[0].Height - btnOpenDir.Height;
+            MyToolTip.SetToolTip(btnOpenDir, AppString.Tip.OpenDictionariesDir);
+            btnOpenDir.MouseDown += (sender, e) => Process.Start(AppConfig.DicsDir);
         }
 
         readonly TabPage[] pages = new TabPage[] {
@@ -98,7 +85,12 @@ namespace ContextMenuManager.Controls
             new TabPage(AppString.Other.ThridRulesDictionary),
             new TabPage(AppString.Other.CommonItemsDictionary)
         };
-        readonly AboutAppBox[] boxs = new AboutAppBox[5];
+        readonly ReadOnlyRichTextBox[] boxs = new ReadOnlyRichTextBox[5];
+        readonly PictureButton btnOpenDir = new PictureButton(AppImage.Open)
+        {
+            Anchor = AnchorStyles.Left | AnchorStyles.Bottom,
+            Left = 0
+        };
         readonly ContextMenuStrip cms = new ContextMenuStrip();
         readonly ToolStripItem[] items = new ToolStripItem[] {
             new ToolStripMenuItem(AppString.Menu.Edit),
@@ -114,31 +106,33 @@ namespace ContextMenuManager.Controls
         const int WM_SETTEXT = 0x000C;
         private void EditText()
         {
-            Process process = Process.Start("notepad.exe");
-            Thread.Sleep(200);
-            IntPtr handle = FindWindowEx(process.MainWindowHandle, IntPtr.Zero, "Edit", null);
-            SendMessage(handle, WM_SETTEXT, 0, GetInitialText());
+            using(Process process = Process.Start("notepad.exe"))
+            {
+                Thread.Sleep(200);
+                IntPtr handle = FindWindowEx(process.MainWindowHandle, IntPtr.Zero, "Edit", null);
+                SendMessage(handle, WM_SETTEXT, 0, GetInitialText());
+            }
         }
 
         private void SaveFile()
         {
             using(SaveFileDialog dlg = new SaveFileDialog())
             {
-                string dirPath = Program.ConfigDir;
+                string dirPath = AppConfig.UserDicsDir;
                 switch(SelectedIndex)
                 {
                     case 1:
-                        dirPath = Program.LanguagesDir;
-                        dlg.FileName = Program.ZH_CNINI;
+                        dirPath = AppConfig.LangsDir;
+                        dlg.FileName = AppConfig.ZH_CNINI;
                         break;
                     case 2:
-                        dlg.FileName = Program.GUIDINFOSDICINI;
+                        dlg.FileName = AppConfig.GUIDINFOSDICINI;
                         break;
                     case 3:
-                        dlg.FileName = Program.ThIRDRULESDICXML;
+                        dlg.FileName = AppConfig.ThIRDRULESDICXML;
                         break;
                     case 4:
-                        dlg.FileName = Program.SHELLCOMMONDICXML;
+                        dlg.FileName = AppConfig.ENHANCEMENUSICXML;
                         break;
                 }
                 dlg.Filter = $"{dlg.FileName}|*{Path.GetExtension(dlg.FileName)}";
@@ -162,7 +156,7 @@ namespace ContextMenuManager.Controls
                 case 3:
                     return Properties.Resources.ThirdRulesDic;
                 case 4:
-                    return Properties.Resources.ShellCommonDic;
+                    return Properties.Resources.EnhanceMenusDic;
                 default:
                     return string.Empty;
             }
@@ -177,22 +171,24 @@ namespace ContextMenuManager.Controls
             this.BeginInvoke(new Action<string>(boxs[1].LoadIni), new[] { Properties.Resources.AppLanguageDic });
             this.BeginInvoke(new Action<string>(boxs[2].LoadIni), new[] { Properties.Resources.GuidInfosDic });
             this.BeginInvoke(new Action<string>(boxs[3].LoadXml), new[] { Properties.Resources.ThirdRulesDic });
-            this.BeginInvoke(new Action<string>(boxs[4].LoadXml), new[] { Properties.Resources.ShellCommonDic });
+            this.BeginInvoke(new Action<string>(boxs[4].LoadXml), new[] { Properties.Resources.EnhanceMenusDic });
         }
     }
 
     sealed class LanguagesBox : Panel
     {
-        const string OtherLanguagesUrl = "https://gitee.com/BluePointLilac/ContextMenuManager/tree/master/languages";
+        const string OtherLanguagesUrl = "https://github.com/BluePointLilac/ContextMenuManager/tree/master/languages";
 
         public LanguagesBox()
         {
             this.Dock = DockStyle.Fill;
-            this.Font = new Font(SystemFonts.MenuFont.FontFamily, 11F);
-            this.Controls.AddRange(new Control[] { cmbLanguages, llbOtherLanguages, txtTranslators });
+            this.Font = new Font(SystemFonts.MenuFont.FontFamily, 10F);
+            this.Controls.AddRange(new Control[] { cmbLanguages, btnOpenDir, llbOtherLanguages, txtTranslators });
             this.OnResize(null);
             cmbLanguages.SelectionChangeCommitted += (sender, e) => ChangeLanguage();
             llbOtherLanguages.LinkClicked += (sender, e) => Process.Start(OtherLanguagesUrl);
+            btnOpenDir.MouseDown += (sender, e) => Process.Start(AppConfig.LangsDir);
+            MyToolTip.SetToolTip(btnOpenDir, AppString.Tip.OpenLanguagesDir);
         }
 
         readonly ComboBox cmbLanguages = new ComboBox
@@ -214,6 +210,8 @@ namespace ContextMenuManager.Controls
             ScrollBars = ScrollBars.Vertical
         };
 
+        readonly PictureButton btnOpenDir = new PictureButton(AppImage.Open);
+
         readonly List<string> iniPaths = new List<string>();
 
         protected override void OnResize(EventArgs e)
@@ -221,6 +219,8 @@ namespace ContextMenuManager.Controls
             base.OnResize(e);
             int a = 20.DpiZoom();
             txtTranslators.Left = cmbLanguages.Left = cmbLanguages.Top = llbOtherLanguages.Top = a;
+            btnOpenDir.Left = cmbLanguages.Right + a;
+            btnOpenDir.Top = cmbLanguages.Top + (cmbLanguages.Height - btnOpenDir.Height) / 2;
             txtTranslators.Top = cmbLanguages.Bottom + a;
             txtTranslators.Width = this.ClientSize.Width - 2 * a;
             txtTranslators.Height = this.ClientSize.Height - txtTranslators.Top - a;
@@ -231,10 +231,9 @@ namespace ContextMenuManager.Controls
         public void LoadLanguages()
         {
             cmbLanguages.Items.Clear();
-            cmbLanguages.Items.Add("(默认) 简体中文");
-
-            string str = AppString.Other.Translators + Environment.NewLine;
-            DirectoryInfo di = new DirectoryInfo(Program.LanguagesDir);
+            cmbLanguages.Items.Add("(default) 简体中文");
+            string str = AppString.Other.Translators + Environment.NewLine + new string('-', 74);
+            DirectoryInfo di = new DirectoryInfo(AppConfig.LangsDir);
             if(di.Exists)
             {
                 iniPaths.Clear();
@@ -248,8 +247,8 @@ namespace ContextMenuManager.Controls
                     str += Environment.NewLine + language + new string('\t', 5) + translator;
                     cmbLanguages.Items.Add(language);
                 }
-                txtTranslators.Text = str;
             }
+            txtTranslators.Text = str;
             cmbLanguages.SelectedIndex = GetSelectIndex();
         }
 
@@ -265,18 +264,126 @@ namespace ContextMenuManager.Controls
             }
             else
             {
-                new IniFileHelper(Program.ConfigIniPath).SetValue("General", "Language", path);
+                AppConfig.LanguageIniPath = path;
                 Application.Restart();
             }
         }
 
         private int GetSelectIndex()
         {
+            string path = AppConfig.LanguageIniPath;
             for(int i = 0; i < iniPaths.Count; i++)
             {
-                if(iniPaths[i].Equals(Program.LanguageFilePath, StringComparison.OrdinalIgnoreCase)) return i + 1;
+                if(iniPaths[i].Equals(path, StringComparison.OrdinalIgnoreCase)) return i + 1;
             }
             return 0;
         }
     }
+
+    sealed class AppSettingBox : MyList
+    {
+        private const string GITHUBRELEASES = "https://github.com/BluePointLilac/ContextMenuManager/releases";
+        private const string GITEERELEASES = "https://gitee.com/BluePointLilac/ContextMenuManager/releases";
+
+        public AppSettingBox()
+        {
+            this.Font = new Font(SystemFonts.MenuFont.FontFamily, 10F);
+            mliConfigDir.AddCtrs(new Control[] { cmbConfigDir, btnConfigDir });
+            mliBackup.AddCtrs(new Control[] { chkBackup, btnBackupDir });
+            mliUpdate.AddCtrs(new Control[] { lblGitee, lblGithub, lblUpdate });
+            mliProtect.AddCtr(chkProtect);
+            MyToolTip.SetToolTip(btnConfigDir, AppString.Other.OpenConfigDir);
+            MyToolTip.SetToolTip(btnBackupDir, AppString.Other.OpenBackupDir);
+            MyToolTip.SetToolTip(lblUpdate, AppString.Tip.CheckUpdate + Environment.NewLine
+                + AppString.Tip.LastCheckUpdateTime + AppConfig.LastCheckUpdateTime.ToLongDateString());
+            cmbConfigDir.Items.AddRange(new[] { AppString.Other.SaveToAppData, AppString.Other.SaveToAppDir });
+            cmbConfigDir.Width = 160.DpiZoom();
+            btnConfigDir.MouseDown += (sender, e) => Process.Start(AppConfig.ConfigDir);
+            btnBackupDir.MouseDown += (sender, e) => Process.Start(AppConfig.BackupDir);
+            lblGithub.Click += (sender, e) => Process.Start(GITHUBRELEASES);
+            lblGitee.Click += (sender, e) => Process.Start(GITEERELEASES);
+            lblUpdate.Click += (sender, e) =>
+            {
+                if(!Updater.CheckUpdate()) MessageBoxEx.Show(AppString.MessageBox.NoUpdateDetected);
+            };
+            cmbConfigDir.SelectionChangeCommitted += (sender, e) =>
+            {
+                string newPath = (cmbConfigDir.SelectedIndex == 0) ? AppConfig.AppDataConfigDir : AppConfig.AppConfigDir;
+                if(newPath == AppConfig.ConfigDir) return;
+                if(MessageBoxEx.Show(AppString.MessageBox.RestartApp, MessageBoxButtons.OKCancel) != DialogResult.OK)
+                {
+                    cmbConfigDir.SelectedIndex = AppConfig.SaveToAppDir ? 1 : 0;
+                }
+                else
+                {
+                    DirectoryEx.CopyTo(AppConfig.ConfigDir, newPath);
+                    Directory.Delete(AppConfig.ConfigDir, true);
+                    Application.Restart();
+                }
+            };
+            chkBackup.MouseDown += (sender, e) => AppConfig.AutoBackup = chkBackup.Checked = !chkBackup.Checked;
+            chkProtect.MouseDown += (sender, e) => AppConfig.ProtectOpenItem = chkProtect.Checked = !chkProtect.Checked;
+        }
+
+        readonly MyListItem mliConfigDir = new MyListItem
+        {
+            Text = AppString.Other.ConfigFile,
+            HasImage = false
+        };
+        readonly ComboBox cmbConfigDir = new ComboBox
+        {
+            DropDownStyle = ComboBoxStyle.DropDownList
+        };
+        readonly PictureButton btnConfigDir = new PictureButton(AppImage.Open);
+
+        readonly MyListItem mliBackup = new MyListItem
+        {
+            Text = AppString.Other.AutoBackup,
+            HasImage = false
+        };
+        readonly MyCheckBox chkBackup = new MyCheckBox();
+        readonly PictureButton btnBackupDir = new PictureButton(AppImage.Open);
+
+        readonly MyListItem mliUpdate = new MyListItem
+        {
+            Text = AppString.Other.CheckUpdate,
+            HasImage = false
+        };
+        readonly Label lblUpdate = new Label
+        {
+            Text = AppString.Other.ImmediatelyCheckUpdate,
+            BorderStyle = BorderStyle.FixedSingle,
+            Cursor = Cursors.Hand,
+            AutoSize = true
+        };
+        readonly Label lblGithub = new Label
+        {
+            Text = "Github",
+            BorderStyle = BorderStyle.FixedSingle,
+            Cursor = Cursors.Hand,
+            AutoSize = true
+        };
+        readonly Label lblGitee = new Label
+        {
+            Text = "Gitee",
+            BorderStyle = BorderStyle.FixedSingle,
+            Cursor = Cursors.Hand,
+            AutoSize = true
+        };
+
+        readonly MyListItem mliProtect = new MyListItem
+        {
+            Text = AppString.Other.ProtectOpenItem,
+            HasImage = false
+        };
+        readonly MyCheckBox chkProtect = new MyCheckBox();
+
+        public void LoadItems()
+        {
+            this.AddItems(new[] { mliUpdate, mliConfigDir, mliBackup, mliProtect });
+            cmbConfigDir.SelectedIndex = AppConfig.SaveToAppDir ? 1 : 0;
+            chkBackup.Checked = AppConfig.AutoBackup;
+            chkProtect.Checked = AppConfig.ProtectOpenItem;
+        }
+    }
 }

+ 2 - 2
ContextMenuManager/Controls/AddGuidDicDialog.cs

@@ -87,8 +87,7 @@ namespace ContextMenuManager.Controls
             };
             readonly PictureBox picIcon = new PictureBox
             {
-                Size = SystemInformation.IconSize,
-                BackColor = Color.White
+                Size = SystemInformation.IconSize
             };
             readonly Button btnBrowse = new Button
             {
@@ -140,6 +139,7 @@ namespace ContextMenuManager.Controls
                 using(IconDialog dlg = new IconDialog())
                 {
                     dlg.IconPath = this.ItemIconPath;
+                    dlg.IconIndex = this.ItemIconIndex;
                     if(dlg.ShowDialog() != DialogResult.OK) return;
                     ItemIconPath = dlg.IconPath;
                     ItemIconIndex = dlg.IconIndex;

+ 107 - 0
ContextMenuManager/Controls/CommandDialog.cs

@@ -0,0 +1,107 @@
+using BulePointLilac.Controls;
+using BulePointLilac.Methods;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace ContextMenuManager.Controls
+{
+    sealed class CommandDialog : CommonDialog
+    {
+        public string Command { get; set; }
+        public string Arguments { get; set; }
+
+        public override void Reset() { }
+
+        protected override bool RunDialog(IntPtr hwndOwner)
+        {
+            using(CommandForm frm = new CommandForm())
+            {
+                frm.Command = this.Command;
+                frm.Arguments = this.Arguments;
+                bool flag = frm.ShowDialog() == DialogResult.OK;
+                if(flag)
+                {
+                    this.Command = frm.Command;
+                    this.Arguments = frm.Arguments;
+                }
+                return flag;
+            }
+        }
+
+        sealed class CommandForm : ResizbleForm
+        {
+            public CommandForm()
+            {
+                this.AcceptButton = btnOk;
+                this.CancelButton = btnCancel;
+                this.VerticalResizable = false;
+                this.Font = SystemFonts.MessageBoxFont;
+                this.Text = AppString.Menu.ChangeCommand;
+                this.SizeGripStyle = SizeGripStyle.Hide;
+                this.StartPosition = FormStartPosition.CenterParent;
+                this.MaximizeBox = MinimizeBox = ShowIcon = ShowInTaskbar = false;
+                InitializeComponents();
+            }
+
+            public string Command
+            {
+                get => txtCommand.Text;
+                set => txtCommand.Text = value;
+            }
+
+            public string Arguments
+            {
+                get => txtArguments.Text;
+                set => txtArguments.Text = value;
+            }
+
+            readonly Label lblCommand = new Label
+            {
+                Text = AppString.Dialog.ItemCommand,
+                AutoSize = true
+            };
+            readonly Label lblArguments = new Label
+            {
+                Text = AppString.Dialog.CommandArguments,
+                AutoSize = true
+            };
+            readonly TextBox txtCommand = new TextBox();
+            readonly TextBox txtArguments = new TextBox();
+            readonly Button btnOk = new Button
+            {
+                DialogResult = DialogResult.OK,
+                Text = AppString.Dialog.Ok,
+                AutoSize = true
+            };
+            readonly Button btnCancel = new Button
+            {
+                DialogResult = DialogResult.Cancel,
+                Text = AppString.Dialog.Cancel,
+                AutoSize = true
+            };
+
+            private void InitializeComponents()
+            {
+                this.Controls.AddRange(new Control[] { lblCommand, lblArguments, txtCommand, txtArguments, btnOk, btnCancel });
+                int a = 20.DpiZoom();
+                lblArguments.Left = lblCommand.Left = lblCommand.Top = txtCommand.Top = a;
+                lblArguments.Top = txtArguments.Top = txtCommand.Bottom + a;
+                btnOk.Top = btnCancel.Top = txtArguments.Bottom + a;
+                int b = Math.Max(lblCommand.Width, lblArguments.Width) + 3 * a;
+                this.ClientSize = new Size(250.DpiZoom() + b, btnOk.Bottom + a);
+                btnOk.Anchor = btnCancel.Anchor = AnchorStyles.Right | AnchorStyles.Top;
+                btnCancel.Left = this.ClientSize.Width - btnCancel.Width - a;
+                btnOk.Left = btnCancel.Left - btnOk.Width - a;
+                this.Resize += (sender, e) =>
+                {
+                    txtArguments.Width = txtCommand.Width = this.ClientSize.Width - b;
+                    txtArguments.Left = txtCommand.Left = btnCancel.Right - txtCommand.Width;
+                };
+                this.OnResize(null);
+                this.MinimumSize = this.Size;
+            }
+        }
+    }
+
+}

+ 1 - 0
ContextMenuManager/Controls/EnhanceMenusItem.cs

@@ -32,6 +32,7 @@ namespace ContextMenuManager.Controls
         public EnhanceShellItem()
         {
             ChkVisible = new VisibleCheckBox(this);
+            this.SetNoClickEvent();
         }
 
         private static void WriteAttributesValue(XmlNode valueXN, string regPath)

+ 90 - 87
ContextMenuManager/Controls/EnhanceMenusList.cs

@@ -13,106 +13,109 @@ namespace ContextMenuManager.Controls
     {
         public void LoadItems()
         {
-            this.ClearItems();
-            XmlDocument doc = ReadXml();
-            foreach(XmlNode xn in doc.DocumentElement.ChildNodes)
+            try
             {
-                string path = null;
-                string text = null;
-                Image image = null;
-                switch(xn.Name)
+                foreach(XmlNode xn in ReadXml().DocumentElement.ChildNodes)
                 {
-                    case "File":
-                        path = ShellList.MENUPATH_FILE;
-                        text = AppString.SideBar.File;
-                        image = AppImage.File;
-                        break;
-                    case "Folder":
-                        path = ShellList.MENUPATH_FOLDER;
-                        text = AppString.SideBar.Folder;
-                        image = AppImage.Folder;
-                        break;
-                    case "Directory":
-                        path = ShellList.MENUPATH_FOLDER;
-                        text = AppString.SideBar.Directory;
-                        image = AppImage.Directory;
-                        break;
-                    case "Background":
-                        path = ShellList.MENUPATH_BACKGROUND;
-                        text = AppString.SideBar.Background;
-                        image = AppImage.Background;
-                        break;
-                    case "Desktop":
-                        path = ShellList.MENUPATH_DESKTOP;
-                        //Vista没有桌面右键菜单的独立注册表项
-                        if(WindowsOsVersion.IsEqualVista) path = ShellList.MENUPATH_BACKGROUND;
-                        text = AppString.SideBar.Desktop;
-                        image = AppImage.Desktop;
-                        break;
-                    case "Drive":
-                        path = ShellList.MENUPATH_DRIVE;
-                        text = AppString.SideBar.Drive;
-                        image = AppImage.Drive;
-                        break;
-                    case "AllObjects":
-                        path = ShellList.MENUPATH_ALLOBJECTS;
-                        text = AppString.SideBar.AllObjects;
-                        image = AppImage.AllObjects;
-                        break;
-                    case "Computer":
-                        path = ShellList.MENUPATH_COMPUTER;
-                        text = AppString.SideBar.Computer;
-                        image = AppImage.Computer;
-                        break;
-                    case "RecycleBin":
-                        path = ShellList.MENUPATH_RECYCLEBIN;
-                        text = AppString.SideBar.RecycleBin;
-                        image = AppImage.RecycleBin;
-                        break;
-                    default:
-                        XmlElement xe = (XmlElement)xn;
-                        path = xe.GetAttribute("RegPath");
-                        text = ResourceString.GetDirectString(xe.GetAttribute("Text"));
-                        image = ResourceIcon.GetIcon(xe.GetAttribute("Icon"))?.ToBitmap() ?? AppImage.NotFound;
-                        break;
+                    string path = null;
+                    string text = null;
+                    Image image = null;
+                    switch(xn.Name)
+                    {
+                        case "File":
+                            path = ShellList.MENUPATH_FILE;
+                            text = AppString.SideBar.File;
+                            image = AppImage.File;
+                            break;
+                        case "Folder":
+                            path = ShellList.MENUPATH_FOLDER;
+                            text = AppString.SideBar.Folder;
+                            image = AppImage.Folder;
+                            break;
+                        case "Directory":
+                            path = ShellList.MENUPATH_FOLDER;
+                            text = AppString.SideBar.Directory;
+                            image = AppImage.Directory;
+                            break;
+                        case "Background":
+                            path = ShellList.MENUPATH_BACKGROUND;
+                            text = AppString.SideBar.Background;
+                            image = AppImage.Background;
+                            break;
+                        case "Desktop":
+                            path = ShellList.MENUPATH_DESKTOP;
+                            //Vista没有桌面右键菜单的独立注册表项
+                            if(WindowsOsVersion.IsEqualVista) path = ShellList.MENUPATH_BACKGROUND;
+                            text = AppString.SideBar.Desktop;
+                            image = AppImage.Desktop;
+                            break;
+                        case "Drive":
+                            path = ShellList.MENUPATH_DRIVE;
+                            text = AppString.SideBar.Drive;
+                            image = AppImage.Drive;
+                            break;
+                        case "AllObjects":
+                            path = ShellList.MENUPATH_ALLOBJECTS;
+                            text = AppString.SideBar.AllObjects;
+                            image = AppImage.AllObjects;
+                            break;
+                        case "Computer":
+                            path = ShellList.MENUPATH_COMPUTER;
+                            text = AppString.SideBar.Computer;
+                            image = AppImage.Computer;
+                            break;
+                        case "RecycleBin":
+                            path = ShellList.MENUPATH_RECYCLEBIN;
+                            text = AppString.SideBar.RecycleBin;
+                            image = AppImage.RecycleBin;
+                            break;
+                        default:
+                            XmlElement xe = (XmlElement)xn;
+                            path = xe.GetAttribute("RegPath");
+                            text = ResourceString.GetDirectString(xe.GetAttribute("Text"));
+                            image = ResourceIcon.GetIcon(xe.GetAttribute("Icon"))?.ToBitmap() ?? AppImage.NotFound;
+                            break;
+                    }
+                    if(string.IsNullOrEmpty(path) || string.IsNullOrEmpty(text)) continue;
+                    GroupPathItem groupItem = new GroupPathItem(path, ObjectPath.PathType.Registry)
+                    {
+                        Image = image,
+                        Text = text,
+                    };
+                    this.AddItem(groupItem);
+                    XmlElement shellXE = (XmlElement)xn.SelectSingleNode("Shell");
+                    XmlElement shellExXE = (XmlElement)xn.SelectSingleNode("ShellEx");
+                    if(shellXE != null) LoadShellItems(shellXE, groupItem);
+                    if(shellExXE != null) LoadShellExItems(shellExXE, groupItem);
+                    groupItem.IsFold = true;
                 }
-                if(string.IsNullOrEmpty(path) || string.IsNullOrEmpty(text)) continue;
-                GroupPathItem groupItem = new GroupPathItem
-                {
-                    PathType = ObjectPath.PathType.Registry,
-                    TargetPath = path,
-                    Image = image,
-                    Text = text,
-                };
-                this.AddItem(groupItem);
-                XmlElement shellXE = (XmlElement)xn.SelectSingleNode("Shell");
-                XmlElement shellExXE = (XmlElement)xn.SelectSingleNode("ShellEx");
-                if(shellXE != null) LoadShellItems(shellXE, groupItem);
-                if(shellExXE != null) LoadShellExItems(shellExXE, groupItem);
-                groupItem.IsFold = true;
             }
-
+            catch { }
         }
 
         private XmlDocument ReadXml()
         {
             XmlDocument doc1 = new XmlDocument();
-            //如果没有网络下载的,则将程序内置的写入
-            if(!File.Exists(Program.AppDataEnhanceMenusDicPath))
+            try
             {
-                File.WriteAllText(Program.AppDataEnhanceMenusDicPath, Properties.Resources.EnhanceMenusDic, Encoding.UTF8);
-            }
-            doc1.Load(Program.AppDataEnhanceMenusDicPath);
-            if(File.Exists(Program.EnhanceMenusDicPath))
-            {
-                XmlDocument doc2 = new XmlDocument();
-                doc2.Load(Program.EnhanceMenusDicPath);
-                foreach(XmlNode xn in doc2.DocumentElement.ChildNodes)
+                //如果没有网络下载的,则将程序内置的写入
+                if(!File.Exists(AppConfig.WebEnhanceMenusDic))
+                {
+                    File.WriteAllText(AppConfig.WebEnhanceMenusDic, Properties.Resources.EnhanceMenusDic, Encoding.UTF8);
+                }
+                doc1.Load(AppConfig.WebEnhanceMenusDic);
+                if(File.Exists(AppConfig.UserEnhanceMenusDic))
                 {
-                    XmlNode node = doc1.ImportNode(xn, true);
-                    doc1.DocumentElement.AppendChild(node);
+                    XmlDocument doc2 = new XmlDocument();
+                    doc2.Load(AppConfig.UserEnhanceMenusDic);
+                    foreach(XmlNode xn in doc2.DocumentElement.ChildNodes)
+                    {
+                        XmlNode node = doc1.ImportNode(xn, true);
+                        doc1.DocumentElement.AppendChild(node);
+                    }
                 }
             }
+            catch { }
             return doc1;
         }
 

+ 10 - 7
ContextMenuManager/Controls/ExplorerRestarter.cs

@@ -27,7 +27,7 @@ namespace ContextMenuManager.Controls
             if(this.Parent != null) this.Parent.Height += Visible ? Height : -Height;
         }
 
-        private readonly PictureButton BtnRestart = new PictureButton(AppImage.Refresh);
+        private readonly PictureButton BtnRestart = new PictureButton(AppImage.RestartExplorer);
 
         private static event EventHandler RestartHandler;
 
@@ -45,19 +45,22 @@ namespace ContextMenuManager.Controls
 
     public static class Explorer
     {
-        /// <summary>重启Explorer</summary>
         public static void ReStart()
         {
-            new Process
+            using(Process process = new Process())
             {
-                StartInfo = new ProcessStartInfo
+                process.StartInfo = new ProcessStartInfo
                 {
                     FileName = "cmd.exe",
-                    Arguments = "/s /c tskill explorer",
+                    Arguments = "/c taskkill -f -im explorer.exe",
                     WindowStyle = ProcessWindowStyle.Hidden,
                     UseShellExecute = true
-                }
-            }.Start();
+                };
+                process.Start();
+                process.WaitForExit();
+                process.StartInfo.Arguments = "/c explorer";
+                process.Start();
+            }
         }
     }
 }

+ 2 - 0
ContextMenuManager/Controls/GuidBlockedItem.cs

@@ -54,6 +54,8 @@ namespace ContextMenuManager.Controls
 
             ContextMenuStrip.Items.AddRange(new ToolStripItem[] {TsiSearch, new ToolStripSeparator(),
                 TsiFileProperties, TsiFileLocation, TsiRegLocation });
+
+            MyToolTip.SetToolTip(BtnDelete, AppString.Menu.Delete);
         }
 
         public void DeleteMe()

+ 10 - 3
ContextMenuManager/Controls/GuidBlockedList.cs

@@ -12,7 +12,6 @@ namespace ContextMenuManager.Controls
     {
         public void LoadItems()
         {
-            this.ClearItems();
             this.AddNewItem();
             this.LoadCommonItems();
         }
@@ -34,9 +33,17 @@ namespace ContextMenuManager.Controls
 
         private void AddNewItem()
         {
-            NewItem newItem = new NewItem { Text = AppString.Item.AddGuidBlockedItem };
+            MyListItem newItem = new MyListItem
+            {
+                Text = AppString.Item.AddGuidBlockedItem,
+                Image = AppImage.AddNewItem
+            };
+            PictureButton btnAddNewItem = new PictureButton(AppImage.AddNewItem);
+            newItem.AddCtr(btnAddNewItem);
+            newItem.SetNoClickEvent();
             this.AddItem(newItem);
-            newItem.NewItemAdd += (sender, e) =>
+            MyToolTip.SetToolTip(btnAddNewItem, newItem.Text);
+            btnAddNewItem.MouseDown += (sender, e) =>
             {
                 using(InputDialog dlg = new InputDialog { Title = AppString.Dialog.InputGuid })
                 {

+ 0 - 1
ContextMenuManager/Controls/Interfaces/IBtnMoveUpDownItem.cs

@@ -13,7 +13,6 @@ namespace ContextMenuManager.Controls.Interfaces
         public MoveButton(IBtnMoveUpDownItem item, bool isUp) : base(isUp ? AppImage.Up : AppImage.Down)
         {
             ((MyListItem)item).AddCtr(this);
-            ((MyListItem)item).SetCtrIndex(this, isUp ? 2 : 1);
         }
     }
 }

+ 25 - 1
ContextMenuManager/Controls/Interfaces/IFoldGroupItem.cs

@@ -1,5 +1,7 @@
 using BulePointLilac.Controls;
+using BulePointLilac.Methods;
 using System.Drawing;
+using System.IO;
 using System.Windows.Forms;
 using static BulePointLilac.Methods.ObjectPath;
 
@@ -63,10 +65,32 @@ namespace ContextMenuManager.Controls.Interfaces
         public ObjectPathButton BtnOpenPath { get; set; }
         public FoldButton BtnFold { get; set; }
 
-        public GroupPathItem()
+        public GroupPathItem(string targetPath, PathType pathType)
         {
             BtnFold = new FoldButton(this);
             BtnOpenPath = new ObjectPathButton(this);
+            this.Font = new Font(base.Font, FontStyle.Bold);
+            this.TargetPath = targetPath;
+            this.PathType = pathType;
+            string tip = null;
+            switch(pathType)
+            {
+                case PathType.File:
+                    tip = AppString.Menu.FileLocation;
+                    Text = Path.GetFileNameWithoutExtension(targetPath);
+                    Image = ResourceIcon.GetExtensionIcon(targetPath).ToBitmap();
+                    break;
+                case PathType.Directory:
+                    tip = AppString.Menu.FileLocation;
+                    Text = Path.GetFileNameWithoutExtension(targetPath);
+                    Image = ResourceIcon.GetFolderIcon(targetPath).ToBitmap();
+                    break;
+                case PathType.Registry:
+                    tip = AppString.Menu.RegistryLocation;
+                    break;
+            }
+            MyToolTip.SetToolTip(BtnOpenPath, tip);
+            this.SetNoClickEvent();
         }
     }
 }

+ 19 - 0
ContextMenuManager/Controls/Interfaces/ITsiDeleteItem.cs

@@ -1,4 +1,6 @@
 using BulePointLilac.Methods;
+using System;
+using System.IO;
 using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls.Interfaces
@@ -9,6 +11,12 @@ namespace ContextMenuManager.Controls.Interfaces
         void DeleteMe();
     }
 
+    interface ITsiRegDeleteItem : ITsiDeleteItem
+    {
+        string ItemText { get; }
+        string RegPath { get; }
+    }
+
     sealed class DeleteMeMenuItem : ToolStripMenuItem
     {
         public DeleteMeMenuItem(ITsiDeleteItem item) : base(AppString.Menu.Delete)
@@ -17,7 +25,18 @@ namespace ContextMenuManager.Controls.Interfaces
             {
                 if(MessageBoxEx.Show(AppString.MessageBox.ConfirmDeletePermanently,
                     MessageBoxButtons.YesNo) == DialogResult.Yes)
+                {
+                    if(item is ITsiRegDeleteItem regItem && AppConfig.AutoBackup)
+                    {
+                        string date = DateTime.Today.ToString("yyyy-MM-dd");
+                        string fileName = ObjectPath.RemoveIllegalChars(regItem.ItemText);
+                        string filePath = $@"{AppConfig.BackupDir}\{date}\{fileName}.reg";
+                        filePath = ObjectPath.GetNewPathWithIndex(filePath, ObjectPath.PathType.File);
+                        Directory.CreateDirectory(Path.GetDirectoryName(filePath));
+                        RegistryEx.Export(regItem.RegPath, filePath);
+                    }
                     item.DeleteMe();
+                }
             };
         }
     }

+ 42 - 0
ContextMenuManager/Controls/Interfaces/ITsiRegExportItem.cs

@@ -0,0 +1,42 @@
+using BulePointLilac.Methods;
+using System;
+using System.IO;
+using System.Windows.Forms;
+
+namespace ContextMenuManager.Controls.Interfaces
+{
+    interface ITsiRegExportItem
+    {
+        string Text { get; set; }
+        string RegPath { get; set; }
+        ContextMenuStrip ContextMenuStrip { get; set; }
+        RegExportMenuItem TsiRegExport { get; set; }
+    }
+
+    sealed class RegExportMenuItem : ToolStripMenuItem
+    {
+        public RegExportMenuItem(ITsiRegExportItem item) : base(AppString.Menu.ExportRegistry)
+        {
+            this.Click += (sender, e) =>
+            {
+                using(SaveFileDialog dlg = new SaveFileDialog())
+                {
+                    string dirPath = $@"{AppConfig.BackupDir}\{DateTime.Today.ToString("yyyy-MM-dd")}";
+                    Directory.CreateDirectory(dirPath);
+                    dlg.FileName = item.Text;
+                    dlg.InitialDirectory = dirPath;
+                    dlg.Filter = $"{AppString.Dialog.RegistryFile}|*.reg";
+                    if(dlg.ShowDialog() != DialogResult.OK)
+                    {
+                        if(Directory.GetFiles(dirPath).Length == 0 && Directory.GetDirectories(dirPath).Length == 0)
+                            Directory.Delete(dirPath);
+                    }
+                    else
+                    {
+                        RegistryEx.Export(item.RegPath, dlg.FileName);
+                    }
+                }
+            };
+        }
+    }
+}

+ 1 - 3
ContextMenuManager/Controls/Interfaces/ITsiTextItem.cs

@@ -18,9 +18,7 @@ namespace ContextMenuManager.Controls.Interfaces
             this.Click += (sender, e) =>
             {
                 string name = ChangeText(item.Text);
-                if(name == null) return;
-                item.ItemText = name;
-                item.Text = ResourceString.GetDirectString(item.ItemText);
+                if(name != null) item.ItemText = name;
             };
         }
 

+ 98 - 0
ContextMenuManager/Controls/LockNewItem.cs

@@ -0,0 +1,98 @@
+using BulePointLilac.Controls;
+using BulePointLilac.Methods;
+using ContextMenuManager.Controls.Interfaces;
+using Microsoft.Win32;
+using System;
+using System.Security.AccessControl;
+using System.Security.Principal;
+using System.Windows.Forms;
+
+namespace ContextMenuManager.Controls
+{
+    sealed class LockNewItem : MyListItem, IChkVisibleItem
+    {
+        public LockNewItem(ShellNewList list)
+        {
+            this.Owner = list;
+            this.Image = AppImage.Lock;
+            this.Text = AppString.Item.LockNewMenu;
+            this.SetNoClickEvent();
+            ChkVisible = new VisibleCheckBox(this)
+            {
+                Margin = new Padding(Margin.Left, Margin.Top, RegRuleItem.SysMarginRignt, Margin.Bottom),
+                Checked = IsLocked()
+            };
+            MyToolTip.SetToolTip(ChkVisible, AppString.Tip.LockNewMenu);
+        }
+
+        public VisibleCheckBox ChkVisible { get; set; }
+        public ShellNewList Owner { get; private set; }
+
+        public bool ItemVisible
+        {
+            get => IsLocked();
+            set
+            {
+                if(value) Lock();
+                else UnLock();
+                foreach(Control ctr in Owner.Controls)
+                {
+                    if(ctr.GetType() == typeof(ShellNewItem))
+                    {
+                        ShellNewItem item = (ShellNewItem)ctr;
+                        if(item.CanSort)
+                        {
+                            item.BtnMoveDown.Visible = item.BtnMoveUp.Visible = value;
+                        }
+                    }
+                }
+            }
+        }
+
+        public static bool IsLocked()
+        {
+            using(RegistryKey key = RegistryEx.GetRegistryKey(ShellNewList.ShellNewPath))
+            {
+                RegistrySecurity rs = key.GetAccessControl();
+                foreach(RegistryAccessRule rar in rs.GetAccessRules(true, true, typeof(NTAccount)))
+                {
+                    if(rar.AccessControlType.ToString().Equals("Deny", StringComparison.OrdinalIgnoreCase))
+                    {
+                        if(rar.IdentityReference.ToString().Equals("Everyone", StringComparison.OrdinalIgnoreCase)) return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public static void Lock()
+        {
+            using(RegistryKey key = RegistryEx.GetRegistryKey(ShellNewList.ShellNewPath, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.ChangePermissions))
+            {
+                RegistrySecurity rs = new RegistrySecurity();
+                RegistryAccessRule rar = new RegistryAccessRule("Everyone", RegistryRights.Delete | RegistryRights.WriteKey, AccessControlType.Deny);
+                rs.AddAccessRule(rar);
+                key.SetAccessControl(rs);
+            }
+        }
+
+        public static void UnLock()
+        {
+            using(RegistryKey key = RegistryEx.GetRegistryKey(ShellNewList.ShellNewPath, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.ChangePermissions))
+            {
+                RegistrySecurity rs = key.GetAccessControl();
+                foreach(RegistryAccessRule rar in rs.GetAccessRules(true, true, typeof(NTAccount)))
+                {
+                    if(rar.AccessControlType.ToString().Equals("Deny", StringComparison.OrdinalIgnoreCase))
+                    {
+                        if(rar.IdentityReference.ToString().Equals("Everyone", StringComparison.OrdinalIgnoreCase))
+                        {
+                            rs.RemoveAccessRule(rar);
+                        }
+                    }
+                }
+                key.SetAccessControl(rs);
+            }
+        }
+    }
+}

+ 4 - 2
ContextMenuManager/Controls/NewItem.cs

@@ -1,4 +1,5 @@
 using BulePointLilac.Controls;
+using BulePointLilac.Methods;
 using System;
 
 namespace ContextMenuManager.Controls
@@ -9,11 +10,12 @@ namespace ContextMenuManager.Controls
         {
             this.Image = AppImage.NewItem;
             this.Text = AppString.Item.NewItem;
+            this.SetNoClickEvent();
             this.AddCtr(BtnAddNewItem);
             MyToolTip.SetToolTip(BtnAddNewItem, AppString.Item.NewItem);
-            BtnAddNewItem.MouseDown += (sender, e) => NewItemAdd?.Invoke(null, null);
+            BtnAddNewItem.MouseDown += (sender, e) => AddNewItem?.Invoke(null, null);
         }
-        public event EventHandler NewItemAdd;
+        public event EventHandler AddNewItem;
         readonly PictureButton BtnAddNewItem = new PictureButton(AppImage.AddNewItem);
     }
 }

+ 25 - 7
ContextMenuManager/Controls/NewItemForm.cs

@@ -22,7 +22,17 @@ namespace ContextMenuManager.Controls
         }
 
         public string ItemText { get => txtText.Text; set => txtText.Text = value; }
-        public string ItemCommand { get => txtCommand.Text; set => txtCommand.Text = value; }
+        public string Command { get => txtCommand.Text; set => txtCommand.Text = value; }
+        public string Arguments { get => txtArguments.Text; set => txtArguments.Text = value; }
+        public string FullCommand
+        {
+            get
+            {
+                if(Arguments.IsNullOrWhiteSpace()) return Command;
+                else if(Command.IsNullOrWhiteSpace()) return Arguments;
+                else return $"\"{Command}\" \"{Arguments}\"";
+            }
+        }
 
         protected readonly Label lblText = new Label
         {
@@ -34,8 +44,14 @@ namespace ContextMenuManager.Controls
             Text = AppString.Dialog.ItemCommand,
             AutoSize = true
         };
+        protected readonly Label lblArguments = new Label
+        {
+            Text = AppString.Dialog.CommandArguments,
+            AutoSize = true
+        };
         protected readonly TextBox txtText = new TextBox();
         protected readonly TextBox txtCommand = new TextBox();
+        protected readonly TextBox txtArguments = new TextBox();
         protected readonly Button btnBrowse = new Button
         {
             Text = AppString.Dialog.Browse,
@@ -57,21 +73,23 @@ namespace ContextMenuManager.Controls
 
         protected virtual void InitializeComponents()
         {
-            this.Controls.AddRange(new Control[] { lblText, lblCommand, txtText, txtCommand, btnBrowse, btnOk, btnCancel });
+            this.Controls.AddRange(new Control[] { lblText, lblCommand, lblArguments,
+                txtText, txtCommand, txtArguments, btnBrowse, btnOk, btnCancel });
             int a = 20.DpiZoom();
             btnBrowse.Anchor = btnOk.Anchor = btnCancel.Anchor = AnchorStyles.Right | AnchorStyles.Top;
-            txtText.Top = lblText.Top = lblText.Left = lblCommand.Left = a;
+            txtText.Top = lblText.Top = lblText.Left = lblCommand.Left = lblArguments.Left = a;
             btnBrowse.Top = txtCommand.Top = lblCommand.Top = txtText.Bottom + a;
-            btnOk.Top = btnCancel.Top = btnBrowse.Bottom + a;
+            lblArguments.Top = txtArguments.Top = txtCommand.Bottom + a;
+            btnOk.Top = btnCancel.Top = txtArguments.Bottom + a;
             btnCancel.Left = btnBrowse.Left = this.ClientSize.Width - btnCancel.Width - a;
             btnOk.Left = btnCancel.Left - btnOk.Width - a;
-            int b = Math.Max(lblText.Width, lblCommand.Width) + btnBrowse.Width + 4 * a;
+            int b = Math.Max(Math.Max(lblText.Width, lblCommand.Width), lblArguments.Width) + btnBrowse.Width + 4 * a;
             this.ClientSize = new Size(250.DpiZoom() + b, btnOk.Bottom + a);
             this.MinimumSize = this.Size;
             this.Resize += (sender, e) =>
             {
-                txtText.Width = txtCommand.Width = this.ClientSize.Width - b;
-                txtText.Left = txtCommand.Left = btnBrowse.Left - txtCommand.Width - a;
+                txtText.Width = txtCommand.Width = txtArguments.Width = this.ClientSize.Width - b;
+                txtText.Left = txtCommand.Left = txtArguments.Left = btnBrowse.Left - txtCommand.Width - a;
                 LastSize = this.Size;
             };
             if(LastSize != null) this.Size = LastSize;

+ 5 - 4
ContextMenuManager/Controls/NewOpenWithDialog.cs

@@ -40,12 +40,12 @@ namespace ContextMenuManager.Controls
                         MessageBoxEx.Show(AppString.MessageBox.TextCannotBeEmpty);
                         return;
                     }
-                    if(ItemCommand.IsNullOrWhiteSpace())
+                    if(Command.IsNullOrWhiteSpace())
                     {
                         MessageBoxEx.Show(AppString.MessageBox.TextCannotBeEmpty);
                         return;
                     }
-                    FilePath = ObjectPath.ExtractFilePath(ItemCommand);
+                    FilePath = ObjectPath.ExtractFilePath(Command);
                     AppRegPath = $@"HKEY_CLASSES_ROOT\Applications\{Path.GetFileName(FilePath)}";
                     if(FilePath == null || RegistryEx.GetRegistryKey(AppRegPath) != null)
                     {
@@ -64,7 +64,8 @@ namespace ContextMenuManager.Controls
                     dlg.Filter = $"{AppString.Dialog.Program}|*.exe";
                     if(dlg.ShowDialog() == DialogResult.OK)
                     {
-                        ItemCommand = $"\"{dlg.FileName}\" \"%1\"";
+                        Command = dlg.FileName;
+                        Arguments = "%1";
                         ItemText = FileVersionInfo.GetVersionInfo(dlg.FileName).FileDescription;
                     }
                 }
@@ -77,7 +78,7 @@ namespace ContextMenuManager.Controls
                     key.SetValue("FriendlyAppName", ItemText);
                     using(var cmdKey = key.CreateSubKey(@"shell\open\command", true))
                     {
-                        cmdKey.SetValue("", ItemCommand);
+                        cmdKey.SetValue("", FullCommand);
                         RegPath = cmdKey.Name;
                     }
                 }

+ 22 - 20
ContextMenuManager/Controls/NewSendToDialog.cs

@@ -12,7 +12,7 @@ namespace ContextMenuManager.Controls
 
         protected override bool RunDialog(IntPtr hwndOwner)
         {
-            using(NewSendToItemForm frm = new NewSendToItemForm())
+            using(NewSendToForm frm = new NewSendToForm())
             {
                 bool flag = frm.ShowDialog() == DialogResult.OK;
                 if(flag) this.FilePath = frm.FilePath;
@@ -20,7 +20,7 @@ namespace ContextMenuManager.Controls
             }
         }
 
-        sealed class NewSendToItemForm : NewItemForm
+        sealed class NewSendToForm : NewItemForm
         {
             public string FilePath { get; set; }
 
@@ -40,7 +40,7 @@ namespace ContextMenuManager.Controls
             {
                 base.InitializeComponents();
                 this.Text = AppString.Dialog.NewSendToItem;
-                this.Controls.AddRange(new[] { rdoFile, rdoFolder });
+                this.Controls.AddRange(new Control[] { rdoFile, rdoFolder });
                 rdoFile.Top = rdoFolder.Top = btnOk.Top;
                 rdoFile.Left = lblCommand.Left;
                 rdoFolder.Left = rdoFile.Right + 20.DpiZoom();
@@ -58,14 +58,19 @@ namespace ContextMenuManager.Controls
                         MessageBoxEx.Show(AppString.MessageBox.TextCannotBeEmpty);
                         return;
                     }
-                    if(ItemCommand.IsNullOrWhiteSpace())
+                    if(Command.IsNullOrWhiteSpace())
                     {
                         MessageBoxEx.Show(AppString.MessageBox.CommandCannotBeEmpty);
                         return;
                     }
-                    if(ObjectPath.ExtractFilePath(ItemCommand) == null && !Directory.Exists(ItemCommand))
+                    if(rdoFile.Checked && !ObjectPath.GetFullFilePath(Command, out _))
                     {
-                        MessageBoxEx.Show(AppString.MessageBox.FileOrFolderNotExists);
+                        MessageBoxEx.Show(AppString.MessageBox.FileNotExists);
+                        return;
+                    }
+                    if(rdoFolder.Checked && !Directory.Exists(Command))
+                    {
+                        MessageBoxEx.Show(AppString.MessageBox.FolderNotExists);
                         return;
                     }
                     AddNewItem();
@@ -80,7 +85,7 @@ namespace ContextMenuManager.Controls
                     dlg.Filter = $"{AppString.Dialog.Program}|*.exe;*.bat;*.cmd;*.vbs;*.vbe;*.jse;*.wsf";
                     if(dlg.ShowDialog() == DialogResult.OK)
                     {
-                        ItemCommand = $"\"{dlg.FileName}\"";
+                        Command = dlg.FileName;
                         ItemText = Path.GetFileNameWithoutExtension(dlg.FileName);
                     }
                 }
@@ -90,10 +95,11 @@ namespace ContextMenuManager.Controls
             {
                 using(FolderBrowserDialog dlg = new FolderBrowserDialog())
                 {
-                    dlg.SelectedPath = ItemCommand;
+                    if(Directory.Exists(Command)) dlg.SelectedPath = Command;
+                    else dlg.SelectedPath = Application.StartupPath;
                     if(dlg.ShowDialog() == DialogResult.OK)
                     {
-                        ItemCommand = dlg.SelectedPath;
+                        Command = dlg.SelectedPath;
                         ItemText = new DirectoryInfo(dlg.SelectedPath).Name;
                     }
                 }
@@ -103,19 +109,15 @@ namespace ContextMenuManager.Controls
             {
                 FilePath = $@"{SendToList.SendToPath}\{ObjectPath.RemoveIllegalChars(ItemText)}.lnk";
                 FilePath = ObjectPath.GetNewPathWithIndex(FilePath, ObjectPath.PathType.File);
-
-                WshShortcut shortcut = new WshShortcut { FullName = FilePath };
-                if(rdoFile.Checked)
+                WshShortcut shortcut = new WshShortcut
                 {
-                    ItemCommand = Environment.ExpandEnvironmentVariables(ItemCommand);
-                    shortcut.TargetPath = ObjectPath.ExtractFilePath(ItemCommand, out string shortPath);
-                    string str = ItemCommand.Substring(ItemCommand.IndexOf(shortPath) + shortPath.Length);
-                    shortcut.Arguments = str.Substring(str.IndexOf(" ") + 1);
-                    shortcut.WorkingDirectory = Path.GetDirectoryName(shortcut.TargetPath);
-                }
-                else shortcut.TargetPath = ItemCommand;
+                    FullName = FilePath,
+                    TargetPath = Command,
+                    WorkingDirectory = Path.GetDirectoryName(Command),
+                    Arguments = Arguments
+                };
                 shortcut.Save();
-                DesktopIniHelper.SetLocalizedFileName(FilePath, ItemText);
+                SendToList.DesktopIniWriter.SetValue("LocalizedFileNames", Path.GetFileName(FilePath), ItemText);
             }
         }
     }

+ 20 - 11
ContextMenuManager/Controls/NewShellDialog.cs

@@ -16,7 +16,7 @@ namespace ContextMenuManager.Controls
 
         protected override bool RunDialog(IntPtr hwndOwner)
         {
-            using(NewShellItemForm frm = new NewShellItemForm
+            using(NewShellForm frm = new NewShellForm
             {
                 ScenePath = this.ScenePath,
                 ShellPath = this.ShellPath
@@ -28,7 +28,7 @@ namespace ContextMenuManager.Controls
             }
         }
 
-        sealed class NewShellItemForm : NewItemForm
+        sealed class NewShellForm : NewItemForm
         {
             public string ShellPath { get; set; }
             public string NewItemRegPath { get; private set; }//返回的新建菜单项注册表路径
@@ -57,7 +57,10 @@ namespace ContextMenuManager.Controls
                 ShellList.MENUPATH_FOLDER,
                 ShellList.MENUPATH_ALLOBJECTS,
                 ShellList.SYSFILEASSPATH,
-                ShellList.MENUPATH_UNKNOWN
+                ShellList.MENUPATH_UNKNOWN,
+                ShellList.MENUPATH_LNKFILE,
+                ShellList.MENUPATH_EXEFILE,
+                ShellList.MENUPATH_UWPLNK
             };
 
             protected override void InitializeComponents()
@@ -71,8 +74,14 @@ namespace ContextMenuManager.Controls
 
                 rdoMulti.CheckedChanged += (sender, e) =>
                 {
-                    lblCommand.Enabled = txtCommand.Enabled
-                    = btnBrowse.Enabled = !rdoMulti.Checked;
+                    if(WindowsOsVersion.IsEqualVista && rdoMulti.Checked)
+                    {
+                        MessageBoxEx.Show(AppString.MessageBox.VistaUnsupportedMulti);
+                        rdoSingle.Checked = true;
+                        return;
+                    }
+                    lblCommand.Enabled = txtCommand.Enabled = lblArguments.Enabled 
+                    = txtArguments.Enabled = btnBrowse.Enabled = !rdoMulti.Checked;
                 };
 
                 btnBrowse.Click += (sender, e) => BrowseFile();
@@ -97,17 +106,17 @@ namespace ContextMenuManager.Controls
                 {
                     dlg.Filter = $"{AppString.Dialog.Program}|*.exe;*.bat;*.cmd;*.pif;*.com";
                     if(dlg.ShowDialog() != DialogResult.OK) return;
-                    ItemCommand = $"\"{dlg.FileName}\"";
+                    Command = dlg.FileName;
                     ItemText = Path.GetFileNameWithoutExtension(dlg.FileName);
                     if(Array.FindIndex(DirScenePaths, path
                        => ScenePath.Equals(path, StringComparison.OrdinalIgnoreCase)) != -1)
                     {
-                        ItemCommand += " \"%V\"";//自动加目录后缀
+                        Arguments = "%V";//自动加目录后缀
                     }
                     else if(Array.FindIndex(FileObjectsScenePaths, path
                        => ScenePath.StartsWith(path, StringComparison.OrdinalIgnoreCase)) != -1)
                     {
-                        ItemCommand += " \"%1\"";//自动加文件对象后缀
+                        Arguments += "%1";//自动加文件对象后缀
                     }
                 }
             }
@@ -116,7 +125,7 @@ namespace ContextMenuManager.Controls
             {
                 using(var shellKey = RegistryEx.GetRegistryKey(ShellPath, true, true))
                 {
-                    string keyName = ItemText.Replace("\\", "").Trim();
+                    string keyName = "Item";
                     NewItemRegPath = ObjectPath.GetNewPathWithIndex($@"{ShellPath}\{keyName}", ObjectPath.PathType.Registry);
                     keyName = RegistryEx.GetKeyName(NewItemRegPath);
 
@@ -127,8 +136,8 @@ namespace ContextMenuManager.Controls
                             key.SetValue("SubCommands", "");
                         else
                         {
-                            if(!ItemCommand.IsNullOrWhiteSpace())
-                                key.CreateSubKey("command", true).SetValue("", ItemCommand);
+                            if(!FullCommand.IsNullOrWhiteSpace())
+                                key.CreateSubKey("command", true).SetValue("", FullCommand);
                         }
                     }
                 }

+ 6 - 2
ContextMenuManager/Controls/OpenWithItem.cs

@@ -11,7 +11,7 @@ using System.Windows.Forms;
 namespace ContextMenuManager.Controls
 {
     sealed class OpenWithItem : MyListItem, IChkVisibleItem, IBtnShowMenuItem, ITsiTextItem,
-        ITsiCommandItem, ITsiWebSearchItem, ITsiFilePathItem, ITsiRegPathItem, ITsiDeleteItem
+        ITsiCommandItem, ITsiWebSearchItem, ITsiFilePathItem, ITsiRegPathItem, ITsiRegDeleteItem, ITsiRegExportItem
     {
 
         public OpenWithItem(string regPath)
@@ -55,6 +55,7 @@ namespace ContextMenuManager.Controls
             set
             {
                 Registry.SetValue(AppPath, "FriendlyAppName", value);
+                this.Text = ResourceString.GetDirectString(value);
             }
         }
 
@@ -93,6 +94,8 @@ namespace ContextMenuManager.Controls
         public FileLocationMenuItem TsiFileLocation { get; set; }
         public RegLocationMenuItem TsiRegLocation { get; set; }
         public DeleteMeMenuItem TsiDeleteMe { get; set; }
+        public RegExportMenuItem TsiRegExport { get; set; }
+
         readonly ToolStripMenuItem TsiDetails = new ToolStripMenuItem(AppString.Menu.Details);
 
         private void InitializeComponents()
@@ -105,13 +108,14 @@ namespace ContextMenuManager.Controls
             TsiFileProperties = new FilePropertiesMenuItem(this);
             TsiFileLocation = new FileLocationMenuItem(this);
             TsiRegLocation = new RegLocationMenuItem(this);
+            TsiRegExport = new RegExportMenuItem(this);
             TsiDeleteMe = new DeleteMeMenuItem(this);
 
             ContextMenuStrip.Items.AddRange(new ToolStripItem[] { TsiChangeText,
                 new ToolStripSeparator(), TsiDetails, new ToolStripSeparator(), TsiDeleteMe });
 
             TsiDetails.DropDownItems.AddRange(new ToolStripItem[] { TsiSearch, new ToolStripSeparator(),
-                TsiChangeCommand, TsiFileProperties, TsiFileLocation, TsiRegLocation });
+                TsiChangeCommand, TsiFileProperties, TsiFileLocation, TsiRegLocation, TsiRegExport });
 
             ContextMenuStrip.Opening += (sender, e) => TsiChangeText.Enabled = this.NameEquals;
         }

+ 3 - 4
ContextMenuManager/Controls/OpenWithList.cs

@@ -12,15 +12,14 @@ namespace ContextMenuManager.Controls
     {
         public void LoadItems()
         {
-            this.ClearItems();
             this.LoadCommonItems();
             this.SortItemByText();
             this.AddNewItem();
-            Version ver = Environment.OSVersion.Version;
             RegRuleItem storeItem = new RegRuleItem(RegRuleItem.UseStoreOpenWith)
             {
                 MarginRight = RegRuleItem.SysMarginRignt,
-                Visible = (ver.Major == 10) || (ver.Major == 6 && ver.Minor >= 2)
+                //Win8、Win8.1、Win10才有在应用商店中查找应用
+                Visible = WindowsOsVersion.ISAfterOrEqual8
             };
             this.InsertItem(storeItem, 1);
         }
@@ -61,7 +60,7 @@ namespace ContextMenuManager.Controls
         {
             NewItem newItem = new NewItem();
             this.InsertItem(newItem, 0);
-            newItem.NewItemAdd += (sender, e) =>
+            newItem.AddNewItem += (sender, e) =>
             {
                 using(NewOpenWithDialog dlg = new NewOpenWithDialog())
                 {

+ 3 - 2
ContextMenuManager/Controls/RegRuleItem.cs

@@ -46,6 +46,7 @@ namespace ContextMenuManager.Controls
             this.RestartExplorer = info.RestartExplorer;
             ChkVisible = new VisibleCheckBox(this);
             MyToolTip.SetToolTip(ChkVisible, info.Tip);
+            this.SetNoClickEvent();
         }
 
         public RegRuleItem(RegRule[] rules, ItemInfo info)
@@ -131,7 +132,7 @@ namespace ContextMenuManager.Controls
             ItemInfo = new ItemInfo
             {
                 Text = AppString.Item.CustomFolder,
-                Image = AppImage.CustomFolder,
+                Image = AppImage.Folder,
                 Tip = AppString.Tip.CustomFolder,
                 RestartExplorer = true
             }
@@ -160,7 +161,7 @@ namespace ContextMenuManager.Controls
             ItemInfo = new ItemInfo
             {
                 Text = AppString.Item.RecycleBinProperties,
-                Image = AppImage.RecycleBinProperties,
+                Image = AppImage.RecycleBin,
                 RestartExplorer = true
             }
         };

+ 74 - 22
ContextMenuManager/Controls/SendToItem.cs

@@ -8,7 +8,8 @@ using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls
 {
-    sealed class SendToItem : MyListItem, IChkVisibleItem, IBtnShowMenuItem, ITsiTextItem, ITsiIconItem, ITsiWebSearchItem, ITsiFilePathItem, ITsiDeleteItem
+    sealed class SendToItem : MyListItem, IChkVisibleItem, IBtnShowMenuItem, ITsiTextItem,
+        ITsiIconItem, ITsiWebSearchItem, ITsiFilePathItem, ITsiDeleteItem
     {
         public SendToItem(string filePath)
         {
@@ -66,14 +67,16 @@ namespace ContextMenuManager.Controls
         {
             get
             {
-                string name = SendToList.GetMenuName(FileName);
+                string name = SendToList.DesktopIniReader.GetValue("LocalizedFileNames", FileName);
+                name = ResourceString.GetDirectString(name);
                 if(name == string.Empty) name = Path.GetFileNameWithoutExtension(FilePath);
                 if(name == string.Empty) name = FileExtension;
                 return name;
             }
             set
             {
-                DesktopIniHelper.SetLocalizedFileName(FilePath, value);
+                SendToList.DesktopIniWriter.SetValue("LocalizedFileNames", FileName, value);
+                this.Text = ResourceString.GetDirectString(value);
                 ExplorerRestarter.NeedRestart = true;
             }
         }
@@ -82,16 +85,12 @@ namespace ContextMenuManager.Controls
         {
             get
             {
-                Icon icon = null;
-                if(IsShortcut)
+                Icon icon = ResourceIcon.GetIcon(IconLocation, out string iconPath, out int iconIndex);
+                IconPath = iconPath; IconIndex = iconIndex;
+                if(icon == null && IsShortcut)
                 {
-                    icon = ResourceIcon.GetIcon(IconLocation, out string iconPath, out int iconIndex);
-                    IconPath = iconPath; IconIndex = iconIndex;
-                    if(icon == null)
-                    {
-                        if(File.Exists(Shortcut.TargetPath)) icon = Icon.ExtractAssociatedIcon(Shortcut.TargetPath);
-                        else if(Directory.Exists(Shortcut.TargetPath)) icon = ResourceIcon.GetFolderIcon(Shortcut.TargetPath);
-                    }
+                    if(File.Exists(Shortcut.TargetPath)) icon = Icon.ExtractAssociatedIcon(Shortcut.TargetPath);
+                    else if(Directory.Exists(Shortcut.TargetPath)) icon = ResourceIcon.GetFolderIcon(Shortcut.TargetPath);
                 }
                 icon = icon ?? ResourceIcon.GetExtensionIcon(FileExtension);
                 return icon;
@@ -102,14 +101,51 @@ namespace ContextMenuManager.Controls
         {
             get
             {
-                string location = Shortcut.IconLocation;
-                if(location.StartsWith(",")) location = $"{Shortcut.TargetPath}{location}";
+                string location = null;
+                if(IsShortcut)
+                {
+                    location = Shortcut.IconLocation;
+                    if(location.StartsWith(",")) location = $"{Shortcut.TargetPath}{location}";
+                }
+                else
+                {
+                    using(RegistryKey root = Registry.ClassesRoot)
+                    using(RegistryKey extensionKey = root.OpenSubKey(FileExtension))
+                    {
+                        string guidPath = extensionKey.GetValue("")?.ToString();
+                        if(guidPath != null)
+                        {
+                            using(RegistryKey guidKey = root.OpenSubKey($@"{guidPath}\DefaultIcon"))
+                            {
+                                location = guidKey.GetValue("")?.ToString();
+                            }
+                        }
+                    }
+                }
                 return location;
             }
             set
             {
-                Shortcut.IconLocation = value;
-                Shortcut.Save();
+                if(IsShortcut)
+                {
+                    Shortcut.IconLocation = value;
+                    Shortcut.Save();
+                }
+                else
+                {
+                    using(RegistryKey root = Registry.ClassesRoot)
+                    using(RegistryKey extensionKey = root.OpenSubKey(FileExtension))
+                    {
+                        string guidPath = extensionKey.GetValue("")?.ToString();
+                        if(guidPath != null)
+                        {
+                            string regPath = $@"{root.Name}\{guidPath}\DefaultIcon";
+                            RegTrustedInstaller.TakeRegTreeOwnerShip(regPath);
+                            Registry.SetValue(regPath, "", value);
+                            ExplorerRestarter.NeedRestart = true;
+                        }
+                    }
+                }
             }
         }
 
@@ -124,8 +160,8 @@ namespace ContextMenuManager.Controls
         public FilePropertiesMenuItem TsiFileProperties { get; set; }
         public FileLocationMenuItem TsiFileLocation { get; set; }
         public DeleteMeMenuItem TsiDeleteMe { get; set; }
-        readonly ToolStripSeparator TsiIconSeparator = new ToolStripSeparator();
         readonly ToolStripMenuItem TsiDetails = new ToolStripMenuItem(AppString.Menu.Details);
+        readonly ToolStripMenuItem TsiChangeCommand = new ToolStripMenuItem(AppString.Menu.ChangeCommand);
 
         private void InitializeComponents()
         {
@@ -138,19 +174,35 @@ namespace ContextMenuManager.Controls
             TsiFileProperties = new FilePropertiesMenuItem(this);
             TsiDeleteMe = new DeleteMeMenuItem(this);
 
-            ContextMenuStrip.Opening += (sender, e) => TsiChangeIcon.Visible = TsiIconSeparator.Visible = IsShortcut;
-
             ContextMenuStrip.Items.AddRange(new ToolStripItem[] { TsiChangeText, new ToolStripSeparator(),
-                TsiChangeIcon, TsiIconSeparator, TsiDetails, new ToolStripSeparator(), TsiDeleteMe });
+                TsiChangeIcon, new ToolStripSeparator(), TsiDetails, new ToolStripSeparator(), TsiDeleteMe });
 
             TsiDetails.DropDownItems.AddRange(new ToolStripItem[] { TsiSearch, new ToolStripSeparator(),
-                TsiFileProperties, TsiFileLocation });
+                TsiChangeCommand, TsiFileProperties, TsiFileLocation });
+
+            ContextMenuStrip.Opening += (sender, e) => TsiChangeCommand.Visible = IsShortcut;
+
+            TsiChangeCommand.Click += (sender, e) => ChangeCommand();
+
+        }
+
+        private void ChangeCommand()
+        {
+            using(CommandDialog dlg = new CommandDialog())
+            {
+                dlg.Command = Shortcut.TargetPath;
+                dlg.Arguments = Shortcut.Arguments;
+                if(dlg.ShowDialog() != DialogResult.OK) return;
+                Shortcut.TargetPath = dlg.Command;
+                Shortcut.Arguments = dlg.Arguments;
+                Shortcut.Save();
+            }
         }
 
         public void DeleteMe()
         {
             File.Delete(this.FilePath);
-            DesktopIniHelper.DeleteLocalizedFileName(FilePath);
+            SendToList.DesktopIniWriter.DeleteKey("LocalizedFileNames", FileName);
             this.Dispose();
         }
     }

+ 25 - 20
ContextMenuManager/Controls/SendToList.cs

@@ -1,6 +1,7 @@
 using BulePointLilac.Controls;
 using BulePointLilac.Methods;
 using System;
+using System.Diagnostics;
 using System.IO;
 using System.Windows.Forms;
 
@@ -8,28 +9,12 @@ namespace ContextMenuManager.Controls
 {
     sealed class SendToList : MyList
     {
-        public static string SendToPath => Environment.ExpandEnvironmentVariables(@"%AppData%\Microsoft\Windows\SendTo");
-        private static string DesktopIniPath => $@"{SendToPath}\desktop.ini";
-
+        public static readonly string SendToPath = Environment.ExpandEnvironmentVariables(@"%AppData%\Microsoft\Windows\SendTo");
+        public static readonly string DesktopIniPath = $@"{SendToPath}\desktop.ini";
+        public static IniWriter DesktopIniWriter = new IniWriter(DesktopIniPath);
         public static IniReader DesktopIniReader;
 
-        public static string GetMenuName(string fileName)
-        {
-            string name = DesktopIniReader.GetValue("LocalizedFileNames", fileName);
-            return ResourceString.GetDirectString(name);
-        }
-
         public void LoadItems()
-        {
-            this.ClearItems();
-            this.LoadCommonItems();
-            this.SortItemByText();
-            this.AddNewItem();
-            this.AddItem(new RegRuleItem(RegRuleItem.SendToDrive) { MarginRight = RegRuleItem.SysMarginRignt });
-            this.AddItem(new RegRuleItem(RegRuleItem.DeferBuildSendTo) { MarginRight = RegRuleItem.SysMarginRignt });
-        }
-
-        private void LoadCommonItems()
         {
             DesktopIniReader = new IniReader(DesktopIniPath);
             Array.ForEach(new DirectoryInfo(SendToPath).GetFiles(), fi =>
@@ -37,13 +22,18 @@ namespace ContextMenuManager.Controls
                 if(fi.Name.ToLower() != "desktop.ini")
                     this.AddItem(new SendToItem(fi.FullName));
             });
+            this.SortItemByText();
+            this.AddNewItem();
+            this.AddDirItem();
+            this.AddItem(new RegRuleItem(RegRuleItem.SendToDrive) { MarginRight = RegRuleItem.SysMarginRignt });
+            this.AddItem(new RegRuleItem(RegRuleItem.DeferBuildSendTo) { MarginRight = RegRuleItem.SysMarginRignt });
         }
 
         private void AddNewItem()
         {
             NewItem newItem = new NewItem();
             this.InsertItem(newItem, 0);
-            newItem.NewItemAdd += (sender, e) =>
+            newItem.AddNewItem += (sender, e) =>
             {
                 using(NewSendToDialog dlg = new NewSendToDialog())
                 {
@@ -52,5 +42,20 @@ namespace ContextMenuManager.Controls
                 }
             };
         }
+
+        private void AddDirItem()
+        {
+            MyListItem item = new MyListItem
+            {
+                Text = Path.GetFileNameWithoutExtension(SendToPath),
+                Image = ResourceIcon.GetFolderIcon(SendToPath).ToBitmap()
+            };
+            PictureButton btnPath = new PictureButton(AppImage.Open);
+            MyToolTip.SetToolTip(btnPath, AppString.Menu.FileLocation);
+            btnPath.MouseDown += (sender, e) => Process.Start(SendToPath);
+            item.AddCtr(btnPath);
+            item.SetNoClickEvent();
+            this.InsertItem(item, 1);
+        }
     }
 }

+ 31 - 21
ContextMenuManager/Controls/ShellExItem.cs

@@ -10,7 +10,7 @@ using System.Windows.Forms;
 namespace ContextMenuManager.Controls
 {
     sealed class ShellExItem : MyListItem, IChkVisibleItem, IBtnShowMenuItem,
-        ITsiWebSearchItem, ITsiFilePathItem, ITsiRegPathItem, ITsiDeleteItem
+        ITsiWebSearchItem, ITsiFilePathItem, ITsiRegPathItem, ITsiRegDeleteItem, ITsiRegExportItem
     {
         public static Dictionary<string, Guid> GetPathAndGuids(string shellExPath)
         {
@@ -65,11 +65,11 @@ namespace ContextMenuManager.Controls
         private string ShellExPath => RegistryEx.GetParentPath(RegistryEx.GetParentPath(RegPath));
         private string CmhKeyName => RegistryEx.GetKeyName(RegistryEx.GetParentPath(RegPath));
         private string DefaultValue => Registry.GetValue(RegPath, "", null)?.ToString();
-        private string ItemText => GuidInfo.GetText(Guid) ?? ((Guid.ToString("B") == KeyName) ? DefaultValue : KeyName);
-        private string BuckupPath => $@"{ShellExPath}\{(ItemVisible ? CmhParts[1] : CmhParts[0])}\{KeyName}";
+        public string ItemText => GuidInfo.GetText(Guid) ?? ((Guid.ToString("B") == KeyName) ? DefaultValue : KeyName);
+        private string BackupPath => $@"{ShellExPath}\{(ItemVisible ? CmhParts[1] : CmhParts[0])}\{KeyName}";
         private GuidInfo.IconLocation IconLocation => GuidInfo.GetIconLocation(this.Guid);
         private bool IsOpenLnkItem => Guid.ToString() == LnkOpenGuid;
-        private bool TryProtectOpenItem => IsOpenLnkItem && MessageBoxEx.Show
+        private bool TryProtectOpenItem => IsOpenLnkItem && AppConfig.ProtectOpenItem && MessageBoxEx.Show
             (AppString.MessageBox.PromptIsOpenItem, MessageBoxButtons.YesNo) != DialogResult.Yes;
 
         public bool ItemVisible
@@ -78,11 +78,8 @@ namespace ContextMenuManager.Controls
             set
             {
                 if(!value && TryProtectOpenItem) return;
-                using(RegistryKey srcKey = RegistryEx.GetRegistryKey(RegPath))
-                using(RegistryKey dstKey = RegistryEx.GetRegistryKey(BuckupPath, true, true))
-                    srcKey?.CopyTo(dstKey);
-                RegistryEx.DeleteKeyTree(RegPath);
-                RegPath = BuckupPath;
+                RegistryEx.MoveTo(RegPath, BackupPath);
+                RegPath = BackupPath;
             }
         }
 
@@ -93,6 +90,8 @@ namespace ContextMenuManager.Controls
         public FileLocationMenuItem TsiFileLocation { get; set; }
         public RegLocationMenuItem TsiRegLocation { get; set; }
         public DeleteMeMenuItem TsiDeleteMe { get; set; }
+        public RegExportMenuItem TsiRegExport { get; set; }
+
         readonly ToolStripMenuItem TsiDetails = new ToolStripMenuItem(AppString.Menu.Details);
         readonly ToolStripMenuItem TsiHandleGuid = new ToolStripMenuItem(AppString.Menu.HandleGuid);
         readonly ToolStripMenuItem TsiCopyGuid = new ToolStripMenuItem(AppString.Menu.CopyGuid);
@@ -107,6 +106,7 @@ namespace ContextMenuManager.Controls
             TsiFileLocation = new FileLocationMenuItem(this);
             TsiFileProperties = new FilePropertiesMenuItem(this);
             TsiRegLocation = new RegLocationMenuItem(this);
+            TsiRegExport = new RegExportMenuItem(this);
             TsiDeleteMe = new DeleteMeMenuItem(this);
 
             ContextMenuStrip.Items.AddRange(new ToolStripItem[] { TsiHandleGuid, new ToolStripSeparator(),
@@ -116,7 +116,7 @@ namespace ContextMenuManager.Controls
                 TsiBlockGuid, new ToolStripSeparator(), TsiAddGuidDic });
 
             TsiDetails.DropDownItems.AddRange(new ToolStripItem[] { TsiSearch, new ToolStripSeparator(),
-                TsiFileProperties, TsiFileLocation, TsiRegLocation});
+                TsiFileProperties, TsiFileLocation, TsiRegLocation, TsiRegExport});
 
             ContextMenuStrip.Opening += (sender, e) => RefreshMenuItem();
             TsiCopyGuid.Click += (sender, e) => CopyGuid();
@@ -127,7 +127,7 @@ namespace ContextMenuManager.Controls
         private void CopyGuid()
         {
             Clipboard.SetText(Guid.ToString());
-            MessageBoxEx.Show($"{AppString.MessageBox.CopiedToClipboard}:\n{Guid}",
+            MessageBoxEx.Show($"{AppString.MessageBox.CopiedToClipboard}\n{Guid}",
                 MessageBoxButtons.OK, MessageBoxIcon.Information);
         }
 
@@ -155,12 +155,17 @@ namespace ContextMenuManager.Controls
                 dlg.ItemIcon = this.Image;
                 dlg.ItemIconPath = this.IconLocation.IconPath;
                 dlg.ItemIconIndex = this.IconLocation.IconIndex;
-                IniFileHelper helper = new IniFileHelper(Program.GuidInfosDicPath);
+                IniWriter writer = new IniWriter
+                {
+                    FilePath = AppConfig.UserGuidInfosDic,
+                    DeleteFileWhenEmpty = true
+                };
                 string section = this.Guid.ToString();
                 if(dlg.ShowDialog() != DialogResult.OK)
                 {
-                    if(dlg.IsDelete) {
-                        helper.DeleteSection(section);
+                    if(dlg.IsDelete)
+                    {
+                        writer.DeleteSection(section);
                         GuidInfo.ItemTextDic.Remove(this.Guid);
                         GuidInfo.ItemImageDic.Remove(this.Guid);
                         GuidInfo.IconLocationDic.Remove(this.Guid);
@@ -170,11 +175,11 @@ namespace ContextMenuManager.Controls
                     }
                     return;
                 }
-                Directory.CreateDirectory(Program.ConfigDir);
-                if(!dlg.ItemName.IsNullOrWhiteSpace())
+                string name = ResourceString.GetDirectString(dlg.ItemName);
+                if(!name.IsNullOrWhiteSpace())
                 {
-                    helper.SetValue(section, "Text", dlg.ItemName);
-                    this.Text = ResourceString.GetDirectString(dlg.ItemName);
+                    writer.SetValue(section, "Text", dlg.ItemName);
+                    this.Text = name;
                     if(GuidInfo.ItemTextDic.ContainsKey(this.Guid))
                     {
                         GuidInfo.ItemTextDic[this.Guid] = this.Text;
@@ -184,9 +189,14 @@ namespace ContextMenuManager.Controls
                         GuidInfo.ItemTextDic.Add(this.Guid, this.Text);
                     }
                 }
+                else
+                {
+                    MessageBoxEx.Show(AppString.MessageBox.StringParsingFailed);
+                    return;
+                }
                 if(dlg.ItemIconLocation != null)
                 {
-                    helper.SetValue(section, "Icon", dlg.ItemIconLocation);
+                    writer.SetValue(section, "Icon", dlg.ItemIconLocation);
                     var location = new GuidInfo.IconLocation { IconPath = dlg.ItemIconPath, IconIndex = dlg.ItemIconIndex };
                     if(GuidInfo.IconLocationDic.ContainsKey(this.Guid))
                     {
@@ -211,7 +221,7 @@ namespace ContextMenuManager.Controls
 
         private void RefreshMenuItem()
         {
-            TsiDeleteMe.Enabled = !IsOpenLnkItem;
+            TsiDeleteMe.Enabled = !(IsOpenLnkItem && AppConfig.ProtectOpenItem);
             TsiBlockGuid.Checked = false;
             foreach(string path in GuidBlockedItem.BlockedPaths)
             {
@@ -226,7 +236,7 @@ namespace ContextMenuManager.Controls
         public void DeleteMe()
         {
             RegistryEx.DeleteKeyTree(this.RegPath);
-            RegistryEx.DeleteKeyTree(this.BuckupPath);
+            RegistryEx.DeleteKeyTree(this.BackupPath);
             this.Dispose();
         }
     }

+ 174 - 44
ContextMenuManager/Controls/ShellItem.cs

@@ -10,18 +10,89 @@ using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls
 {
-    class ShellItem : MyListItem, IChkVisibleItem, IBtnShowMenuItem, ITsiTextItem,
-        ITsiCommandItem, ITsiIconItem, ITsiWebSearchItem, ITsiFilePathItem, ITsiRegPathItem, ITsiDeleteItem
+    class ShellItem : MyListItem, IChkVisibleItem, IBtnShowMenuItem, ITsiTextItem, ITsiCommandItem,
+        ITsiIconItem, ITsiWebSearchItem, ITsiFilePathItem, ITsiRegPathItem, ITsiRegDeleteItem, ITsiRegExportItem
     {
-        /// <summary>Shell子菜单注册表项路径</summary>
+        /// <summary>Shell公共引用子菜单注册表项路径</summary>
         public const string CommandStorePath = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell";
 
+        /// <summary>系统原有Shell公共子菜单项名</summary>
+        public static readonly string[] SysStoreItemNames = { "Windows.aboutWindows", "Windows.AddColumns",
+                "Windows.AddDevice", "Windows.AddMediaServer", "Windows.AddNetworkLocation", "Windows.AddPrinter",
+                "Windows.AddRemovePrograms", "Windows.AddToFavorites", "Windows.Autoplay", "Windows.Backup",
+                "Windows.BitLocker", "Windows.BitLocker.Encrypt", "Windows.BitLocker.Manage",
+                "Windows.BitLocker.ResetPasswordPin", "Windows.burn", "Windows.Burn.Action", "Windows.change-passphrase",
+                "Windows.change-pin", "Windows.ChangeIndexedLocations", "Windows.ChooseColumns", "Windows.CleanUp",
+                "Windows.ClearAddressBarHistory", "Windows.ClearFrequentHistory", "Windows.clearRecentDocs",
+                "Windows.closewindow", "Windows.cmd", "Windows.cmdPromptAsAdministrator", "Windows.CompressedFile.extract",
+                "Windows.CompressedFile.ExtractTo", "Windows.CompressedFolder.extract", "Windows.CompressedItem.extract",
+                "Windows.Computer.Manage", "Windows.connectNetworkDrive", "Windows.copy", "Windows.copyaspath",
+                "Windows.CopyToBrowser", "Windows.CopyToMenu", "Windows.CscSync", "Windows.CscWorkOfflineOnline",
+                "Windows.cut", "Windows.Defragment", "Windows.delete", "Windows.Dialog.DisconnectNetworkDrive",
+                "Windows.DiscImage.burn", "Windows.DisconnectNetworkDrive", "Windows.DiskFormat",
+                "Windows.DriveFolder.DisconnectNetworkDrive", "Windows.edit", "Windows.Eject", "Windows.email",
+                "Windows.encrypt-bde", "Windows.encrypt-bde-elev", "Windows.Enqueue", "Windows.EraseDisc",
+                "Windows.EraseDisc.Action", "Windows.fax", "Windows.FinishBurn", "Windows.folderoptions",
+                "Windows.GroupByColumn", "Windows.help", "Windows.HideSelected", "Windows.HistoryVaultRestore",
+                "Windows.HomeGroupCPL", "Windows.HomeGroupJoin", "Windows.HomeGroupPassword", "Windows.HomeGroupSharing",
+                "Windows.HomeGroupTroubleshooter", "Windows.IconSize", "Windows.includeinlibrary", "Windows.invertselection",
+                "Windows.layout", "Windows.LibraryChangeIcon", "Windows.LibraryDefaultSaveLocation",
+                "Windows.LibraryIncludeInLibrary", "Windows.LibraryManageLibrary", "Windows.LibraryOptimizeLibraryFor",
+                "Windows.LibraryPublicSaveLocation", "Windows.LibraryRestoreDefaults", "Windows.LibrarySelChangeIcon",
+                "Windows.LibrarySelDefaultSaveLocation", "Windows.LibrarySelManageLibrary", "Windows.LibrarySelOptimizeLibraryFor",
+                "Windows.LibrarySelPublicSaveLocation", "Windows.LibrarySelRestoreDefaults", "Windows.LibrarySelShowInNavPane",
+                "Windows.LibraryShowInNavPane", "Windows.location.cmd", "Windows.location.cmdPromptAsAdministrator",
+                "Windows.location.opennewprocess", "Windows.location.opennewtab", "Windows.location.opennewwindow",
+                "Windows.location.Powershell", "Windows.location.PowershellAsAdmin", "Windows.manage-bde",
+                "Windows.manage-bde-elev", "Windows.MapNetworkDrive", "Windows.menubar", "Windows.ModernShare",
+                "Windows.mount", "Windows.MoveToBrowser", "Windows.MoveToMenu", "Windows.MultiVerb.cmd",
+                "Windows.MultiVerb.cmdPromptAsAdministrator", "Windows.MultiVerb.opennewprocess", "Windows.MultiVerb.opennewtab",
+                "Windows.MultiVerb.opennewwindow", "Windows.MultiVerb.Powershell", "Windows.MultiVerb.PowershellAsAdmin",
+                "Windows.navpane", "Windows.NavPaneExpandToCurrentFolder", "Windows.NavPaneShowAllFolders",
+                "Windows.NavPaneShowLibraries", "Windows.NetworkAndSharing", "Windows.NetworkViewDeviceWebpage",
+                "Windows.newfolder", "Windows.newitem", "Windows.open", "Windows.OpenContainingFolder.opencontaining",
+                "Windows.OpenControlPanel", "Windows.opennewprocess", "Windows.opennewtab", "Windows.opennewwindow",
+                "Windows.OpenPrinterServerProperty", "Windows.OpenPrintQueue", "Windows.OpenSearch.openfilelocation",
+                "Windows.OpenSearchViewSite", "Windows.OpenWith", "Windows.organize", "Windows.paste", "Windows.pastelink",
+                "Windows.PermanentDelete", "Windows.PinToHome", "Windows.pintostartscreen", "Windows.play", "Windows.playall",
+                "Windows.playmusic", "Windows.PowershellAsAdmin", "Windows.previewpane", "Windows.print", "Windows.properties",
+                "Windows.readingpane", "Windows.recycle", "Windows.RecycleBin.Empty", "Windows.RecycleBin.Location.properties",
+                "Windows.RecycleBin.properties", "Windows.RecycleBin.RestoreAll", "Windows.RecycleBin.RestoreItems",
+                "Windows.RecycleBin.Selection.properties", "Windows.redo", "Windows.remotedesktop", "Windows.RemoveMediaServer",
+                "Windows.removeproperties", "Windows.rename", "Windows.RibbonDelete", "Windows.RibbonPermissionsDialog",
+                "Windows.RibbonShare", "Windows.RibbonSync.MakeAvailableOffline", "Windows.RibbonSync.SyncThisFolder",
+                "Windows.RibbonSync.WorkOfflineOnline", "Windows.rotate270", "Windows.rotate90", "Windows.runas",
+                "Windows.runasuser", "Windows.SearchActiveDirectory", "Windows.SearchClearMru", "Windows.SearchCloseTab",
+                "Windows.SearchFilterDate", "Windows.SearchFilterKind", "Windows.SearchFilterMoreProperties",
+                "Windows.SearchFilterSize", "Windows.SearchMru", "Windows.SearchOpenLocation", "Windows.SearchOptionCompressed",
+                "Windows.SearchOptionContents", "Windows.SearchOptionDeep", "Windows.SearchOptionShallow",
+                "Windows.SearchOptionSystem", "Windows.SearchSave", "Windows.SearchSendTo", "Windows.SearchSendToComputer",
+                "Windows.selectall", "Windows.SelectionCheckboxes", "Windows.selectMode", "Windows.selectnone",
+                "Windows.separator", "Windows.setdesktopwallpaper", "Windows.Share", "Windows.SharePrivate",
+                "Windows.ShareSpecificUsers", "Windows.Shortcut.opencontaining", "Windows.ShowFileExtensions",
+                "Windows.ShowHiddenFiles", "Windows.SizeAllColumns", "Windows.slideshow", "Windows.SortAscending",
+                "Windows.SortByColumn", "Windows.SortDescending", "Windows.SortGroupsAscending", "Windows.SortGroupsDescending",
+                "Windows.StartScan", "Windows.statusbar", "Windows.Sync", "Windows.SystemProperties", "Windows.taskbarpin",
+                "Windows.ToggleRecycleConfirmations", "Windows.topviewrestoredefault", "Windows.Troubleshoot", "Windows.undo",
+                "Windows.UpdatePrinterDriver", "Windows.v2.Powershell", "Windows.View.OptionsGallery",
+                "Windows.ViewRemotePrinters", "Windows.zip", "Windows.Zip.Action",
+                
+                //Win8.1
+                "Windows.ManageDefaultPrinters", "Windows.NavPaneShowFavorites", "Windows.playto", "Windows.Powershell",
+                "Windows.ShareHomegroupFullAccess", "Windows.ShareHomegroupNoAccess", "Windows.ShareHomegroupReadAccess",
+                //Win8
+                "Windows.SearchOptionPartial",
+                //Win7
+                "Windows.librarypane"
+            };
+
         /// <summary>Shell类型菜单特殊注册表项名默认名称</summary>
         private static readonly Dictionary<string, string> DefaultNames
             = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) {
             {"open", AppString.Item.Open }, {"edit", AppString.Item.Edit }, {"print", AppString.Item.Print },
             {"find", AppString.Item.Find }, {"play", AppString.Item.Play }, {"runas", AppString.Item.Runas },
-            {"explore", AppString.Item.Explore }
+            //Win10为“浏览(&X)”,Win10之前为“资源管理器(&X)”
+            {"explore", WindowsOsVersion.IsBefore10 ? AppString.Item.ExploreOld : AppString.Item.Explore }
         };
 
         /// <summary>菜单项目在菜单中出现的位置</summary>
@@ -54,7 +125,7 @@ namespace ContextMenuManager.Controls
         private bool IsMultiItem => Registry.GetValue(RegPath, "SubCommands", null) != null;
         protected virtual bool IsSubItem => false;
         private bool IsOpenItem => KeyName.ToLower() == "open";
-        private bool TryProtectOpenItem => IsOpenItem && MessageBoxEx.Show(AppString.MessageBox.PromptIsOpenItem,
+        private bool TryProtectOpenItem => IsOpenItem && AppConfig.ProtectOpenItem && MessageBoxEx.Show(AppString.MessageBox.PromptIsOpenItem,
                 MessageBoxButtons.YesNo) != DialogResult.Yes;
 
         public string ItemFilePath => GuidInfo.GetFilePath(Guid) ?? ObjectPath.ExtractFilePath(ItemCommand);
@@ -134,15 +205,18 @@ namespace ContextMenuManager.Controls
         {
             get
             {
-                if(Convert.ToInt32(Registry.GetValue(RegPath, "CommandFlags", 0)) % 16 >= 8) return false;
-                //HideBasedOnVelocityId键值不适用于Win7系统,且在新版Win10为0x639bc8,在低版本Win10中为0x6698a6
-                int value = Convert.ToInt32(Registry.GetValue(RegPath, "HideBasedOnVelocityId", 0));
-                if(value == 0x639bc8 || value == 0x6698a6) return false;
+                if(WindowsOsVersion.IsAfterOrEqualWin10_1703)
+                {
+                    //HideBasedOnVelocityId键值仅适用于Win10系统1703以上版本
+                    if(Convert.ToInt32(Registry.GetValue(RegPath, "HideBasedOnVelocityId", 0)) == 0x639bc8) return false;
+                }
                 if(!IsSubItem)
                 {
                     //LegacyDisable和ProgrammaticAccessOnly键值不适用于子菜单
                     if(Registry.GetValue(RegPath, "LegacyDisable", null) != null) return false;
                     if(Registry.GetValue(RegPath, "ProgrammaticAccessOnly", null) != null) return false;
+                    //CommandFlags键值不适用于Vista系统,子菜单中该键值我用来做分割线键值
+                    if(WindowsOsVersion.IsAfterVista && Convert.ToInt32(Registry.GetValue(RegPath, "CommandFlags", 0)) % 16 >= 8) return false;
                 }
                 return true;
             }
@@ -158,7 +232,19 @@ namespace ContextMenuManager.Controls
                 else
                 {
                     if(TryProtectOpenItem) return;
-                    Registry.SetValue(RegPath, "CommandFlags", 8);
+                    if(!IsSubItem)
+                    {
+                        Registry.SetValue(RegPath, "LegacyDisable", string.Empty);
+                        Registry.SetValue(RegPath, "ProgrammaticAccessOnly", string.Empty);
+                    }
+                    else if(WindowsOsVersion.IsAfterOrEqualWin10_1703)
+                    {
+                        Registry.SetValue(RegPath, "HideBasedOnVelocityId", 0x639bc8);
+                    }
+                    else
+                    {
+                        MessageBoxEx.Show(AppString.MessageBox.CannotHideSubItem);
+                    }
                 }
             }
         }
@@ -184,8 +270,14 @@ namespace ContextMenuManager.Controls
             {
                 //MUIVerb长度不可超过80,超过80系统会隐藏该菜单项目
                 if(ResourceString.GetDirectString(value).Length >= 80)
+                {
                     MessageBoxEx.Show(AppString.MessageBox.TextLengthCannotExceed80);
-                else Registry.SetValue(RegPath, "MUIVerb", value);
+                }
+                else
+                {
+                    Registry.SetValue(RegPath, "MUIVerb", value);
+                    this.Text = ResourceString.GetDirectString(value);
+                }
             }
         }
 
@@ -239,12 +331,12 @@ namespace ContextMenuManager.Controls
                 {
                     icon = ResourceIcon.GetIcon(IconLocation, out iconPath, out iconIndex);
                     if(icon == null && Path.GetExtension(iconPath).ToLower() == ".exe")
-                        icon = ResourceIcon.GetIcon(iconPath = "imageres.dll", iconIndex = 11);//文件为不存在的或没有图标的exe文件,不含图标的默认exe图标
+                        icon = ResourceIcon.GetIcon(iconPath = "imageres.dll", iconIndex = -15);//文件为不存在的或没有图标的exe文件,不含图标的默认exe图标
                 }
                 else if(HasLUAShield)
-                    icon = ResourceIcon.GetIcon(iconPath = "imageres.dll", iconIndex = 73);//管理员小盾牌图标
+                    icon = ResourceIcon.GetIcon(iconPath = "imageres.dll", iconIndex = -78);//管理员小盾牌图标
                 else icon = ResourceIcon.GetIcon(iconPath = ItemFilePath, iconIndex = 0);//文件第一个图标
-                if(icon == null) icon = ResourceIcon.GetIcon(iconPath = "imageres.dll", iconIndex = 2);//图标资源不存在,白纸图标
+                if(icon == null) icon = ResourceIcon.GetIcon(iconPath = "imageres.dll", iconIndex = -2);//图标资源不存在,白纸图标
                 IconPath = iconPath;
                 IconIndex = iconIndex;
                 return icon;
@@ -271,6 +363,7 @@ namespace ContextMenuManager.Controls
         public FileLocationMenuItem TsiFileLocation { get; set; }
         public RegLocationMenuItem TsiRegLocation { get; set; }
         public DeleteMeMenuItem TsiDeleteMe { get; set; }
+        public RegExportMenuItem TsiRegExport { get; set; }
 
         protected readonly ToolStripMenuItem TsiOtherAttributes = new ToolStripMenuItem(AppString.Menu.OtherAttributes);
         readonly ToolStripMenuItem TsiItemIcon = new ToolStripMenuItem(AppString.Menu.ItemIcon);
@@ -282,8 +375,9 @@ namespace ContextMenuManager.Controls
         readonly ToolStripMenuItem TsiShift = new ToolStripMenuItem(AppString.Menu.OnlyWithShift);
         readonly ToolStripMenuItem TsiExplorer = new ToolStripMenuItem(AppString.Menu.OnlyInExplorer);
         readonly ToolStripMenuItem TsiNoWorkDir = new ToolStripMenuItem(AppString.Menu.NoWorkingDirectory);
+        readonly ToolStripMenuItem TsiShieldIcon = new ToolStripMenuItem(AppString.Menu.ShieldIcon);
         readonly ToolStripMenuItem TsiDetails = new ToolStripMenuItem(AppString.Menu.Details);
-        readonly PictureButton BtnSubItems = new PictureButton(AppImage.SubItems);
+        protected readonly PictureButton BtnSubItems = new PictureButton(AppImage.SubItems);
 
         private void InitializeComponents()
         {
@@ -296,19 +390,20 @@ namespace ContextMenuManager.Controls
             TsiFileLocation = new FileLocationMenuItem(this);
             TsiFileProperties = new FilePropertiesMenuItem(this);
             TsiRegLocation = new RegLocationMenuItem(this);
+            TsiRegExport = new RegExportMenuItem(this);
             TsiDeleteMe = new DeleteMeMenuItem(this);
 
             ContextMenuStrip.Items.AddRange(new ToolStripItem[] { TsiChangeText, new ToolStripSeparator(), TsiItemIcon,
                 TsiPosition, TsiOtherAttributes, new ToolStripSeparator(), TsiDetails, new ToolStripSeparator(), TsiDeleteMe});
 
-            TsiItemIcon.DropDownItems.AddRange(new ToolStripItem[] { TsiChangeIcon, TsiDeleteIcon });
+            TsiItemIcon.DropDownItems.AddRange(new ToolStripItem[] { TsiChangeIcon, TsiDeleteIcon, TsiShieldIcon });
 
             TsiPosition.DropDownItems.AddRange(new ToolStripItem[] { TsiDefault, TsiTop, TsiBottom });
 
             TsiOtherAttributes.DropDownItems.AddRange(new ToolStripItem[] { TsiShift, TsiExplorer, TsiNoWorkDir });
 
             TsiDetails.DropDownItems.AddRange(new ToolStripItem[] { TsiSearch, new ToolStripSeparator(),
-                TsiChangeCommand, TsiFileProperties, TsiFileLocation, TsiRegLocation});
+                TsiChangeCommand, TsiFileProperties, TsiFileLocation, TsiRegLocation, TsiRegExport});
 
             TsiDeleteIcon.Click += (sender, e) => DeleteIcon();
             TsiTop.Click += (sender, e) => this.ItemPosition = Positions.Top;
@@ -319,6 +414,12 @@ namespace ContextMenuManager.Controls
             TsiNoWorkDir.Click += (sender, e) => this.NoWorkingDirectory = !TsiNoWorkDir.Checked;
             ContextMenuStrip.Opening += (sender, e) => RefreshMenuItem();
             BtnSubItems.MouseDown += (sender, e) => ShowSubItems();
+            TsiShieldIcon.Click += (sender, e) =>
+            {
+                TsiShieldIcon.Checked = !TsiShieldIcon.Checked;
+                if(TsiShieldIcon.Checked) UseShieldIcon();
+                else DeleteIcon();
+            };
             MyToolTip.SetToolTip(BtnSubItems, AppString.Tip.EditSubItems);
             this.AddCtr(BtnSubItems);
         }
@@ -330,44 +431,73 @@ namespace ContextMenuManager.Controls
             this.Image = this.Image.ToTransparent();
         }
 
+        private void UseShieldIcon()
+        {
+            this.IconLocation = null;
+            this.HasLUAShield = true;
+            this.Image = AppImage.Shield;
+            this.IconPath = "imageres.dll";
+            this.IconIndex = -78;
+        }
+
         private void RefreshMenuItem()
         {
-            if(this.HasIcon)
-            {
-                TsiChangeIcon.Text = AppString.Menu.ChangeIcon;
-                TsiDeleteIcon.Visible = true;
-            }
-            else
-            {
-                TsiChangeIcon.Text = AppString.Menu.AddIcon;
-                TsiDeleteIcon.Visible = false;
-            }
-            TsiDeleteMe.Enabled = !IsOpenItem;
-            TsiChangeCommand.Visible = !IsMultiItem && Guid.Equals(Guid.Empty);
-            TsiPosition.Visible = TsiExplorer.Visible = TsiShift.Visible = !IsSubItem;
+            TsiShift.Visible = !IsSubItem;
+            TsiDeleteMe.Enabled = !(IsOpenItem && AppConfig.ProtectOpenItem);
             TsiNoWorkDir.Checked = this.NoWorkingDirectory;
-            if(!this.IsSubItem)
+            TsiChangeCommand.Visible = !IsMultiItem && Guid.Equals(Guid.Empty);
+            if(!this.IsSubItem) TsiShift.Checked = this.OnlyWithShift;
+
+            if(WindowsOsVersion.IsAfterVista)
             {
-                TsiShift.Checked = this.OnlyWithShift;
-                TsiExplorer.Checked = this.OnlyInExplorer;
-                TsiDefault.Checked = TsiTop.Checked = TsiBottom.Checked = false;
-                switch(this.ItemPosition)
+                TsiItemIcon.Visible = true;
+                TsiPosition.Visible = !IsSubItem;
+                TsiExplorer.Visible = !IsSubItem;
+                if(this.HasIcon)
                 {
-                    case Positions.Default:
-                        TsiDefault.Checked = true;
-                        break;
-                    case Positions.Top:
-                        TsiTop.Checked = true;
-                        break;
-                    case Positions.Bottom:
-                        TsiBottom.Checked = true;
-                        break;
+                    TsiChangeIcon.Text = AppString.Menu.ChangeIcon;
+                    TsiDeleteIcon.Visible = true;
+                }
+                else
+                {
+                    TsiChangeIcon.Text = AppString.Menu.AddIcon;
+                    TsiDeleteIcon.Visible = false;
+                }
+                TsiShieldIcon.Checked = (IconLocation == null) && HasLUAShield;
+
+                if(!this.IsSubItem)
+                {
+                    TsiExplorer.Checked = this.OnlyInExplorer;
+                    TsiDefault.Checked = TsiTop.Checked = TsiBottom.Checked = false;
+                    switch(this.ItemPosition)
+                    {
+                        case Positions.Default:
+                            TsiDefault.Checked = true;
+                            break;
+                        case Positions.Top:
+                            TsiTop.Checked = true;
+                            break;
+                        case Positions.Bottom:
+                            TsiBottom.Checked = true;
+                            break;
+                    }
                 }
             }
+            else
+            {
+                TsiItemIcon.Visible = false;
+                TsiPosition.Visible = false;
+                TsiExplorer.Visible = false;
+            }
         }
 
         private void ShowSubItems()
         {
+            if(WindowsOsVersion.IsEqualVista)
+            {
+                MessageBoxEx.Show(AppString.MessageBox.VistaUnsupportedMulti);
+                return;
+            }
             using(ShellSubMenuDialog dlg = new ShellSubMenuDialog())
             {
                 dlg.Text = AppString.Item.EditSubItems.Replace("%s", this.Text);

+ 45 - 40
ContextMenuManager/Controls/ShellList.cs

@@ -3,6 +3,7 @@ using BulePointLilac.Methods;
 using Microsoft.Win32;
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls
@@ -40,7 +41,7 @@ namespace ContextMenuManager.Controls
         {
             File, Folder, Directory, Background, Desktop, Drive, AllObjects, Computer, RecycleBin,
             Library, LnkFile, UwpLnk, ExeFile, TextFile, ImageFile, VideoFile, AudioFile,
-            ImageDirectory, VideoDirectory, AudioDirectory, UnknownType, CustomType
+            ImageDirectory, VideoDirectory, AudioDirectory, UnknownType, CustomType, CommandStore
         }
 
         private Scenes scene;
@@ -55,12 +56,15 @@ namespace ContextMenuManager.Controls
 
         public ShellList()
         {
-            TypeItem.ExtensionChanged += (sender, e) => this.Scene = Scenes.CustomType;
+            TypeItem.ExtensionChanged += (sender, e) =>
+            {
+                this.ClearItems();
+                this.Scene = Scenes.CustomType;
+            };
         }
 
         private void LoadItems()
         {
-            this.ClearItems();
             string scenePath = null;
             switch(Scene)
             {
@@ -73,6 +77,8 @@ namespace ContextMenuManager.Controls
                 case Scenes.Background:
                     scenePath = MENUPATH_BACKGROUND; break;
                 case Scenes.Desktop:
+                    //Vista系统没有这一项
+                    if(WindowsOsVersion.IsEqualVista) return;
                     scenePath = MENUPATH_DESKTOP; break;
                 case Scenes.Drive:
                     scenePath = MENUPATH_DRIVE; break;
@@ -83,10 +89,14 @@ namespace ContextMenuManager.Controls
                 case Scenes.RecycleBin:
                     scenePath = MENUPATH_RECYCLEBIN; break;
                 case Scenes.Library:
+                    //Vista系统没有这一项
+                    if(WindowsOsVersion.IsEqualVista) return;
                     scenePath = MENUPATH_LIBRARY; break;
                 case Scenes.LnkFile:
                     scenePath = MENUPATH_LNKFILE; break;
                 case Scenes.UwpLnk:
+                    //Win8之前没有Uwp
+                    if(WindowsOsVersion.IsBefore8) return;
                     scenePath = MENUPATH_UWPLNK; break;
                 case Scenes.ExeFile:
                     scenePath = MENUPATH_EXEFILE; break;
@@ -108,9 +118,13 @@ namespace ContextMenuManager.Controls
                     scenePath = MENUPATH_UNKNOWN; break;
                 case Scenes.CustomType:
                     scenePath = TypeItem.SysAssExtPath; break;
+                case Scenes.CommandStore:
+                    this.AddNewItem(RegistryEx.GetParentPath(ShellItem.CommandStorePath));
+                    this.LoadCommandStoreItems();
+                    return;
             }
             this.AddNewItem(scenePath);
-            this.AddItems(scenePath);
+            this.LoadItems(scenePath);
 
             switch(scene)
             {
@@ -127,30 +141,30 @@ namespace ContextMenuManager.Controls
                     this.AddItem(new RegRuleItem(RegRuleItem.RecycleBinProperties) { MarginRight = RegRuleItem.SysMarginRignt });
                     break;
                 case Scenes.Library:
-                    this.AddItems(MENUPATH_LIBRARY_BACKGROUND);
-                    this.AddItems(MENUPATH_LIBRARY_USER);
+                    this.LoadItems(MENUPATH_LIBRARY_BACKGROUND);
+                    this.LoadItems(MENUPATH_LIBRARY_USER);
                     break;
                 case Scenes.LnkFile:
-                    this.AddItems(MENUPATH_SYSLNKFILE);
+                    this.LoadItems(MENUPATH_SYSLNKFILE);
                     break;
                 case Scenes.ExeFile:
-                    this.AddItems(MENUPATH_SYSEXEFILE);
+                    this.LoadItems(MENUPATH_SYSEXEFILE);
                     break;
                 case Scenes.CustomType:
                     this.InsertItem(new TypeItem(), 0);
-                    this.AddItems(TypeItem.AssExtPath);
+                    this.LoadItems(TypeItem.AssExtPath);
                     break;
             }
         }
 
-        private void AddItems(string scenePath)
+        private void LoadItems(string scenePath)
         {
             if(this.Scene == Scenes.CustomType && TypeItem.Extension == null) return;
-            this.AddShellItems(GetShellPath(scenePath));
-            this.AddShellExItems(GetShellExPath(scenePath));
+            this.LoadShellItems(GetShellPath(scenePath));
+            this.LoadShellExItems(GetShellExPath(scenePath));
         }
 
-        private void AddShellItems(string shellPath)
+        private void LoadShellItems(string shellPath)
         {
             using(RegistryKey shellKey = RegistryEx.GetRegistryKey(shellPath))
             {
@@ -163,9 +177,9 @@ namespace ContextMenuManager.Controls
             }
         }
 
-        private void AddShellExItems(string shellExPath)
+        private void LoadShellExItems(string shellExPath)
         {
-            List<Guid> guids = new List<Guid> { Guid.Empty };
+            List<string> names = new List<string>();
             using(RegistryKey shellExKey = RegistryEx.GetRegistryKey(shellExPath))
             {
                 if(shellExKey == null) return;
@@ -173,11 +187,11 @@ namespace ContextMenuManager.Controls
                 Dictionary<string, Guid> dic = ShellExItem.GetPathAndGuids(shellExPath);
                 foreach(string path in dic.Keys)
                 {
-                    Guid guid = dic[path];
-                    if(!guids.Contains(guid))
+                    string keyName = RegistryEx.GetKeyName(path);
+                    if(!names.Contains(keyName))
                     {
-                        this.AddItem(new ShellExItem(guid, path));
-                        guids.Add(guid);
+                        this.AddItem(new ShellExItem(dic[path], path));
+                        names.Add(keyName);
                     }
                 }
             }
@@ -186,17 +200,14 @@ namespace ContextMenuManager.Controls
         private void AddNewItem(string scenePath)
         {
             string shellPath = GetShellPath(scenePath);
-            string shellExPath = GetShellExPath(scenePath);
             NewItem newItem = new NewItem();
-            AddCommonButton btnAddCommon = new AddCommonButton();
-            newItem.AddCtr(btnAddCommon);
             this.AddItem(newItem);
             if(this.Scene == Scenes.CustomType)
             {
                 newItem.Visible = TypeItem.Extension != null;
                 TypeItem.ExtensionChanged += (sender, e) => newItem.Visible = TypeItem.Extension != null;
             }
-            newItem.NewItemAdd += (sender, e) =>
+            newItem.AddNewItem += (sender, e) =>
             {
                 using(NewShellDialog dlg = new NewShellDialog
                 {
@@ -208,25 +219,18 @@ namespace ContextMenuManager.Controls
                         this.InsertItem(new ShellItem(dlg.NewItemRegPath), GetItemIndex(newItem) + 1);
                 }
             };
-            btnAddCommon.MouseDown += (sender, e) =>
+        }
+
+        private void LoadCommandStoreItems()
+        {
+            using(var shellKey = RegistryEx.GetRegistryKey(ShellItem.CommandStorePath))
             {
-                using(ShellCommonDialog dlg = new ShellCommonDialog
-                {
-                    ScenePath = scenePath,
-                    ShellPath = shellPath,
-                    ShellExPath = shellExPath
-                })
-                {
-                    if(dlg.ShowDialog() == DialogResult.OK)
+                Array.ForEach(Array.FindAll(shellKey.GetSubKeyNames(), itemName =>
+                    !ShellItem.SysStoreItemNames.Contains(itemName, StringComparer.OrdinalIgnoreCase)), itemName =>
                     {
-                        foreach(string path in dlg.SelectedShellExPathAndGuids.Keys)
-                        {
-                            this.InsertItem(new ShellExItem(dlg.SelectedShellExPathAndGuids[path], path), 1);
-                        }
-                        dlg.SelectedShellPaths.ForEach(path => this.InsertItem(new ShellItem(path), 1));
-                    }
-                }
-            };
+                        this.AddItem(new ShellItem($@"{ShellItem.CommandStorePath}\{itemName}"));
+                    });
+            }
         }
 
         sealed class TypeItem : MyListItem
@@ -253,6 +257,7 @@ namespace ContextMenuManager.Controls
             {
                 GetImageAndText();
                 this.AddCtr(BtnType);
+                this.SetNoClickEvent();
                 BtnType.MouseDown += (sender, e) =>
                 {
                     using(FileExtensionDialog dlg = new FileExtensionDialog())

+ 31 - 33
ContextMenuManager/Controls/ShellNewItem.cs

@@ -4,19 +4,24 @@ using ContextMenuManager.Controls.Interfaces;
 using Microsoft.Win32;
 using System;
 using System.Drawing;
+using System.Linq;
 using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls
 {
-    sealed class ShellNewItem : MyListItem, IChkVisibleItem, ITsiTextItem, IBtnShowMenuItem,
-        ITsiIconItem, ITsiWebSearchItem, ITsiFilePathItem, ITsiRegPathItem, ITsiDeleteItem
+    sealed class ShellNewItem : MyListItem, IChkVisibleItem, ITsiTextItem, IBtnShowMenuItem, IBtnMoveUpDownItem,
+         ITsiIconItem, ITsiWebSearchItem, ITsiFilePathItem, ITsiRegPathItem, ITsiRegDeleteItem, ITsiRegExportItem
     {
         public static readonly string[] SnParts = { "ShellNew", "-ShellNew" };
+        public static readonly string[] UnableSortExtensions = { ".library-ms", ".lnk", "Folder" };
+        private static readonly string[] UnableEditDataValues = { "Directory", "FileName", "Handler", "Command" };
 
-        public ShellNewItem(string regPath)
+        public ShellNewItem(ShellNewList list, string regPath)
         {
+            this.Owner = list;
             InitializeComponents();
             this.RegPath = regPath;
+            BtnMoveUp.Visible = BtnMoveDown.Visible = this.CanSort && LockNewItem.IsLocked();
         }
 
         private string regPath;
@@ -33,30 +38,17 @@ namespace ContextMenuManager.Controls
         }
 
         public string SearchText => $"{AppString.SideBar.New} {Text}";
-        private string Extension => RegPath.Split('\\')[1];
+        public string Extension => RegPath.Split('\\')[1];
         private string SnKeyName => RegistryEx.GetKeyName(RegPath);
-        private string BuckupPath => $@"{RegistryEx.GetParentPath(RegPath)}\{(ItemVisible ? SnParts[1] : SnParts[0])}";
+        private string BackupPath => $@"{RegistryEx.GetParentPath(RegPath)}\{(ItemVisible ? SnParts[1] : SnParts[0])}";
 
         private const string HKCR = "HKEY_CLASSES_ROOT";
         private string TypePath => $@"{HKCR}\{FileExtensionDialog.GetTypeName(Extension)}";//关联类型路径
         private string DefaultTypePath => $@"{HKCR}\{FileExtensionDialog.GetTypeName(Extension, false)}";//默认关联类型路径
         private string TypeDefaultIcon => Registry.GetValue($@"{TypePath}\DefaultIcon", "", null)?.ToString();//关联类型默认图标路径
         private string DefaultTypeDefaultIcon => Registry.GetValue($@"{DefaultTypePath}\DefaultIcon", "", null)?.ToString();//默认关联类型默认图标路径
-        private bool IsFolderItem => Registry.GetValue(RegPath, "Directory", null) != null;
-
-        private bool CanEditData
-        {
-            get
-            {
-                using(RegistryKey key = RegistryEx.GetRegistryKey(RegPath))
-                {
-                    foreach(string valueName in new[] { "Directory", "FileName", "Handler" })
-                        if(key.GetValue(valueName) != null) return false;
-                    if(key.GetValue("Data") != null && key.GetValueKind("Data") != RegistryValueKind.String) return false;
-                    else return true;
-                }
-            }
-        }
+        private bool CanEditData => UnableEditDataValues.All(value => Registry.GetValue(RegPath, value, null) == null);//能够编辑初始数据的
+        public bool CanSort => !UnableSortExtensions.Contains(Extension, StringComparer.OrdinalIgnoreCase);//能够排序的
 
         public string ItemFilePath
         {
@@ -86,11 +78,8 @@ namespace ContextMenuManager.Controls
             get => SnKeyName.Equals(SnParts[0], StringComparison.OrdinalIgnoreCase);
             set
             {
-                using(RegistryKey srcKey = RegistryEx.GetRegistryKey(RegPath))
-                using(RegistryKey dstkey = RegistryEx.GetRegistryKey(BuckupPath, true, true))
-                    srcKey.CopyTo(dstkey);
-                RegistryEx.DeleteKeyTree(RegPath);
-                this.RegPath = BuckupPath;
+                RegistryEx.MoveTo(RegPath, BackupPath);
+                this.RegPath = BackupPath;
             }
         }
 
@@ -113,6 +102,7 @@ namespace ContextMenuManager.Controls
             {
                 RegistryEx.DeleteValue(RegPath, "MenuText");
                 Registry.SetValue(DefaultTypePath, "FriendlyTypeName", value);
+                this.Text = ResourceString.GetDirectString(value);
             }
         }
 
@@ -151,8 +141,11 @@ namespace ContextMenuManager.Controls
             set => Registry.SetValue(RegPath, "Data", value);
         }
 
-        public VisibleCheckBox ChkVisible { get; set; }
+        public ShellNewList Owner { get; private set; }
+        public MoveButton BtnMoveUp { get; set; }
+        public MoveButton BtnMoveDown { get; set; }
         public MenuButton BtnShowMenu { get; set; }
+        public VisibleCheckBox ChkVisible { get; set; }
         public ChangeTextMenuItem TsiChangeText { get; set; }
         public ChangeIconMenuItem TsiChangeIcon { get; set; }
         public WebSearchMenuItem TsiSearch { get; set; }
@@ -160,6 +153,8 @@ namespace ContextMenuManager.Controls
         public FileLocationMenuItem TsiFileLocation { get; set; }
         public RegLocationMenuItem TsiRegLocation { get; set; }
         public DeleteMeMenuItem TsiDeleteMe { get; set; }
+        public RegExportMenuItem TsiRegExport { get; set; }
+
         readonly ToolStripMenuItem TsiDetails = new ToolStripMenuItem(AppString.Menu.Details);
         readonly ToolStripMenuItem TsiEditData = new ToolStripMenuItem(AppString.Menu.InitialData);
 
@@ -167,12 +162,15 @@ namespace ContextMenuManager.Controls
         {
             BtnShowMenu = new MenuButton(this);
             ChkVisible = new VisibleCheckBox(this);
+            BtnMoveDown = new MoveButton(this, false);
+            BtnMoveUp = new MoveButton(this, true);
             TsiSearch = new WebSearchMenuItem(this);
             TsiChangeText = new ChangeTextMenuItem(this);
             TsiChangeIcon = new ChangeIconMenuItem(this);
             TsiFileLocation = new FileLocationMenuItem(this);
             TsiFileProperties = new FilePropertiesMenuItem(this);
             TsiRegLocation = new RegLocationMenuItem(this);
+            TsiRegExport = new RegExportMenuItem(this);
             TsiDeleteMe = new DeleteMeMenuItem(this);
 
             ContextMenuStrip.Items.AddRange(new ToolStripItem[] {TsiChangeText,
@@ -180,14 +178,13 @@ namespace ContextMenuManager.Controls
                 TsiDetails, new ToolStripSeparator(), TsiDeleteMe });
 
             TsiDetails.DropDownItems.AddRange(new ToolStripItem[] { TsiSearch, new ToolStripSeparator(),
-                TsiEditData, TsiFileProperties, TsiFileLocation, TsiRegLocation });
+                TsiEditData, TsiFileProperties, TsiFileLocation, TsiRegLocation, TsiRegExport });
 
             TsiEditData.Click += (sender, e) => EditInitialData();
-            ContextMenuStrip.Opening += (sender, e) =>
-            {
-                TsiEditData.Visible = CanEditData;
-                TsiDeleteMe.Enabled = !IsFolderItem;
-            };
+            ContextMenuStrip.Opening += (sender, e) => TsiEditData.Visible = CanEditData;
+
+            BtnMoveUp.MouseDown += (sender, e) => Owner.MoveItem(this, true);
+            BtnMoveDown.MouseDown += (sender, e) => Owner.MoveItem(this, false);
         }
 
         private void EditInitialData()
@@ -207,8 +204,9 @@ namespace ContextMenuManager.Controls
         public void DeleteMe()
         {
             RegistryEx.DeleteKeyTree(this.RegPath);
-            RegistryEx.DeleteKeyTree(this.BuckupPath);
+            RegistryEx.DeleteKeyTree(this.BackupPath);
             this.Dispose();
+            if(LockNewItem.IsLocked()) Owner.WriteRegistry();
         }
     }
 }

+ 90 - 11
ContextMenuManager/Controls/ShellNewList.cs

@@ -10,27 +10,53 @@ namespace ContextMenuManager.Controls
 {
     sealed class ShellNewList : MyList
     {
+        public const string ShellNewPath = @"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Discardable\PostSetup\ShellNew";
         private static readonly string[] ValueNames = { "NullFile", "Data", "FileName", "Directory", "Command" };
 
         public void LoadItems()
         {
-            this.ClearItems();
             this.AddNewItem();
-            this.LoadCommonItems();
+            this.AddItem(new LockNewItem(this));
+            if(LockNewItem.IsLocked()) this.LoadLockItems();
+            else this.LoadUnlockItems();
         }
 
-        private void LoadCommonItems()
+        /// <summary>直接扫描所有扩展名</summary>
+        private void LoadUnlockItems()
         {
-            List<string> extensions = new List<string> { "Folder" };
+            List<string> extensions = new List<string> { "Folder" };//文件夹
             using(RegistryKey root = Registry.ClassesRoot)
             {
                 extensions.AddRange(Array.FindAll(root.GetSubKeyNames(), keyName => keyName.StartsWith(".")));
-                if(Environment.OSVersion.Version.Major <= 6 && Environment.OSVersion.Version.Minor <= 1) extensions.Add("Briefcase");//Win7公文包
-                foreach(string extension in extensions)
+                if(WindowsOsVersion.IsBefore10) extensions.Add("Briefcase");//公文包(Win10没有)
+                this.LoadItems(extensions);
+            }
+        }
+
+        /// <summary>根据ShellNewPath的Classes键值扫描</summary>
+        private void LoadLockItems()
+        {
+            string[] extensions = (string[])Registry.GetValue(ShellNewPath, "Classes", null);
+            this.LoadItems(extensions.ToList());
+        }
+
+        private void LoadItems(List<string> extensions)
+        {
+            foreach(string extension in ShellNewItem.UnableSortExtensions)
+            {
+                string str = extensions.Find(ext => ext.Equals(extension, StringComparison.OrdinalIgnoreCase));
+                if(str != null)
                 {
-                    string typeName = FileExtensionDialog.GetTypeName(extension, false);
+                    extensions.Remove(str);
+                    extensions.Insert(0, str);
+                }
+            }
+            foreach(string extension in extensions)
+            {
+                using(RegistryKey extKey = Registry.ClassesRoot.OpenSubKey(extension))
+                {
+                    string typeName = extKey.GetValue("")?.ToString();
                     if(typeName == null) continue;
-                    using(RegistryKey extKey = root.OpenSubKey(extension))
                     using(RegistryKey tKey = extKey.OpenSubKey(typeName))
                     {
                         foreach(string part in ShellNewItem.SnParts)
@@ -41,7 +67,7 @@ namespace ContextMenuManager.Controls
                             {
                                 if(ValueNames.Any(valueName => snKey?.GetValue(valueName) != null))
                                 {
-                                    ShellNewItem item = new ShellNewItem(snKey.Name);
+                                    ShellNewItem item = new ShellNewItem(this, snKey.Name);
                                     if(item.ItemText != null) { this.AddItem(item); break; }
                                     else item.Dispose();
                                 }
@@ -52,16 +78,68 @@ namespace ContextMenuManager.Controls
             }
         }
 
+        public void MoveItem(ShellNewItem item, bool isUp)
+        {
+            int index = this.GetItemIndex(item);
+            int firstIndex = 0;
+            for(int i = 0; i < this.Controls.Count; i++)
+            {
+                Control ctr = this.Controls[i];
+                if(ctr.GetType() == typeof(ShellNewItem) && ((ShellNewItem)ctr).CanSort)
+                {
+                    firstIndex = i; break;
+                }
+            }
+            if(isUp)
+            {
+                if(index > firstIndex)
+                {
+                    this.SetItemIndex(item, index - 1);
+                }
+            }
+            else
+            {
+                if(index < this.Controls.Count - 1)
+                {
+                    this.SetItemIndex(item, index + 1);
+                }
+            }
+            this.WriteRegistry();
+        }
+
+        public void WriteRegistry()
+        {
+            List<string> extensions = new List<string>();
+            for(int i = 2; i < this.Controls.Count; i++)
+            {
+                extensions.Add(((ShellNewItem)Controls[i]).Extension);
+            }
+            LockNewItem.UnLock();
+            Registry.SetValue(ShellNewPath, "Classes", extensions.ToArray());
+            LockNewItem.Lock();
+        }
+
         private void AddNewItem()
         {
             NewItem newItem = new NewItem();
             this.AddItem(newItem);
-            newItem.NewItemAdd += (sender, e) =>
+            newItem.AddNewItem += (sender, e) =>
             {
                 using(FileExtensionDialog dlg = new FileExtensionDialog())
                 {
                     if(dlg.ShowDialog() != DialogResult.OK) return;
                     string extension = dlg.Extension;
+                    foreach(Control ctr in this.Controls)
+                    {
+                        if(ctr.GetType() == typeof(ShellNewItem))
+                        {
+                            if(((ShellNewItem)ctr).Extension.Equals(extension, StringComparison.OrdinalIgnoreCase))
+                            {
+                                MessageBoxEx.Show(AppString.MessageBox.HasBeenAdded);
+                                return;
+                            }
+                        }
+                    }
                     string typeName = FileExtensionDialog.GetTypeName(extension, false);
                     using(RegistryKey exKey = Registry.ClassesRoot.OpenSubKey(extension, true))
                     {
@@ -69,7 +147,8 @@ namespace ContextMenuManager.Controls
                         using(RegistryKey snKey = exKey.CreateSubKey("ShellNew", true))
                         {
                             snKey.SetValue("NullFile", string.Empty);
-                            this.InsertItem(new ShellNewItem(snKey.Name), GetItemIndex(newItem) + 1);
+                            this.AddItem(new ShellNewItem(this, snKey.Name));
+                            if(LockNewItem.IsLocked()) this.WriteRegistry();
                         }
                     }
                 }

+ 85 - 78
ContextMenuManager/Controls/ShellStoreDialog.cs

@@ -1,6 +1,8 @@
-using BulePointLilac.Methods;
+using BulePointLilac.Controls;
+using BulePointLilac.Methods;
 using System;
 using System.Collections.Generic;
+using System.Drawing;
 using System.Linq;
 using System.Windows.Forms;
 
@@ -9,102 +11,96 @@ namespace ContextMenuManager.Controls
     sealed class ShellStoreDialog : CommonDialog
     {
         public List<string> SelectedKeyNames { get; private set; }
+        public List<string> IgnoredKeyNames { get; set; }
+        public string ShellPath { get; set; }
+
         public override void Reset() { }
 
         protected override bool RunDialog(IntPtr hwndOwner)
         {
-            using(ShellStoreForm frm = new ShellStoreForm())
+            using(ShellStoreForm frm = new ShellStoreForm(this.ShellPath, this.IgnoredKeyNames))
             {
                 bool flag = frm.ShowDialog() == DialogResult.OK;
-                if(flag) this.SelectedKeyNames = frm.SelectedItemNames;
+                if(flag) this.SelectedKeyNames = frm.SelectedKeyNames;
                 return flag;
             }
         }
 
-        sealed class ShellStoreForm : SelectItemsForm
+        sealed class ShellStoreForm : Form
         {
-            /// <summary>系统原有项目</summary>
-            private static readonly string[] SystemItemNames = { "Windows.aboutWindows", "Windows.AddColumns",
-                "Windows.AddDevice", "Windows.AddMediaServer", "Windows.AddNetworkLocation", "Windows.AddPrinter",
-                "Windows.AddRemovePrograms", "Windows.AddToFavorites", "Windows.Autoplay", "Windows.Backup",
-                "Windows.BitLocker", "Windows.BitLocker.Encrypt", "Windows.BitLocker.Manage",
-                "Windows.BitLocker.ResetPasswordPin", "Windows.burn", "Windows.Burn.Action", "Windows.change-passphrase",
-                "Windows.change-pin", "Windows.ChangeIndexedLocations", "Windows.ChooseColumns", "Windows.CleanUp",
-                "Windows.ClearAddressBarHistory", "Windows.ClearFrequentHistory", "Windows.clearRecentDocs",
-                "Windows.closewindow", "Windows.cmd", "Windows.cmdPromptAsAdministrator", "Windows.CompressedFile.extract",
-                "Windows.CompressedFile.ExtractTo", "Windows.CompressedFolder.extract", "Windows.CompressedItem.extract",
-                "Windows.Computer.Manage", "Windows.connectNetworkDrive", "Windows.copy", "Windows.copyaspath",
-                "Windows.CopyToBrowser", "Windows.CopyToMenu", "Windows.CscSync", "Windows.CscWorkOfflineOnline",
-                "Windows.cut", "Windows.Defragment", "Windows.delete", "Windows.Dialog.DisconnectNetworkDrive",
-                "Windows.DiscImage.burn", "Windows.DisconnectNetworkDrive", "Windows.DiskFormat",
-                "Windows.DriveFolder.DisconnectNetworkDrive", "Windows.edit", "Windows.Eject", "Windows.email",
-                "Windows.encrypt-bde", "Windows.encrypt-bde-elev", "Windows.Enqueue", "Windows.EraseDisc",
-                "Windows.EraseDisc.Action", "Windows.fax", "Windows.FinishBurn", "Windows.folderoptions",
-                "Windows.GroupByColumn", "Windows.help", "Windows.HideSelected", "Windows.HistoryVaultRestore",
-                "Windows.HomeGroupCPL", "Windows.HomeGroupJoin", "Windows.HomeGroupPassword", "Windows.HomeGroupSharing",
-                "Windows.HomeGroupTroubleshooter", "Windows.IconSize", "Windows.includeinlibrary", "Windows.invertselection",
-                "Windows.layout", "Windows.LibraryChangeIcon", "Windows.LibraryDefaultSaveLocation",
-                "Windows.LibraryIncludeInLibrary", "Windows.LibraryManageLibrary", "Windows.LibraryOptimizeLibraryFor",
-                "Windows.LibraryPublicSaveLocation", "Windows.LibraryRestoreDefaults", "Windows.LibrarySelChangeIcon",
-                "Windows.LibrarySelDefaultSaveLocation", "Windows.LibrarySelManageLibrary", "Windows.LibrarySelOptimizeLibraryFor",
-                "Windows.LibrarySelPublicSaveLocation", "Windows.LibrarySelRestoreDefaults", "Windows.LibrarySelShowInNavPane",
-                "Windows.LibraryShowInNavPane", "Windows.location.cmd", "Windows.location.cmdPromptAsAdministrator",
-                "Windows.location.opennewprocess", "Windows.location.opennewtab", "Windows.location.opennewwindow",
-                "Windows.location.Powershell", "Windows.location.PowershellAsAdmin", "Windows.manage-bde",
-                "Windows.manage-bde-elev", "Windows.MapNetworkDrive", "Windows.menubar", "Windows.ModernShare",
-                "Windows.mount", "Windows.MoveToBrowser", "Windows.MoveToMenu", "Windows.MultiVerb.cmd",
-                "Windows.MultiVerb.cmdPromptAsAdministrator", "Windows.MultiVerb.opennewprocess", "Windows.MultiVerb.opennewtab",
-                "Windows.MultiVerb.opennewwindow", "Windows.MultiVerb.Powershell", "Windows.MultiVerb.PowershellAsAdmin",
-                "Windows.navpane", "Windows.NavPaneExpandToCurrentFolder", "Windows.NavPaneShowAllFolders",
-                "Windows.NavPaneShowLibraries", "Windows.NetworkAndSharing", "Windows.NetworkViewDeviceWebpage",
-                "Windows.newfolder", "Windows.newitem", "Windows.open", "Windows.OpenContainingFolder.opencontaining",
-                "Windows.OpenControlPanel", "Windows.opennewprocess", "Windows.opennewtab", "Windows.opennewwindow",
-                "Windows.OpenPrinterServerProperty", "Windows.OpenPrintQueue", "Windows.OpenSearch.openfilelocation",
-                "Windows.OpenSearchViewSite", "Windows.OpenWith", "Windows.organize", "Windows.paste", "Windows.pastelink",
-                "Windows.PermanentDelete", "Windows.PinToHome", "Windows.pintostartscreen", "Windows.play", "Windows.playall",
-                "Windows.playmusic", "Windows.PowershellAsAdmin", "Windows.previewpane", "Windows.print", "Windows.properties",
-                "Windows.readingpane", "Windows.recycle", "Windows.RecycleBin.Empty", "Windows.RecycleBin.Location.properties",
-                "Windows.RecycleBin.properties", "Windows.RecycleBin.RestoreAll", "Windows.RecycleBin.RestoreItems",
-                "Windows.RecycleBin.Selection.properties", "Windows.redo", "Windows.remotedesktop", "Windows.RemoveMediaServer",
-                "Windows.removeproperties", "Windows.rename", "Windows.RibbonDelete", "Windows.RibbonPermissionsDialog",
-                "Windows.RibbonShare", "Windows.RibbonSync.MakeAvailableOffline", "Windows.RibbonSync.SyncThisFolder",
-                "Windows.RibbonSync.WorkOfflineOnline", "Windows.rotate270", "Windows.rotate90", "Windows.runas",
-                "Windows.runasuser", "Windows.SearchActiveDirectory", "Windows.SearchClearMru", "Windows.SearchCloseTab",
-                "Windows.SearchFilterDate", "Windows.SearchFilterKind", "Windows.SearchFilterMoreProperties",
-                "Windows.SearchFilterSize", "Windows.SearchMru", "Windows.SearchOpenLocation", "Windows.SearchOptionCompressed",
-                "Windows.SearchOptionContents", "Windows.SearchOptionDeep", "Windows.SearchOptionShallow",
-                "Windows.SearchOptionSystem", "Windows.SearchSave", "Windows.SearchSendTo", "Windows.SearchSendToComputer",
-                "Windows.selectall", "Windows.SelectionCheckboxes", "Windows.selectMode", "Windows.selectnone",
-                "Windows.separator", "Windows.setdesktopwallpaper", "Windows.Share", "Windows.SharePrivate",
-                "Windows.ShareSpecificUsers", "Windows.Shortcut.opencontaining", "Windows.ShowFileExtensions",
-                "Windows.ShowHiddenFiles", "Windows.SizeAllColumns", "Windows.slideshow", "Windows.SortAscending",
-                "Windows.SortByColumn", "Windows.SortDescending", "Windows.SortGroupsAscending", "Windows.SortGroupsDescending",
-                "Windows.StartScan", "Windows.statusbar", "Windows.Sync", "Windows.SystemProperties", "Windows.taskbarpin",
-                "Windows.ToggleRecycleConfirmations", "Windows.topviewrestoredefault", "Windows.Troubleshoot", "Windows.undo",
-                "Windows.UpdatePrinterDriver", "Windows.v2.Powershell", "Windows.View.OptionsGallery",
-                "Windows.ViewRemotePrinters", "Windows.zip", "Windows.Zip.Action", "Windows.librarypane",
-                "Windows.ManageDefaultPrinters", "Windows.ShareHomegroupFullAccess", "Windows.ShareHomegroupReadAccess"
-            };
-
-            public List<string> SelectedItemNames { get; private set; } = new List<string>();
+            public string ShellPath { get; private set; }
+            public List<string> IgnoredKeyNames { get; private set; }
+            public List<string> SelectedKeyNames { get; private set; } = new List<string>();
+            private bool IsPublic => ShellPath.Equals(ShellItem.CommandStorePath, StringComparison.OrdinalIgnoreCase);
 
-            public ShellStoreForm()
+            public ShellStoreForm(string shellPath, List<string> ignoredKeyNames)
             {
-                this.Text = AppString.Dialog.CheckReference;
+                this.ShellPath = shellPath;
+                this.IgnoredKeyNames = ignoredKeyNames;
+                this.AcceptButton = btnOk;
+                this.CancelButton = btnCancel;
+                this.Font = SystemFonts.MessageBoxFont;
+                this.ShowIcon = this.ShowInTaskbar = false;
+                this.StartPosition = FormStartPosition.CenterParent;
+                this.MinimumSize = this.Size = new Size(652, 425).DpiZoom();
+                this.Text = IsPublic ? AppString.Dialog.CheckReference : AppString.Dialog.CheckCopy;
                 btnOk.Click += (sender, e) => GetSelectedItems();
+                list.Owner = listBox;
+                InitializeComponents();
                 LoadItems();
             }
 
+            readonly MyList list = new MyList();
+            readonly MyListBox listBox = new MyListBox();
+            readonly Panel pnlBorder = new Panel
+            {
+                BackColor = Color.FromArgb(200, 200, 200)
+            };
+            readonly Button btnOk = new Button
+            {
+                Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
+                DialogResult = DialogResult.OK,
+                Text = AppString.Dialog.Ok,
+                AutoSize = true
+            };
+            readonly Button btnCancel = new Button
+            {
+                Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
+                DialogResult = DialogResult.Cancel,
+                Text = AppString.Dialog.Cancel,
+                AutoSize = true
+            };
+
+            private void InitializeComponents()
+            {
+                this.Controls.AddRange(new Control[] { listBox, pnlBorder, btnOk, btnCancel });
+                int a = 20.DpiZoom();
+                listBox.Location = new Point(a, a);
+                pnlBorder.Location = new Point(a - 1, a - 1);
+                btnOk.Top = btnCancel.Top = this.ClientSize.Height - btnCancel.Height - a;
+                btnCancel.Left = this.ClientSize.Width - btnCancel.Width - a;
+                btnOk.Left = btnCancel.Left - btnOk.Width - a;
+                this.OnResize(null);
+            }
+
+            protected override void OnResize(EventArgs e)
+            {
+                base.OnResize(e);
+                listBox.Width = ClientSize.Width - 2 * listBox.Left;
+                listBox.Height = btnOk.Top - 2 * listBox.Top;
+                pnlBorder.Width = listBox.Width + 2;
+                pnlBorder.Height = listBox.Height + 2;
+            }
+
             private void LoadItems()
             {
-                using(var shellKey = RegistryEx.GetRegistryKey(ShellItem.CommandStorePath))
+                using(var shellKey = RegistryEx.GetRegistryKey(ShellPath))
                 {
                     Array.ForEach(Array.FindAll(shellKey.GetSubKeyNames(), itemName =>
-                        !SystemItemNames.Contains(itemName, StringComparer.OrdinalIgnoreCase)), itemName =>
+                        !IgnoredKeyNames.Contains(itemName, StringComparer.OrdinalIgnoreCase)), itemName =>
                         {
-                            string regPath = $@"{ShellItem.CommandStorePath}\{itemName}";
-                            list.AddItem(new StoreShellItem(regPath));
-                            RegTrustedInstaller.TakeRegTreeOwnerShip(regPath);
+                            string regPath = $@"{ShellPath}\{itemName}";
+                            list.AddItem(new StoreShellItem(regPath, IsPublic));
                         });
                 }
             }
@@ -112,18 +108,29 @@ namespace ContextMenuManager.Controls
             private void GetSelectedItems()
             {
                 foreach(StoreShellItem item in list.Controls)
-                    if(item.IsSelected) SelectedItemNames.Add(item.KeyName);
+                    if(item.IsSelected) SelectedKeyNames.Add(item.KeyName);
             }
 
             sealed class StoreShellItem : ShellItem
             {
-                public StoreShellItem(string regPath) : base(regPath)
+                public StoreShellItem(string regPath, bool isPublic) : base(regPath)
                 {
+                    this.IsPublic = isPublic;
                     this.AddCtr(chkSelected);
-                    this.SetCtrIndex(chkSelected, 2);
+                    //this.SetCtrIndex(chkSelected, 2);
+                    ChkVisible.Visible = BtnSubItems.Visible = false;
+                    RegTrustedInstaller.TakeRegTreeOwnerShip(regPath);
                 }
                 public bool IsSelected => chkSelected.Checked;
+                public bool IsPublic { get; set; }
                 readonly CheckBox chkSelected = new CheckBox { AutoSize = true };
+
+                public override void DeleteMe()
+                {
+                    if(IsPublic && MessageBoxEx.Show(AppString.MessageBox.ConfirmDeleteReferenced,
+                        MessageBoxButtons.YesNo) != DialogResult.Yes) return;
+                    base.DeleteMe();
+                }
             }
         }
     }

+ 326 - 182
ContextMenuManager/Controls/ShellSubMenuDialog.cs

@@ -4,6 +4,8 @@ using ContextMenuManager.Controls.Interfaces;
 using System;
 using System.Collections.Generic;
 using System.Drawing;
+using System.Linq;
+using System.Reflection;
 using System.Windows.Forms;
 using static Microsoft.Win32.Registry;
 
@@ -19,53 +21,126 @@ namespace ContextMenuManager.Controls
         /// <param name="parentPath">子菜单的父菜单的注册表路径</param>
         public void ShowDialog(string parentPath)
         {
-            using(ShellSubMenuForm frm = new ShellSubMenuForm(parentPath))
+            using(ShellSubMenuForm frm = new ShellSubMenuForm())
             {
                 frm.Text = this.Text;
                 frm.Icon = this.Icon;
+                frm.ParentPath = parentPath;
                 frm.ShowDialog();
             }
         }
 
         sealed class ShellSubMenuForm : Form
         {
-            /// <param name="parentPath">子菜单的父菜单的注册表路径</param>
-            public ShellSubMenuForm(string parentPath)
+            public ShellSubMenuForm()
             {
-                this.ShowInTaskbar = false;
+                this.ShowInTaskbar = this.MinimizeBox = this.MaximizeBox = false;
                 this.StartPosition = FormStartPosition.CenterParent;
                 this.MinimumSize = this.Size = new Size(646, 389).DpiZoom();
-                LstSubItems = new MyListBox { Dock = DockStyle.Fill, Parent = this };
-                string value = GetValue(parentPath, "SubCommands", null)?.ToString();
+                this.Controls.Add(MlbSubItems);
+                this.OnResize(null);
+            }
+
+            /// <summary>子菜单的父菜单的注册表路径</summary>
+            public string ParentPath { get; set; }
+            readonly MyListBox MlbSubItems = new MyListBox { Dock = DockStyle.Fill };
+
+            protected override void OnLoad(EventArgs e)
+            {
+                base.OnLoad(e);
+                bool isPublic = true;
+                string value = GetValue(ParentPath, "SubCommands", null)?.ToString();
                 if(value.IsNullOrWhiteSpace())
                 {
-                    using(var shellKey = RegistryEx.GetRegistryKey($@"{parentPath}\shell"))
+                    using(var shellKey = RegistryEx.GetRegistryKey($@"{ParentPath}\shell"))
                     {
-                        if(shellKey != null && shellKey.GetSubKeyNames().Length > 0)
-                        {
-                            new MultiItemsList(LstSubItems).LoadItems(parentPath);
-                            return;
-                        }
+                        if(shellKey != null && shellKey.GetSubKeyNames().Length > 0) isPublic = false;
                         else
                         {
                             using(SubMenuModeForm frm = new SubMenuModeForm())
                             {
                                 frm.ShowDialog();
-                                if(frm.SubMenuMode == 1)
+                                switch(frm.Mode)
                                 {
-                                    new MultiItemsList(LstSubItems).LoadItems(parentPath);
-                                    return;
+                                    case SubMenuModeForm.SubMode.Public:
+                                        isPublic = true; break;
+                                    case SubMenuModeForm.SubMode.Private:
+                                        isPublic = false; break;
+                                    case SubMenuModeForm.SubMode.None:
+                                        this.Dispose(); return;
                                 }
                             }
                         }
                     }
                 }
-                new CommonMultiItemsList(LstSubItems).LoadItems(parentPath);
+                if(isPublic)
+                {
+                    new PulicMultiItemsList(MlbSubItems).LoadItems(ParentPath);
+                    this.Text += $"({AppString.Dialog.Public})";
+                }
+                else
+                {
+                    new PrivateMultiItemsList(MlbSubItems).LoadItems(ParentPath);
+                    this.Text += $"({AppString.Dialog.Private})";
+                }
             }
 
-            readonly MyListBox LstSubItems;
+            sealed class SubMenuModeForm : Form
+            {
+                public SubMenuModeForm()
+                {
+                    this.Text = AppString.General.AppName;
+                    this.ShowIcon = this.ShowInTaskbar = false;
+                    this.MinimizeBox = this.MaximizeBox = false;
+                    this.FormBorderStyle = FormBorderStyle.FixedSingle;
+                    this.StartPosition = FormStartPosition.CenterParent;
+                    this.Font = new Font(SystemFonts.MessageBoxFont.FontFamily, 9F);
+                    this.Controls.AddRange(new Control[] { pnlTop, btnPrivate, btnPublic });
+                    pnlTop.Controls.Add(lblInfo);
+                    int a = 20.DpiZoom();
+                    this.ClientSize = new Size(lblInfo.Width + 2 * a, lblInfo.Height + btnPrivate.Height + 3 * a);
+                    lblInfo.Location = new Point(a, a);
+                    pnlTop.Height = lblInfo.Bottom + a;
+                    btnPrivate.Top = btnPublic.Top = pnlTop.Bottom + a / 2;
+                    btnPublic.Left = pnlTop.Width - btnPublic.Width - a;
+                    btnPrivate.Left = btnPublic.Left - btnPrivate.Width - a;
+                    btnPrivate.Click += (sender, e) => Mode = SubMode.Private;
+                    btnPublic.Click += (sender, e) => Mode = SubMode.Public;
+                }
+
+                public enum SubMode { Public, Private, None }
+
+                public SubMode Mode { get; private set; } = SubMode.None;
+
+                readonly Label lblInfo = new Label
+                {
+                    Text = AppString.Dialog.SelectSubMenuMode,
+                    AutoSize = true
+                };
+
+                readonly Panel pnlTop = new Panel
+                {
+                    BackColor = Color.White,
+                    Dock = DockStyle.Top
+                };
+
+                readonly Button btnPrivate = new Button
+                {
+                    Text = AppString.Dialog.Private,
+                    DialogResult = DialogResult.OK,
+                    AutoSize = true
+                };
 
-            sealed class CommonMultiItemsList : MyList
+                readonly Button btnPublic = new Button
+                {
+                    Text = AppString.Dialog.Public,
+                    DialogResult = DialogResult.OK,
+                    AutoSize = true
+                };
+            }
+
+            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+            sealed class PulicMultiItemsList : MyList
             {
                 readonly List<string> SubKeyNames = new List<string>();
                 /// <summary>子菜单的父菜单的注册表路径</summary>
@@ -73,21 +148,14 @@ namespace ContextMenuManager.Controls
                 /// <summary>菜单所处环境注册表路径</summary>
                 private string ScenePath => RegistryEx.GetParentPath(RegistryEx.GetParentPath(ParentPath));
 
-                readonly NewItem newItem = new NewItem();
-                readonly AddCommonButton btnAddCommon = new AddCommonButton();
-                readonly PictureButton btnAddExisting = new PictureButton(AppImage.AddExisting);
-                readonly PictureButton btnAddSeparator = new PictureButton(AppImage.AddSeparator);
+                readonly SubNewItem subNewItem = new SubNewItem(true);
 
-                public CommonMultiItemsList(MyListBox owner) : base(owner)
+                public PulicMultiItemsList(MyListBox owner) : base(owner)
                 {
-                    this.AddItem(newItem);
-                    newItem.AddCtrs(new[] { btnAddCommon, btnAddExisting, btnAddSeparator });
-                    MyToolTip.SetToolTip(btnAddExisting, AppString.Tip.AddExistingItems);
-                    MyToolTip.SetToolTip(btnAddSeparator, AppString.Tip.AddSeparator);
-                    newItem.NewItemAdd += (sender, e) => AddNewItem();
-                    btnAddCommon.MouseDown += (sender, e) => AddCommonItems();
-                    btnAddExisting.MouseDown += (sender, e) => AddExistingItems();
-                    btnAddSeparator.MouseDown += (sender, e) => AddSeparator();
+                    this.AddItem(subNewItem);
+                    subNewItem.AddNewItem += (sender, e) => AddNewItem();
+                    subNewItem.AddExisting += (sender, e) => AddReference();
+                    subNewItem.AddSeparator += (sender, e) => AddSeparator();
                 }
 
                 /// <param name="parentPath">子菜单的父菜单的注册表路径</param>
@@ -116,7 +184,7 @@ namespace ContextMenuManager.Controls
 
                 private void AddNewItem()
                 {
-                    if(!CanAddMore()) return;
+                    if(!SubShellTypeItem.CanAddMore(this)) return;
                     using(NewShellDialog dlg = new NewShellDialog
                     {
                         ScenePath = this.ScenePath,
@@ -126,48 +194,26 @@ namespace ContextMenuManager.Controls
                         if(dlg.ShowDialog() != DialogResult.OK) return;
                         SubKeyNames.Add(dlg.NewItemKeyName);
                         WriteRegistry();
-                        SubShellItem item = new SubShellItem(this, dlg.NewItemKeyName);
-                        this.AddItem(item);
-                        this.HoveredItem = item;
+                        this.AddItem(new SubShellItem(this, dlg.NewItemKeyName));
                     }
                 }
 
-                private void AddCommonItems()
+                private void AddReference()
                 {
-                    if(!CanAddMore()) return;
-                    using(ShellCommonDialog dlg = new ShellCommonDialog
+                    if(!SubShellTypeItem.CanAddMore(this)) return;
+                    using(ShellStoreDialog dlg = new ShellStoreDialog
                     {
-                        ScenePath = this.ScenePath,
-                        ShellPath = ShellItem.CommandStorePath
+                        ShellPath = ShellItem.CommandStorePath,
+                        IgnoredKeyNames = ShellItem.SysStoreItemNames.ToList()
                     })
-                    {
-                        if(dlg.ShowDialog() == DialogResult.OK)
-                        {
-                            dlg.SelectedShellPaths.ForEach(path =>
-                            {
-                                string keyName = RegistryEx.GetKeyName(path);
-                                this.AddItem(new SubShellItem(this, keyName));
-                                SubKeyNames.Add(keyName);
-                            });
-                            WriteRegistry();
-                        }
-                    }
-                }
-
-                private void AddExistingItems()
-                {
-                    if(!CanAddMore()) return;
-                    using(ShellStoreDialog dlg = new ShellStoreDialog())
                     {
                         if(dlg.ShowDialog() != DialogResult.OK) return;
                         dlg.SelectedKeyNames.ForEach(keyName =>
                         {
-                            SubShellItem item = new SubShellItem(this, keyName);
-                            this.AddItem(item);
+                            this.AddItem(new SubShellItem(this, keyName));
                             this.SubKeyNames.Add(keyName);
                             WriteRegistry();
                         });
-                        this.HoveredItem = (MyListItem)Controls[Controls.Count - 1];
                     }
                 }
 
@@ -175,21 +221,7 @@ namespace ContextMenuManager.Controls
                 {
                     this.SubKeyNames.Add("|");
                     WriteRegistry();
-                    SeparatorItem item = new SeparatorItem(this);
-                    this.AddItem(item);
-                    this.HoveredItem = item;
-                }
-
-                private bool CanAddMore()
-                {
-                    int count = 0;
-                    foreach(Control item in Controls)
-                    {
-                        if(item.GetType() == typeof(SubShellItem)) count++;
-                    }
-                    bool flag = count < 16;
-                    if(!flag) MessageBoxEx.Show(AppString.MessageBox.CannotAddNewItem);
-                    return flag;
+                    this.AddItem(new SeparatorItem(this));
                 }
 
                 private void WriteRegistry()
@@ -197,106 +229,83 @@ namespace ContextMenuManager.Controls
                     SetValue(ParentPath, "SubCommands", string.Join(";", SubKeyNames.ToArray()));
                 }
 
-                private static void MoveItem(MyListItem item, CommonMultiItemsList list, bool isUp)
+                private void MoveItem(MyListItem item, bool isUp)
                 {
-                    int index = list.GetItemIndex(item);
+                    int index = this.GetItemIndex(item);
                     if(isUp)
                     {
                         if(index > 1)
                         {
-                            list.SetItemIndex(item, index - 1);
-                            list.SubKeyNames.Reverse(index - 2, 2);
+                            this.SetItemIndex(item, index - 1);
+                            this.SubKeyNames.Reverse(index - 2, 2);
                         }
                     }
                     else
                     {
-                        if(index < list.Controls.Count - 1)
+                        if(index < this.Controls.Count - 1)
                         {
-                            list.SetItemIndex(item, index + 1);
-                            list.SubKeyNames.Reverse(index - 1, 2);
+                            this.SetItemIndex(item, index + 1);
+                            this.SubKeyNames.Reverse(index - 1, 2);
                         }
                     }
-                    list.WriteRegistry();
+                    this.WriteRegistry();
                 }
 
-                private static void RemoveItem(CommonMultiItemsList list, MyListItem item)
+                private void DeleteItem(MyListItem item)
                 {
-                    int index = list.GetItemIndex(item);
-                    list.Controls.Remove(item);
-                    list.Controls[index - 1].Focus();
-                    list.SubKeyNames.RemoveAt(index - 1);
-                    list.WriteRegistry();
+                    int index = this.GetItemIndex(item);
+                    this.Controls.Remove(item);
+                    this.Controls[index - 1].Focus();
+                    this.SubKeyNames.RemoveAt(index - 1);
+                    this.WriteRegistry();
                     item.Dispose();
                 }
 
-                sealed class SubShellItem : ShellItem, IBtnMoveUpDownItem
+                sealed class SubShellItem : SubShellTypeItem
                 {
-                    public SubShellItem(CommonMultiItemsList list, string keyName) : base($@"{CommandStorePath}\{keyName}")
+                    public SubShellItem(PulicMultiItemsList list, string keyName) : base($@"{CommandStorePath}\{keyName}")
                     {
                         this.Owner = list;
-                        BtnMoveDown = new MoveButton(this, false);
-                        BtnMoveUp = new MoveButton(this, true);
-                        BtnMoveUp.MouseDown += (sender, e) => MoveItem(this, Owner, true);
-                        BtnMoveDown.MouseDown += (sender, e) => MoveItem(this, Owner, false);
+                        BtnMoveUp.MouseDown += (sender, e) => Owner.MoveItem(this, true);
+                        BtnMoveDown.MouseDown += (sender, e) => Owner.MoveItem(this, false);
                         ContextMenuStrip.Items.Remove(TsiDeleteMe);
                         ContextMenuStrip.Items.Add(TsiDeleteRef);
                         TsiDeleteRef.Click += (sender, e) => DeleteReference();
                     }
 
-                    protected override bool IsSubItem => true;
-
                     readonly ToolStripMenuItem TsiDeleteRef = new ToolStripMenuItem(AppString.Menu.DeleteReference);
-                    public CommonMultiItemsList Owner { get; private set; }
-                    public MoveButton BtnMoveUp { get; set; }
-                    public MoveButton BtnMoveDown { get; set; }
+                    public PulicMultiItemsList Owner { get; private set; }
 
                     private void DeleteReference()
                     {
                         if(MessageBoxEx.Show(AppString.MessageBox.ConfirmDeleteReference,
                             MessageBoxButtons.YesNo) == DialogResult.Yes)
                         {
-                            RemoveItem(Owner, this);
+                            Owner.DeleteItem(this);
                         }
                     }
-
-                    public override void DeleteMe()
-                    {
-                        if(MessageBoxEx.Show(AppString.MessageBox.ConfirmDeleteReferenced,
-                            MessageBoxButtons.YesNo) == DialogResult.Yes) base.DeleteMe();
-                    }
                 }
 
-                sealed class SeparatorItem : MyListItem, IBtnDeleteItem, IBtnMoveUpDownItem
+                sealed class SeparatorItem : SubSeparatorItem
                 {
-                    public SeparatorItem(CommonMultiItemsList list)
+                    public SeparatorItem(PulicMultiItemsList list) : base()
                     {
                         this.Owner = list;
-                        this.Text = AppString.Item.Separator;
-                        this.Image = AppImage.Separator;
-                        BtnDelete = new DeleteButton(this);
-                        BtnMoveDown = new MoveButton(this, false);
-                        BtnMoveUp = new MoveButton(this, true);
-                        BtnMoveUp.MouseDown += (sender, e) => MoveItem(this, Owner, true);
-                        BtnMoveDown.MouseDown += (sender, e) => MoveItem(this, Owner, false);
-                        MyToolTip.SetToolTip(BtnDelete, AppString.Tip.Separator);
+                        BtnMoveUp.MouseDown += (sender, e) => Owner.MoveItem(this, true);
+                        BtnMoveDown.MouseDown += (sender, e) => Owner.MoveItem(this, false);
                     }
 
-                    public DeleteButton BtnDelete { get; set; }
+                    public PulicMultiItemsList Owner { get; private set; }
 
-                    public CommonMultiItemsList Owner { get; private set; }
-                    public MoveButton BtnMoveUp { get; set; }
-                    public MoveButton BtnMoveDown { get; set; }
-
-                    public void DeleteMe()
+                    public override void DeleteMe()
                     {
-                        RemoveItem(Owner, this);
-                        this.Dispose();
+                        Owner.DeleteItem(this);
                     }
                 }
 
                 sealed class InvalidItem : MyListItem, IBtnDeleteItem, IBtnMoveUpDownItem
                 {
-                    public InvalidItem(CommonMultiItemsList list, string keyName)
+                    public InvalidItem(PulicMultiItemsList list, string keyName)
                     {
                         this.Owner = list;
                         this.Text = $"{AppString.Item.InvalidItem} {keyName}";
@@ -304,43 +313,47 @@ namespace ContextMenuManager.Controls
                         BtnDelete = new DeleteButton(this);
                         BtnMoveDown = new MoveButton(this, false);
                         BtnMoveUp = new MoveButton(this, true);
-                        BtnMoveUp.MouseDown += (sender, e) => MoveItem(this, Owner, true);
-                        BtnMoveDown.MouseDown += (sender, e) => MoveItem(this, Owner, false);
-                        MyToolTip.SetToolTip(BtnDelete, AppString.Tip.InvalidItem);
+                        BtnMoveUp.MouseDown += (sender, e) => Owner.MoveItem(this, true);
+                        BtnMoveDown.MouseDown += (sender, e) => Owner.MoveItem(this, false);
+                        MyToolTip.SetToolTip(this, AppString.Tip.InvalidItem);
+                        MyToolTip.SetToolTip(BtnDelete, AppString.Menu.Delete);
                     }
 
                     public DeleteButton BtnDelete { get; set; }
-                    public CommonMultiItemsList Owner { get; private set; }
+                    public PulicMultiItemsList Owner { get; private set; }
                     public MoveButton BtnMoveUp { get; set; }
                     public MoveButton BtnMoveDown { get; set; }
 
                     public void DeleteMe()
                     {
-                        RemoveItem(Owner, this);
-                        this.Dispose();
+                        Owner.DeleteItem(this);
                     }
                 }
             }
 
-            sealed class MultiItemsList : MyList
+            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+            sealed class PrivateMultiItemsList : MyList
             {
-                public MultiItemsList(MyListBox owner) : base(owner)
+                public PrivateMultiItemsList(MyListBox owner) : base(owner)
                 {
-                    this.AddItem(newItem);
-                    newItem.AddCtr(btnAddCommon);
-                    newItem.NewItemAdd += (sender, e) => AddNewItem();
-                    btnAddCommon.MouseDown += (sender, e) => AddCommonItems();
+                    this.AddItem(subNewItem);
+                    subNewItem.AddNewItem += (sender, e) => AddNewItem();
+                    subNewItem.AddSeparator += (sender, e) => AddSeparator();
+                    subNewItem.AddExisting += (sender, e) => AddFromParentMenu();
                 }
 
-                readonly NewItem newItem = new NewItem();
-                readonly AddCommonButton btnAddCommon = new AddCommonButton();
-                /// <summary>子菜单的父菜单的注册表路径</summary>
+                readonly SubNewItem subNewItem = new SubNewItem(false);
+
+                /// <summary>父菜单的注册表路径</summary>
                 public string ParentPath { get; set; }
                 /// <summary>子菜单的Shell项注册表路径</summary>
                 private string ShellPath => $@"{ParentPath}\shell";
+                /// <summary>父菜单的Shell项注册表路径</summary>
+                private string ParentShellPath => RegistryEx.GetParentPath(ParentPath);
                 /// <summary>菜单所处环境注册表路径</summary>
-                private string ScenePath => RegistryEx.GetParentPath(RegistryEx.GetParentPath(ParentPath));
-
+                private string ScenePath => RegistryEx.GetParentPath(ParentShellPath);
+                /// <summary>父菜单的项名</summary>
+                private string ParentKeyName => RegistryEx.GetKeyName(ParentPath);
 
                 public void LoadItems(string parentPath)
                 {
@@ -351,82 +364,213 @@ namespace ContextMenuManager.Controls
                         RegTrustedInstaller.TakeRegTreeOwnerShip(shellKey.Name);
                         Array.ForEach(shellKey.GetSubKeyNames(), keyName =>
                         {
-                            this.AddItem(new SubShellItem($@"{ShellPath}\{keyName}"));
+                            string regPath = $@"{ShellPath}\{keyName}";
+                            int value = Convert.ToInt32(GetValue(regPath, "CommandFlags", 0));
+                            if(value % 16 >= 8)
+                            {
+                                this.AddItem(new SeparatorItem(this, regPath));
+                            }
+                            else
+                            {
+                                this.AddItem(new SubShellItem(this, regPath));
+                            }
                         });
                     }
                 }
 
                 private void AddNewItem()
                 {
-                    if(!CanAddMore()) return;
+                    if(!SubShellTypeItem.CanAddMore(this)) return;
                     using(NewShellDialog dlg = new NewShellDialog
                     {
                         ScenePath = this.ScenePath,
                         ShellPath = this.ShellPath
                     })
                     {
-                        if(dlg.ShowDialog() == DialogResult.OK)
-                            this.InsertItem(new SubShellItem(dlg.NewItemRegPath), GetItemIndex(newItem) + 1);
+                        if(dlg.ShowDialog() != DialogResult.OK) return;
+                        this.AddItem(new SubShellItem(this, dlg.NewItemRegPath));
                     }
                 }
 
-                private void AddCommonItems()
+                private void AddSeparator()
                 {
-                    if(!CanAddMore()) return;
-                    using(ShellCommonDialog dlg = new ShellCommonDialog
+                    string regPath = null;
+                    if(this.Controls.Count > 1)
                     {
-                        ScenePath = this.ScenePath,
-                        ShellPath = this.ShellPath
+                        regPath = GetItemRegPath((MyListItem)Controls[Controls.Count - 1]);
+                    }
+                    else
+                    {
+                        regPath = $@"{ShellPath}\Item";
+                    }
+                    regPath = ObjectPath.GetNewPathWithIndex(regPath, ObjectPath.PathType.Registry);
+                    SetValue(regPath, "CommandFlags", 0x8);
+                    this.AddItem(new SeparatorItem(this, regPath));
+                }
+
+                private void AddFromParentMenu()
+                {
+                    if(!SubShellTypeItem.CanAddMore(this)) return;
+                    using(ShellStoreDialog dlg = new ShellStoreDialog
+                    {
+                        ShellPath = this.ParentShellPath,
+                        IgnoredKeyNames = new List<string> { this.ParentKeyName }
                     })
                     {
-                        if(dlg.ShowDialog() == DialogResult.OK)
+                        if(dlg.ShowDialog() != DialogResult.OK) return;
+                        dlg.SelectedKeyNames.ForEach(keyName =>
+                        {
+                            string srcPath = $@"{dlg.ShellPath}\{keyName}";
+                            string dstPath = ObjectPath.GetNewPathWithIndex($@"{this.ShellPath}\{keyName}", ObjectPath.PathType.Registry);
+
+                            RegistryEx.CopyTo(srcPath, dstPath);
+                            this.AddItem(new SubShellItem(this, dstPath));
+                        });
+                    }
+                }
+
+                public void MoveItem(MyListItem item, bool isUp)
+                {
+                    int index = this.GetItemIndex(item);
+                    MyListItem otherItem = null;
+                    if(isUp)
+                    {
+                        if(index > 1)
                         {
-                            dlg.SelectedShellPaths.ForEach(path => this.AddItem(new SubShellItem(path)));
-                            this.SortItemByText();
-                            this.SetItemIndex(newItem, 0);
+                            otherItem = (MyListItem)this.Controls[index - 1];
+                            this.SetItemIndex(item, index - 1);
                         }
                     }
+                    else
+                    {
+                        if(index < this.Controls.Count - 1)
+                        {
+                            otherItem = (MyListItem)this.Controls[index + 1];
+                            this.SetItemIndex(item, index + 1);
+                        }
+                    }
+                    if(otherItem != null)
+                    {
+                        string path1 = GetItemRegPath(item);
+                        string path2 = GetItemRegPath(otherItem);
+                        string tempPath = ObjectPath.GetNewPathWithIndex(path1, ObjectPath.PathType.Registry);
+                        RegistryEx.MoveTo(path1, tempPath);
+                        RegistryEx.MoveTo(path2, path1);
+                        RegistryEx.MoveTo(tempPath, path2);
+                        SetItemRegPath(item, path2);
+                        SetItemRegPath(otherItem, path1);
+                    }
                 }
 
-                private bool CanAddMore()
+                private string GetItemRegPath(MyListItem item)
                 {
-                    int count = 0;
-                    foreach(Control item in Controls)
+                    PropertyInfo pi = item.GetType().GetProperty("RegPath");
+                    return pi.GetValue(item, null).ToString();
+                }
+
+                private void SetItemRegPath(MyListItem item, string regPath)
+                {
+                    PropertyInfo pi = item.GetType().GetProperty("RegPath");
+                    pi.SetValue(item, regPath, null);
+                }
+
+                sealed class SubShellItem : SubShellTypeItem
+                {
+                    public SubShellItem(PrivateMultiItemsList list, string regPath) : base(regPath)
                     {
-                        if(item.GetType() == typeof(SubShellItem)) count++;
+                        this.Owner = list;
+                        BtnMoveUp.MouseDown += (sender, e) => Owner.MoveItem(this, true);
+                        BtnMoveDown.MouseDown += (sender, e) => Owner.MoveItem(this, false);
                     }
-                    bool flag = count < 16;
-                    if(!flag) MessageBoxEx.Show(AppString.MessageBox.CannotAddNewItem);
-                    return flag;
+
+                    public PrivateMultiItemsList Owner { get; private set; }
                 }
 
-                sealed class SubShellItem : ShellItem
+                sealed class SeparatorItem : SubSeparatorItem
                 {
-                    public SubShellItem(string regPath) : base(regPath)
+                    public SeparatorItem(PrivateMultiItemsList list, string regPath)
                     {
-                        TsiOtherAttributes.DropDownItems.Add(tsiShowSeparator);
-                        tsiShowSeparator.Click += (sender, e) => ShowSeparator = !tsiShowSeparator.Checked;
-                        ContextMenuStrip.Opening += (sender, e) => tsiShowSeparator.Checked = ShowSeparator;
+                        this.Owner = list;
+                        this.RegPath = regPath;
+                        BtnMoveUp.MouseDown += (sender, e) => Owner.MoveItem(this, true);
+                        BtnMoveDown.MouseDown += (sender, e) => Owner.MoveItem(this, false);
                     }
 
-                    protected override bool IsSubItem => true;
+                    public PrivateMultiItemsList Owner { get; private set; }
+                    public string RegPath { get; private set; }
 
-                    private bool ShowSeparator
+                    public override void DeleteMe()
                     {
-                        get
-                        {
-                            int value = Convert.ToInt32(GetValue(RegPath, "CommandFlags", 0)) % 64;
-                            return value >= 32 && value < 56;
-                        }
-                        set
-                        {
-                            if(value) SetValue(RegPath, "CommandFlags", 32, Microsoft.Win32.RegistryValueKind.DWord);
-                            else RegistryEx.DeleteValue(RegPath, "CommandFlags");
-                        }
+                        RegistryEx.DeleteKeyTree(this.RegPath);
+                        this.Dispose();
                     }
+                }
+            }
+
+            class SubSeparatorItem : MyListItem, IBtnDeleteItem, IBtnMoveUpDownItem
+            {
+                public SubSeparatorItem()
+                {
+                    this.Text = AppString.Item.Separator;
+                    this.Image = AppImage.Separator;
+                    BtnDelete = new DeleteButton(this);
+                    BtnMoveDown = new MoveButton(this, false);
+                    BtnMoveUp = new MoveButton(this, true);
+                    MyToolTip.SetToolTip(this, AppString.Tip.Separator);
+                    MyToolTip.SetToolTip(BtnDelete, AppString.Menu.Delete);
+                }
+
+                public DeleteButton BtnDelete { get; set; }
+                public MoveButton BtnMoveUp { get; set; }
+                public MoveButton BtnMoveDown { get; set; }
+
+                public virtual void DeleteMe() { }
+            }
 
-                    readonly ToolStripMenuItem tsiShowSeparator = new ToolStripMenuItem(AppString.Menu.ShowSeparator);
+            class SubShellTypeItem : ShellItem, IBtnMoveUpDownItem
+            {
+                public SubShellTypeItem(string regPath) : base(regPath)
+                {
+                    BtnMoveDown = new MoveButton(this, false);
+                    BtnMoveUp = new MoveButton(this, true);
+                    this.SetCtrIndex(BtnMoveDown, 1);
+                    this.SetCtrIndex(BtnMoveUp, 2);
                 }
+
+                public MoveButton BtnMoveUp { get; set; }
+                public MoveButton BtnMoveDown { get; set; }
+
+                protected override bool IsSubItem => true;
+
+                public static bool CanAddMore(MyList list)
+                {
+                    int count = 0;
+                    foreach(Control item in list.Controls)
+                    {
+                        if(item.GetType().BaseType == typeof(SubShellTypeItem)) count++;
+                    }
+                    bool flag = count < 16;
+                    if(!flag) MessageBoxEx.Show(AppString.MessageBox.CannotAddNewItem);
+                    return flag;
+                }
+            }
+
+            sealed class SubNewItem : NewItem
+            {
+                public SubNewItem(bool isPublic)
+                {
+                    this.AddCtrs(new[] { btnAddExisting, btnAddSeparator });
+                    MyToolTip.SetToolTip(btnAddExisting, isPublic ? AppString.Tip.AddReference : AppString.Tip.AddFromParentMenu);
+                    MyToolTip.SetToolTip(btnAddSeparator, AppString.Tip.AddSeparator);
+                    btnAddExisting.MouseDown += (sender, e) => AddExisting?.Invoke(null, null);
+                    btnAddSeparator.MouseDown += (sender, e) => AddSeparator?.Invoke(null, null);
+                }
+
+                readonly PictureButton btnAddExisting = new PictureButton(AppImage.AddExisting);
+                readonly PictureButton btnAddSeparator = new PictureButton(AppImage.AddSeparator);
+
+                public event EventHandler AddExisting;
+                public event EventHandler AddSeparator;
             }
         }
     }

+ 0 - 57
ContextMenuManager/Controls/SubMenuModeForm.cs

@@ -1,57 +0,0 @@
-using BulePointLilac.Methods;
-using System.Drawing;
-using System.Windows.Forms;
-
-namespace ContextMenuManager.Controls
-{
-    class SubMenuModeForm : Form
-    {
-        public SubMenuModeForm()
-        {
-            this.Text = AppString.General.AppName;
-            this.FormBorderStyle = FormBorderStyle.FixedSingle;
-            this.StartPosition = FormStartPosition.CenterParent;
-            this.ControlBox = this.ShowIcon = this.ShowInTaskbar = false;
-            this.Font = new Font(SystemFonts.MessageBoxFont.FontFamily, 9F);
-            this.Controls.AddRange(new Control[] { pnlTop, btnOne, btnTwo });
-            pnlTop.Controls.Add(lblInfo);
-            int a = 20.DpiZoom();
-            this.ClientSize = new Size(lblInfo.Width + 2 * a, lblInfo.Height + btnOne.Height + 3 * a);
-            lblInfo.Location = new Point(a, a);
-            pnlTop.Height = lblInfo.Bottom + a;
-            btnOne.Top = btnTwo.Top = pnlTop.Bottom + a / 2;
-            btnTwo.Left = pnlTop.Width - btnTwo.Width - a;
-            btnOne.Left = btnTwo.Left - btnOne.Width - a;
-            btnOne.Click += (sender, e) => SubMenuMode = 1;
-            btnTwo.Click += (sender, e) => SubMenuMode = 2;
-        }
-
-        public int SubMenuMode { get; private set; }
-
-        readonly Label lblInfo = new Label
-        {
-            AutoSize = true,
-            Text = AppString.Dialog.SelectSubMenuMode,
-        };
-
-        readonly Panel pnlTop = new Panel
-        {
-            BackColor = Color.White,
-            Dock = DockStyle.Top
-        };
-
-        readonly Button btnOne = new Button
-        {
-            DialogResult = DialogResult.OK,
-            AutoSize = true,
-            Text = "①",
-        };
-
-        readonly Button btnTwo = new Button
-        {
-            DialogResult = DialogResult.OK,
-            AutoSize = true,
-            Text = "②",
-        };
-    }
-}

+ 61 - 49
ContextMenuManager/Controls/ThirdRulesList.cs

@@ -13,68 +13,80 @@ namespace ContextMenuManager.Controls
     {
         public void LoadItems()
         {
-            this.ClearItems();
-            XmlDocument doc1 = new XmlDocument();
-            if(!File.Exists(Program.AppDataThirdRulesDicPath))
-            {
-                File.WriteAllText(Program.AppDataThirdRulesDicPath, Properties.Resources.ThirdRulesDic, Encoding.UTF8);
-            }
-            doc1.Load(Program.AppDataThirdRulesDicPath);
-            if(File.Exists(Program.ThirdRulesDicPath))
-            {
-                XmlDocument doc2 = new XmlDocument();
-                doc2.Load(Program.ThirdRulesDicPath);
-                foreach(XmlNode xn in doc2.DocumentElement.ChildNodes)
-                {
-                    XmlNode node = doc1.ImportNode(xn, true);
-                    doc1.DocumentElement.AppendChild(node);
-                }
-            }
-            foreach(XmlElement groupXE in doc1.DocumentElement.ChildNodes)
+            try
             {
-                Guid guid = Guid.Empty;
-                if(groupXE.HasAttribute("Guid") && !GuidInfo.TryGetGuid(groupXE.GetAttribute("Guid"), out guid)) continue;
-
-                GroupPathItem groupItem = new GroupPathItem
+                foreach(XmlElement groupXE in ReadXml().DocumentElement.ChildNodes)
                 {
-                    Text = groupXE.GetAttribute("Text"),
-                    TargetPath = groupXE.GetAttribute("RegPath"),
-                    PathType = ObjectPath.PathType.Registry,
-                    Image = GuidInfo.GetImage(guid),
-                };
-                if(groupItem.Text.IsNullOrWhiteSpace()) groupItem.Text = GuidInfo.GetText(guid);
-                this.AddItem(groupItem);
+                    Guid guid = Guid.Empty;
+                    if(groupXE.HasAttribute("Guid") && !GuidInfo.TryGetGuid(groupXE.GetAttribute("Guid"), out guid)) continue;
 
-                foreach(XmlElement itemXE in groupXE.ChildNodes)
-                {
-                    RegRuleItem.ItemInfo itemInfo = new RegRuleItem.ItemInfo
+                    GroupPathItem groupItem = new GroupPathItem(groupXE.GetAttribute("RegPath"), ObjectPath.PathType.Registry)
                     {
-                        Text = itemXE.GetAttribute("Text"),
-                        Tip = itemXE.GetAttribute("Tip"),
-                        RestartExplorer = itemXE.HasAttribute("RestartExplorer"),
+                        Text = groupXE.GetAttribute("Text"),
+                        Image = GuidInfo.GetImage(guid),
                     };
+                    if(groupItem.Text.IsNullOrWhiteSpace()) groupItem.Text = GuidInfo.GetText(guid);
+                    this.AddItem(groupItem);
 
-                    XmlNodeList ruleXNList = itemXE.GetElementsByTagName("Rule");//Rules
-                    RegRuleItem.RegRule[] rules = new RegRuleItem.RegRule[ruleXNList.Count];
-                    for(int i = 0; i < ruleXNList.Count; i++)
+                    foreach(XmlElement itemXE in groupXE.ChildNodes)
                     {
-                        XmlElement ruleXE = (XmlElement)ruleXNList[i];
-                        rules[i] = new RegRuleItem.RegRule
+                        XmlElement verXE = (XmlElement)itemXE.SelectSingleNode("OSVersion");
+                        if(!EnhanceMenusList.JudgeOSVersion(verXE)) continue;
+                        RegRuleItem.ItemInfo itemInfo = new RegRuleItem.ItemInfo
                         {
-                            RegPath = ruleXE.GetAttribute("RegPath"),
-                            ValueName = ruleXE.GetAttribute("ValueName"),
-                            TurnOnValue = ruleXE.GetAttribute("On"),
-                            TurnOffValue = ruleXE.GetAttribute("Off"),
-                            ValueKind = GetValueKind(ruleXE.GetAttribute("ValueKind"))
+                            Text = itemXE.GetAttribute("Text"),
+                            Tip = itemXE.GetAttribute("Tip"),
+                            RestartExplorer = itemXE.HasAttribute("RestartExplorer"),
                         };
-                        if(string.IsNullOrEmpty(rules[i].RegPath)) rules[i].RegPath = groupItem.TargetPath;
-                        else if(rules[i].RegPath.StartsWith("\\")) rules[i].RegPath = groupItem.TargetPath + rules[i].RegPath;
+
+                        XmlNodeList ruleXNList = itemXE.GetElementsByTagName("Rule");//Rules
+                        RegRuleItem.RegRule[] rules = new RegRuleItem.RegRule[ruleXNList.Count];
+                        for(int i = 0; i < ruleXNList.Count; i++)
+                        {
+                            XmlElement ruleXE = (XmlElement)ruleXNList[i];
+                            rules[i] = new RegRuleItem.RegRule
+                            {
+                                RegPath = ruleXE.GetAttribute("RegPath"),
+                                ValueName = ruleXE.GetAttribute("ValueName"),
+                                TurnOnValue = ruleXE.GetAttribute("On"),
+                                TurnOffValue = ruleXE.GetAttribute("Off"),
+                                ValueKind = GetValueKind(ruleXE.GetAttribute("ValueKind"))
+                            };
+                            if(string.IsNullOrEmpty(rules[i].RegPath)) rules[i].RegPath = groupItem.TargetPath;
+                            else if(rules[i].RegPath.StartsWith("\\")) rules[i].RegPath = groupItem.TargetPath + rules[i].RegPath;
+                        }
+
+                        this.AddItem(new RegRuleItem(rules, itemInfo) { FoldGroupItem = groupItem, HasImage = false });
                     }
+                    groupItem.IsFold = true;
+                }
+            }
+            catch { }
+        }
 
-                    this.AddItem(new RegRuleItem(rules, itemInfo) { FoldGroupItem = groupItem });
+        private XmlDocument ReadXml()
+        {
+            XmlDocument doc1 = new XmlDocument();
+            try
+            {
+                if(!File.Exists(AppConfig.WebThirdRulesDic))
+                {
+                    File.WriteAllText(AppConfig.WebThirdRulesDic, Properties.Resources.ThirdRulesDic, Encoding.UTF8);
+                }
+                doc1.Load(AppConfig.WebThirdRulesDic);
+                if(File.Exists(AppConfig.UserThirdRulesDic))
+                {
+                    XmlDocument doc2 = new XmlDocument();
+                    doc2.Load(AppConfig.UserThirdRulesDic);
+                    foreach(XmlNode xn in doc2.DocumentElement.ChildNodes)
+                    {
+                        XmlNode node = doc1.ImportNode(xn, true);
+                        doc1.DocumentElement.AppendChild(node);
+                    }
                 }
-                groupItem.IsFold = true;
             }
+            catch { }
+            return doc1;
         }
 
         private static RegistryValueKind GetValueKind(string data)

+ 2 - 1
ContextMenuManager/Controls/WinXItem.cs

@@ -36,7 +36,7 @@ namespace ContextMenuManager.Controls
             get
             {
                 string name = Shortcut.Description.Trim();
-                if(name == string.Empty) name = WinXList.GetMenuName(FilePath);
+                if(name == string.Empty) name = WinXList.GetItemText(FilePath);
                 if(name == string.Empty) name = Path.GetFileNameWithoutExtension(FilePath);
                 return name;
             }
@@ -44,6 +44,7 @@ namespace ContextMenuManager.Controls
             {
                 Shortcut.Description = value;
                 Shortcut.Save();
+                this.Text = ResourceString.GetDirectString(value);
                 ExplorerRestarter.NeedRestart = true;
             }
         }

+ 4 - 11
ContextMenuManager/Controls/WinXList.cs

@@ -12,7 +12,7 @@ namespace ContextMenuManager.Controls
         public static readonly string WinXPath = Environment.ExpandEnvironmentVariables(@"%LocalAppData%\Microsoft\Windows\WinX");
         private static readonly Dictionary<string, IniReader> DesktopIniReaders = new Dictionary<string, IniReader>();
 
-        public static string GetMenuName(string filePath)
+        public static string GetItemText(string filePath)
         {
             string dirPath = Path.GetDirectoryName(filePath);
             string fileName = Path.GetFileName(filePath);
@@ -27,26 +27,19 @@ namespace ContextMenuManager.Controls
 
         public void LoadItems()
         {
-            Version ver = Environment.OSVersion.Version;
-            bool isWin10= ver.Major == 10;
-            bool isWin8 = (ver.Major == 6) && (ver.Minor >= 2);
-            if(isWin10 || isWin8)
+            if(WindowsOsVersion.ISAfterOrEqual8)
             {
-                this.ClearItems();
                 DesktopIniReaders.Clear();
                 Array.ForEach(new DirectoryInfo(WinXPath).GetDirectories(), di => LoadSubDirItems(di));
-                if(isWin10) this.AddItem(new RegRuleItem(RegRuleItem.WinXPowerShell) { MarginRight = RegRuleItem.SysMarginRignt });
             }
         }
 
         private void LoadSubDirItems(DirectoryInfo di)
         {
-            GroupPathItem groupItem = new GroupPathItem
+            GroupPathItem groupItem = new GroupPathItem(di.FullName, ObjectPath.PathType.Directory)
             {
-                TargetPath = di.FullName,
                 Text = Path.GetFileNameWithoutExtension(di.FullName),
-                Image = ResourceIcon.GetFolderIcon(di.FullName).ToBitmap(),
-                PathType = ObjectPath.PathType.Directory
+                Image = ResourceIcon.GetFolderIcon(di.FullName).ToBitmap()
             };
             this.AddItem(groupItem);
             string iniPath = $@"{di.FullName}\desktop.ini";

+ 24 - 9
ContextMenuManager/GuidInfo.cs

@@ -2,6 +2,7 @@
 using Microsoft.Win32;
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Drawing;
 using System.IO;
 using System.Text;
@@ -23,7 +24,7 @@ namespace ContextMenuManager
         }
 
         private static IniReader AppDic;
-        public static readonly IniReader UserDic = new IniReader(Program.GuidInfosDicPath);
+        public static readonly IniReader UserDic = new IniReader(AppConfig.UserGuidInfosDic);
         public static readonly Dictionary<Guid, IconLocation> IconLocationDic = new Dictionary<Guid, IconLocation>();
         private static readonly Dictionary<Guid, string> FilePathDic = new Dictionary<Guid, string>();
         public static readonly Dictionary<Guid, string> ItemTextDic = new Dictionary<Guid, string>();
@@ -52,11 +53,10 @@ namespace ContextMenuManager
         private static bool TryGetValue(string section, string key, out string value)
         {
             //用户自定义字典优先
-            if(UserDic != null && UserDic.TryGetValue(section, key, out value)) return true;
-            if(!File.Exists(Program.AppDataGuidInfosDicPath))
-                File.WriteAllText(Program.AppDataGuidInfosDicPath, Properties.Resources.GuidInfosDic, Encoding.UTF8);
-            if(AppDic == null)
-                AppDic = new IniReader(Program.AppDataGuidInfosDicPath);
+            if(UserDic.TryGetValue(section, key, out value)) return true;
+            if(!File.Exists(AppConfig.WebGuidInfosDic))
+                File.WriteAllText(AppConfig.WebGuidInfosDic, Properties.Resources.GuidInfosDic, Encoding.UTF8);
+            AppDic = AppDic ?? new IniReader(AppConfig.WebGuidInfosDic);
             if(AppDic.TryGetValue(section, key, out value)) return true;
             return false;
         }
@@ -82,6 +82,7 @@ namespace ContextMenuManager
                                 if(File.Exists(filePath)) break;
                             }
                         }
+                        if(File.Exists(filePath)) break;
                     }
                 }
                 FilePathDic.Add(guid, filePath);
@@ -99,6 +100,7 @@ namespace ContextMenuManager
                 if(TryGetValue(guid.ToString(), "Text", out itemText))
                 {
                     itemText = GetAbsStr(guid, itemText, true);
+                    itemText = ResourceString.GetDirectString(itemText);
                 }
                 if(itemText.IsNullOrWhiteSpace())
                 {
@@ -107,12 +109,25 @@ namespace ContextMenuManager
                         foreach(string value in new[] { "LocalizedString", "InfoTip", "" })
                         {
                             itemText = Registry.GetValue($@"{clsidPath}\{guid:B}", value, null)?.ToString();
-                            if(!string.IsNullOrEmpty(itemText)) break;
+                            itemText = ResourceString.GetDirectString(itemText);
+                            if(!itemText.IsNullOrWhiteSpace()) break;
                         }
+                        if(!itemText.IsNullOrWhiteSpace()) break;
                     }
                 }
-                itemText = ResourceString.GetDirectString(itemText);
-                if(itemText.IsNullOrWhiteSpace()) itemText = null;
+                if(itemText.IsNullOrWhiteSpace())
+                {
+                    string filePath = GetFilePath(guid);
+                    if(filePath != null)
+                    {
+                        itemText = FileVersionInfo.GetVersionInfo(filePath).FileDescription;
+                        if(itemText.IsNullOrWhiteSpace())
+                        {
+                            itemText = Path.GetFileName(filePath);
+                        }
+                    }
+                    else itemText = null;
+                }
                 ItemTextDic.Add(guid, itemText);
             }
             return itemText;

+ 65 - 27
ContextMenuManager/MainForm.cs

@@ -2,6 +2,7 @@
 using ContextMenuManager.Controls;
 using System;
 using System.Linq;
+using System.Windows.Forms;
 
 namespace ContextMenuManager
 {
@@ -12,12 +13,13 @@ namespace ContextMenuManager
             SetSideBarWidth();
             this.Text = AppString.General.AppName;
             this.Controls.Add(new ExplorerRestarter());
-            shellList.Owner = shellNewList.Owner = sendToList.Owner = openWithList.Owner
-                = winXList.Owner = guidBlockedList.Owner = thirdRuleList.Owner = MainBody;
+            appSettingBox.Owner = shellList.Owner = shellNewList.Owner = sendToList.Owner = openWithList.Owner
+                = winXList.Owner = guidBlockedList.Owner = enhanceMenusList.Owner = thirdRuleList.Owner = MainBody;
             donateBox.Parent = aboutMeBox.Parent = dictionariesBox.Parent = languagesBox.Parent = MainBody;
             SideBar.SelectIndexChanged += (sender, e) => SwitchItem();
             SideBar.HoverIndexChanged += (sender, e) => ShowItemInfo();
             ToolBar.SelectedButtonChanged += (sender, e) => SwitchTab();
+            ((RefreshButton)ToolBarButtons[3]).ClickMe += (sender, e) => SideBar.SelectIndex = SideBar.SelectIndex;
             ToolBar.AddButtons(ToolBarButtons);
             ToolBar.SelectedIndex = 0;
         }
@@ -26,6 +28,7 @@ namespace ContextMenuManager
             new MyToolBarButton(AppImage.Home, AppString.ToolBar.Home),//主页
             new MyToolBarButton(AppImage.Type, AppString.ToolBar.Type),//文件类型
             new MyToolBarButton(AppImage.Star, AppString.ToolBar.Rule),//其他规则
+            new RefreshButton(),//刷新
             new MyToolBarButton(AppImage.About, AppString.ToolBar.About)//关于
         };
         readonly ShellList shellList = new ShellList();
@@ -34,14 +37,16 @@ namespace ContextMenuManager
         readonly OpenWithList openWithList = new OpenWithList();
         readonly WinXList winXList = new WinXList();
         readonly GuidBlockedList guidBlockedList = new GuidBlockedList();
+        readonly EnhanceMenusList enhanceMenusList = new EnhanceMenusList();
         readonly ThirdRulesList thirdRuleList = new ThirdRulesList();
-        readonly AboutAppBox aboutMeBox = new AboutAppBox
+        readonly ReadOnlyRichTextBox aboutMeBox = new ReadOnlyRichTextBox
         {
             Text = AppString.Other.AboutApp
         };
         readonly DonateBox donateBox = new DonateBox();
         readonly LanguagesBox languagesBox = new LanguagesBox();
         readonly DictionariesBox dictionariesBox = new DictionariesBox();
+        readonly AppSettingBox appSettingBox = new AppSettingBox();
 
         static readonly string[] GeneralItems = {
             AppString.SideBar.File,
@@ -118,18 +123,25 @@ namespace ContextMenuManager
         };
 
         static readonly string[] OtherRuleItems = {
-            AppString.SideBar.GuidBlocked,
-            AppString.SideBar.ThirdRules
+            AppString.SideBar.EnhanceMenu,
+            AppString.SideBar.ThirdRules,
+            null,
+            AppString.SideBar.PublicReferences,
+            AppString.SideBar.GuidBlocked
         };
         static readonly string[] OtherRuleItemInfos = {
-            AppString.StatusBar.GuidBlocked,
-            AppString.StatusBar.ThirdRules
+            AppString.StatusBar.EnhanceMenu,
+            AppString.StatusBar.ThirdRules,
+            null,
+            AppString.StatusBar.PublicReferences,
+            AppString.StatusBar.GuidBlocked
         };
 
         static readonly string[] AboutItems = {
-            AppString.SideBar.AboutApp,
-            AppString.SideBar.Dictionaries,
+            AppString.SideBar.AppSetting,
             AppString.SideBar.AppLanguage,
+            AppString.SideBar.Dictionaries,
+            AppString.SideBar.AboutApp,
             AppString.SideBar.Donate
         };
 
@@ -169,9 +181,15 @@ namespace ContextMenuManager
 
         private void HideAllParts()
         {
-            shellList.Visible = shellNewList.Visible = sendToList.Visible = openWithList.Visible
-                = winXList.Visible = guidBlockedList.Visible = thirdRuleList.Visible
-                = donateBox.Visible = aboutMeBox.Visible = dictionariesBox.Visible = languagesBox.Visible = false;
+            foreach(Control ctr in MainBody.Controls)
+            {
+                ctr.Visible = false;
+                if(ctr.GetType().BaseType == typeof(MyList))
+                {
+                    if(ctr == appSettingBox) continue;
+                    ((MyList)ctr).ClearItems();
+                }
+            }
         }
 
         private void SwitchTab()
@@ -184,7 +202,7 @@ namespace ContextMenuManager
                     SideBar.ItemNames = TypeItems; break;
                 case 2:
                     SideBar.ItemNames = OtherRuleItems; break;
-                case 3:
+                case 4:
                     SideBar.ItemNames = AboutItems; break;
             }
             SideBar.SelectIndex = 0;
@@ -197,13 +215,13 @@ namespace ContextMenuManager
             switch(ToolBar.SelectedIndex)
             {
                 case 0:
-                    SwitchGeneralItem(); return;
+                    SwitchGeneralItem(); break;
                 case 1:
-                    SwitchTypeItem(); return;
+                    SwitchTypeItem(); break;
                 case 2:
-                    SwitchOtherRuleItem(); return;
-                case 3:
-                    SwitchAboutItem(); return;
+                    SwitchOtherRuleItem(); break;
+                case 4:
+                    SwitchAboutItem(); break;
             }
         }
 
@@ -258,9 +276,13 @@ namespace ContextMenuManager
             switch(SideBar.SelectIndex)
             {
                 case 0:
-                    guidBlockedList.LoadItems(); guidBlockedList.Visible = true; return;
+                    enhanceMenusList.LoadItems(); enhanceMenusList.Visible = true; break;
                 case 1:
-                    thirdRuleList.LoadItems(); thirdRuleList.Visible = true; return;
+                    thirdRuleList.LoadItems(); thirdRuleList.Visible = true; break;
+                case 3:
+                    shellList.Scene = ShellList.Scenes.CommandStore; shellList.Visible = true; break;
+                case 4:
+                    guidBlockedList.LoadItems(); guidBlockedList.Visible = true; break;
             }
         }
 
@@ -269,19 +291,23 @@ namespace ContextMenuManager
             switch(SideBar.SelectIndex)
             {
                 case 0:
-                    aboutMeBox.Visible = true;
-                    return;
+                    appSettingBox.LoadItems();
+                    appSettingBox.Visible = true;
+                    break;
                 case 1:
-                    dictionariesBox.Visible = true;
-                    dictionariesBox.LoadTexts();
-                    return;
-                case 2:
                     languagesBox.LoadLanguages();
                     languagesBox.Visible = true;
                     break;
+                case 2:
+                    dictionariesBox.LoadTexts();
+                    dictionariesBox.Visible = true;
+                    break;
                 case 3:
+                    aboutMeBox.Visible = true;
+                    break;
+                case 4:
                     donateBox.Visible = true;
-                    return;
+                    break;
             }
         }
 
@@ -292,5 +318,17 @@ namespace ContextMenuManager
             Array.ForEach(strs, str => maxWidth = Math.Max(maxWidth, SideBar.GetItemWidth(str)));
             SideBar.Width = maxWidth;
         }
+
+        sealed class RefreshButton : MyToolBarButton
+        {
+            public RefreshButton() : base(AppImage.Refresh, AppString.ToolBar.Refresh) { }
+
+            public EventHandler ClickMe;
+
+            protected override void OnMouseDown(MouseEventArgs e)
+            {
+                ClickMe?.Invoke(null, null);
+            }
+        }
     }
 }

+ 7 - 81
ContextMenuManager/Program.cs

@@ -1,97 +1,23 @@
-using BulePointLilac.Methods;
-using System;
-using System.Globalization;
-using System.IO;
-using System.Runtime.InteropServices;
+using System;
 using System.Windows.Forms;
 
 namespace ContextMenuManager
 {
-    //完美兼容.Net Framework 3.5(Win7)、.Net Framework 4.5(Win8、Win8.1)、.Net Framework 4.6(Win10)
-    //避免用户未安装或不会安装系统未自带的.Net Framework版本,这样可以直接启动程序,不用担心框架问题,
-    //Win10和Win8、Win8.1可共用一个exe文件(.Net Framework 4.5),Win7另用一个版本(.Net Framework 3.5)
+    //使用VS 2017、VS 2019编译通过,最低兼容.Net Framework 3.5
     //在编译前在Properties\应用程序\目标框架中修改为对应框架即可
+    //完美兼容.Net Framework 3.5(Win7自带)、.Net Framework 4(Win8、Win8.1、Win10自带)
+    //避免用户未安装或不会安装系统未携带对应版本的.Net Framework,这样可以直接启动程序,不用担心.Net框架问题,
+    //同时兼容Vista,但是需要已安装.Net Framework 3.5或.Net Framework 4才能使用对应的版本
+    //实在不想再往.Net Framework 3.0兼容了,xp系统更不用说,直接放弃
     static class Program
     {
-        public const string ZH_CNINI = "zh-CN.ini";
-        public const string CONFIGINI = "config.ini";
-        public const string GUIDINFOSDICINI = "GuidInfosDic.ini";
-        public const string ThIRDRULESDICXML = "ThirdRulesDic.xml";
-        public const string SHELLCOMMONDICXML = "ShellCommonDic.xml";
-        public static readonly string ConfigDir = $@"{Application.StartupPath}\config";
-        public static readonly string LanguagesDir = $@"{ConfigDir}\languages";
-        public static readonly string AppDataConfigDir = $@"{Environment.ExpandEnvironmentVariables("%AppData%")}\ContextMenuManager\config";
-        public static readonly string ConfigIniPath = $@"{AppDataConfigDir}\{CONFIGINI}";
-        public static readonly string GuidInfosDicPath = $@"{ConfigDir}\{GUIDINFOSDICINI}";
-        public static readonly string AppDataGuidInfosDicPath = $@"{AppDataConfigDir}\{GUIDINFOSDICINI}";
-        public static readonly string ThirdRulesDicPath = $@"{ConfigDir}\{ThIRDRULESDICXML}";
-        public static readonly string AppDataThirdRulesDicPath = $@"{AppDataConfigDir}\{ThIRDRULESDICXML}";
-        public static readonly string ShellCommonDicPath = $@"{ConfigDir}\{SHELLCOMMONDICXML}";
-        public static readonly string AppDataShellCommonDicPath = $@"{AppDataConfigDir}\{SHELLCOMMONDICXML}";
-        private static readonly IniReader ConfigReader = new IniReader(ConfigIniPath);
-        public static readonly DateTime LastCheckUpdateTime;
-
-        private static string languageFilePath = null;
-        public static string LanguageFilePath
-        {
-            get
-            {
-                if(languageFilePath != null) return languageFilePath;
-                languageFilePath = ConfigReader.GetValue("General", "Language");
-                DirectoryInfo di = new DirectoryInfo(LanguagesDir);
-                if(languageFilePath.Equals(string.Empty) && di.Exists)
-                {
-                    string sysLanguageName = new CultureInfo(GetUserDefaultUILanguage()).Name;
-                    foreach(FileInfo fi in di.GetFiles())
-                    {
-                        string fileName = Path.GetFileNameWithoutExtension(fi.Name);
-                        if(fileName.Equals(sysLanguageName, StringComparison.OrdinalIgnoreCase))
-                        {
-                            languageFilePath = fi.FullName; break;
-                        }
-                    }
-                }
-                else if(!File.Exists(languageFilePath))
-                {
-                    languageFilePath = string.Empty;
-                }
-                return languageFilePath;
-            }
-        }
-
         [STAThread]
         static void Main()
         {
+            Updater.PeriodicUpdate();
             Application.EnableVisualStyles();
             Application.SetCompatibleTextRenderingDefault(false);
             Application.Run(new MainForm());
         }
-
-        [DllImport("kernel32.dll")]
-        private static extern ushort GetUserDefaultUILanguage();
-
-        static Program()
-        {
-            Directory.CreateDirectory(AppDataConfigDir);
-            try
-            {
-                string time = ConfigReader.GetValue("General", "LastCheckUpdateTime");
-                //二进制数据时间不会受系统时间格式影响
-                LastCheckUpdateTime = DateTime.FromBinary(Convert.ToInt64(time));
-            }
-            catch
-            {
-                //将上次检测更新时间推前到两个月前
-                LastCheckUpdateTime = DateTime.Today.AddMonths(-2);
-            }
-            //如果上次检测更新时间为一个月以前就进行更新操作
-            if(LastCheckUpdateTime.AddMonths(1).CompareTo(DateTime.Today) < 0)
-            {
-                Updater.CheckUpdate();
-                string time = DateTime.Today.ToBinary().ToString();
-                IniFileHelper helper = new IniFileHelper(ConfigIniPath);
-                new IniFileHelper(ConfigIniPath).SetValue("General", "LastCheckUpdateTime", time);
-            }
-        }
     }
 }

+ 2 - 2
ContextMenuManager/Properties/AssemblyInfo.cs

@@ -11,5 +11,5 @@ using System.Runtime.InteropServices;
 [assembly: AssemblyCulture("")]
 [assembly: ComVisible(false)]
 [assembly: Guid("35190ec1-2515-488d-a2e9-825d6ff67aa2")]
-[assembly: AssemblyVersion("3.0.0.0")]
-[assembly: AssemblyFileVersion("3.0.0.0")]
+[assembly: AssemblyVersion("2.1.0.0")]
+[assembly: AssemblyFileVersion("2.1.0.0")]

+ 34 - 31
ContextMenuManager/Properties/Resources.Designer.cs

@@ -80,16 +80,6 @@ namespace ContextMenuManager.Properties {
             }
         }
         
-        /// <summary>
-        ///   查找 System.Drawing.Bitmap 类型的本地化资源。
-        /// </summary>
-        internal static System.Drawing.Bitmap AddCommon {
-            get {
-                object obj = ResourceManager.GetObject("AddCommon", resourceCulture);
-                return ((System.Drawing.Bitmap)(obj));
-            }
-        }
-        
         /// <summary>
         ///   查找 System.Drawing.Bitmap 类型的本地化资源。
         /// </summary>
@@ -113,7 +103,7 @@ namespace ContextMenuManager.Properties {
         /// <summary>
         ///   查找类似 ;此文件为ContextMenuManager程序的显示文本字典, 字典内换行符使用\n转义
         ///;如果你想要帮助作者为此程序添加其他语言字典, 可以修改此文本并保存在.\config\languages文件夹内, 
-        ///;比如美国英语字典保存为en-US.ini, 并给[General]\Language赋值 en-US 英语
+        ///;比如美国英语字典保存为en-US.ini, 并给[General]\Language赋值 en-US English
         ///;可以在Github或Gitee上Fork该项目并提交申请给我,或者直接发送文件到邮箱[email protected]
         ///
         ///[General]
@@ -125,6 +115,7 @@ namespace ContextMenuManager.Properties {
         ///Home = 主页
         ///Type = 文件类型
         ///Rule = 其他规则
+        ///Refresh = 刷新
         ///About = 关于
         ///
         ///[SideBar]
@@ -135,8 +126,7 @@ namespace ContextMenuManager.Properties {
         ///Desktop = 桌面背景
         ///Drive = 磁盘分区
         ///AllObjects = 所有对象
-        ///Computer = 此电脑
-        ///Recy [字符串的其余部分被截断]&quot;; 的本地化字符串。
+        ///C [字符串的其余部分被截断]&quot;; 的本地化字符串。
         /// </summary>
         internal static string AppLanguageDic {
             get {
@@ -174,6 +164,26 @@ namespace ContextMenuManager.Properties {
             }
         }
         
+        /// <summary>
+        ///   查找类似 &lt;?xml version=&apos;1.0&apos; encoding=&apos;utf-8&apos; ?&gt;
+        ///&lt;!--此文件为常用右键菜单字典,
+        ///Tip属性为鼠标悬浮在开关上时的提示信息,从每个Item节点开始, 子元素Value表示该项的注册表键值,目前仅支持REG_SZ、REG_DWORD、REG_EXPAND_SZ的键值类型,
+        ///子元素SubKey的所有子元素是该项的子项,项名即为元素名; 每一Item项和SubKey的所有子元素的属性Default为该注册表项默认值,不放在Value\REG_SZ元素里面是为了防止与可能存在的键名为Default的键产生冲突--&gt;
+        ///&lt;Data&gt;
+        ///  &lt;File&gt;
+        ///    &lt;Shell&gt;
+        ///      &lt;Item KeyName=&apos;CopyContent&apos; Tip=&apos;不需打开文件直接复制文件文本内容&amp;#x000A;非UTF-16 LE(或带BOM)编码会乱码&apos;&gt;
+        ///        &lt;Value&gt;
+        ///          &lt;REG_SZ MUIVerb=&apos;复制内容到剪切板&apos; Icon=&apos;DxpTaskSync.dll,-52&apos;/&gt;
+        ///        &lt;/Value&gt;
+        ///        &lt;Sub [字符串的其余部分被截断]&quot;; 的本地化字符串。
+        /// </summary>
+        internal static string EnhanceMenusDic {
+            get {
+                return ResourceManager.GetString("EnhanceMenusDic", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   查找类似 ;&lt;说明&gt;:
         ///;由于ShellEx类型右键菜单的菜单名称和图标无法直接获取,只能通过制作字典给用户更直观的体验
@@ -246,9 +256,9 @@ namespace ContextMenuManager.Properties {
         /// <summary>
         ///   查找 System.Drawing.Bitmap 类型的本地化资源。
         /// </summary>
-        internal static System.Drawing.Bitmap SeparatorItem {
+        internal static System.Drawing.Bitmap Refresh {
             get {
-                object obj = ResourceManager.GetObject("SeparatorItem", resourceCulture);
+                object obj = ResourceManager.GetObject("Refresh", resourceCulture);
                 return ((System.Drawing.Bitmap)(obj));
             }
         }
@@ -256,28 +266,20 @@ namespace ContextMenuManager.Properties {
         /// <summary>
         ///   查找 System.Drawing.Bitmap 类型的本地化资源。
         /// </summary>
-        internal static System.Drawing.Bitmap Setting {
+        internal static System.Drawing.Bitmap SeparatorItem {
             get {
-                object obj = ResourceManager.GetObject("Setting", resourceCulture);
+                object obj = ResourceManager.GetObject("SeparatorItem", resourceCulture);
                 return ((System.Drawing.Bitmap)(obj));
             }
         }
         
         /// <summary>
-        ///   查找类似 &lt;?xml version=&apos;1.0&apos; encoding=&apos;utf-8&apos; ?&gt;
-        ///&lt;!--此文件为常用右键菜单字典,
-        ///Tip属性为鼠标悬浮在开关上时的提示信息,从每个Item节点开始, 子元素Value表示该项的注册表键值,目前仅支持REG_SZ、REG_DWORD、REG_EXPAND_SZ的键值类型,
-        ///,子元素SubKey的所有子元素是该项的子项,项名即为元素名; 每一Item项和SubKey的所有子元素的属性Default为该注册表项默认值,不放在Value\REG_SZ元素里面是为了防止与可能存在的键名为Default的键产生冲突--&gt;
-        ///&lt;Data&gt;
-        ///  &lt;Group RegPath=&apos;HKEY_CLASSES_ROOT\*&apos;&gt;
-        ///    &lt;Shell&gt;
-        ///      &lt;Item KeyName=&apos;CopyContent&apos; Tip=&apos;不需打开文件直接复制文件文本内容&amp;#x000A;非UTF-16 LE(或带BOM)编码会乱码&apos;&gt;
-        ///        &lt;Value&gt;
-        ///          &lt;REG_SZ MUIVerb=&apos;复制内容到剪切板&apos; Icon=&apos;DxpTaskSync.dll,-52&apos;/&gt; [字符串的其余部分被截断]&quot;; 的本地化字符串。
+        ///   查找 System.Drawing.Bitmap 类型的本地化资源。
         /// </summary>
-        internal static string ShellCommonDic {
+        internal static System.Drawing.Bitmap Setting {
             get {
-                return ResourceManager.GetString("ShellCommonDic", resourceCulture);
+                object obj = ResourceManager.GetObject("Setting", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
             }
         }
         
@@ -303,11 +305,12 @@ namespace ContextMenuManager.Properties {
         
         /// <summary>
         ///   查找类似 &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
-        ///&lt;!--每个程序为一个Group,Text为Group项显示文本,Guid用于判断用户是否安装此程序并决定是否显示该Group,常驻菜单时须添加属性Common,RegPath为程序相关注册表主路径;
+        ///&lt;!--每个程序为一个Group,Text为Group项显示文本,Guid用于判断用户是否安装此程序并决定是否显示该Group,不设置Guid则为常驻菜单,RegPath为程序相关注册表主路径;
         ///其相关菜单项目设置作为一个Item子元素,Item的Text为该Item项显示文本,Tip属性为鼠标悬浮在开关上时的提示信息,需要重启资源管理器生效则添加属性RestartExplorer;
         ///Item的子元素Rule为相关注册表内容,RegPath省略则默认为Group主路径,以\开头则为Group主路径的子项路径;ValueName为相关键名,On为启用键值,Off为禁用键值;
         ///每个Item可能受多个注册表Rule影响,按照顺序进行键值判定;程序优先判定为On,即只要所有Rule不匹配Off键值就判定为On,键值类型不符时也判定为On;
-        ///ValueKind为键值类型,默认键值类型ValueKind为REG_DWORD,为默认值时可省略,目前仅支持REG_SZ、REG_DWORD、REG_EXPAND_SZ的键值类型--&gt; [字符串的其余部分被截断]&quot;; 的本地化字符串。
+        ///ValueKind为键值类型,默认键值类型ValueKind为REG_DWORD,为默认值时可省略,目前仅支持REG_SZ、REG_DWORD、REG_EXPAND_SZ的键值类型--&gt;
+        ///&lt; [字符串的其余部分被截断]&quot;; 的本地化字符串。
         /// </summary>
         internal static string ThirdRulesDic {
             get {

+ 9 - 9
ContextMenuManager/Properties/Resources.resx

@@ -112,21 +112,18 @@
     <value>2.0</value>
   </resheader>
   <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
   <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
-  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
   <data name="About" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>resources\images\about.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
   <data name="Add" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>resources\images\add.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
-  <data name="AddCommon" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>resources\images\addcommon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
-  </data>
   <data name="AddExisting" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>resources\images\addexisting.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
@@ -145,6 +142,9 @@
   <data name="Donate" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>resources\images\donate.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
+  <data name="EnhanceMenusDic" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>resources\texts\enhancemenusdic.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
+  </data>
   <data name="GuidInfosDic" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>resources\texts\guidinfosdic.ini;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
   </data>
@@ -160,15 +160,15 @@
   <data name="Open" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>resources\images\open.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
+  <data name="Refresh" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>resources\images\refresh.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
   <data name="SeparatorItem" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>resources\images\separatoritem.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
   <data name="Setting" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>resources\images\setting.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
-  <data name="ShellCommonDic" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>resources\texts\shellcommondic.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
-  </data>
   <data name="Star" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>resources\images\star.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>

二進制
ContextMenuManager/Properties/Resources/Images/Refresh.png


二進制
ContextMenuManager/Properties/Resources/Images/SeparatorItem.png


文件差異過大導致無法顯示
+ 41 - 19
ContextMenuManager/Properties/Resources/Texts/AppLanguageDic.ini


+ 15 - 24
ContextMenuManager/Properties/Resources/Texts/EnhanceMenusDic.xml

@@ -36,10 +36,7 @@ Tip属性为鼠标悬浮在开关上时的提示信息,从每个Item节点开
       </Item>
     </Shell>
   </File>
-  
-  <Folder>
-  </Folder>
-  
+
   <Directory>
     <Shell>
       <Item KeyName="TakeOwnerShip">
@@ -60,18 +57,6 @@ Tip属性为鼠标悬浮在开关上时的提示信息,从每个Item节点开
 
   <Background>
     <Shell>
-      <Item KeyName='Windows.ShowHiddenFiles'>
-        <OSVersion Compare=">=">6.2</OSVersion>
-        <Value>
-          <REG_SZ MUIVerb='显示/隐藏 隐藏文件' Icon='imageres.dll,-5314' Position='bottom' CommandStateSync='' ExplorerCommandHandler='{f7300245-1f4b-41ba-8948-6fd392064494}'/>
-        </Value>
-      </Item>
-      <Item KeyName='Windows.ShowFileExtensions'>
-        <OSVersion Compare=">=">6.2</OSVersion>
-        <Value>
-          <REG_SZ MUIVerb='显示/隐藏 文件扩展名' Icon='imageres.dll,-5314' Position='bottom' CommandStateSync='' ExplorerCommandHandler='{4ac6c205-2853-4bf5-b47c-919a42a48a16}'/>
-        </Value>
-      </Item>
       <!--清空回收站-->
       <Item KeyName='Windows.RecycleBin.Empty'>
         <OSVersion Compare=">=">6.1</OSVersion>
@@ -86,6 +71,18 @@ Tip属性为鼠标悬浮在开关上时的提示信息,从每个Item节点开
           </Command>
         </SubKey>
       </Item>
+      <Item KeyName='Windows.ShowHiddenFiles'>
+        <OSVersion Compare=">=">6.2</OSVersion>
+        <Value>
+          <REG_SZ MUIVerb='显示/隐藏 隐藏文件' Icon='imageres.dll,-5314' Position='bottom' CommandStateSync='' ExplorerCommandHandler='{f7300245-1f4b-41ba-8948-6fd392064494}'/>
+        </Value>
+      </Item>
+      <Item KeyName='Windows.ShowFileExtensions'>
+        <OSVersion Compare=">=">6.2</OSVersion>
+        <Value>
+          <REG_SZ MUIVerb='显示/隐藏 文件扩展名' Icon='imageres.dll,-5314' Position='bottom' CommandStateSync='' ExplorerCommandHandler='{4ac6c205-2853-4bf5-b47c-919a42a48a16}'/>
+        </Value>
+      </Item>
       <Item KeyName='RunasCmd'>
         <Value>
           <REG_SZ MUIVerb='以管理员身份打开命令提示符' HasLUAShield='' NoWorkingDirectory=''/>
@@ -121,7 +118,7 @@ Tip属性为鼠标悬浮在开关上时的提示信息,从每个Item节点开
       <Item KeyName='RestartExplorer'>
         <OSVersion Compare=">=">6.1</OSVersion>
         <Value>
-          <REG_SZ MUIVerb='重启资源管理器' Icon='explorer.exe,0'/>
+          <REG_SZ MUIVerb='重启资源管理器' Icon='shell32.dll,238'/>
         </Value>
         <SubKey>
           <Command Default='tskill explorer'/>
@@ -145,7 +142,7 @@ Tip属性为鼠标悬浮在开关上时的提示信息,从每个Item节点开
         </SubKey>
       </Item>
       <Item KeyName='SlideToShutDown'>
-        <!--OSVersion Compare=">=">10.0</OSVersion-->
+        <OSVersion Compare=">=">6.3</OSVersion>
         <Value>
           <REG_SZ MUIVerb='滑动关机' Icon='shell32.dll,-28'/>
         </Value>
@@ -202,10 +199,4 @@ Tip属性为鼠标悬浮在开关上时的提示信息,从每个Item节点开
       <Item Text='@shell32.dll,-30305' Icon='imageres.dll,-5303' KeyName='MoveTo' Guid='{c2fbb631-2971-11d1-a18c-00c04fd75d13}'/>
     </ShellEx>
   </AllObjects>
-  
-  <Computer>
-  </Computer>
-  
-  <RecycleBin>
-  </RecycleBin>
 </Data>

+ 207 - 101
ContextMenuManager/Properties/Resources/Texts/GuidInfosDic.ini

@@ -31,6 +31,7 @@
 ;针对<资源文件路径>:存在引用资源不在<GUID文件路径>的文件中,而是在当前目录或子目录或父目录
 ;中其他文件中;相对<GUID文件路径>,当前目录用".\"代替,父目录用"..\"代替,文件为其本身用"*"代替
 
+;----------------系统------------------
 ;打开(快捷方式)
 [00021401-0000-0000-c000-000000000046]
 [email protected],-12850
@@ -72,16 +73,16 @@ [email protected],-51201
 Icon=imageres.dll,-5376
 [a2a9545d-a0c2-42b4-9708-a0b2badd77c8]
 Text=附到「开始」菜单(&U)
-Icon=imageres.dll,75
-;Text=发送到(&N)
+Icon=imageres.dll,-80
+;发送到(&N)
 [7BA4C740-9E81-11CF-99D3-00AA004AE837]
 Text=@*,-30312
-Icon=imageres.dll,176
-;Text=下一个桌面背景(&N)
+Icon=imageres.dll,-185
+;下一个桌面背景(&N)
 [0bf754aa-c967-445c-ab3d-d8fda9bae7ef]
 Text=@*,-416
 Icon=imageres.dll,-5346
-;Text=新建(&W)
+;新建(&W)
 [D969A300-E7FF-11d0-A93B-00A0C90F2719]
 Text=@*,-95851
 Icon=imageres.dll,-5307
@@ -89,7 +90,7 @@ Icon=imageres.dll,-5307
 Text=Windows 小工具
 [A470F8CF-A1E8-4f65-8335-227475AA5C46]
 Text=加密(&Y)
-Icon=imageres.dll,54
+Icon=imageres.dll,-59
 ;共享
 [e2bf9676-5f8f-435c-97eb-11607a5bedf7]
 Text=@*,-107
@@ -110,7 +111,7 @@ Text=@*,-101
 ;刻录到光盘(&T)
 [fbeb8a05-beee-4442-804e-409d6c4515e9]
 Text=@*,-12560
-Icon=imageres.dll,25
+Icon=imageres.dll,-30
 [59099400-57ff-11ce-bd94-0020af85b590]
 Text=复制磁盘(&Y)...
 ;便携设备菜单
@@ -125,6 +126,9 @@ Text=@*,-1037
 ;公文包
 [85bbd920-42a0-1069-a2e4-08002b30309d]
 [email protected],-22978
+[645ff040-5081-101b-9f08-00aa002f954e]
+Text=清空回收站(&B)
+Icon=shell32.dll,-254
 ;全部解压缩(&T)...
 [b8cdcb65-b1bf-4b42-9428-1dfdb7ee92af]
 [email protected],-37514
@@ -139,13 +143,8 @@ Icon=imageres.dll,-5303
 [3080f90e-d7ad-11d9-bd98-0000947b0257]
 Text=窗口转换程序
 Icon=imageres.dll,0
-[8a734961-c4aa-4741-ac1e-791acebf5b39]
-Text=联机购买音乐
-[e598560b-28d5-46aa-a14a-8a3bea34b576]
-Text=幻灯片放映
-[cb3d0f55-bc2c-4c1a-85ed-23ed75b5106b]
-Text=OneDrive
-Icon=%LocalAppData%\Microsoft\OneDrive\OneDrive.exe,0
+
+;----------------显卡------------------
 ;用图形处理器运行
 [a929c4ce-fd36-4270-b4f5-34ecac5bd63c]
 [email protected],-103
@@ -160,19 +159,10 @@ Icon=nvcpl.dll,0
 [9B5F5829-A529-4B12-814A-E81BCB8D93FC]
 Text=英特尔® 显卡设置
 Icon=.\Gfxv4_0.exe,0
-;使用 Microsoft Defender扫描...
-[09A47860-11B0-4DA5-AFA5-26D86198A780]
-Text=Microsoft Defender
-Icon=.\EppManifest.dll,0
-[18A3E590-F219-4105-9079-93DAFA51B9D6]
-Text=使用火绒安全进行杀毒
-[9F012318-CAA5-402C-9BF6-28EB36F61496]
-Text=使用火绒安全粉碎文件
-[53D2405C-48AB-4C8A-8F59-CE0610F13BBC]
-Text=通过QQ发送到
-[9B6D38F3-8EF4-48A5-AD30-FFFFFFFFFFFF]
-Text=Honeyview
-Icon=.\Honeyview.exe,0
+[5E2121EE-0300-11D4-8D3B-444553540000]
+Text=AMD 显卡
+
+;----------------压缩------------------
 [5B69A6B4-393B-459C-8EBB-214237A9E7AC]
 Text=Bandizip
 Icon=.\Bandizip.exe,0
@@ -183,45 +173,6 @@ Icon=.\360zip.exe,0
 Text=WinRAR 64bit
 [B41DB860-8EE4-11D2-9906-E49FADC173CA]
 Text=WinRAR 32bit
-[6D85624F-305A-491d-8848-C1927AA0D790]
-Text=上传到百度网盘
-Icon=.\BaiduNetdisk.exe,0
-[67F4D210-BFC2-4ADD-9A2A-C9B9E1F42C4F]
-Text=上传到 “WPS云文档”
-[AA147FFB-0B1F-4BB1-9B1E-8D062B35C145]
-Text=自动同步文件夹到 “WPS云文档”
-[1ECDA7BF-4DFA-41D8-9380-1A27B26CFC41]
-Text=使用WPS PDF编辑
-Icon=..\..\wpspdf.exe,0
-[E3ED4700-22D4-41B6-8144-E3F5F1AC5153]
-Text=使用WPS PDF编辑
-Icon=..\..\wpspdf.exe,0
-[AF1D7D2F-6AE8-4BAA-ABFA-738201F4871C]
-Text=WPS Office PDF
-Icon=.\wpspdf.exe,0
-[B298D29A-A6ED-11DE-BA8C-A68E55D89593]
-Text=Edit with &Notepad++
-[5D652B62-B702-496A-92BC-92C308251FEA]
-Text=坚果云
-[AD392E40-428C-459F-961E-9B147782D099]
-Text=UltraISO
-Icon=.\UltraISO.exe,0
-[A3777921-CFD3-4A6B-89BF-08E6B95716E8]
-Text=格式工厂(&F)
-Icon=.\FormatFactory.exe,0
-[63332668-8CE1-445D-A5EE-25929176714E]
-Text=扫描病毒(电脑管家)
-[754DF2CE-51E8-4895-B53C-6381418B84AE]
-Text=文件粉碎(电脑管家)
-[CBDECEF7-7A29-4cbf-A009-2673D82C7BF9]
-Text=强力卸载(电脑管家)
-Icon=.\QQPCSoftMgr.exe,0
-[C5617F6A-39BB-436D-91CF-61C1B45DD688]
-Text=深度加速(管家小火箭)
-[CF444751-60FC-48B8-AC0F-363063EB2A9E]
-Text=开启桌面整理(电脑管家)
-[B3A2F1A4-10A2-410C-9C19-622B621C61D0]
-Text=换壁纸(小鸟壁纸)
 [23170F69-40C1-278A-1000-000100020000]
 Text=7-zip
 Icon=.\7zG.exe,0
@@ -239,6 +190,71 @@ Text=快压
 Text=快压
 [903D855A-D671-4A8E-A592-9168755917DB]
 Text=快压
+[e0d79304-84be-11ce-9641-444553540000]
+Text=WinZip
+Icon=.\WzPreloader.exe,0
+[acf03765-1658-485f-9615-fe03c372fb8c]
+Text=微压
+[dd847e93-86df-4d75-a421-46d29228f6da]
+Text=极光压缩
+Icon=.\plFM.exe,0
+[5e3b6ea4-de96-464f-bb86-5587969f4c62]
+Text=万能压缩
+[9175e343-1c41-4490-b178-14f36504f07e]
+Text=160压缩
+Icon=.\160zip.exe,0
+[5e3ca55c-d9f3-4d1c-8b94-ad192b0f7c16]
+Text=速压
+Icon=.\Suzip.exe,0
+[02e77c8d-2798-441e-8e6d-0c2ed9fe206e]
+Text=简压缩
+Icon=.\SimpleZip.exe,0
+[5c551008-a347-4db3-af48-014076fd2b46]
+Text=极速压缩
+Icon=.\JsZip.exe,0
+[0a4861a5-448a-48b4-812a-cf71a07a674f]
+Text=6789压缩
+[7522b611-f22b-4f24-9ce4-3ecbba85c126]
+Text=CoffeeZip
+[aa7f8063-f898-44d0-b147-8a6e9891e32e]
+Text=布丁压缩
+Icon=.\PDZip.exe,0
+[9b8dff9d-0cb2-4100-8f21-c6dd6ce01141]
+Text=布丁压缩
+Icon=.\PDZip.exe,0
+[d81a0ed9-6c47-417b-b298-4ebd813cabd0]
+Text=极客压缩
+Icon=.\GeekZip.exe,0
+[e677c7ad-2b66-4539-aa29-3771a1cfeda9]
+Text=jZip
+Icon=.\jZip.exe,0
+[a6630968-27dc-8db8-9bce-e12b3198a9b1]
+Text=WinArchiver
+Icon=.\WinArchiver.exe,0
+[1532b32d-3a75-4a4d-9b38-5a6000ea7045]
+Text=FreeArc
+Icon=..\FreeArc.exe,0
+[AD392E40-428C-459F-961E-9B147782D099]
+Text=UltraISO
+Icon=.\UltraISO.exe,0
+
+;----------------杀软------------------
+[09A47860-11B0-4DA5-AFA5-26D86198A780]
+Text=Microsoft Defender
+Icon=.\EppManifest.dll,0
+[18A3E590-F219-4105-9079-93DAFA51B9D6]
+Text=使用火绒安全进行杀毒
+[9F012318-CAA5-402C-9BF6-28EB36F61496]
+Text=使用火绒安全粉碎文件
+[63332668-8CE1-445D-A5EE-25929176714E]
+Text=扫描病毒(电脑管家)
+[754DF2CE-51E8-4895-B53C-6381418B84AE]
+Text=文件粉碎(电脑管家)
+[CBDECEF7-7A29-4cbf-A009-2673D82C7BF9]
+Text=强力卸载(电脑管家)
+Icon=.\QQPCSoftMgr.exe,0
+[C5617F6A-39BB-436D-91CF-61C1B45DD688]
+Text=深度加速(管家小火箭)
 [086F171D-5ED1-4ED2-B736-CFF3AD6A128E]
 Text=使用 360杀毒 扫描
 Icon=.\msdev.exe,0
@@ -260,26 +276,122 @@ Icon=.\kismain.exe,0
 [D21D88E8-4123-48BA-B0B1-3FDBE4AE5FA4]
 Text=金山毒霸(32位)扫描 && 文件粉碎
 Icon=.\kismain.exe,0
-[8f556da3-987d-47b0-aa88-eb8d52fe1b9a]
-Text=迅雷播放组件
-Icon=..\Program\XMP\XMP.exe,0
-[dde4beeb-dde6-48fd-8eb5-035c09923f83]
-Text=Unlocker
-Icon=.\Unlocker.exe,0
+[758c684b-4d10-4bc1-90da-6bebf0b4e0b4]
+Text=使用联想电脑管家进行扫描
+[C49499AC-DC25-478B-B903-E005012B3DD1]
+Text=使用智量扫描
+Icon=.\WiseVector.exe,0
+[cca9efd3-29ed-430a-ba6d-e6bbff0a60c2]
+Text=McAfee
+Icon=.\McInstru.exe,0
+[472083b0-c522-11cf-8763-00608cc02f24]
+Text=Avast
+Icon=..\AvastUI.exe,0
+[45ac2688-0253-4ed8-97de-b5370fa7d48a]
+Text=使用 Avira 扫描所选文件
+Icon=..\Launcher\Avira.Systray.exe,0
+
+;--------------上传下载----------------
+[cb3d0f55-bc2c-4c1a-85ed-23ed75b5106b]
+Text=OneDrive
+Icon=%LocalAppData%\Microsoft\OneDrive\OneDrive.exe,0
+[53D2405C-48AB-4C8A-8F59-CE0610F13BBC]
+Text=通过QQ发送到
+[6D85624F-305A-491d-8848-C1927AA0D790]
+Text=上传到百度网盘
+Icon=.\BaiduNetdisk.exe,0
+[2008caf4-a5c1-4037-99a8-699e4d01456d]
+Text=天翼云盘
+Icon=.\eCloud.exe,0
+[1d39a523-4df5-4562-8fff-08c740632f4f]
+Text=360云盘
+Icon=.\360WangPan.exe,0
+[eee949eb-c9ed-4967-98b0-ed4e543befa5]
+Text=115网盘
+Icon=..\115chrome.exe,0
+[171b6b53-17b1-40b7-afb2-a415b2b40401]
+Text=上传到腾讯微云
+Icon=..\..\..\..\..\..\..\WeiyunApp.exe,0
+[5D652B62-B702-496A-92BC-92C308251FEA]
+Text=坚果云
+[67F4D210-BFC2-4ADD-9A2A-C9B9E1F42C4F]
+Text=上传到 “WPS云文档”
+[AA147FFB-0B1F-4BB1-9B1E-8D062B35C145]
+Text=自动同步文件夹到 “WPS云文档”
+[2e7a2c6c-b938-40a4-ba1c-c7ec982dc202]
+Text=发布DWF
+Icon=.\AcLauncher.exe,0
+[30351349-7b7d-4fcc-81b4-1e394ca267eb]
+Text=TortoiseSVN
+Icon=.\TortoiseIDiff.exe,0
+[10A0FDD2-B0C0-4CD4-A7AE-E594CE3B91C8]
+Text=TortoiseGit
+Icon=.\TortoiseGitProc.exe,0
+[2a535b11-6cfc-4e85-a75f-0e397b1584cf]
+Text=通过网易邮箱大师发送
+Icon=..\mailmaster.exe,0
+
+;----------------PDF------------------
 [9c5397bb-07be-4e38-98ba-395f94045091]
 Text=福昕PDF编辑器
 Icon=..\FoxitPhantom.exe,0
 [a6595cd1-bf77-430a-a452-18696685f7c7]
 Text=Adobe Acrobat
 Icon=..\Acrobat\Acrobat.exe,0
-[eee949eb-c9ed-4967-98b0-ed4e543befa5]
-Text=115网盘
-Icon=..\115chrome.exe,0
-[C49499AC-DC25-478B-B903-E005012B3DD1]
-Text=使用智量扫描
-Icon=.\WiseVector.exe,0
-[758c684b-4d10-4bc1-90da-6bebf0b4e0b4]
-Text=使用联想电脑管家进行扫描
+[d25b2cab-8a9a-4517-a9b2-cb5f68a5a802]
+Text=转换为Adobe PDF(&B)
+[1ECDA7BF-4DFA-41D8-9380-1A27B26CFC41]
+Text=使用WPS PDF编辑
+Icon=..\..\wpspdf.exe,0
+[E3ED4700-22D4-41B6-8144-E3F5F1AC5153]
+Text=使用WPS PDF编辑
+Icon=..\..\wpspdf.exe,0
+[AF1D7D2F-6AE8-4BAA-ABFA-738201F4871C]
+Text=WPS Office PDF
+Icon=.\wpspdf.exe,0
+[b4e15cd0-f916-4c8e-830a-15e3e9d01a1b]
+Text=迅读PDF大师 合并、拆分、转换
+Icon=.\MasterPDF.exe,0
+[19a73c67-f0b8-4a28-8c33-9d4eddd6fcbc]
+Text=云上PDF
+Icon=.\iPDF.exe,0
+[29424e92-60a1-40c0-bf79-1b8472dde706]
+Text=使用PDF猫编辑器打开
+Icon=.\M_pdfEdit.exe,0
+[29424e91-60a1-40c0-bf79-1b8472dde606]
+Text=使用转转大师PDF编辑器打开
+Icon=.\ZPDFEdit.exe,0
+[098a124a-aa1c-38c8-a65e-d1199a14516a]
+Text=Convert to...(万兴PDF专家)
+
+;--------------影音图像----------------
+[8a734961-c4aa-4741-ac1e-791acebf5b39]
+Text=联机购买音乐
+[f1b9284f-e9dc-4e68-9d7e-42362a59f0fd]
+Text=添加到“Windows Media Player”列表(&W)
+[ce3fb1d1-02ae-4a5f-a6e9-d9f1b4073e6c]
+Text=使用“Windows Media Player”播放(&P)
+[7d4734e6-047e-41e2-aeaa-e763b4739dc4]
+Text=使用 Media Player 播放(&P)
+[e598560b-28d5-46aa-a14a-8a3bea34b576]
+Text=幻灯片放映
+[9B6D38F3-8EF4-48A5-AD30-FFFFFFFFFFFF]
+Text=Honeyview
+Icon=.\Honeyview.exe,0
+[c2396f1e-4ba2-4b7d-857a-f764761c012b]
+Text=ACD看图
+Icon=.\AcdKantu.exe,0
+[83a97a48-f5d7-4d12-8ba3-5263a016d936]
+Text=使用光影4.0编辑
+[8f556da3-987d-47b0-aa88-eb8d52fe1b9a]
+Text=迅雷播放组件
+Icon=..\Program\XMP\XMP.exe,0
+
+;----------------美化------------------
+[CF444751-60FC-48B8-AC0F-363063EB2A9E]
+Text=开启桌面整理(电脑管家)
+[B3A2F1A4-10A2-410C-9C19-622B621C61D0]
+Text=换壁纸(小鸟壁纸)
 [3b7162fb-4389-40c8-83a5-da10d491ec66]
 Text=映射此文件夹到桌面(小智桌面)
 Icon=.\XZDesktop.exe,0
@@ -289,27 +401,21 @@ Icon=*,3
 [a2a9545d-a0c2-42b4-9708-a0b2badd77c9]
 Text=附到「开始」菜单(&U)(StartIsBack)
 Icon=.\StartIsBackCfg.exe,0
-[e0d79304-84be-11ce-9641-444553540000]
-Text=WinZip
-Icon=.\WzPreloader.exe,0
-[acf03765-1658-485f-9615-fe03c372fb8c]
-Text=微压
-[dd847e93-86df-4d75-a421-46d29228f6da]
-Text=极光压缩
-Icon=.\plFM.exe,0
-[5e3b6ea4-de96-464f-bb86-5587969f4c62]
-Text=万能压缩
-[9175e343-1c41-4490-b178-14f36504f07e]
-Text=160压缩
-Icon=.\160zip.exe,0
-[2008caf4-a5c1-4037-99a8-699e4d01456d]
-Text=天翼云盘
-Icon=.\eCloud.exe,0
-[83a97a48-f5d7-4d12-8ba3-5263a016d936]
-Text=使用光影4.0编辑
+
+;--------------文件处理----------------
+[B298D29A-A6ED-11DE-BA8C-A68E55D89593]
+Text=Edit with &Notepad++
+[A3777921-CFD3-4A6B-89BF-08E6B95716E8]
+Text=格式工厂(&F)
+Icon=.\FormatFactory.exe,0
+[dde4beeb-dde6-48fd-8eb5-035c09923f83]
+Text=Unlocker
+Icon=.\Unlocker.exe,0
 [410bf280-86ef-4e0f-8279-ec5848546ad3]
 Text=IObit Unlocker
 Icon=.\IObitUnlocker.exe,0
-[cca9efd3-29ed-430a-ba6d-e6bbff0a60c2]
-Text=McAfee
-Icon=.\McInstru.exe,0
+[836ab26c-2de4-41d3-ac24-4c6c2699b960]
+Text=强力卸载(IObit Uninstaller)
+[6CB83A5A-AA68-4895-9F54-175E789AE149]
+Text=Balabolka
+Icon=.\balabolka.exe,0

+ 37 - 11
ContextMenuManager/Properties/Resources/Texts/ThirdRulesDic.xml

@@ -6,6 +6,32 @@ Item的子元素Rule为相关注册表内容,RegPath省略则默认为Group主
 ValueKind为键值类型,默认键值类型ValueKind为REG_DWORD,为默认值时可省略,目前仅支持REG_SZ、REG_DWORD、REG_EXPAND_SZ的键值类型-->
 <Data>
   <Group Text="System">
+    <Item Text="系统 右键菜单" RestartExplorer="">
+      <Rule RegPath="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" ValueName="NoViewContextMenu" On="0" Off="1"/>
+      <Rule RegPath="HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer" ValueName="NoViewContextMenu" On="0" Off="1"/>
+    </Item>
+    <Item Text="任务栏 右键菜单" RestartExplorer="">
+      <Rule RegPath="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" ValueName="NoTrayContextMenu" On="0" Off="1"/>
+      <Rule RegPath="HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer" ValueName="NoTrayContextMenu" On="0" Off="1"/>
+    </Item>
+    <Item Text="任务栏 任务栏设置 锁定任务栏" RestartExplorer="">
+      <Rule RegPath="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" ValueName="TaskbarLockAll" On="0" Off="1"/>
+      <Rule RegPath="HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer" ValueName="TaskbarLockAll" On="0" Off="1"/>
+    </Item>    
+    <Item Text="任务栏 工具栏" RestartExplorer="" Tip="禁用后已启用工具栏将被禁用, 请谨慎操作">
+      <Rule RegPath="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" ValueName="NoToolbarsOnTaskbar" On="0" Off="1"/>
+      <Rule RegPath="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" ValueName="NoCloseDragDropBands" On="0" Off="1"/>
+      <Rule RegPath="HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer" ValueName="NoToolbarsOnTaskbar" On="0" Off="1"/>
+      <Rule RegPath="HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer" ValueName="NoCloseDragDropBands" On="0" Off="1"/>
+    </Item>
+    <Item Text="任务栏 固定到任务栏" RestartExplorer="" Tip="禁用时已固定图标会被隐藏,重新启用会重现&#x000A;文件右键菜单“固定到任务栏”会同时消失&#x000A;且无法拖拽文件到任务栏进行固定">
+      <Rule RegPath="HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Explorer" ValueName="TaskbarNoPinnedList" On="0" Off="1"/>
+      <Rule RegPath="HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\Explorer" ValueName="TaskbarNoPinnedList" On="0" Off="1"/>
+    </Item>
+    <Item Text="任务栏 Windows lnk 工作区" Tip="禁用此项将同时禁用 Win+W 快捷键">
+      <OSVersion Compare=">=">10.0</OSVersion>
+      <Rule RegPath="HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\WindowsInkWorkspace" ValueName="AllowWindowsInkWorkspace" On="1" Off="0"/>
+    </Item>
     <Item Text="目录背景 自定义文件夹" RestartExplorer="" Tip="禁用此项将会同时禁用文件系统&#x000A;对象属性面板中的自定义选项卡">
       <Rule RegPath="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" ValueName="NoCustomizeThisFolder" On="0" Off="1"/>
       <Rule RegPath="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" ValueName="NoCustomizeWebView" On="0" Off="1"/>
@@ -24,19 +50,22 @@ ValueKind为键值类型,默认键值类型ValueKind为REG_DWORD,为默认
       <Rule RegPath="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" ValueName="NoDrivesInSendToMenu" On="0" Off="1"/>
       <Rule RegPath="HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer" ValueName="NoDrivesInSendToMenu" On="0" Off="1"/>
     </Item>
-    <Item Text="发送到 快速构建子菜单" Tip="禁用此项将加快主菜单弹出速度">
+    <Item Text="发送到 快速构建子菜单" Tip="禁用此项将加快主菜单弹出速度&#x000A;但会延缓发送到子菜单弹出速度">
       <Rule RegPath="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer" ValueName="DelaySendToMenuBuild" On="0" Off="1"/>
       <Rule RegPath="HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer" ValueName="DelaySendToMenuBuild" On="0" Off="1"/>
     </Item>
-    <Item Text="Win10、Win8 在Microsoft Store中查找应用">
+    <Item Text="打开方式 在Microsoft Store中查找应用">
+      <OSVersion Compare=">=">6.2</OSVersion>
       <Rule RegPath="HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Explorer" ValueName="NoUseStoreOpenWith" On="0" Off="1"/>
       <Rule RegPath="HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\Explorer" ValueName="NoUseStoreOpenWith" On="0" Off="1"/>
     </Item>
-    <Item Text="Win10 开始屏幕程序右键菜单卸载" RestartExplorer="">
+    <Item Text="开始屏幕 程序右键菜单卸载" RestartExplorer="">
+      <OSVersion Compare=">=">10.0</OSVersion>
       <Rule RegPath="HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Explorer" ValueName="NoUninstallFromStart" On="0" Off="1"/>
       <Rule RegPath="HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\Windows\Explorer" ValueName="NoUninstallFromStart" On="0" Off="1"/>
     </Item>
-    <Item Text="Win10 WinX菜单命令提示符替换为PowerShell" RestartExplorer="">
+    <Item Text="Win+X 菜单命令提示符替换为 PowerShell" RestartExplorer="">
+      <OSVersion Compare=">=">10.0</OSVersion>
       <Rule RegPath="HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced" ValueName="DontUsePowerShellOnWinX" On="0" Off="1"/>
     </Item>
   </Group>
@@ -136,13 +165,10 @@ ValueKind为键值类型,默认键值类型ValueKind为REG_DWORD,为默认
       <Rule RegPath="\Global\CoProcManager" ValueName="ShowTrayIcon" On="1" Off="0"/>
     </Item>
   </Group>
-
-  <Group Text="极光压缩" Guid="dd847e93-86df-4d75-a421-46d29228f6da" RegPath="HKEY_CURRENT_USER\SOFTWARE\PLZip">
-    <Item Text="层叠右键菜单">
-      <Rule RegPath="\Options" ValueName="CascadedMenu" On="1" Off="0"/>
-    </Item>
-    <Item Text="右键菜单显示图标">
-      <Rule RegPath="\Options" ValueName="MenuIcons" On="1" Off="0"/>
+  
+  <Group Text="ACD看图" Guid="c2396f1e-4ba2-4b7d-857a-f764761c012b" RegPath="HKEY_CURRENT_USER\SOFTWARE\acdkantu">
+    <Item Text="显示桌面右键菜单">
+      <Rule ValueName="menu" On="1" Off="0" ValueKind="REG_SZ"/>
     </Item>
   </Group>
 </Data>

+ 19 - 8
ContextMenuManager/Updater.cs

@@ -13,17 +13,27 @@ namespace ContextMenuManager
         const string UpdateUrl = "https://gitee.com/BluePointLilac/ContextMenuManager/raw/master/Update.ini";
         const string GuidInfosDicUrl = "https://gitee.com/BluePointLilac/ContextMenuManager/raw/master/ContextMenuManager/Properties/Resources/Texts/GuidInfosDic.ini";
         const string ThirdRulesDicUrl = "https://gitee.com/BluePointLilac/ContextMenuManager/raw/master/ContextMenuManager/Properties/Resources/Texts/ThirdRulesDic.xml";
-        const string ShellCommonDicUrl = "https://gitee.com/BluePointLilac/ContextMenuManager/raw/master/ContextMenuManager/Properties/Resources/Texts/ShellCommonDic.xml";
+        const string EnhanceMenusDicUrl = "https://gitee.com/BluePointLilac/ContextMenuManager/raw/master/ContextMenuManager/Properties/Resources/Texts/EnhanceMenusDic.xml";
 
-        public static void CheckUpdate()
+        public static void PeriodicUpdate()
         {
-            UpdateText(Program.AppDataGuidInfosDicPath, GuidInfosDicUrl);
-            UpdateText(Program.AppDataThirdRulesDicPath, ThirdRulesDicUrl);
-            UpdateText(Program.AppDataShellCommonDicPath, ShellCommonDicUrl);
-            try { UpdateApp(); } catch { }
+            //如果上次检测更新时间为一个月以前就进行更新操作
+            if(AppConfig.LastCheckUpdateTime.AddMonths(1).CompareTo(DateTime.Today) < 0)
+            {
+                CheckUpdate();
+                AppConfig.LastCheckUpdateTime = DateTime.Today;
+            }
+        }
+
+        public static bool CheckUpdate()
+        {
+            UpdateText(AppConfig.WebGuidInfosDic, GuidInfosDicUrl);
+            UpdateText(AppConfig.WebThirdRulesDic, ThirdRulesDicUrl);
+            UpdateText(AppConfig.WebEnhanceMenusDic, EnhanceMenusDicUrl);
+            try { return UpdateApp(); } catch { return false; }
         }
 
-        private static void UpdateApp()
+        private static bool UpdateApp()
         {
             IniReader reader = new IniReader(new StringBuilder(GetWebString(UpdateUrl).Replace("\\n", "\n")));
             Version version1 = new Version(reader.GetValue("Update", "Version"));
@@ -35,9 +45,10 @@ namespace ContextMenuManager
                     MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
                 {
                     Process.Start(reader.GetValue("Update", "Url"));
-                    Process.GetCurrentProcess().Kill();
+                    return true;
                 }
             }
+            return false;
         }
 
         private static void UpdateText(string filePath, string url)

+ 41 - 0
Donate.md

@@ -0,0 +1,41 @@
+# ContextMenuManager 捐赠名单
+
+## 捐赠说明
+
+> ContextMenuManager完全开源免费,如果你觉得此程序帮助到了你,可以对作者进行捐赠,金额请随意,谢谢支持!
+
+> 备注:收款码平台会隐藏付款方ID,可在支付时备注昵称,已支付用户可通过[email protected]联系我更新用户ID。
+
+## 捐赠方式
+
+> 微信、支付宝、QQ
+
+<img src="https://gitee.com/BluePointLilac/ContextMenuManager/raw/master/ContextMenuManager/Properties/Resources/Images/Donate.png" width="600" height="200"/>
+
+## 捐赠名单
+
+> 此名单不定期更新
+
+> 捐赠金额合计:96.94元
+
+|日期|用户ID|平台|金额|备注
+|:--:|:--:|:--:|:--:|:--:
+|2020-10-20|W*t|微信|30|
+|2020-10-24|*远|微信|6|右键,一份迟到的支持
+|2020-10-28|*班|微信|3|
+|2020-11-03|*方|微信|5|
+|2020-11-03|m*c|微信|5|
+|2020-11-04|*海|支付宝|5|
+|2020-11-06|*龙|微信|6.66|软件好,但用不了
+|2020-11-08|lty2002|QQ|1.88|右键管理好评!
+|2020-11-09|*熊|微信|1|加油
+|2020-11-09|m*s|微信|5|支持一下!CMM
+|2020-11-15|*德|微信|1|
+|2020-11-20|**骅|支付宝|1|
+|2020-11-24|*师|微信|10|
+|2020-11-25|*城|微信|1|
+|2020-11-27|*文|微信|3|
+|2020-12-5|*勋|支付宝|0.5|
+|2020-12-5|**宇|支付宝|9.9|
+|2020-12-6|*經|微信|1|
+|2020-12-7|*白|微信|1|

+ 2 - 2
README.md

@@ -8,8 +8,8 @@
 * 对上述场景右键菜单自定义添加项目,自定义菜单命令
 
 ## 兼容性能
-* 适用于Win7、8、8.1、10系统
-* 适用于64位和32位操作系统
+* 适用于Win7、8、8.1、10、Vista
+* 适用于 x64、x32 CPU 操作系统
 * 适用于高分屏,最佳显示缩放比为150%
 * 程序支持国际化多语言显示,欢迎为此程序制作语言字典
 

+ 1 - 1
Update.ini

@@ -1,4 +1,4 @@
 [Update]
 Version=2.0.0.0
 Url=https://github.com/BluePointLilac/ContextMenuManager/releases/download/2.0.0.0/ContextMenuManager.zip
-Info=优化部分代码,添加部分GUID字典;适配Win7系统(依赖框架.Net Framework 3.5,Win7自带无需另外安装);Win10版依赖框架为.Net Framework 4.6,Win10自带无需安装;可单独下载对应系统版本.exe文件,或下载.zip包解压后仅保留对应系统的版本
+Info=【兼容支持】\n(1).完美兼容Win10、8.1、8、7以及Vista系统;\n(2).最低支持.Net Framework 3.5;\n\n【新增功能】\n(1).添加新建菜单锁定及排序功能;\n(2).添加特殊规则禁用文件右键“使用 Skype 共享”;\n(3)支持程序内添加用户自定义字典;\n(4).添加“刷新”按钮点击即时刷新功能;\n(5).添加部分程序GUID字典和增强菜单字典;\n\n【问题修复】\n(1).修复多次切换后拖拽窗体鼠标延迟;(2).修复部分小错误,优化部分代码。

文件差異過大導致無法顯示
+ 0 - 0
languages/ja-JP.ini


文件差異過大導致無法顯示
+ 41 - 19
languages/zh-CN.ini


部分文件因文件數量過多而無法顯示