瀏覽代碼

更新3.3.3.0版本

蓝点lilac 4 年之前
父節點
當前提交
fc425347d1
共有 100 個文件被更改,包括 4561 次插入3509 次删除
  1. 1 1
      ContextMenuManager/App.config
  2. 0 191
      ContextMenuManager/AppConfig.cs
  3. 0 339
      ContextMenuManager/AppString.cs
  4. 22 9
      ContextMenuManager/BluePointLilac.Controls/DownloadDialog.cs
  5. 23 20
      ContextMenuManager/BluePointLilac.Controls/InputDialog.cs
  6. 69 13
      ContextMenuManager/BluePointLilac.Controls/MyCheckBox.cs
  7. 32 15
      ContextMenuManager/BluePointLilac.Controls/MyListBox.cs
  8. 68 10
      ContextMenuManager/BluePointLilac.Controls/MyMainForm.cs
  9. 17 15
      ContextMenuManager/BluePointLilac.Controls/MySideBar.cs
  10. 4 6
      ContextMenuManager/BluePointLilac.Controls/MyStatusBar.cs
  11. 23 12
      ContextMenuManager/BluePointLilac.Controls/MyToolBar.cs
  12. 21 1
      ContextMenuManager/BluePointLilac.Controls/ReadOnlyTextBox.cs
  13. 2 3
      ContextMenuManager/BluePointLilac.Controls/ResizeLimitedForm.cs
  14. 13 10
      ContextMenuManager/BluePointLilac.Controls/SelectDialog.cs
  15. 66 0
      ContextMenuManager/BluePointLilac.Controls/UAWebClient.cs
  16. 6 18
      ContextMenuManager/BluePointLilac.Methods/ControlExtension.cs
  17. 3 3
      ContextMenuManager/BluePointLilac.Methods/ElevatedFileDroper.cs
  18. 8 8
      ContextMenuManager/BluePointLilac.Methods/ExternalProgram.cs
  19. 19 29
      ContextMenuManager/BluePointLilac.Methods/FileExtension.cs
  20. 39 0
      ContextMenuManager/BluePointLilac.Methods/FormExtension.cs
  21. 4 2
      ContextMenuManager/BluePointLilac.Methods/HighDpi.cs
  22. 81 5
      ContextMenuManager/BluePointLilac.Methods/IniReader.cs
  23. 12 14
      ContextMenuManager/BluePointLilac.Methods/IniWriter.cs
  24. 249 4
      ContextMenuManager/BluePointLilac.Methods/MessageBoxEx.cs
  25. 20 11
      ContextMenuManager/BluePointLilac.Methods/RegistryEx.cs
  26. 12 3
      ContextMenuManager/BluePointLilac.Methods/ResourceString.cs
  27. 43 37
      ContextMenuManager/BluePointLilac.Methods/RichTextBoxExtension.cs
  28. 0 1
      ContextMenuManager/BluePointLilac.Methods/ShellLink.cs
  29. 52 30
      ContextMenuManager/BluePointLilac.Methods/SingleInstance.cs
  30. 1 1
      ContextMenuManager/BluePointLilac.Methods/TextBoxExtension.cs
  31. 0 26
      ContextMenuManager/BluePointLilac.Methods/UAWebClient.cs
  32. 29 0
      ContextMenuManager/BluePointLilac.Methods/WinOsVersion.cs
  33. 0 49
      ContextMenuManager/BluePointLilac.Methods/WindowsOsVersion.cs
  34. 68 36
      ContextMenuManager/ContextMenuManager.csproj
  35. 0 598
      ContextMenuManager/Controls/AboutApp.cs
  36. 258 0
      ContextMenuManager/Controls/AppSettingBox.cs
  37. 32 0
      ContextMenuManager/Controls/DetailedEditDialog.cs
  38. 82 87
      ContextMenuManager/Controls/DetailedEditList.cs
  39. 135 0
      ContextMenuManager/Controls/DictionariesBox.cs
  40. 237 0
      ContextMenuManager/Controls/DonateBox.cs
  41. 0 112
      ContextMenuManager/Controls/DonateListDialog.cs
  42. 31 0
      ContextMenuManager/Controls/EnhanceMenusDialog.cs
  43. 40 24
      ContextMenuManager/Controls/EnhanceMenusItem.cs
  44. 72 180
      ContextMenuManager/Controls/EnhanceMenusList.cs
  45. 21 7
      ContextMenuManager/Controls/ExplorerRestarter.cs
  46. 2 1
      ContextMenuManager/Controls/FileExtensionDialog.cs
  47. 135 0
      ContextMenuManager/Controls/FoldSubItem.cs
  48. 13 18
      ContextMenuManager/Controls/GuidBlockedItem.cs
  49. 3 2
      ContextMenuManager/Controls/GuidBlockedList.cs
  50. 2 2
      ContextMenuManager/Controls/IEItem.cs
  51. 2 10
      ContextMenuManager/Controls/Interfaces/IBtnDeleteItem.cs
  52. 1 0
      ContextMenuManager/Controls/Interfaces/IBtnMoveUpDownItem.cs
  53. 0 34
      ContextMenuManager/Controls/Interfaces/IBtnOpenPathItem.cs
  54. 8 1
      ContextMenuManager/Controls/Interfaces/IBtnShowMenuItem.cs
  55. 4 3
      ContextMenuManager/Controls/Interfaces/IChkVisibleItem.cs
  56. 0 130
      ContextMenuManager/Controls/Interfaces/IFoldGroupItem.cs
  57. 1 0
      ContextMenuManager/Controls/Interfaces/ITsiAdministratorItem.cs
  58. 3 2
      ContextMenuManager/Controls/Interfaces/ITsiCommandItem.cs
  59. 16 5
      ContextMenuManager/Controls/Interfaces/ITsiDeleteItem.cs
  60. 1 0
      ContextMenuManager/Controls/Interfaces/ITsiFilePathItem.cs
  61. 88 77
      ContextMenuManager/Controls/Interfaces/ITsiGuidItem.cs
  62. 1 7
      ContextMenuManager/Controls/Interfaces/ITsiIconItem.cs
  63. 1 0
      ContextMenuManager/Controls/Interfaces/ITsiRegExportItem.cs
  64. 1 0
      ContextMenuManager/Controls/Interfaces/ITsiRegPathItem.cs
  65. 11 13
      ContextMenuManager/Controls/Interfaces/ITsiShortcutCommandItem.cs
  66. 3 9
      ContextMenuManager/Controls/Interfaces/ITsiTextItem.cs
  67. 1 0
      ContextMenuManager/Controls/Interfaces/ITsiWebSearchItem.cs
  68. 485 0
      ContextMenuManager/Controls/LanguagesBox.cs
  69. 5 3
      ContextMenuManager/Controls/NewIEDialog.cs
  70. 3 3
      ContextMenuManager/Controls/NewItem.cs
  71. 17 17
      ContextMenuManager/Controls/NewItemForm.cs
  72. 8 6
      ContextMenuManager/Controls/NewLnkFileDialog.cs
  73. 8 6
      ContextMenuManager/Controls/NewOpenWithDialog.cs
  74. 9 9
      ContextMenuManager/Controls/NewShellDialog.cs
  75. 2 2
      ContextMenuManager/Controls/OpenWithItem.cs
  76. 3 2
      ContextMenuManager/Controls/OpenWithList.cs
  77. 37 30
      ContextMenuManager/Controls/RuleItem.cs
  78. 5 4
      ContextMenuManager/Controls/SendToItem.cs
  79. 23 0
      ContextMenuManager/Controls/SendToList.cs
  80. 11 20
      ContextMenuManager/Controls/ShellExItem.cs
  81. 19 12
      ContextMenuManager/Controls/ShellExecuteDialog.cs
  82. 41 38
      ContextMenuManager/Controls/ShellItem.cs
  83. 132 123
      ContextMenuManager/Controls/ShellList.cs
  84. 41 18
      ContextMenuManager/Controls/ShellNewItem.cs
  85. 35 6
      ContextMenuManager/Controls/ShellNewList.cs
  86. 17 15
      ContextMenuManager/Controls/ShellStoreDialog.cs
  87. 383 476
      ContextMenuManager/Controls/ShellSubMenuDialog.cs
  88. 42 0
      ContextMenuManager/Controls/SubItemsForm.cs
  89. 71 0
      ContextMenuManager/Controls/SwitchDicList.cs
  90. 0 233
      ContextMenuManager/Controls/TranslateDialog.cs
  91. 8 55
      ContextMenuManager/Controls/UwpModeItem.cs
  92. 22 36
      ContextMenuManager/Controls/WinXGroupItem.cs
  93. 11 7
      ContextMenuManager/Controls/WinXItem.cs
  94. 22 10
      ContextMenuManager/Controls/WinXList.cs
  95. 248 111
      ContextMenuManager/MainForm.cs
  96. 278 0
      ContextMenuManager/Methods/AppConfig.cs
  97. 8 16
      ContextMenuManager/Methods/AppImage.cs
  98. 14 0
      ContextMenuManager/Methods/AppMessageBox.cs
  99. 333 0
      ContextMenuManager/Methods/AppString.cs
  100. 8 7
      ContextMenuManager/Methods/DesktopIni.cs

+ 1 - 1
ContextMenuManager/App.config

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

+ 0 - 191
ContextMenuManager/AppConfig.cs

@@ -1,191 +0,0 @@
-using BluePointLilac.Methods;
-using System;
-using System.Globalization;
-using System.IO;
-using System.Windows.Forms;
-
-namespace ContextMenuManager
-{
-    static class AppConfig
-    {
-        static AppConfig()
-        {
-            foreach(string dirPath in new[] { AppDataDir, ConfigDir, ProgramsDir, BackupDir, LangsDir, DicsDir, WebDicsDir, UserDicsDir })
-            {
-                Directory.CreateDirectory(dirPath);
-                Application.ApplicationExit += (sender, e) =>
-                {
-                    if(Directory.GetFileSystemEntries(dirPath).Length == 0)
-                    {
-                        Directory.Delete(dirPath);
-                    }
-                };
-            }
-        }
-
-        public static readonly string AppConfigDir = $@"{Application.StartupPath}\Config";
-        public static readonly string AppDataDir = Environment.ExpandEnvironmentVariables(@"%AppData%\ContextMenuManager");
-        public static readonly string AppDataConfigDir = $@"{AppDataDir}\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 ProgramsDir = $@"{ConfigDir}\Programs";
-        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 WebThirdRulesDic = $@"{WebDicsDir}\{THIRDRULESDICXML}";
-        public static string WebEnhanceMenusDic = $@"{WebDicsDir}\{ENHANCEMENUSICXML}";
-        public static string WebUwpModeItemsDic = $@"{WebDicsDir}\{UWPMODEITEMSDICXML}";
-
-        public static string UserGuidInfosDic = $@"{UserDicsDir}\{GUIDINFOSDICINI}";
-        public static string UserThirdRulesDic = $@"{UserDicsDir}\{THIRDRULESDICXML}";
-        public static string UserEnhanceMenusDic = $@"{UserDicsDir}\{ENHANCEMENUSICXML}";
-        public static string UserUwpModeItemsDic = $@"{UserDicsDir}\{UWPMODEITEMSDICXML}";
-
-        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";
-        public const string UWPMODEITEMSDICXML = "UwpModeItemsDic.xml";
-
-        public static readonly string[] EngineUrls =
-        {
-            "https://www.bing.com/search?q=%s",       //必应搜索
-            "https://www.baidu.com/s?wd=%s",          //百度搜索
-            "https://www.google.com/search?q=%s",     //谷歌搜索
-            "https://duckduckgo.com/?q=%s",           //DuckDuckGo
-            "https://www.sogou.com/web?query=%s",     //搜狗搜索
-            "https://www.so.com/s?q=%s",              //360搜索
-        };
-
-        private static readonly IniWriter ConfigWriter = new IniWriter(ConfigIni);
-        private static string GetGeneralValue(string key) => ConfigWriter.GetValue("General", key);
-        private static void SetGeneralValue(string key, object value) => ConfigWriter.SetValue("General", key, value);
-        public static string LanguageIniPath => $@"{LangsDir}\{Language}.ini";
-
-        public static string Language
-        {
-            get
-            {
-                string language = GetGeneralValue("Language");
-                if(language == string.Empty)
-                {
-                    language = CultureInfo.CurrentUICulture.Name;
-                }
-                if(!File.Exists($@"{LangsDir}\{language}.ini"))
-                {
-                    language = string.Empty;
-                }
-                return language;
-            }
-            set => SetGeneralValue("Language", value);
-        }
-
-        public static bool AutoBackup
-        {
-            get => GetGeneralValue("AutoBackup") != "0";
-            set => SetGeneralValue("AutoBackup", value ? 1 : 0);
-        }
-
-        public static DateTime LastCheckUpdateTime
-        {
-            get
-            {
-                try
-                {
-                    string time = GetGeneralValue("LastCheckUpdateTime");
-                    //二进制数据时间不会受系统时间格式影响
-                    return DateTime.FromBinary(Convert.ToInt64(time));
-                }
-                catch
-                {
-                    //返回文件上次修改时间
-                    return new FileInfo(Application.ExecutablePath).LastWriteTime;
-                }
-            }
-            set => SetGeneralValue("LastCheckUpdateTime", value.ToBinary());
-        }
-
-        public static bool ProtectOpenItem
-        {
-            get => GetGeneralValue("ProtectOpenItem") != "0";
-            set => SetGeneralValue("ProtectOpenItem", value ? 1 : 0);
-        }
-
-        public static string EngineUrl
-        {
-            get
-            {
-                string url = GetGeneralValue("EngineUrl");
-                if(url.IsNullOrWhiteSpace()) url = EngineUrls[0];
-                return url;
-            }
-            set => SetGeneralValue("EngineUrl", value);
-        }
-
-        public static bool ShowFilePath
-        {
-            get => GetGeneralValue("ShowFilePath") == "1";
-            set => SetGeneralValue("ShowFilePath", value ? 1 : 0);
-        }
-
-        public static bool WinXSortable
-        {
-            get => GetGeneralValue("WinXSortable") == "1";
-            set => SetGeneralValue("WinXSortable", value ? 1 : 0);
-        }
-
-        public static bool OpenMoreRegedit
-        {
-            get => GetGeneralValue("OpenMoreRegedit") == "1";
-            set => SetGeneralValue("OpenMoreRegedit", value ? 1 : 0);
-        }
-
-        public static bool OpenMoreExplorer
-        {
-            get => GetGeneralValue("OpenMoreExplorer") == "1";
-            set => SetGeneralValue("OpenMoreExplorer", value ? 1 : 0);
-        }
-
-        public static bool HideDisabledItems
-        {
-            get => GetGeneralValue("HideDisabledItems") == "1";
-            set => SetGeneralValue("HideDisabledItems", value ? 1 : 0);
-        }
-
-        public static bool HideSysStoreItems
-        {
-            get => GetGeneralValue("HideSysStoreItems") != "0";
-            set => SetGeneralValue("HideSysStoreItems", value ? 1 : 0);
-        }
-
-        public static bool RequestUseGithub
-        {
-            get
-            {
-                if(GetGeneralValue("RequestUseGithub") == "1") return true;
-                if(CultureInfo.CurrentCulture.Name == "zh-CN") return false;
-                return true;
-            }
-            set => SetGeneralValue("RequestUseGithub", value ? 1 : 0);
-        }
-
-        public static int UpdateFrequency
-        {
-            get
-            {
-                string value = GetGeneralValue("UpdateFrequency");
-                if(int.TryParse(value, out int day))
-                {
-                    if(day == -1 || day == 7 || day == 90) return day;
-                }
-                return 30;
-            }
-            set => SetGeneralValue("UpdateFrequency", value);
-        }
-    }
-}

+ 0 - 339
ContextMenuManager/AppString.cs

@@ -1,339 +0,0 @@
-using BluePointLilac.Methods;
-using System.Text;
-
-namespace ContextMenuManager
-{
-    public static class AppString
-    {
-        public static readonly IniReader UserLanguage = new IniReader(AppConfig.LanguageIniPath);
-        public static readonly IniReader DefaultLanguage = new IniReader(new StringBuilder(Properties.Resources.AppLanguageDic));
-
-        private static string GetStringValue(string section, string key)
-        {
-            string value = UserLanguage.GetValue(section, key);
-            if(string.IsNullOrEmpty(value)) value = DefaultLanguage.GetValue(section, key);
-            return value.Replace("\\r\\n", "\r\n").Replace("\\n", "\n");
-        }
-
-        /// <summary>常规</summary>
-        public static class General
-        {
-            private static string GetValue(string key) => GetStringValue("General", key);
-            public static string AppName => GetValue("AppName");
-        }
-
-        /// <summary>工具栏</summary>
-        public static class ToolBar
-        {
-            private static string GetValue(string key) => GetStringValue("ToolBar", key);
-            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");
-        }
-
-        /// <summary>侧边栏</summary>
-        public static class SideBar
-        {
-            private static string GetValue(string key) => GetStringValue("SideBar", key);
-            public static string File => GetValue("File");
-            public static string Folder => GetValue("Folder");
-            public static string Directory => GetValue("Directory");
-            public static string Background => GetValue("Background");
-            public static string Desktop => GetValue("Desktop");
-            public static string Drive => GetValue("Drive");
-            public static string AllObjects => GetValue("AllObjects");
-            public static string Computer => GetValue("Computer");
-            public static string RecycleBin => GetValue("RecycleBin");
-            public static string Library => GetValue("Library");
-            public static string New => GetValue("New");
-            public static string SendTo => GetValue("SendTo");
-            public static string OpenWith => GetValue("OpenWith");
-            public static string WinX => GetValue("WinX");
-            public static string LnkFile => GetValue("LnkFile");
-            public static string UwpLnk => GetValue("UwpLnk");
-            public static string ExeFile => GetValue("ExeFile");
-            public static string UnknownType => GetValue("UnknownType");
-            public static string MenuAnalysis => GetValue("MenuAnalysis");
-            public static string CustomExtension => GetValue("CustomExtension");
-            public static string PerceivedType => GetValue("PerceivedType");
-            public static string DirectoryType => GetValue("DirectoryType");
-            public static string EnhanceMenu => GetValue("EnhanceMenu");
-            public static string ThirdRules => GetValue("ThirdRules");
-            public static string OtherAccounts => GetValue("OtherAccounts");
-            public static string GuidBlocked => GetValue("GuidBlocked");
-            public static string DragDrop => GetValue("DragDrop");
-            public static string PublicReferences => GetValue("PublicReferences");
-            public static string CustomRegPath => GetValue("CustomRegPath");
-            public static string IEMenu => GetValue("IEMenu");
-            public static string AppSetting => GetValue("AppSetting");
-            public static string CheckUpdate => GetValue("CheckUpdate");
-            public static string AboutApp => GetValue("AboutApp");
-            public static string Dictionaries => GetValue("Dictionaries");
-            public static string AppLanguage => GetValue("AppLanguage");
-            public static string Donate => GetValue("Donate");
-        }
-
-        /// <summary>状态栏</summary>
-        public static class StatusBar
-        {
-            private static string GetValue(string key) => GetStringValue("StatusBar", key);
-            public static string File => GetValue("File");
-            public static string Folder => GetValue("Folder");
-            public static string Directory => GetValue("Directory");
-            public static string Background => GetValue("Background");
-            public static string Desktop => GetValue("Desktop");
-            public static string Drive => GetValue("Drive");
-            public static string AllObjects => GetValue("AllObjects");
-            public static string Computer => GetValue("Computer");
-            public static string RecycleBin => GetValue("RecycleBin");
-            public static string Library => GetValue("Library");
-            public static string New => GetValue("New");
-            public static string SendTo => GetValue("SendTo");
-            public static string OpenWith => GetValue("OpenWith");
-            public static string WinX => GetValue("WinX");
-            public static string LnkFile => GetValue("LnkFile");
-            public static string UwpLnk => GetValue("UwpLnk");
-            public static string ExeFile => GetValue("ExeFile");
-            public static string UnknownType => GetValue("UnknownType");
-            public static string MenuAnalysis => GetValue("MenuAnalysis");
-            public static string CustomExtension => GetValue("CustomExtension");
-            public static string PerceivedType => GetValue("PerceivedType");
-            public static string DirectoryType => GetValue("DirectoryType");
-            public static string EnhanceMenu => GetValue("EnhanceMenu");
-            public static string ThirdRules => GetValue("ThirdRules");
-            public static string GuidBlocked => GetValue("GuidBlocked");
-            public static string DragDrop => GetValue("DragDrop");
-            public static string PublicReferences => GetValue("PublicReferences");
-            public static string CustomRegPath => GetValue("CustomRegPath");
-            public static string IEMenu => GetValue("IEMenu");
-        }
-
-        /// <summary>程序内右键菜单</summary>
-        public static class Menu
-        {
-            private static string GetValue(string key) => GetStringValue("Menu", key);
-            public static string ChangeText => GetValue("ChangeText");
-            public static string ItemIcon => GetValue("ItemIcon");
-            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");
-            public static string SetBottom => GetValue("SetBottom");
-            public static string OtherAttributes => GetValue("OtherAttributes");
-            public static string OnlyWithShift => GetValue("OnlyWithShift");
-            public static string OnlyInExplorer => GetValue("OnlyInExplorer");
-            public static string NoWorkingDirectory => GetValue("NoWorkingDirectory");
-            public static string NeverDefault => GetValue("NeverDefault");
-            public static string ShowAsDisabledIfHidden => GetValue("ShowAsDisabledIfHidden");
-            public static string Details => GetValue("Details");
-            public static string WebSearch => GetValue("WebSearch");
-            public static string ChangeCommand => GetValue("ChangeCommand");
-            public static string RunAsAdministrator => GetValue("RunAsAdministrator");
-            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");
-            public static string CopyGuid => GetValue("CopyGuid");
-            public static string BlockGuid => GetValue("BlockGuid");
-            public static string AddGuidDic => GetValue("AddGuidDic");
-            public static string ClsidLocation => GetValue("ClsidLocation");
-            public static string InitialData => GetValue("InitialData");
-            public static string BeforeSeparator => GetValue("BeforeSeparator");
-            public static string ChangeGroup => GetValue("ChangeGroup");
-            public static string RestoreDefault => GetValue("RestoreDefault");
-            public static string Edit => GetValue("Edit");
-            public static string Save => GetValue("Save");
-        }
-
-        /// <summary>对话框子窗口</summary>
-        public static class Dialog
-        {
-            private static string GetValue(string key) => GetStringValue("Dialog", key);
-            public static string Ok => GetValue("Ok");
-            public static string Cancel => GetValue("Cancel");
-            public static string Browse => GetValue("Browse");
-            public static string Program => GetValue("Program");
-            public static string AllFiles => GetValue("AllFiles");
-            public static string RegistryFile => GetValue("RegistryFile");
-            public static string ItemText => GetValue("ItemText");
-            public static string ItemCommand => GetValue("ItemCommand");
-            public static string CommandArguments => GetValue("CommandArguments");
-            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 SelectAll => GetValue("SelectAll");
-            public static string InputGuid => GetValue("InputGuid");
-            public static string AddGuidDic => GetValue("AddGuidDic");
-            public static string DeleteGuidDic => GetValue("DeleteGuidDic");
-            public static string NoPerceivedType => GetValue("NoPerceivedType");
-            public static string TextFile => GetValue("TextFile");
-            public static string DocumentFile => GetValue("DocumentFile");
-            public static string ImageFile => GetValue("ImageFile");
-            public static string VideoFile => GetValue("VideoFile");
-            public static string AudioFile => GetValue("AudioFile");
-            public static string CompressedFile => GetValue("CompressedFile");
-            public static string SystemFile => GetValue("SystemFile");
-            public static string DocumentDirectory => GetValue("DocumentDirectory");
-            public static string ImageDirectory => GetValue("ImageDirectory");
-            public static string VideoDirectory => GetValue("VideoDirectory");
-            public static string AudioDirectory => GetValue("AudioDirectory");
-            public static string EditSubItems => GetValue("EditSubItems");
-            public static string CheckReference => GetValue("CheckReference");
-            public static string CheckCopy => GetValue("CheckCopy");
-            public static string SelectExtension => GetValue("SelectExtension");
-            public static string SelectPerceivedType => GetValue("SelectPerceivedType");
-            public static string SelectDirectoryType => GetValue("SelectDirectoryType");
-            public static string SelectNewItemType => GetValue("SelectNewItemType");
-            public static string SelectGroup => GetValue("SelectGroup");
-            public static string SelectObjectType => GetValue("SelectObjectType");
-            public static string SelectDropEffect => GetValue("SelectDropEffect");
-            public static string DefaultDropEffect => GetValue("DefaultDropEffect");
-            public static string CopyDropEffect => GetValue("CopyDropEffect");
-            public static string MoveDropEffect => GetValue("MoveDropEffect");
-            public static string CreateLinkDropEffect => GetValue("CreateLinkDropEffect");
-            public static string DownloadLanguages => GetValue("DownloadLanguages");
-            public static string TranslateTool => GetValue("TranslateTool");
-            public static string DefaultText => GetValue("DefaultText");
-            public static string OldTranslation => GetValue("OldTranslation");
-            public static string NewTranslation => GetValue("NewTranslation");
-            public static string SelectSubMenuMode => GetValue("SelectSubMenuMode");
-            public static string DonateInfo => GetValue("DonateInfo");
-        }
-
-        /// <summary>消息</summary>
-        public static class Message
-        {
-            private static string GetValue(string key) => GetStringValue("Message", key);
-            public static string TextCannotBeEmpty => GetValue("TextCannotBeEmpty");
-            public static string CommandCannotBeEmpty => GetValue("CommandCannotBeEmpty");
-            public static string StringParsingFailed => GetValue("StringParsingFailed");
-            public static string TextLengthCannotExceed80 => GetValue("TextLengthCannotExceed80");
-            public static string ConfirmDeletePermanently => GetValue("ConfirmDeletePermanently");
-            public static string DeleteButCanRestore => GetValue("DeleteButCanRestore");
-            public static string ConfirmDeleteReference => GetValue("ConfirmDeleteReference");
-            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 NoOpenModeExtension => GetValue("NoOpenModeExtension");
-            public static string CannotChangePath => GetValue("CannotChangePath");
-            public static string CopiedToClipboard => GetValue("CopiedToClipboard");
-            public static string MalformedGuid => GetValue("MalformedGuid");
-            public static string HasBeenAdded => GetValue("HasBeenAdded");
-            public static string EditInitialData => GetValue("EditInitialData");
-            public static string PromptIsOpenItem => GetValue("PromptIsOpenItem");
-            public static string SelectRegPath => GetValue("SelectRegPath");
-            public static string RestartApp => GetValue("RestartApp");
-            public static string UpdateInfo => GetValue("UpdateInfo");
-            public static string UpdateSucceeded => GetValue("UpdateSucceeded");
-            public static string DicUpdateSucceeded => GetValue("DicUpdateSucceeded");
-            public static string FileNotExists => GetValue("FileNotExists");
-            public static string FolderNotExists => GetValue("FolderNotExists");
-            public static string VersionIsLatest => GetValue("VersionIsLatest");
-            public static string AuthorityProtection => GetValue("AuthorityProtection");
-            public static string WinXSorted => GetValue("WinXSorted");
-            public static string RestoreDefault => GetValue("RestoreDefault");
-            public static string DeleteGroup => GetValue("DeleteGroup");
-            public static string WebDataReadFailed => GetValue("WebDataReadFailed");
-            public static string OpenWebUrl => GetValue("OpenWebUrl");
-        }
-
-        /// <summary>其他文本</summary>
-        public static class Other
-        {
-            private static string GetValue(string key) => GetStringValue("Other", key);
-            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");
-            public static string Runas => GetValue("Runas");
-            public static string CustomFolder => GetValue("CustomFolder");
-            public static string MapNetworkDrive => GetValue("MapNetworkDrive");
-            public static string DisconnectNetworkDrive => GetValue("DisconnectNetworkDrive");
-            public static string RecycleBinProperties => GetValue("RecycleBinProperties");
-            public static string RemovableDrive => GetValue("RemovableDrive");
-            public static string BuildSendtoMenu => GetValue("BuildSendtoMenu");
-            public static string UseStoreOpenWith => GetValue("UseStoreOpenWith");
-            public static string NewItem => GetValue("NewItem");
-            public static string AddGuidBlockedItem => GetValue("AddGuidBlockedItem");
-            public static string CurrentExtension => GetValue("CurrentExtension");
-            public static string CurrentPerceivedType => GetValue("CurrentPerceivedType");
-            public static string CurrentDirectoryType => GetValue("CurrentDirectoryType");
-            public static string CurrentFilePath => GetValue("CurrentFilePath");
-            public static string CurrentRegPath => GetValue("CurrentRegPath");
-            public static string SelectRegPath => GetValue("SelectRegPath");
-            public static string InvalidItem => GetValue("InvalidItem");
-            public static string Separator => GetValue("Separator");
-            public static string LockNewMenu => GetValue("LockNewMenu");
-            public static string RestartExplorer => GetValue("RestartExplorer");
-            public static string UserDictionaries => GetValue("UserDictionaries");
-            public static string DictionaryDescription => GetValue("DictionaryDescription");
-            public static string GuidInfosDictionary => GetValue("GuidInfosDictionary");
-            public static string UwpMode => GetValue("UWPMode");
-            public static string Translators => GetValue("Translators");
-            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 ConfigPath => GetValue("ConfigPath");
-            public static string AppDataDir => GetValue("AppDataDir");
-            public static string AppDir => GetValue("AppDir");
-            public static string AutoBackup => GetValue("AutoBackup");
-            public static string SetUpdateFrequency => GetValue("SetUpdateFrequency");
-            public static string OnceAWeek => GetValue("OnceAWeek");
-            public static string OnceAMonth => GetValue("OnceAMonth");
-            public static string OnceASeason => GetValue("OnceASeason");
-            public static string NeverCheck => GetValue("NeverCheck");
-            public static string SetRequestRepo => GetValue("SetRequestRepo");
-            public static string ImmediatelyCheck => GetValue("ImmediatelyCheck");
-            public static string ProtectOpenItem => GetValue("ProtectOpenItem");
-            public static string WebSearchEngine => GetValue("WebSearchEngine");
-            public static string CustomEngine => GetValue("CustomEngine");
-            public static string SetCustomEngine => GetValue("SetCustomEngine");
-            public static string WinXSortable => GetValue("WinXSortable");
-            public static string ShowFilePath => GetValue("ShowFilePath");
-            public static string OpenMoreRegedit => GetValue("OpenMoreRegedit");
-            public static string OpenMoreExplorer => GetValue("OpenMoreExplorer");
-            public static string HideDisabledItems => GetValue("HideDisabledItems");
-            public static string HideSysStoreItems => GetValue("HideSysStoreItems");
-            public static string SetPerceivedType => GetValue("SetPerceivedType");
-            public static string SetDefaultDropEffect => GetValue("SetDefaultDropEffect");
-        }
-
-        /// <summary>提示文本</summary>
-        public static class Tip
-        {
-            private static string GetValue(string key) => GetStringValue("Tip", key);
-            public static string RestartExplorer => GetValue("RestartExplorer");
-            public static string CustomFolder => GetValue("CustomFolder");
-            public static string SendToDrive => GetValue("SendToDrive");
-            public static string BuildSendtoMenu => GetValue("BuildSendtoMenu");
-            public static string EditSubItems => GetValue("EditSubItems");
-            public static string InvalidItem => GetValue("InvalidItem");
-            public static string AddSeparator => GetValue("AddSeparator");
-            public static string AddReference => GetValue("AddReference");
-            public static string AddFromPublic => GetValue("AddFromPublic");
-            public static string AddFromParentMenu => GetValue("AddFromParentMenu");
-            public static string DeleteGuidDic => GetValue("DeleteGuidDic");
-            public static string LockNewMenu => GetValue("LockNewMenu");
-            public static string ConfigPath => GetValue("ConfigPath");
-            public static string CommandFiles => GetValue("CommandFiles");
-            public static string CreateGroup => GetValue("CreateGroup");
-            public static string DropOrSelectObject => GetValue("DropOrSelectObject");
-        }
-    }
-}

+ 22 - 9
ContextMenuManager/BluePointLilac.Controls/DownloadDialog.cs

@@ -1,5 +1,4 @@
 using BluePointLilac.Methods;
-using ContextMenuManager;
 using System;
 using System.Diagnostics;
 using System.Drawing;
@@ -10,6 +9,7 @@ namespace BluePointLilac.Controls
 {
     sealed class DownloadDialog : CommonDialog
     {
+        public string Text { get; set; }
         public string Url { get; set; }
         public string FilePath { get; set; }
         public override void Reset() { }
@@ -17,10 +17,11 @@ namespace BluePointLilac.Controls
         protected override bool RunDialog(IntPtr hwndOwner)
         {
             using(Process process = Process.GetCurrentProcess())
-            using(DownloadForm frm = new DownloadForm { Url = this.Url, FilePath = this.FilePath })
+            using(DownloadForm frm = new DownloadForm())
             {
-                bool isAsyn = hwndOwner == process.MainWindowHandle;
-                frm.StartPosition = isAsyn ? FormStartPosition.CenterParent : FormStartPosition.CenterScreen;
+                frm.Url = this.Url;
+                frm.Text = this.Text;
+                frm.FilePath = this.FilePath;
                 return frm.ShowDialog() == DialogResult.OK;
             }
         }
@@ -29,15 +30,15 @@ namespace BluePointLilac.Controls
         {
             public DownloadForm()
             {
-                this.Text = AppString.General.AppName;
+                this.SuspendLayout();
+                this.Font = SystemFonts.MessageBoxFont;
                 this.FormBorderStyle = FormBorderStyle.FixedSingle;
-                this.StartPosition = FormStartPosition.CenterParent;
                 this.MinimizeBox = this.MaximizeBox = this.ShowInTaskbar = false;
-                this.Font = new Font(SystemFonts.MessageBoxFont.FontFamily, 9F);
                 this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
                 this.Controls.AddRange(new Control[] { pgbDownload, btnCancel });
                 this.Load += (sender, e) => DownloadFile(Url, FilePath);
                 this.InitializeComponents();
+                this.ResumeLayout();
             }
 
             readonly ProgressBar pgbDownload = new ProgressBar
@@ -48,7 +49,7 @@ namespace BluePointLilac.Controls
             readonly Button btnCancel = new Button
             {
                 DialogResult = DialogResult.Cancel,
-                Text = AppString.Dialog.Cancel,
+                Text = ResourceString.Cancel,
                 AutoSize = true
             };
 
@@ -90,10 +91,22 @@ namespace BluePointLilac.Controls
                 }
                 catch(Exception e)
                 {
-                    MessageBoxEx.Show(e.Message);
+                    MessageBox.Show(e.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                     this.DialogResult = DialogResult.Cancel;
                 }
             }
+
+            protected override void OnLoad(EventArgs e)
+            {
+                if(this.Owner == null && Form.ActiveForm != this) this.Owner = Form.ActiveForm;
+                if(this.Owner == null) this.StartPosition = FormStartPosition.CenterScreen;
+                else
+                {
+                    this.TopMost = this.Owner.TopMost;
+                    this.StartPosition = FormStartPosition.CenterParent;
+                }
+                base.OnLoad(e);
+            }
         }
     }
 }

+ 23 - 20
ContextMenuManager/BluePointLilac.Controls/InputDialog.cs

@@ -1,5 +1,4 @@
 using BluePointLilac.Methods;
-using ContextMenuManager;
 using System;
 using System.Drawing;
 using System.Windows.Forms;
@@ -9,7 +8,7 @@ namespace BluePointLilac.Controls
     public sealed class InputDialog : CommonDialog
     {
         /// <summary>输入对话框标题</summary>
-        public string Title { get; set; } = AppString.General.AppName;
+        public string Title { get; set; } = Application.ProductName;
         /// <summary>输入对话框文本框文本</summary>
         public string Text { get; set; }
         public Size Size { get; set; }
@@ -23,6 +22,8 @@ namespace BluePointLilac.Controls
                 frm.Text = Title;
                 frm.InputedText = this.Text;
                 frm.Size = this.Size;
+                Form owner = (Form)Control.FromHandle(hwndOwner);
+                if(owner != null) frm.TopMost = owner.TopMost;
                 bool flag = frm.ShowDialog() == DialogResult.OK;
                 this.Text = flag ? frm.InputedText : null;
                 return flag;
@@ -33,14 +34,14 @@ namespace BluePointLilac.Controls
         {
             public InputBox()
             {
-                this.AcceptButton = btnOk;
+                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 });
+                this.Controls.AddRange(new Control[] { txtInput, btnOK, btnCancel });
+                txtInput.Font = new Font(txtInput.Font.FontFamily, txtInput.Font.Size + 2F);
                 txtInput.CanResizeFont();
                 InitializeComponents();
             }
@@ -53,40 +54,42 @@ namespace BluePointLilac.Controls
 
             readonly TextBox txtInput = new TextBox
             {
-                Font = new Font(SystemFonts.MenuFont.FontFamily, 11F),
+                Font = SystemFonts.MenuFont,
                 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,
+                Text = ResourceString.OK,
                 AutoSize = true
             };
             readonly Button btnCancel = new Button
             {
                 Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
                 DialogResult = DialogResult.Cancel,
-                Text = AppString.Dialog.Cancel,
+                Text = ResourceString.Cancel,
                 AutoSize = true
             };
 
-            protected override void OnResize(EventArgs e)
-            {
-                base.OnResize(e);
-                txtInput.Width = btnCancel.Right - txtInput.Left;
-                txtInput.Height = btnCancel.Top - 2 * txtInput.Top;
-            }
-
             private void InitializeComponents()
             {
+                this.SuspendLayout();
                 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;
-                this.OnResize(null);
+                txtInput.Size = new Size(340, 24).DpiZoom();
+                this.ClientSize = new Size(txtInput.Width + a * 2, txtInput.Height + btnOK.Height + a * 3);
+                btnCancel.Top = btnOK.Top = txtInput.Bottom + a;
+                btnCancel.Left = txtInput.Right - btnCancel.Width;
+                btnOK.Left = btnCancel.Left - btnOK.Width - a;
+                this.ResumeLayout();
+                this.MinimumSize = this.Size;
+                this.Resize += (sender, e) =>
+                {
+                    txtInput.Width = this.ClientSize.Width - 2 * a;
+                    txtInput.Height = btnCancel.Top - 2 * a;
+                };
             }
         }
     }

+ 69 - 13
ContextMenuManager/BluePointLilac.Controls/MyCheckBox.cs

@@ -1,12 +1,22 @@
-using ContextMenuManager;
+using BluePointLilac.Methods;
 using System;
+using System.ComponentModel;
 using System.Drawing;
+using System.Drawing.Drawing2D;
 using System.Windows.Forms;
 
 namespace BluePointLilac.Controls
 {
+    [DefaultProperty("Checked")]
     public class MyCheckBox : PictureBox
     {
+        public MyCheckBox()
+        {
+            this.Image = TurnOff;
+            this.Cursor = Cursors.Hand;
+            this.SizeMode = PictureBoxSizeMode.AutoSize;
+        }
+
         private bool? _Checked = null;
         public bool Checked
         {
@@ -14,7 +24,6 @@ namespace BluePointLilac.Controls
             set
             {
                 if(_Checked == value) return;
-                bool notFirst = _Checked != null;
                 this.Image = SwitchImage(value);
                 if(_Checked == null)
                 {
@@ -40,27 +49,74 @@ namespace BluePointLilac.Controls
             }
         }
 
-        public MyCheckBox()
+        public Func<bool> PreCheckChanging;
+        public Func<bool> PreCheckChanged;
+        public Action CheckChanging;
+        public Action CheckChanged;
+
+        public Image TurnOnImage { get; set; } = TurnOn;
+        public Image TurnOffImage { get; set; } = TurnOff;
+
+        private Image SwitchImage(bool value)
         {
-            this.Image = SwitchImage(false);
-            this.Cursor = Cursors.Hand;
-            this.SizeMode = PictureBoxSizeMode.AutoSize;
+            return value ? TurnOnImage : TurnOffImage;
         }
 
-        public Func<bool> PreCheckChanging { get; set; }
-        public Func<bool> PreCheckChanged { get; set; }
-        public Action CheckChanging { get; set; }
-        public Action CheckChanged { get; set; }
-
         protected override void OnMouseDown(MouseEventArgs e)
         {
             base.OnMouseDown(e);
             if(e.Button == MouseButtons.Left) this.Checked = !this.Checked;
         }
 
-        private static Image SwitchImage(bool value)
+        private static readonly Image TurnOn = DrawImage(true);
+        private static readonly Image TurnOff = DrawImage(false);
+
+        private static Image DrawImage(bool value)
         {
-            return value ? AppImage.TurnOn : AppImage.TurnOff;
+            int w = 80.DpiZoom();
+            int r1 = 16.DpiZoom();
+            float r2 = 13F.DpiZoom();
+            int d1 = r1 * 2;
+            float d2 = r2 * 2;
+            float a = r1 - r2;
+            Bitmap bitmap = new Bitmap(w, d1);
+            using(Graphics g = Graphics.FromImage(bitmap))
+            {
+                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
+                g.CompositingQuality = CompositingQuality.HighQuality;
+                g.PixelOffsetMode = PixelOffsetMode.HighQuality;
+                g.SmoothingMode = SmoothingMode.HighQuality;
+                using(GraphicsPath path = new GraphicsPath())
+                {
+                    path.AddArc(new RectangleF(0, 0, d1, d1), 90, 180);
+                    path.AddLine(new PointF(r1, 0), new PointF(w - r1, 0));
+                    path.AddArc(new RectangleF(w - d1, 0, d1, d1), -90, 180);
+                    path.AddLine(new PointF(w - r1, d1), new PointF(r1, d1));
+                    Color color = value ? Color.FromArgb(0, 138, 217) : Color.FromArgb(130, 136, 144);
+                    using(Brush brush = new SolidBrush(color))
+                    {
+                        g.FillPath(brush, path);
+                    }
+                }
+                using(GraphicsPath path = new GraphicsPath())
+                {
+                    path.AddArc(new RectangleF(a, a, d2, d2), 90, 180);
+                    path.AddLine(new PointF(r1, a), new PointF(w - r1, a));
+                    path.AddArc(new RectangleF(w - d2 - a, a, d2, d2), -90, 180);
+                    path.AddLine(new PointF(w - r1, d2 + a), new PointF(r1, d2 + a));
+                    Color color = value ? Color.FromArgb(0, 162, 255) : Color.FromArgb(153, 160, 169);
+                    using(Brush brush = new SolidBrush(color))
+                    {
+                        g.FillPath(brush, path);
+                    }
+                }
+                using(GraphicsPath path = new GraphicsPath())
+                {
+                    path.AddEllipse(new RectangleF(value ? (w - d2 - a) : a, a, d2, d2));
+                    g.FillPath(Brushes.White, path);
+                }
+            }
+            return bitmap;
         }
     }
 }

+ 32 - 15
ContextMenuManager/BluePointLilac.Controls/MyListBox.cs

@@ -37,6 +37,7 @@ namespace BluePointLilac.Controls
         public MyList()
         {
             this.AutoSize = true;
+            this.WrapContents = true;
             this.Dock = DockStyle.Top;
             this.DoubleBuffered = true;
             this.AutoSizeMode = AutoSizeMode.GrowAndShrink;
@@ -53,25 +54,32 @@ namespace BluePointLilac.Controls
                 {
                     hoveredItem.ForeColor = Color.FromArgb(90, 90, 90);
                     //hoveredItem.BackColor = Color.FromArgb(250, 250, 250);
+                    //hoveredItem.Font = new Font(hoveredItem.Font, FontStyle.Regular);
                 }
                 hoveredItem = value;
-                value.ForeColor = Color.FromArgb(0, 138, 217);
-                //value.BackColor = Color.FromArgb(200, 230, 250);
-                value.Focus();
-                HoveredItemChanged?.Invoke();
+                if(hoveredItem != null)
+                {
+                    value.ForeColor = Color.FromArgb(0, 138, 217);
+                    //value.BackColor = Color.FromArgb(200, 230, 250);
+                    //value.Font = new Font(hoveredItem.Font, FontStyle.Bold);
+                    value.Focus();
+                }
+                HoveredItemChanged?.Invoke(this, null);
             }
         }
 
-        public Action HoveredItemChanged;
+        public event EventHandler HoveredItemChanged;
 
         public void AddItem(MyListItem item)
         {
+            this.SuspendLayout();
             item.Parent = this;
             item.MouseEnter += (sender, e) => HoveredItem = item;
             this.MouseWheel += (sender, e) => item.ContextMenuStrip?.Close();
             void ResizeItem() => item.Width = Owner.Width - item.Margin.Horizontal;
             Owner.Resize += (sender, e) => ResizeItem();
             ResizeItem();
+            this.ResumeLayout();
         }
 
         public void AddItems(MyListItem[] items)
@@ -101,10 +109,13 @@ namespace BluePointLilac.Controls
             this.SetItemIndex(item, index);
         }
 
-        public void ClearItems()
+        public virtual void ClearItems()
         {
-            foreach(Control control in Controls) BeginInvoke(new Action(control.Dispose));
+            if(this.Controls.Count == 0) return;
+            this.SuspendLayout();
+            foreach(Control control in this.Controls) BeginInvoke(new Action(control.Dispose));
             this.Controls.Clear();
+            this.ResumeLayout();
         }
 
         public void SortItemByText()
@@ -133,6 +144,7 @@ namespace BluePointLilac.Controls
     {
         public MyListItem()
         {
+            this.SuspendLayout();
             this.HasImage = true;
             this.DoubleBuffered = true;
             this.Height = 50.DpiZoom();
@@ -142,14 +154,15 @@ namespace BluePointLilac.Controls
             this.BackColor = Color.FromArgb(250, 250, 250);
             this.Controls.AddRange(new Control[] { lblSeparator, flpControls, lblText, picImage });
             this.Resize += (Sender, e) => pnlScrollbar.Height = this.ClientSize.Height;
-            picImage.DoubleClick += (sender, e) => ImageDoubleClick?.Invoke();
-            lblText.DoubleClick += (sender, e) => TextDoubleClick?.Invoke();
             flpControls.MouseClick += (sender, e) => this.OnMouseClick(null);
             flpControls.MouseEnter += (sender, e) => this.OnMouseEnter(null);
             flpControls.MouseDown += (sender, e) => this.OnMouseDown(null);
+            lblSeparator.SetEnabled(false);
+            lblText.SetEnabled(false);
             CenterControl(lblText);
             CenterControl(picImage);
             AddCtr(pnlScrollbar, 0);
+            this.ResumeLayout();
         }
 
         public Image Image
@@ -185,29 +198,31 @@ namespace BluePointLilac.Controls
             }
         }
 
-        public Action TextDoubleClick { get; set; }
-        public Action ImageDoubleClick { get; set; }
-
         private readonly Label lblText = new Label
         {
-            AutoSize = true
+            AutoSize = true,
+            Name = "Text"
         };
         private readonly PictureBox picImage = new PictureBox
         {
             SizeMode = PictureBoxSizeMode.AutoSize,
-            Left = 20.DpiZoom()
+            Left = 20.DpiZoom(),
+            Enabled = false,
+            Name = "Image"
         };
         private readonly FlowLayoutPanel flpControls = new FlowLayoutPanel
         {
             AutoSizeMode = AutoSizeMode.GrowAndShrink,
             FlowDirection = FlowDirection.RightToLeft,
             Anchor = AnchorStyles.Right,
-            AutoSize = true
+            AutoSize = true,
+            Name = "Controls"
         };
         private readonly Label lblSeparator = new Label
         {
             BackColor = Color.FromArgb(220, 220, 220),
             Dock = DockStyle.Bottom,
+            Name = "Separator",
             Height = 1
         };//分割线
         private readonly Panel pnlScrollbar = new Panel
@@ -245,11 +260,13 @@ namespace BluePointLilac.Controls
 
         public void AddCtr(Control ctr, int space)
         {
+            this.SuspendLayout();
             ctr.Parent = flpControls;
             ctr.Margin = new Padding(0, 0, space, 0);
             ctr.MouseEnter += (sender, e) => this.OnMouseEnter(null);
             ctr.MouseDown += (sender, e) => this.OnMouseEnter(null);
             CenterControl(ctr);
+            this.ResumeLayout();
         }
 
         public void AddCtrs(Control[] ctrs)

+ 68 - 10
ContextMenuManager/BluePointLilac.Controls/MyMainForm.cs

@@ -9,29 +9,87 @@ namespace BluePointLilac.Controls
     {
         public MyMainForm()
         {
+            this.SuspendLayout();
             this.Text = Application.ProductName;
+            this.ForeColor = Color.FromArgb(80, 80, 80);
+            this.BackColor = Color.FromArgb(250, 250, 250);
+            this.StartPosition = FormStartPosition.CenterScreen;
             this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
             this.Controls.AddRange(new Control[] { MainBody, SideBar, StatusBar, ToolBar });
             SideBar.Resize += (sender, e) => this.OnResize(null);
             this.ClientSize = new Size(850, 610).DpiZoom();
             this.MinimumSize = this.Size;
-            ToolBar.CanMoveForm();
+            MainBody.Dock = DockStyle.Left;
             StatusBar.CanMoveForm();
-            this.CenterToScreen();
+            ToolBar.CanMoveForm();
+            this.ResumeLayout();
         }
 
-        protected MyToolBar ToolBar = new MyToolBar();
-        protected MySideBar SideBar = new MySideBar();
-        protected MyStatusBar StatusBar = new MyStatusBar();
-        protected MyListBox MainBody = new MyListBox
-        {
-            Dock = DockStyle.Left
-        };
+        public readonly MyToolBar ToolBar = new MyToolBar();
+        public readonly MySideBar SideBar = new MySideBar();
+        public readonly MyStatusBar StatusBar = new MyStatusBar();
+        public readonly MyListBox MainBody = new MyListBox();
+
+        /// <summary>窗体移动时是否临时挂起MainBody</summary>
+        public bool SuspendMainBodyWhenMove { get; set; } = false;
+        /// <summary>窗体调整大小时是否临时挂起MainBody</summary>
+        public bool SuspendMainBodyWhenResize { get; set; } = true;
 
         protected override void OnResize(EventArgs e)
         {
             base.OnResize(e);
-            MainBody.Width = ClientSize.Width - SideBar.Width;
+            MainBody.Width = this.ClientSize.Width - SideBar.Width;
+        }
+
+        protected override void WndProc(ref Message m)
+        {
+            const int WM_NCLBUTTONDBLCLK = 0x00A3;
+            const int WM_SYSCOMMAND = 0x0112;
+            const int SC_MAXIMIZE = 0xF030;
+            const int SC_MINIMIZE = 0xF020;
+            const int SC_RESTORE = 0xF120;
+            const int SC_MOVE = 0xF012;
+            const int SC_SIZE = 0xF000;
+            const int HT_CAPTION = 0x2;
+            bool suspend = false;//临时挂起MainBody
+            switch(m.Msg)
+            {
+                case WM_SYSCOMMAND:
+                    switch(m.WParam.ToInt32())
+                    {
+                        //解决控件过多移动窗体时延迟问题
+                        case SC_MOVE:
+                        //解决控件过多调整窗体大小时延迟问题
+                        case SC_SIZE:
+                            suspend = this.SuspendMainBodyWhenMove; break;
+                        //解决控件过多最大化、最小化、还原重绘卡顿问题
+                        case SC_RESTORE:
+                        case SC_MINIMIZE:
+                        case SC_MAXIMIZE:
+                            suspend = this.SuspendMainBodyWhenResize; break;
+                    }
+                    break;
+                case WM_NCLBUTTONDBLCLK:
+                    switch(m.WParam.ToInt32())
+                    {
+                        //双击标题栏最大化和还原窗口
+                        case HT_CAPTION:
+                            suspend = this.SuspendMainBodyWhenResize; break;
+                    }
+                    break;
+            }
+            if(suspend)
+            {
+                this.SuspendLayout();
+                MainBody.SuspendLayout();
+                this.Controls.Remove(MainBody);
+                base.WndProc(ref m);
+                this.Controls.Add(MainBody);
+                MainBody.BringToFront();
+                MainBody.ResumeLayout();
+                this.ResumeLayout();
+            }
+            else base.WndProc(ref m);
         }
     }
 }

+ 17 - 15
ContextMenuManager/BluePointLilac.Controls/MySideBar.cs

@@ -11,14 +11,15 @@ namespace BluePointLilac.Controls
         {
             this.Dock = DockStyle.Left;
             this.ItemHeight = 30.DpiZoom();
-            this.Font = new Font(SystemFonts.MenuFont.FontFamily, 10F);
+            this.Font = SystemFonts.MenuFont;
+            this.Font = new Font(this.Font.FontFamily, this.Font.Size + 1F);
             this.ForeColor = Color.FromArgb(80, 80, 80);
             this.BackColor = Color.FromArgb(245, 245, 245);
             this.BackgroundImageLayout = ImageLayout.None;
             this.Controls.AddRange(new Control[] { LblSeparator, PnlSelected, PnlHovered });
             PnlHovered.Paint += PaintItem;
             PnlSelected.Paint += PaintItem;
-            this.SelectIndex = -1;
+            this.SelectedIndex = -1;
         }
 
         private string[] itemNames;
@@ -36,7 +37,7 @@ namespace BluePointLilac.Controls
                 }
                 PnlHovered.Width = PnlSelected.Width = this.Width;
                 PaintItems();
-                SelectIndex = -1;
+                SelectedIndex = -1;
             }
         }
 
@@ -152,16 +153,16 @@ namespace BluePointLilac.Controls
         {
             if(itemNames == null) return;
             int index = (e.Y - TopSpace) / ItemHeight;
-            if(index >= itemNames.Length || index < 0 || string.IsNullOrEmpty(itemNames[index]) || index == SelectIndex)
+            if(index >= itemNames.Length || index < 0 || string.IsNullOrEmpty(itemNames[index]) || index == SelectedIndex)
             {
                 this.Cursor = Cursors.Default;
-                HoverIndex = SelectIndex;
+                HoveredIndex = SelectedIndex;
             }
             else
             {
                 this.Cursor = Cursors.Hand;
-                if(panel == PnlSelected) SelectIndex = index;
-                else HoverIndex = index;
+                if(panel == PnlSelected) SelectedIndex = index;
+                else HoveredIndex = index;
             }
         }
 
@@ -178,28 +179,29 @@ namespace BluePointLilac.Controls
         protected override void OnMouseLeave(EventArgs e)
         {
             base.OnMouseLeave(e);
-            HoverIndex = SelectIndex;
+            HoveredIndex = SelectedIndex;
         }
 
-        public Action SelectIndexChanged { get; set; }
+        public event EventHandler SelectIndexChanged;
 
-        public Action HoverIndexChanged { get; set; }
+        public event EventHandler HoverIndexChanged;
 
         private int selectIndex;
-        public int SelectIndex
+        public int SelectedIndex
         {
             get => selectIndex;
             set
             {
-                HoverIndex = value;
+                if(selectIndex == value) return;
+                HoveredIndex = value;
                 RefreshItem(PnlSelected, value);
                 selectIndex = value;
-                SelectIndexChanged?.Invoke();
+                SelectIndexChanged?.Invoke(this, null);
             }
         }
 
         private int hoverIndex;
-        public int HoverIndex
+        public int HoveredIndex
         {
             get => hoverIndex;
             set
@@ -207,7 +209,7 @@ namespace BluePointLilac.Controls
                 if(hoverIndex == value) return;
                 RefreshItem(PnlHovered, value);
                 hoverIndex = value;
-                HoverIndexChanged?.Invoke();
+                HoverIndexChanged?.Invoke(this, null);
             }
         }
     }

+ 4 - 6
ContextMenuManager/BluePointLilac.Controls/MyStatusBar.cs

@@ -1,5 +1,6 @@
 using BluePointLilac.Methods;
 using System;
+using System.ComponentModel;
 using System.Drawing;
 using System.Windows.Forms;
 
@@ -19,11 +20,8 @@ namespace BluePointLilac.Controls
             this.ForeColor = Color.White;
         }
 
-        public override string Text
-        {
-            get => base.Text;
-            set => base.Text = value;
-        }
+        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
+        public override string Text { get => base.Text; set => base.Text = value; }
 
         protected override void OnPaint(PaintEventArgs e)
         {
@@ -68,4 +66,4 @@ namespace BluePointLilac.Controls
             base.OnBackColorChanged(e); this.Refresh();
         }
     }
-}
+}

+ 23 - 12
ContextMenuManager/BluePointLilac.Controls/MyToolBar.cs

@@ -28,27 +28,39 @@ namespace BluePointLilac.Controls
                     selectedButton.Cursor = Cursors.Hand;
                 }
                 selectedButton = value;
-                selectedButton.Opacity = 0.4F;
-                selectedButton.Cursor = Cursors.Default;
-                SelectedButtonChanged?.Invoke();
+                if(selectedButton != null)
+                {
+                    selectedButton.Opacity = 0.4F;
+                    selectedButton.Cursor = Cursors.Default;
+                }
+                SelectedButtonChanged?.Invoke(this, null);
             }
         }
 
-        public Action SelectedButtonChanged { get; set; }
+        public event EventHandler SelectedButtonChanged;
 
         public int SelectedIndex
         {
-            get => Controls.GetChildIndex(SelectedButton);
-            set => SelectedButton = (MyToolBarButton)Controls[value];
+            get
+            {
+                if(SelectedButton == null) return -1;
+                else return Controls.GetChildIndex(SelectedButton);
+            }
+            set
+            {
+                if(value < 0 || value >= this.Controls.Count) SelectedButton = null;
+                else SelectedButton = (MyToolBarButton)Controls[value];
+            }
         }
 
         public void AddButton(MyToolBarButton button)
         {
+            this.SuspendLayout();
             button.Parent = this;
             button.Margin = new Padding(12, 4, 0, 0).DpiZoom();
             button.MouseDown += (sender, e) =>
             {
-                if(button.CanBeSelected) SelectedButton = button;
+                if(e.Button == MouseButtons.Left && button.CanBeSelected) SelectedButton = button;
             };
             button.MouseEnter += (sender, e) =>
             {
@@ -58,6 +70,7 @@ namespace BluePointLilac.Controls
             {
                 if(button != SelectedButton) button.Opacity = 0;
             };
+            this.ResumeLayout();
         }
 
         public void AddButtons(MyToolBarButton[] buttons)
@@ -72,7 +85,9 @@ namespace BluePointLilac.Controls
     {
         public MyToolBarButton(Image image, string text)
         {
+            this.SuspendLayout();
             this.DoubleBuffered = true;
+            this.Cursor = Cursors.Hand;
             this.Size = new Size(72, 72).DpiZoom();
             this.Controls.AddRange(new Control[] { picImage, lblText });
             lblText.Resize += (sender, e) => this.OnResize(null);
@@ -81,6 +96,7 @@ namespace BluePointLilac.Controls
             lblText.SetEnabled(false);
             this.Image = image;
             this.Text = text;
+            this.ResumeLayout();
         }
 
         readonly PictureBox picImage = new PictureBox
@@ -116,11 +132,6 @@ namespace BluePointLilac.Controls
         }
         public bool CanBeSelected { get; set; } = true;
 
-        protected override void OnMouseDown(MouseEventArgs e)
-        {
-            if(e.Button == MouseButtons.Left) base.OnMouseDown(e);
-        }
-
         protected override void OnResize(EventArgs e)
         {
             base.OnResize(e);

+ 21 - 1
ContextMenuManager/BluePointLilac.Controls/ReadOnlyTextBox.cs

@@ -1,4 +1,5 @@
 using BluePointLilac.Methods;
+using System;
 using System.Drawing;
 using System.Windows.Forms;
 
@@ -27,6 +28,15 @@ namespace BluePointLilac.Controls
             }
             base.WndProc(ref m);
         }
+
+        private bool firstEnter = true;
+
+        protected override void OnMouseEnter(EventArgs e)
+        {
+            base.OnMouseEnter(e);
+            if(firstEnter) this.Focus();
+            firstEnter = false;
+        }
     }
 
     public sealed class ReadOnlyRichTextBox : RichTextBox
@@ -54,9 +64,19 @@ namespace BluePointLilac.Controls
             base.WndProc(ref m);
         }
 
+        private bool firstEnter = true;
+
+        protected override void OnMouseEnter(EventArgs e)
+        {
+            base.OnMouseEnter(e);
+            if(firstEnter) this.Focus();
+            firstEnter = false;
+        }
+
         protected override void OnLinkClicked(LinkClickedEventArgs e)
         {
-            base.OnLinkClicked(e); ExternalProgram.OpenWebUrl(e.LinkText);
+            base.OnLinkClicked(e);
+            ExternalProgram.OpenWebUrl(e.LinkText);
         }
     }
 }

+ 2 - 3
ContextMenuManager/BluePointLilac.Controls/ResizeLimitedForm.cs

@@ -18,8 +18,7 @@ namespace BluePointLilac.Controls
             if(m.Msg == WM_NCHITTEST && this.WindowState == FormWindowState.Normal)
             {
                 IntPtr hNowhere = new IntPtr((int)HitTest.Nowhere);
-                HitTest value = (HitTest)m.Result;
-                switch(value)
+                switch((HitTest)m.Result)
                 {
                     case HitTest.Top:
                     case HitTest.Bottom:
@@ -41,7 +40,7 @@ namespace BluePointLilac.Controls
 
         const int WM_NCHITTEST = 0x84;//光标移动或鼠标按下、释放时的消息
         /// <summary>鼠标击中位置</summary>
-        public enum HitTest : int
+        enum HitTest : int
         {
             Error = -2,
             Transparent = -1,

+ 13 - 10
ContextMenuManager/BluePointLilac.Controls/SelectDialog.cs

@@ -1,12 +1,11 @@
 using BluePointLilac.Methods;
-using ContextMenuManager;
 using System;
 using System.Drawing;
 using System.Windows.Forms;
 
 namespace BluePointLilac.Controls
 {
-    class SelectDialog : CommonDialog
+    public class SelectDialog : CommonDialog
     {
         public string Title { get; set; }
         public string Selected { get; set; }
@@ -25,6 +24,8 @@ namespace BluePointLilac.Controls
                 if(this.Selected != null) frm.Selected = this.Selected;
                 else frm.SelectedIndex = this.SelectedIndex;
                 frm.CanEdit = this.CanEdit;
+                Form owner = (Form)Control.FromHandle(hwndOwner);
+                if(owner != null) frm.TopMost = owner.TopMost;
                 bool flag = frm.ShowDialog() == DialogResult.OK;
                 if(flag)
                 {
@@ -39,7 +40,8 @@ namespace BluePointLilac.Controls
         {
             public SelectForm()
             {
-                this.AcceptButton = btnOk;
+                this.SuspendLayout();
+                this.AcceptButton = btnOK;
                 this.CancelButton = btnCancel;
                 this.Font = SystemFonts.MenuFont;
                 this.ShowIcon = this.ShowInTaskbar = false;
@@ -47,6 +49,7 @@ namespace BluePointLilac.Controls
                 this.FormBorderStyle = FormBorderStyle.FixedSingle;
                 this.StartPosition = FormStartPosition.CenterParent;
                 this.InitializeComponents();
+                this.ResumeLayout();
             }
 
             public string Selected
@@ -82,16 +85,16 @@ namespace BluePointLilac.Controls
                 set => cmbItems.SelectedIndex = value;
             }
 
-            readonly Button btnOk = new Button
+            readonly Button btnOK = new Button
             {
                 DialogResult = DialogResult.OK,
-                Text = AppString.Dialog.Ok,
+                Text = ResourceString.OK,
                 AutoSize = true
             };
             readonly Button btnCancel = new Button
             {
                 DialogResult = DialogResult.Cancel,
-                Text = AppString.Dialog.Cancel,
+                Text = ResourceString.Cancel,
                 AutoSize = true
             };
             readonly ComboBox cmbItems = new ComboBox
@@ -104,13 +107,13 @@ namespace BluePointLilac.Controls
 
             private void InitializeComponents()
             {
-                this.Controls.AddRange(new Control[] { cmbItems, btnOk, btnCancel });
+                this.Controls.AddRange(new Control[] { cmbItems, btnOK, btnCancel });
                 int a = 20.DpiZoom();
                 cmbItems.Left = a;
                 cmbItems.Width = 85.DpiZoom();
-                cmbItems.Top = btnOk.Top = btnCancel.Top = a;
-                btnOk.Left = cmbItems.Right + a;
-                btnCancel.Left = btnOk.Right + a;
+                cmbItems.Top = btnOK.Top = btnCancel.Top = a;
+                btnOK.Left = cmbItems.Right + a;
+                btnCancel.Left = btnOK.Right + a;
                 this.ClientSize = new Size(btnCancel.Right + a, btnCancel.Bottom + a);
                 cmbItems.AutosizeDropDownWidth();
             }

+ 66 - 0
ContextMenuManager/BluePointLilac.Controls/UAWebClient.cs

@@ -0,0 +1,66 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Runtime.Serialization.Json;
+using System.Text;
+using System.Xml;
+
+namespace BluePointLilac.Controls
+{
+    public sealed class UAWebClient : WebClient
+    {
+        public UAWebClient()
+        {
+            //此类主要为了解决访问Github的一些问题
+            //请求被中止: 未能创建 SSL/TLS 安全通道; 基础连接已经关闭: 发送时发生错误,一般添加TLS12即可
+            //TLS12------0xc00,TLS11------0x300,TLS------0xc0,SSL------0x30;
+            ServicePointManager.SecurityProtocol = (SecurityProtocolType)(0xc00 | 0x300 | 0xc0 | 0x30);
+            //网络传输默认文本编码 UTF-8
+            this.Encoding = Encoding.UTF8;
+            //远程服务器返回错误: (403) 已禁止
+            //浏览器 F12 console 输入 console.log(navigator.userAgent); 获取 User Agent
+            this.Headers.Add("User-Agent",
+                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " +
+                "Chrome/90.0.4430.212 Safari/537.36 Edg/90.0.818.66");
+        }
+
+        /// <summary>获取网页文本</summary>
+        public string GetWebString(string url)
+        {
+            try
+            {
+                string str = this.DownloadString(url);
+                str = str?.Replace("\n", Environment.NewLine);//换行符转换
+                return str;
+            }
+            catch { return null; }
+        }
+
+        /// <summary>将网络文本写入本地文件</summary>
+        /// <param name="filePath">本地文件路径</param>
+        /// <param name="fileUrl">网络文件Raw路径</param>
+        public bool WebStringToFile(string filePath, string fileUrl)
+        {
+            string contents = GetWebString(fileUrl);
+            bool flag = contents != null;
+            if(flag) File.WriteAllText(filePath, contents, Encoding.Unicode);
+            return flag;
+        }
+
+        /// <summary>获取网页Json文本并加工为Xml</summary>
+        public XmlDocument GetWebJsonToXml(string url)
+        {
+            try
+            {
+                byte[] bytes = this.DownloadData(url);
+                using(XmlReader xReader = JsonReaderWriterFactory.CreateJsonReader(bytes, XmlDictionaryReaderQuotas.Max))
+                {
+                    XmlDocument doc = new XmlDocument();
+                    doc.Load(xReader);
+                    return doc;
+                }
+            }
+            catch { return null; }
+        }
+    }
+}

+ 6 - 18
ContextMenuManager/BluePointLilac.Methods/ControlExtension.cs

@@ -7,33 +7,22 @@ namespace BluePointLilac.Methods
     public static class ControlExtension
     {
         [DllImport("user32.dll")]
-        private static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
+        private static extern int PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
 
         [DllImport("user32.dll")]
         private static extern bool ReleaseCapture();
 
-        private const int WM_NCLBUTTONDOWN = 0xA1;
-        private const int HT_CAPTION = 0x2;
-
         /// <summary>使控件能够移动所属窗体</summary>
         /// <param name="ctr">目标控件</param>
         public static void CanMoveForm(this Control ctr)
         {
-            bool isDown = false;
-            DateTime downTime = DateTime.MinValue;
-            ctr.MouseDown += (sender, e) =>
-            {
-                isDown = e.Button == MouseButtons.Left;
-                downTime = DateTime.Now;
-            };
-            ctr.MouseUp += (sender, e) => isDown = false;
+            const int WM_NCLBUTTONDOWN = 0xA1;
+            const int HT_CAPTION = 0x2;
             ctr.MouseMove += (sender, e) =>
             {
                 if(e.Button != MouseButtons.Left) return;
-                //避免ReleaseCapture影响控件的其他鼠标事件
-                if((DateTime.Now - downTime).TotalMilliseconds < 20) return;
                 ReleaseCapture();
-                SendMessage(ctr.FindForm().Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
+                PostMessage(ctr.FindForm().Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
             };
         }
 
@@ -43,15 +32,14 @@ namespace BluePointLilac.Methods
         [DllImport("user32.dll")]
         private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
 
-        private const int GWL_STYLE = -16;
-        private const int WS_DISABLED = 0x8000000;
-
         /// <summary>通过Win32API禁用/启用目标控件</summary>
         /// <remarks>控件被禁用时仍可更改字体颜色,不需要同时设置ctr.Enabled=false</remarks>
         /// <param name="ctr">目标控件</param>
         /// <param name="enabled">启用为true,禁用为false</param>
         public static void SetEnabled(this Control ctr, bool enabled)
         {
+            const int GWL_STYLE = -16;
+            const int WS_DISABLED = 0x8000000;
             int value = GetWindowLong(ctr.Handle, GWL_STYLE);
             if(enabled) value &= ~WS_DISABLED;
             else value |= WS_DISABLED;

+ 3 - 3
ContextMenuManager/BluePointLilac.Methods/ElevatedFileDroper.cs

@@ -12,7 +12,7 @@ namespace BluePointLilac.Methods
     /// 代码来源2:https://github.com/volschin/sdimager/blob/master/ElevatedDragDropManager.cs
     /// 代码作者:雨少主(知乎)、volschin(Github)、蓝点lilac(转载、修改)
     /// 调用方法:var droper = new ElevatedFileDroper(control);
-    /// droper.DragDrop += () => MessageBox.Show(droper.DropFilePaths[0]);
+    /// droper.DragDrop += (sender, e) => MessageBox.Show(droper.DropFilePaths[0]);
     /// 备注:此类只能生效一个实例,不能将control.AllowDrop设为true,droper.DragDrop与control.DragDrop不共存
 
     public sealed class ElevatedFileDroper : IMessageFilter
@@ -69,7 +69,7 @@ namespace BluePointLilac.Methods
         const uint WM_COPYDATA = 0x004A;
         const uint WM_DROPFILES = 0x0233;
 
-        public Action DragDrop { get; set; }
+        public event EventHandler DragDrop;
         public string[] DropFilePaths { get; private set; }
         public Point DropPoint { get; private set; }
 
@@ -132,7 +132,7 @@ namespace BluePointLilac.Methods
             DragFinish(handle);
             DropPoint = point;
             DropFilePaths = filePaths;
-            DragDrop?.Invoke();
+            DragDrop?.Invoke(this, null);
             return true;
         }
     }

+ 8 - 8
ContextMenuManager/BluePointLilac.Methods/ExternalProgram.cs

@@ -20,7 +20,7 @@ namespace BluePointLilac.Methods
             //还有一种方法,修改HKCU\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit
             //中的LastKey键值(记录上次关闭注册表编辑器时的注册表路径)为要跳转的注册表项路径regPath,
             //再使用Process.Start("regedit.exe", "-m")打开注册表编辑器
-            //优点:代码少、不会有Bug。缺点:不能定位具体键,没有展开效果
+            //优点:代码少、不会有Bug。缺点:不能定位具体键,没有逐步展开效果
             if(regPath == null) return;
             Process process;
             IntPtr hMain = FindWindow("RegEdit_RegEdit", null);
@@ -124,7 +124,8 @@ namespace BluePointLilac.Methods
             SHELLEXECUTEINFO info = new SHELLEXECUTEINFO
             {
                 lpVerb = "Properties",
-                //lpParameters = "详细信息";//显示选项卡,此处有语言差异
+                //显示详细信息选项卡, 此处有语言差异
+                //lpParameters = ResourceString.GetDirectString("@shell32.dll,-31433"),//"详细信息",
                 lpFile = filePath,
                 nShow = SW_SHOW,
                 fMask = SEE_MASK_INVOKEIDLIST,
@@ -140,8 +141,7 @@ namespace BluePointLilac.Methods
             //Win10 调用 SHOpenWithDialog API 或调用 OpenWith.exe -override "%1"
             //或调用 rundll32.exe shell32.dll,OpenAs_RunDLL %1 能显示打开方式对话框,但都不能设置默认应用
             //以下方法只针对未关联打开方式的扩展名显示系统打开方式对话框,对于已关联打开方式的扩展名会报错
-            string tempPath = $"{Path.GetTempPath()}{extension}";
-            tempPath = ObjectPath.GetNewPathWithIndex(tempPath, ObjectPath.PathType.File);
+            string tempPath = $"{Path.GetTempPath()}{Guid.NewGuid()}{extension}";
             File.WriteAllText(tempPath, "");
             using(Process process = new Process())
             {
@@ -159,9 +159,9 @@ namespace BluePointLilac.Methods
         /// <summary>重启Explorer</summary>
         public static void RestartExplorer()
         {
-            //有些系统有tskill.exe可以直接调用tskill explorer命令
             using(Process process = new Process())
             {
+                //有些系统有tskill.exe可以直接调用tskill explorer命令
                 process.StartInfo = new ProcessStartInfo
                 {
                     FileName = "taskkill.exe",
@@ -185,8 +185,7 @@ namespace BluePointLilac.Methods
             using(Process process = new Process())
             {
                 //通过explorer来调用默认浏览器打开链接,避免管理员权限影响
-                process.StartInfo.FileName = "explorer.exe";
-                process.StartInfo.Arguments = $"\"{url}\"";
+                process.StartInfo = new ProcessStartInfo($"\"{url}\"");
                 process.Start();
             }
         }
@@ -200,6 +199,7 @@ namespace BluePointLilac.Methods
             {
                 process.StartInfo.FileName = "regedit.exe";
                 process.StartInfo.Arguments = $"/e \"{filePath}\" \"{regPath}\"";
+                process.Start();
                 process.WaitForExit();
             }
         }
@@ -235,7 +235,7 @@ namespace BluePointLilac.Methods
         private static extern bool SetFocus(IntPtr hWnd);
 
         [DllImport("user32.dll", CharSet = CharSet.Auto)]
-        public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);
+        private static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);
 
         [DllImport("user32.dll")]
         private static extern IntPtr FindWindow(string lpszClass, string lpszWindow);

+ 19 - 29
ContextMenuManager/BluePointLilac.Methods/FileExtension.cs

@@ -23,7 +23,7 @@ namespace BluePointLilac.Methods
             IgnoreBaseClass = 0x200
         }
 
-        enum AssocStr
+        public enum AssocStr
         {
             Command = 1,
             Executable,
@@ -40,9 +40,11 @@ namespace BluePointLilac.Methods
         [DllImport("shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
         private static extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra, [Out] StringBuilder pszOut, ref uint pcchOut);
 
-        public const string FileExtsPath = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts";
+        public const string FILEEXTSPATH = @"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts";
+        private const string HKCRCLASSES = @"HKEY_CURRENT_USER\SOFTWARE\Classes";
+        private const string HKLMCLASSES = @"HKEY_LOCAL_MACHINE\SOFTWARE\Classes";
 
-        private static string GetExtentionInfo(AssocStr assocStr, string extension)
+        public static string GetExtentionInfo(AssocStr assocStr, string extension)
         {
             uint pcchOut = 0;
             AssocQueryString(AssocF.Verify, assocStr, extension, null, null, ref pcchOut);
@@ -51,39 +53,27 @@ namespace BluePointLilac.Methods
             return pszOut.ToString();
         }
 
-        public static string GetExecutablePath(string extension)
-        {
-            return GetExtentionInfo(AssocStr.Executable, extension);
-        }
-
-        public static string GetFriendlyDocName(string extension)
-        {
-            return GetExtentionInfo(AssocStr.FriendlyDocName, extension);
-        }
-
         public static string GetOpenMode(string extension)
         {
             if(string.IsNullOrEmpty(extension)) return null;
-            string mode = Registry.GetValue($@"{FileExtsPath}\{extension}\UserChoice", "ProgId", null)?.ToString();
-            if(!string.IsNullOrEmpty(mode)) return mode;
-            using(RegistryKey root = Registry.ClassesRoot)
-            using(RegistryKey exKey = root.OpenSubKey(extension))
+            string mode;
+            bool CheckMode()
             {
-                if(exKey == null) return null;
-                mode = exKey.GetValue("")?.ToString();
-                if(!mode.IsNullOrWhiteSpace()) return mode;
-                using(RegistryKey pkey = exKey.OpenSubKey("OpenWithProgids"))
+                if(mode.IsNullOrWhiteSpace()) return false;
+                if(mode.Length > 255) return false;
+                if(mode.ToLower().StartsWith(@"applications\")) return false;
+                using(RegistryKey root = Registry.ClassesRoot)
+                using(RegistryKey key = root.OpenSubKey(mode))
                 {
-                    if(pkey == null) return null;
-                    foreach(string name in pkey.GetValueNames())
-                    {
-                        using(RegistryKey mKey = root.OpenSubKey(name))
-                        {
-                            if(mKey.GetValue("") != null) return name;
-                        }
-                    }
+                    return key != null;
                 }
             }
+            mode = Registry.GetValue($@"{FILEEXTSPATH}\{extension}\UserChoice", "ProgId", null)?.ToString();
+            if(CheckMode()) return mode;
+            mode = Registry.GetValue($@"{HKLMCLASSES}\{extension}", "", null)?.ToString();
+            if(CheckMode()) return mode;
+            mode = Registry.GetValue($@"{HKCRCLASSES}\{extension}", "", null)?.ToString();
+            if(CheckMode()) return mode;
             return null;
         }
     }

+ 39 - 0
ContextMenuManager/BluePointLilac.Methods/FormExtension.cs

@@ -0,0 +1,39 @@
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace BluePointLilac.Methods
+{
+    public static class FormExtension
+    {
+        /// <summary>移动窗体时同时移动另一个窗体</summary>
+        public static void MoveAsMove(this Form frm1, Form frm2)
+        {
+            if(frm2 == null) return;
+            Point pLast = Point.Empty;
+            frm1.Load += (sender, e) => pLast = frm1.Location;
+            frm1.LocationChanged += (sender, e) =>
+            {
+                if(pLast == Point.Empty) return;
+                frm2.Left += frm1.Left - pLast.X;
+                frm2.Top += frm1.Top - pLast.Y;
+                pLast = frm1.Location;
+            };
+        }
+
+        /// <summary>给窗体添加ESC键关闭功能</summary>
+        /// <remarks>也可以重写Form的ProcessDialogKey事件,
+        /// 这个方法更简单,但遍历窗体控件时切记多了一个不可见的关闭按钮</remarks>
+        public static void AddEscapeButton(this Form frm, DialogResult dr = DialogResult.Cancel)
+        {
+            Button btn = new Button
+            {
+                Parent = frm,
+                Size = Size.Empty,
+                DialogResult = dr
+            };
+            frm.CancelButton = btn;
+            frm.Disposed += (sender, e) => btn.Dispose();
+            frm.FormClosing += (sender, e) => btn.PerformClick();
+        }
+    }
+}

+ 4 - 2
ContextMenuManager/BluePointLilac.Methods/HighDpi.cs

@@ -5,7 +5,9 @@ using System.Windows.Forms;
 namespace BluePointLilac.Methods
 {
     /// <summary>处理不同DPI缩放比下的像素绘制和字体显示问题</summary>
-    /// <remarks>Font为矢量类型,Point、Size、Rectangle、Padding等为像素类型。
+    /// <remarks>使用此类需要添加引用 PresentationFramework
+    /// 还应在配置清单App.manifest中启用DPI感知自动缩放
+    /// Font为矢量类型,Point、Size、Rectangle、Padding等为像素类型。
     /// 在不同DPI缩放下,矢量类型等比缩放,像素类型保持不变,故会出现排版显示问题。
     /// 解决方案一:项目中所有用到的像素类型实例值都取与缩放比之积,矢量类型不变。
     /// 解决方案二:项目中所有用到的矢量类型实例都取与缩放比之商,像素类型不变</remarks>
@@ -28,7 +30,7 @@ namespace BluePointLilac.Methods
 
         public static Padding DpiZoom(this Padding p) => new Padding(DpiZoom(p.Left), DpiZoom(p.Top), DpiZoom(p.Right), DpiZoom(p.Bottom));
 
-        public static Font DpiZoom(this Font font) => new Font(font.FontFamily, font.Size / DpiZoom(1F));
+        public static Font DpiZoom(this Font font) => new Font(font.FontFamily, font.Size / DpiZoom(1F), font.Style);
 
         public static int DpiZoom(this int num) => (int)(num * DpiScale);
 

+ 81 - 5
ContextMenuManager/BluePointLilac.Methods/IniReader.cs

@@ -8,8 +8,20 @@ namespace BluePointLilac.Methods
 {
     public sealed class IniReader
     {
-        public IniReader(StringBuilder sb)
+        public IniReader() { }
+
+        public IniReader(StringBuilder sb) => LoadStringBuilder(sb);
+
+        public IniReader(string filePath) => LoadFile(filePath);
+
+        private readonly Dictionary<string, Dictionary<string, string>> RootDic
+            = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
+
+        public string[] Sections => RootDic.Keys.ToArray();
+
+        public void LoadStringBuilder(StringBuilder sb)
         {
+            RootDic.Clear();
             if(sb.ToString().IsNullOrWhiteSpace()) return;
             List<string> lines = sb.ToString().Split(new[] { "\r\n", "\n" },
                 StringSplitOptions.RemoveEmptyEntries).ToList();//拆分为行
@@ -17,8 +29,9 @@ namespace BluePointLilac.Methods
             ReadLines(lines);
         }
 
-        public IniReader(string filePath)
+        public void LoadFile(string filePath)
         {
+            RootDic.Clear();
             if(!File.Exists(filePath)) return;
             List<string> lines = new List<string>();
             using(StreamReader reader = new StreamReader(filePath, EncodingType.GetType(filePath)))
@@ -32,9 +45,6 @@ namespace BluePointLilac.Methods
             ReadLines(lines);
         }
 
-        public readonly Dictionary<string, Dictionary<string, string>> RootDic
-            = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
-
         private void ReadLines(List<string> lines)
         {
             lines.RemoveAll(
@@ -84,5 +94,71 @@ namespace BluePointLilac.Methods
             value = GetValue(section, key);
             return value != string.Empty;
         }
+
+        public string[] GetSectionKeys(string section)
+        {
+            if(!RootDic.ContainsKey(section)) return null;
+            else return RootDic[section].Keys.ToArray();
+        }
+
+        public bool RemoveSection(string section)
+        {
+            return RootDic.Remove(section);
+        }
+
+        public bool RemoveKey(string section, string key)
+        {
+            if(RootDic.ContainsKey(section))
+            {
+                return RootDic[section].Remove(key);
+            }
+            return false;
+        }
+
+        public void AddValue(string section, string key, string value)
+        {
+            if(RootDic.ContainsKey(section))
+            {
+                if(RootDic[section].ContainsKey(key))
+                {
+                    RootDic[section][key] = value;
+                }
+                else
+                {
+                    RootDic[section].Add(key, value);
+                }
+            }
+            else
+            {
+                var dic = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+                RootDic.Add(section, dic);
+                dic.Add(key, value);
+            }
+        }
+
+        public void SaveFile(string filePath)
+        {
+            List<string> lines = new List<string>();
+            foreach(var item in RootDic)
+            {
+                lines.Add("[" + item.Key + "]");
+                foreach(var key in item.Value)
+                {
+                    lines.Add(key.Key + " = " + key.Value);
+                }
+                lines.Add("");
+            }
+            Directory.CreateDirectory(Path.GetDirectoryName(filePath));
+            FileAttributes attributes = FileAttributes.Normal;
+            Encoding encoding = Encoding.Unicode;
+            if(File.Exists(filePath))
+            {
+                encoding = EncodingType.GetType(filePath);
+                attributes = File.GetAttributes(filePath);
+                File.SetAttributes(filePath, FileAttributes.Normal);
+            }
+            File.WriteAllLines(filePath, lines.ToArray(), encoding);
+            File.SetAttributes(filePath, attributes);
+        }
     }
 }

+ 12 - 14
ContextMenuManager/BluePointLilac.Methods/IniWriter.cs

@@ -133,23 +133,21 @@ namespace BluePointLilac.Methods
                 }
             }
 
-            if(DeleteFileWhenEmpty && lines.Count == 0 && File.Exists(FilePath))
+            Directory.CreateDirectory(Path.GetDirectoryName(FilePath));
+            FileAttributes attributes = FileAttributes.Normal;
+            Encoding encoding = Encoding.Unicode;
+            if(File.Exists(FilePath))
             {
-                File.Delete(FilePath);
+                encoding = EncodingType.GetType(FilePath);
+                attributes = File.GetAttributes(FilePath);
+                File.SetAttributes(FilePath, FileAttributes.Normal);
             }
-            else
+            File.WriteAllLines(FilePath, lines.ToArray(), encoding);
+            File.SetAttributes(FilePath, attributes);
+
+            if(DeleteFileWhenEmpty && lines.TrueForAll(line => line.IsNullOrWhiteSpace()))
             {
-                Directory.CreateDirectory(Path.GetDirectoryName(FilePath));
-                FileAttributes attributes = FileAttributes.Normal;
-                Encoding encoding = Encoding.Unicode;
-                if(File.Exists(FilePath))
-                {
-                    encoding = EncodingType.GetType(FilePath);
-                    attributes = File.GetAttributes(FilePath);
-                    File.SetAttributes(FilePath, FileAttributes.Normal);
-                }
-                File.WriteAllLines(FilePath, lines.ToArray(), encoding);
-                File.SetAttributes(FilePath, attributes);
+                File.Delete(FilePath);
             }
         }
 

+ 249 - 4
ContextMenuManager/BluePointLilac.Methods/MessageBoxEx.cs

@@ -1,14 +1,259 @@
-using ContextMenuManager;
+using System;
+using System.Drawing;
 using System.Windows.Forms;
 
 namespace BluePointLilac.Methods
 {
+    /// <summary>在窗体居中显示的MessageBox</summary>
     public static class MessageBoxEx
     {
-        public static DialogResult Show(string text, MessageBoxButtons buttons = MessageBoxButtons.OK,
-            MessageBoxIcon icon = MessageBoxIcon.Warning, string caption = null)
+        /// <summary>弹出一个消息框</summary>
+        /// <param name="text">要在消息框中显示的文本</param>
+        /// <param name="caption">要在消息框的标题栏中显示的文本</param>
+        /// <param name="buttons">指定在消息框中显示哪些按钮</param>
+        /// <param name="boxIcon">指定在消息框中显示哪个图标</param>
+        /// <param name="owner">指定消息框的拥有者</param>
+        /// <param name="defaultResult">指定默认结果,使对应按钮预先获取焦点</param>
+        /// <param name="canMoveParent">能否移动父窗体</param>
+        /// <returns>System.Windows.Forms.DialogResult 值之一</returns>
+        public static DialogResult Show(string text, string caption = null,
+            MessageBoxButtons buttons = MessageBoxButtons.OK, MessageBoxIcon boxIcon = MessageBoxIcon.None,
+            IWin32Window owner = null, DialogResult defaultResult = DialogResult.None, bool canMoveParent = true)
         {
-            return MessageBox.Show(text, caption ?? AppString.General.AppName, buttons, icon);
+            using(MessageBoxForm frm = new MessageBoxForm(text, caption, buttons, boxIcon, defaultResult, canMoveParent))
+            {
+                return frm.ShowDialog(owner);
+            }
+        }
+
+        /// <summary>弹出一个消息框</summary>
+        /// <param name="text">要在消息框中显示的文本</param>
+        /// <param name="caption">要在消息框的标题栏中显示的文本</param>
+        /// <param name="buttonTexts">从右至左添加数组长度的个数的按钮,按钮文本为数组对应成员</param>
+        /// <param name="boxImaage">指定在消息框中显示的图标图像</param>
+        /// <param name="owner">指定消息框的拥有者</param>
+        /// <param name="defaultResult">指定默认结果,使对应按钮预先获取焦点</param>
+        /// <param name="canMoveParent">能否移动父窗体</param>
+        /// <param name="closeBox">消息框关闭按钮是否可用</param>
+        /// <returns>返回用户点击的按钮所显示的文本</returns>
+        public static string Show(string text, string caption,
+            string[] buttonTexts, Image boxImaage,
+            IWin32Window owner = null, string defaultResult = null,
+            bool canMoveParent = true, bool closeBox = true)
+        {
+            using(MessageBoxForm frm = new MessageBoxForm(text, caption, buttonTexts, boxImaage, defaultResult, canMoveParent, closeBox))
+            {
+                frm.ShowDialog(owner);
+                return frm.Tag?.ToString();
+            }
+        }
+
+        sealed class MessageBoxForm : Form
+        {
+            private MessageBoxForm(string text, string caption, bool canMoveParent)
+            {
+                lblText.Text = text;
+                this.Text = caption;
+                this.CanMoveParent = canMoveParent;
+                this.Font = SystemFonts.MessageBoxFont;
+                this.ShowIcon = this.ShowInTaskbar = false;
+                this.MaximizeBox = this.MinimizeBox = false;
+                this.FormBorderStyle = FormBorderStyle.FixedSingle;
+                this.StartPosition = FormStartPosition.CenterParent;
+            }
+
+            public MessageBoxForm(string text, string caption,
+                string[] buttonTexts, Image boxImage,
+                string defaultResult, bool canMoveParent, bool closeBox) : this(text, caption, canMoveParent)
+            {
+                this.CloseBox = closeBox;
+                this.InitializeComponents(buttonTexts, boxImage);
+                foreach(Button button in flpButtons.Controls)
+                {
+                    button.Click += (sender, e) =>
+                    {
+                        this.Tag = button.Text;
+                        this.Close();
+                    };
+                    this.Shown += (sender, e) =>
+                    {
+                        if(button.Text == defaultResult) button.Focus();
+                    };
+                }
+            }
+
+            public MessageBoxForm(string text, string caption,
+                MessageBoxButtons buttons, MessageBoxIcon boxIcon,
+                DialogResult defaultResult, bool canMoveParent) : this(text, caption, canMoveParent)
+            {
+                string[] buttonTexts = null;
+                Image boxImage = null;
+                switch(buttons)
+                {
+                    case MessageBoxButtons.OK:
+                        buttonTexts = new[] { "OK" }; break;
+                    case MessageBoxButtons.OKCancel:
+                        buttonTexts = new[] { "Cancel", "OK" }; break;
+                    case MessageBoxButtons.AbortRetryIgnore:
+                        buttonTexts = new[] { "&Ignore", "&Retry", "&Abort" }; break;
+                    case MessageBoxButtons.YesNoCancel:
+                        buttonTexts = new[] { "Cancel", "&No", "&Yes" }; break;
+                    case MessageBoxButtons.YesNo:
+                        buttonTexts = new[] { "&No", "&Yes" }; break;
+                    case MessageBoxButtons.RetryCancel:
+                        buttonTexts = new[] { "Cancel", "&Retry" }; break;
+                }
+                switch(boxIcon)
+                {
+                    case MessageBoxIcon.Question:
+                        boxImage = MessageBoxImage.Question; break;
+                    case MessageBoxIcon.Error:
+                        boxImage = MessageBoxImage.Error; break;
+                    case MessageBoxIcon.Warning:
+                        boxImage = MessageBoxImage.Warning; break;
+                    case MessageBoxIcon.Information:
+                        boxImage = MessageBoxImage.Information; break;
+                }
+                this.InitializeComponents(buttonTexts, boxImage);
+                foreach(Button button in flpButtons.Controls)
+                {
+                    switch(button.Text)
+                    {
+                        case "OK":
+                            if(buttons == MessageBoxButtons.OK)
+                            {
+                                this.CancelButton = button;
+                                this.FormClosing += (sender, e) => button.PerformClick();
+                            }
+                            button.DialogResult = DialogResult.OK; break;
+                        case "Cancel":
+                            this.CancelButton = button;
+                            button.DialogResult = DialogResult.Cancel; break;
+                        case "&Yes":
+                            button.DialogResult = DialogResult.Yes; break;
+                        case "&No":
+                            button.DialogResult = DialogResult.No; break;
+                        case "&Abort":
+                            button.DialogResult = DialogResult.Abort; break;
+                        case "&Retry":
+                            button.DialogResult = DialogResult.Retry; break;
+                        case "&Ignore":
+                            button.DialogResult = DialogResult.Ignore; break;
+                    }
+                    this.Shown += (sender, e) =>
+                    {
+                        if(button.DialogResult == defaultResult) button.Focus();
+                    };
+                }
+                this.CloseBox = this.CancelButton != null;
+            }
+
+            private void InitializeComponents(string[] buttonTexts, Image boxImage)
+            {
+                this.SuspendLayout();
+                int w1 = 36.DpiZoom();
+                Size buttonSize = new Size(75, 27).DpiZoom();
+                for(int i = 0; i < buttonTexts.Length; i++)
+                {
+                    Button button = new Button
+                    {
+                        Margin = new Padding(12, 0, 0, 0).DpiZoom(),
+                        Text = buttonTexts[i],
+                        Parent = flpButtons,
+                        AutoSize = true,
+                    };
+                    button.Width = Math.Max(buttonSize.Width, button.Width);
+                    button.Height = Math.Max(buttonSize.Height, button.Height);
+                    buttonSize = button.Size;
+                    w1 += button.Width + button.Margin.Horizontal;
+                }
+                picIcon.Image = boxImage;
+                if(boxImage == null)
+                {
+                    picIcon.Visible = false;
+                    lblText.Left = picIcon.Left;
+                }
+                pnlInfo.Controls.AddRange(new Control[] { picIcon, lblText });
+                this.Controls.AddRange(new Control[] { pnlInfo, flpButtons });
+                pnlInfo.Height = lblText.Height + lblText.Top * 2;
+                if(picIcon.Height > lblText.Height / 2)
+                {
+                    picIcon.Top = (pnlInfo.Height - picIcon.Height) / 2;
+                }
+                int w2 = lblText.Right + picIcon.Left;
+                int w = Math.Max(w1, w2);
+                int h = pnlInfo.Height + flpButtons.Height;
+                this.ClientSize = new Size(w, h);
+                this.ResumeLayout();
+            }
+
+            readonly FlowLayoutPanel flpButtons = new FlowLayoutPanel
+            {
+                FlowDirection = FlowDirection.RightToLeft,
+                Padding = new Padding(12.DpiZoom()),
+                Dock = DockStyle.Bottom,
+                Height = 50.DpiZoom(),
+                WrapContents = false,
+            };
+            readonly Panel pnlInfo = new Panel
+            {
+                BackColor = Color.White,
+                Dock = DockStyle.Top,
+            };
+            readonly PictureBox picIcon = new PictureBox
+            {
+                SizeMode = PictureBoxSizeMode.AutoSize,
+                Location = new Point(32, 32).DpiZoom(),
+            };
+            readonly Label lblText = new Label
+            {
+                Location = new Point(68, 32).DpiZoom(),
+                AutoSize = true,
+            };
+
+            readonly bool CloseBox = true;//关闭按钮可用性
+            readonly bool CanMoveParent = true;//可移动父窗体
+
+            protected override CreateParams CreateParams
+            {
+                get
+                {
+                    const int CP_NOCLOSE_BUTTON = 0x200;
+                    CreateParams cp = base.CreateParams;
+                    if(!CloseBox) cp.ClassStyle |= CP_NOCLOSE_BUTTON; //禁用关闭按钮
+                    return cp;
+                }
+            }
+
+            protected override void OnLoad(EventArgs e)
+            {
+                if(this.Owner == null && Form.ActiveForm != this) this.Owner = Form.ActiveForm;
+                if(this.Owner == null) this.StartPosition = FormStartPosition.CenterScreen;
+                else
+                {
+                    this.TopMost = this.Owner.TopMost;
+                    this.StartPosition = FormStartPosition.CenterParent;
+                    if(this.CanMoveParent) this.MoveAsMove(this.Owner);
+                }
+                base.OnLoad(e);
+            }
+        }
+    }
+
+    public static class MessageBoxImage
+    {
+        // SystemIcons 里面的图标不是扁平的,❌、⚠️、❔、ℹ️
+        public static readonly Image Error = GetImage(-98);
+        public static readonly Image Warning = GetImage(-84);
+        public static readonly Image Question = GetImage(-99);
+        public static readonly Image Information = GetImage(-81);
+
+        private static Image GetImage(int index)
+        {
+            using(Icon icon = ResourceIcon.GetIcon("imageres.dll", index))
+            {
+                return icon?.ToBitmap();
+            }
         }
     }
 }

+ 20 - 11
ContextMenuManager/BluePointLilac.Methods/RegistryEx.cs

@@ -1,19 +1,23 @@
 using Microsoft.Win32;
 using System;
-using System.Diagnostics;
-using System.IO;
 using System.Security.AccessControl;
 
 namespace BluePointLilac.Methods
 {
     public static class RegistryEx
     {
-        public const string CLASSESROOT = "HKEY_CLASSES_ROOT";
-        public const string CURRENTUSER = "HKEY_CURRENT_USER";
-        public const string LOCALMACHINE = "HKEY_LOCAL_MACHINE";
-        public const string CURRENTCONFIG = "HKEY_CURRENT_CONFIG";
+        public const string CLASSES_ROOT = "HKEY_CLASSES_ROOT";
+        public const string CURRENT_USER = "HKEY_CURRENT_USER";
+        public const string LOCAL_MACHINE = "HKEY_LOCAL_MACHINE";
+        public const string CURRENT_CONFIG = "HKEY_CURRENT_CONFIG";
         public const string USERS = "HKEY_USERS";
 
+        public const string HKCR = "HKCR";
+        public const string HKCU = "HKCU";
+        public const string HKLM = "HKLM";
+        public const string HKCC = "HKCC";
+        public const string HKU = "HKU";
+
         public static void CopyTo(this RegistryKey srcKey, RegistryKey dstKey)
         {
             foreach(string name in srcKey.GetValueNames())
@@ -113,23 +117,28 @@ namespace BluePointLilac.Methods
             }
             switch(rootPath)
             {
-                case CLASSESROOT:
+                case HKCR:
+                case CLASSES_ROOT:
                     root = Registry.ClassesRoot;
                     break;
-                case CURRENTUSER:
+                case HKCU:
+                case CURRENT_USER:
                     root = Registry.CurrentUser;
                     break;
-                case LOCALMACHINE:
+                case HKLM:
+                case LOCAL_MACHINE:
                     root = Registry.LocalMachine;
                     break;
+                case HKU:
                 case USERS:
                     root = Registry.Users;
                     break;
-                case CURRENTCONFIG:
+                case HKCC:
+                case CURRENT_CONFIG:
                     root = Registry.CurrentConfig;
                     break;
                 default:
-                    throw new ArgumentNullException("The root key resolution failed!");
+                    throw new ArgumentNullException(regPath);
             }
         }
 

+ 12 - 3
ContextMenuManager/BluePointLilac.Methods/ResourceString.cs

@@ -6,9 +6,18 @@ namespace BluePointLilac.Methods
 {
     public static class ResourceString
     {
-        /// <summary> 获取格式为"@filename,-strID"直接字符串 </summary>
+        //MSDN文档: https://docs.microsoft.com/windows/win32/api/shlwapi/nf-shlwapi-shloadindirectstring
+        //提取.pri文件资源: https://docs.microsoft.com/windows/uwp/app-resources/makepri-exe-command-options
+        //.pri转储.xml资源列表: MakePri.exe dump /if [priPath] /of [xmlPath]
+
+        [DllImport("shlwapi.dll", BestFitMapping = false, CharSet = CharSet.Unicode,
+            ExactSpelling = true, SetLastError = false, ThrowOnUnmappableChar = true)]
+        private static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, uint cchOutBuf, IntPtr ppvReserved);
+
+        /// <summary>获取格式为"@[filename],-[strID]"或"@{[packageName]?ms-resource://[resPath]}"的直接字符串</summary>
         /// <param name="resStr">要转换的字符串</param>
         /// <returns>resStr为Null时返回值为string.Empty; resStr首字符为@但解析失败时返回string.Empty</returns>
+        /// <remarks>[fileName]:文件路径; [strID]:字符串资源索引; [packageName]:UWP带版本号包名; [resPath]:pri资源路径</remarks>
         public static string GetDirectString(string resStr)
         {
             StringBuilder outBuff = new StringBuilder(1024);
@@ -16,7 +25,7 @@ namespace BluePointLilac.Methods
             return outBuff.ToString();
         }
 
-        [DllImport("shlwapi.dll", BestFitMapping = false, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = false, ThrowOnUnmappableChar = true)]
-        private static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, uint cchOutBuf, IntPtr ppvReserved);
+        public static readonly string OK = GetDirectString("@shell32.dll,-9752");
+        public static readonly string Cancel = GetDirectString("@shell32.dll,-9751");
     }
 }

+ 43 - 37
ContextMenuManager/BluePointLilac.Methods/RichTextBoxExtension.cs

@@ -7,10 +7,44 @@ namespace BluePointLilac.Methods
 {
     public static class RichTextBoxExtension
     {
+        /// <summary>RichTextBox中ini语法高亮</summary>
+        /// <param name="iniStr">要显示的ini文本</param>
+        public static void LoadIni(this RichTextBox box, string iniStr)
+        {
+            string[] lines = iniStr.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
+            for(int i = 0; i < lines.Length; i++)
+            {
+                string str = lines[i].Trim();
+                if(str.StartsWith(";") || str.StartsWith("#"))
+                {
+                    box.AppendText(str, Color.SkyBlue);//注释
+                }
+                else if(str.StartsWith("["))
+                {
+                    if(str.Contains("]"))
+                    {
+                        int index = str.IndexOf(']');
+                        box.AppendText(str.Substring(0, index + 1), Color.DarkCyan, null, true);//section
+                        box.AppendText(str.Substring(index + 1), Color.SkyBlue);//section标签之后的内容视作注释
+                    }
+                    else box.AppendText(str, Color.SkyBlue);//section标签未关闭视作注释
+                }
+                else if(str.Contains("="))
+                {
+                    int index = str.IndexOf('=');
+                    box.AppendText(str.Substring(0, index), Color.DodgerBlue);//key
+                    box.AppendText(str.Substring(index), Color.DimGray);//value
+                }
+                else box.AppendText(str, Color.SkyBlue);//非section行和非key行视作注释
+                if(i != lines.Length - 1) box.AppendText("\r\n");
+            }
+        }
+
         /// 代码原文:https://archive.codeplex.com/?p=xmlrichtextbox
         /// 本人(蓝点lilac)仅作简单修改,将原继承类改写为扩展方法
-        /// <summary>RichTextBox中XML语法高亮</summary>
+        /// <summary>RichTextBox中xml语法高亮</summary>
         /// <param name="xmlStr">要显示的xml文本</param>
+        /// <remarks>可直接用WebBrowser的Url加载本地xml文件,但无法自定义颜色</remarks>
         public static void LoadXml(this RichTextBox box, string xmlStr)
         {
             XmlStateMachine machine = new XmlStateMachine();
@@ -22,8 +56,8 @@ namespace BluePointLilac.Methods
                     xmlStr = XDocument.Parse(xmlStr, LoadOptions.PreserveWhitespace).ToString().Trim();
                     if(string.IsNullOrEmpty(xmlStr) && declaration == string.Empty) return;
                 }
-                catch(Exception e) { throw e; }
-                xmlStr = declaration + Environment.NewLine + xmlStr;
+                catch { throw; }
+                xmlStr = declaration + "\r\n" + xmlStr;
             }
 
             int location = 0;
@@ -50,37 +84,6 @@ namespace BluePointLilac.Methods
             }
         }
 
-        public static void LoadIni(this RichTextBox box, string iniStr)
-        {
-            string[] lines = iniStr.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
-            for(int i = 0; i < lines.Length; i++)
-            {
-                string str = lines[i].Trim();
-                if(str.StartsWith(";") || str.StartsWith("#"))
-                {
-                    box.AppendText(str, Color.SkyBlue);
-                }
-                else if(str.StartsWith("["))
-                {
-                    if(str.Contains("]"))
-                    {
-                        int index = str.IndexOf(']');
-                        box.AppendText(str.Substring(0, index + 1), Color.DarkCyan, null, true);
-                        box.AppendText(str.Substring(index + 1), Color.SkyBlue);
-                    }
-                    else box.AppendText(str, Color.SkyBlue);
-                }
-                else if(str.Contains("="))
-                {
-                    int index = str.IndexOf('=');
-                    box.AppendText(str.Substring(0, index), Color.DodgerBlue);
-                    box.AppendText(str.Substring(index), Color.DimGray);
-                }
-                else box.AppendText(str, Color.SkyBlue);
-                if(i != lines.Length - 1) box.AppendText(Environment.NewLine);
-            }
-        }
-
         public static void AppendText(this RichTextBox box, string text, Color color = default, Font font = null, bool isBold = false)
         {
             FontStyle fontStyle = isBold ? FontStyle.Bold : FontStyle.Regular;
@@ -293,7 +296,7 @@ namespace BluePointLilac.Methods
                     case XmlTokenType.DocTypeDeclaration:
                         return Color.DodgerBlue;
                     default:
-                        return Color.Orange;
+                        return Color.DimGray;
                 }
             }
 
@@ -307,6 +310,7 @@ namespace BluePointLilac.Methods
                 }
                 return string.Empty;
             }
+
             private void HandleAttributeEnd()
             {
                 if(subString.StartsWith(">"))
@@ -365,7 +369,6 @@ namespace BluePointLilac.Methods
                 else if(subString.StartsWith("="))
                 {
                     CurrentState = XmlTokenType.EqualSignStart;
-                    if(CurrentState == XmlTokenType.AttributeValue) CurrentState = XmlTokenType.EqualSignEnd;
                     token = "=";
                 }
                 else if(subString.StartsWith("?>"))
@@ -412,11 +415,14 @@ namespace BluePointLilac.Methods
                 }
                 else if(subString.StartsWith("'"))
                 {
-                    CurrentState = XmlTokenType.SingleQuotationMarkStart;
                     if(CurrentState == XmlTokenType.AttributeValue)
                     {
                         CurrentState = XmlTokenType.SingleQuotationMarkEnd;
                     }
+                    else
+                    {
+                        CurrentState = XmlTokenType.SingleQuotationMarkStart;
+                    }
                     token = "'";
                 }
             }

+ 0 - 1
ContextMenuManager/BluePointLilac.Methods/ShellLink.cs

@@ -121,7 +121,6 @@ namespace BluePointLilac.Methods
         private const int SW_SHOWMINNOACTIVE = 7;
         private const int SW_SHOWNORMAL = 1;
 
-
         private IShellLinkW shellLinkW = null;
         private IPersistFile PersistFile => (IPersistFile)shellLinkW;
         private IShellLinkDataList LinkDataList => (IShellLinkDataList)shellLinkW;

+ 52 - 30
ContextMenuManager/BluePointLilac.Methods/SingleInstance.cs

@@ -17,20 +17,20 @@ namespace BluePointLilac.Methods
         private static extern bool SetForegroundWindow(IntPtr hWnd);
 
         /// <summary>判断单实例程序是否正在运行</summary>
+        /// <remarks>若正在运行激活窗口</remarks>
         public static bool IsRunning()
         {
             using(Process current = Process.GetCurrentProcess())
             {
-                string fileName = current.MainModule.FileName;
-                string processName = Path.GetFileNameWithoutExtension(fileName);
-                foreach(Process process in Process.GetProcessesByName(processName))
+                foreach(Process process in Process.GetProcessesByName(current.ProcessName))
                 {
                     using(process)
                     {
                         if(process.Id == current.Id) continue;
-                        if(process.MainModule.FileName == fileName)
+                        if(process.MainModule.FileName == current.MainModule.FileName)
                         {
-                            ShowWindowAsync(process.MainWindowHandle, 1);//SW_SHOWNORMAL
+                            const int SW_RESTORE = 9;
+                            ShowWindowAsync(process.MainWindowHandle, SW_RESTORE);
                             SetForegroundWindow(process.MainWindowHandle);
                             return true;
                         }
@@ -45,44 +45,66 @@ namespace BluePointLilac.Methods
         /// <param name="updatePath">用于更新程序的新版本文件路径,为null则不更新</param>
         public static void Restart(string[] args = null, string updatePath = null)
         {
+            string appPath = Application.ExecutablePath;
+            string command = appPath;
+            if(args != null && args.Length > 0) command += "," + string.Join(" ", args);
+            List<string> contents = new List<string>();
             using(Process pApp = Process.GetCurrentProcess())
             {
-                string command = Application.ExecutablePath;
-                if(args != null && args.Length > 0) command += "," + string.Join(" ", args);
-                List<string> contents = new List<string>();
+                //Vbs命令逐行执行不等待,故加些代码确定上一条命令执行是否完成
                 contents.AddRange(new[]{
-                    "Dim wsh, fso",
+                    "Dim wsh, fso, wmi, ps",
                     "Set wsh = CreateObject(\"WScript.Shell\")",
                     "Set fso = CreateObject(\"Scripting.FileSystemObject\")",
                     "fso.DeleteFile(WScript.ScriptFullName)",//vbs自删命令
                     $"wsh.Run \"taskkill /pid {pApp.Id} -f\",0",//杀死当前进程
-                    "WScript.Sleep 1000"
+                    "Dim isRun",
+                    "Do",
+                        "isRun = 0",
+                        "WScript.Sleep 100",
+                        "Set wmi = GetObject(\"WinMgmts:\")",
+                        "Set ps = wmi.InstancesOf(\"Win32_Process\")",
+                        //确定进程完全退出
+                        "For Each p in ps",
+                            $"If p.ProcessID = {pApp.Id} Then",
+                                "isRun = 1",
+                                "Exit For",
+                            "End If",
+                        "Next",
+                    "Loop Until isRun = 0",
                 });
+            }
 
-                if(File.Exists(updatePath))
-                {
-                    contents.AddRange(new[]
-                    {
-                        $"fso.DeleteFile \"{Application.ExecutablePath}\"",
-                        "WScript.Sleep 1000",
-                        $"fso.MoveFile \"{updatePath}\",\"{Application.ExecutablePath}\""//更新文件
-                    });
-                }
+            if(File.Exists(updatePath))
+            {
                 contents.AddRange(new[]
                 {
-                    $"wsh.Run \"{command}\"",
-                    "Set wsh = Nothing",
-                    "Set fso = Nothing"
+                    $"fso.DeleteFile \"{appPath}\"",
+                    $"Do",
+                        "WScript.Sleep 100",
+                    "Loop Until fso.FileExists(\"{appPath}\") = False",//确定文件删除完成
+                    $"fso.MoveFile \"{updatePath}\",\"{appPath}\"",//更新文件
+                    $"Do",
+                        "WScript.Sleep 100",
+                    $"Loop Until fso.FileExists(\"{appPath}\")",//确定文件存在
                 });
+            }
+            contents.AddRange(new[]
+            {
+                $"wsh.Run \"{command}\"",
+                "Set wsh = Nothing",
+                "Set fso = Nothing",
+                "Set wmi = Nothing",
+                "Set ps = Nothing",
+            });
 
-                string vbsPath = Path.GetTempPath() + "Restart.vbs";
-                File.WriteAllLines(vbsPath, contents.ToArray(), Encoding.Unicode);
-                using(Process pVbs = new Process())
-                {
-                    pVbs.StartInfo.FileName = "wscript.exe";
-                    pVbs.StartInfo.Arguments = vbsPath;
-                    pVbs.Start();
-                }
+            string vbsPath = Path.GetTempPath() + Guid.NewGuid() + ".vbs";
+            File.WriteAllLines(vbsPath, contents.ToArray(), Encoding.Unicode);
+            using(Process pVbs = new Process())
+            {
+                pVbs.StartInfo.FileName = "wscript.exe";
+                pVbs.StartInfo.Arguments = vbsPath;
+                pVbs.Start();
             }
         }
     }

+ 1 - 1
ContextMenuManager/BluePointLilac.Methods/TextBoxExtension.cs

@@ -14,7 +14,7 @@ namespace BluePointLilac.Methods
                 float size = box.Font.Size;
                 if(size < 8F && e.Delta < 0) return;
                 if(size > 40F && e.Delta > 0) return;
-                box.Font = new Font(box.Font.FontFamily, size + (e.Delta > 0 ? 1 : -1));
+                box.Font = new Font(box.Font.FontFamily, size + (e.Delta > 0 ? 1F : -1F));
             };
         }
 

+ 0 - 26
ContextMenuManager/BluePointLilac.Methods/UAWebClient.cs

@@ -1,26 +0,0 @@
-using System.Net;
-using System.Text;
-
-namespace BluePointLilac.Methods
-{
-    /// <summary>此类主要为了解决访问Github的一些问题</summary>
-    public class UAWebClient : WebClient
-    {
-        static UAWebClient()
-        {
-            //请求被中止: 未能创建 SSL/TLS 安全通道; 基础连接已经关闭: 发送时发生错误
-            ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;//SecurityProtocolType.TLS12
-        }
-
-        public UAWebClient()
-        {
-            //网络传输默认文本编码 UTF-8
-            this.Encoding = Encoding.UTF8;
-            //远程服务器返回错误: (403) 已禁止
-            //浏览器 F12 console 输入 console.log(navigator.userAgent); 获取 User Agent
-            this.Headers.Add("User-Agent",
-                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " +
-                "Chrome/90.0.4430.212 Safari/537.36 Edg/90.0.818.66");
-        }
-    }
-}

+ 29 - 0
ContextMenuManager/BluePointLilac.Methods/WinOsVersion.cs

@@ -0,0 +1,29 @@
+using System;
+
+namespace BluePointLilac.Methods
+{
+    // 判断Windows系统版本
+    // https://docs.microsoft.com/windows/release-health/release-information
+    public static class WinOsVersion
+    {
+        public static readonly Version Current = Environment.OSVersion.Version;
+        public static readonly Version Win10 = new Version(10, 0);
+        public static readonly Version Win8_1 = new Version(6, 3);
+        public static readonly Version Win8 = new Version(6, 2);
+        public static readonly Version Win7 = new Version(6, 1);
+        public static readonly Version Vista = new Version(6, 0);
+        public static readonly Version XP = new Version(5, 1);
+
+        public static readonly Version Win10_1507 = new Version(10, 0, 10240);
+        public static readonly Version Win10_1511 = new Version(10, 0, 10586);
+        public static readonly Version Win10_1607 = new Version(10, 0, 14393);
+        public static readonly Version Win10_1703 = new Version(10, 0, 15063);
+        public static readonly Version Win10_1709 = new Version(10, 0, 16299);
+        public static readonly Version Win10_1803 = new Version(10, 0, 17134);
+        public static readonly Version Win10_1809 = new Version(10, 0, 17763);
+        public static readonly Version Win10_1903 = new Version(10, 0, 18362);
+        public static readonly Version Win10_1909 = new Version(10, 0, 18363);
+        public static readonly Version Win10_2004 = new Version(10, 0, 19041);
+        public static readonly Version Win10_20H2 = new Version(10, 0, 19042);
+    }
+}

+ 0 - 49
ContextMenuManager/BluePointLilac.Methods/WindowsOsVersion.cs

@@ -1,49 +0,0 @@
-using System;
-
-namespace BluePointLilac.Methods
-{
-    //判断Windows系统版本
-    public static class WindowsOsVersion
-    {
-        public static readonly Version OsVersion = Environment.OSVersion.Version;
-        private static readonly float ShortVersion = OsVersion.Major + OsVersion.Minor / 10F;
-
-        private const float Win10 = 10.0F;
-        private const float Win8_1 = 6.3F;
-        private const float Win8 = 6.2F;
-        private const float Win7 = 6.1F;
-        private const float Vista = 6.0F;
-
-        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 > new Version(10, 0, 15063);
-    }
-}

+ 68 - 36
ContextMenuManager/ContextMenuManager.csproj

@@ -8,7 +8,7 @@
     <OutputType>WinExe</OutputType>
     <RootNamespace>ContextMenuManager</RootNamespace>
     <AssemblyName>ContextMenuManager</AssemblyName>
-    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
     <FileAlignment>512</FileAlignment>
     <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
     <Deterministic>true</Deterministic>
@@ -32,29 +32,34 @@
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugSymbols>false</DebugSymbols>
-    <DebugType>none</DebugType>
-    <Optimize>true</Optimize>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
     <OutputPath>bin\Debug\</OutputPath>
     <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>queue</ErrorReport>
+    <ErrorReport>send</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <Prefer32Bit>false</Prefer32Bit>
     <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
-    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+    <GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
     <DocumentationFile>
     </DocumentationFile>
     <FileAlignment>4096</FileAlignment>
+    <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
+    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugType>pdbonly</DebugType>
+    <DebugType>none</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release\</OutputPath>
     <DefineConstants>TRACE</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <Prefer32Bit>false</Prefer32Bit>
+    <FileAlignment>4096</FileAlignment>
+    <DebugSymbols>false</DebugSymbols>
+    <GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
   </PropertyGroup>
   <PropertyGroup>
     <ApplicationIcon>Properties\AppIcon.ico</ApplicationIcon>
@@ -108,6 +113,15 @@
     <ManifestKeyFile>ContextMenuManager_TemporaryKey.pfx</ManifestKeyFile>
   </PropertyGroup>
   <PropertyGroup />
+  <PropertyGroup />
+  <PropertyGroup />
+  <PropertyGroup />
+  <PropertyGroup />
+  <PropertyGroup />
+  <PropertyGroup />
+  <PropertyGroup />
+  <PropertyGroup />
+  <PropertyGroup />
   <PropertyGroup>
     <ApplicationManifest>Properties\App.manifest</ApplicationManifest>
   </PropertyGroup>
@@ -119,6 +133,7 @@
     <Reference Include="System.Data.DataSetExtensions" />
     <Reference Include="System.Deployment" />
     <Reference Include="System.Drawing" />
+    <Reference Include="System.Management" />
     <Reference Include="System.Runtime.Serialization" />
     <Reference Include="System.ServiceModel.Web" />
     <Reference Include="System.Web" />
@@ -127,7 +142,33 @@
     <Reference Include="System.Xml.Linq" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="AppConfig.cs" />
+    <Compile Include="Controls\DetailedEditDialog.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Controls\DictionariesBox.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Controls\DonateBox.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Controls\EnhanceMenusDialog.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Controls\Interfaces\IBtnDeleteItem.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Controls\LanguagesBox.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Controls\SubItemsForm.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Controls\SwitchDicList.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Methods\AppConfig.cs" />
+    <Compile Include="BluePointLilac.Methods\FormExtension.cs" />
+    <Compile Include="BluePointLilac.Methods\MessageBoxEx.cs" />
     <Compile Include="BluePointLilac.Methods\ToolTipBox.cs" />
     <Compile Include="BluePointLilac.Controls\ReadOnlyTextBox.cs">
       <SubType>Component</SubType>
@@ -139,31 +180,29 @@
       <SubType>Component</SubType>
     </Compile>
     <Compile Include="BluePointLilac.Methods\ComboBoxExtension.cs" />
-    <Compile Include="BluePointLilac.Methods\DesktopIni.cs" />
+    <Compile Include="Methods\DesktopIni.cs" />
     <Compile Include="BluePointLilac.Methods\DirectoryEx.cs" />
     <Compile Include="BluePointLilac.Methods\ElevatedFileDroper.cs" />
     <Compile Include="BluePointLilac.Methods\FileExtension.cs" />
     <Compile Include="BluePointLilac.Methods\GuidEx.cs" />
     <Compile Include="BluePointLilac.Methods\IniReader.cs" />
     <Compile Include="BluePointLilac.Methods\IniWriter.cs" />
-    <Compile Include="BluePointLilac.Methods\MessageBoxEx.cs" />
+    <Compile Include="Methods\AppMessageBox.cs" />
     <Compile Include="BluePointLilac.Methods\ExternalProgram.cs" />
     <Compile Include="BluePointLilac.Methods\RichTextBoxExtension.cs" />
     <Compile Include="BluePointLilac.Methods\SingleInstance.cs" />
     <Compile Include="BluePointLilac.Methods\StringExtension.cs" />
     <Compile Include="BluePointLilac.Methods\TextBoxExtension.cs" />
-    <Compile Include="BluePointLilac.Methods\UAWebClient.cs">
+    <Compile Include="BluePointLilac.Controls\UAWebClient.cs">
       <SubType>Component</SubType>
     </Compile>
-    <Compile Include="BluePointLilac.Methods\WindowsOsVersion.cs" />
+    <Compile Include="Methods\UwpHelper.cs" />
+    <Compile Include="BluePointLilac.Methods\WinOsVersion.cs" />
     <Compile Include="BluePointLilac.Methods\ShellLink.cs" />
-    <Compile Include="BluePointLilac.Methods\WinXHasher.cs" />
+    <Compile Include="Methods\WinXHasher.cs" />
     <Compile Include="BluePointLilac.Controls\DownloadDialog.cs">
       <SubType>Component</SubType>
     </Compile>
-    <Compile Include="Controls\DonateListDialog.cs">
-      <SubType>Component</SubType>
-    </Compile>
     <Compile Include="Controls\FileExtensionDialog.cs">
       <SubType>Component</SubType>
     </Compile>
@@ -210,13 +249,7 @@
     <Compile Include="Controls\ShellStoreDialog.cs">
       <SubType>Component</SubType>
     </Compile>
-    <Compile Include="Controls\Interfaces\IFoldGroupItem.cs">
-      <SubType>Component</SubType>
-    </Compile>
-    <Compile Include="Controls\Interfaces\IBtnOpenPathItem.cs">
-      <SubType>Component</SubType>
-    </Compile>
-    <Compile Include="Controls\Interfaces\IBtnDeleteItem.cs">
+    <Compile Include="Controls\FoldSubItem.cs">
       <SubType>Component</SubType>
     </Compile>
     <Compile Include="Controls\Interfaces\ITsiDeleteItem.cs">
@@ -252,7 +285,7 @@
     <Compile Include="Controls\NewItemForm.cs">
       <SubType>Form</SubType>
     </Compile>
-    <Compile Include="Controls\AboutApp.cs">
+    <Compile Include="Controls\AppSettingBox.cs">
       <SubType>Component</SubType>
     </Compile>
     <Compile Include="Controls\GuidBlockedItem.cs">
@@ -294,10 +327,7 @@
     <Compile Include="Controls\ShellNewList.cs">
       <SubType>Component</SubType>
     </Compile>
-    <Compile Include="Controls\ThirdRulesList.cs">
-      <SubType>Component</SubType>
-    </Compile>
-    <Compile Include="Controls\TranslateDialog.cs">
+    <Compile Include="Controls\DetailedEditList.cs">
       <SubType>Component</SubType>
     </Compile>
     <Compile Include="Controls\UwpModeItem.cs">
@@ -352,21 +382,22 @@
     <Compile Include="BluePointLilac.Methods\HighDpi.cs" />
     <Compile Include="BluePointLilac.Methods\RegistryEx.cs" />
     <Compile Include="BluePointLilac.Methods\RegTrustedInstaller.cs" />
-    <Compile Include="AppString.cs" />
-    <Compile Include="AppImage.cs" />
+    <Compile Include="Methods\AppString.cs" />
+    <Compile Include="Methods\AppImage.cs" />
     <Compile Include="BluePointLilac.Methods\EncodingType.cs" />
-    <Compile Include="GuidInfo.cs" />
+    <Compile Include="Methods\GuidInfo.cs" />
     <Compile Include="BluePointLilac.Methods\ImageExtension.cs" />
     <Compile Include="BluePointLilac.Methods\ResourceIcon.cs" />
     <Compile Include="BluePointLilac.Methods\ResourceString.cs" />
-    <Compile Include="BluePointLilac.Methods\ObjectPath.cs" />
+    <Compile Include="Methods\ObjectPath.cs" />
     <Compile Include="Program.cs" />
     <Compile Include="Properties\Resources.Designer.cs">
       <AutoGen>True</AutoGen>
       <DesignTime>True</DesignTime>
       <DependentUpon>Resources.resx</DependentUpon>
     </Compile>
-    <Compile Include="Updater.cs" />
+    <Compile Include="Methods\Updater.cs" />
+    <Compile Include="Methods\XmlDicHelper.cs" />
     <None Include="App.config" />
     <None Include="Properties\App.manifest" />
     <None Include="Properties\Resources\ShellNew\0.rar" />
@@ -376,10 +407,13 @@
     <None Include="Properties\Resources\ShellNew\0.zip" />
     <None Include="Properties\Resources\Texts\AppLanguageDic.ini" />
     <None Include="Properties\Resources\Texts\GuidInfosDic.ini" />
+    <Content Include="Properties\Resources\Images\CheckUpdate.png" />
     <Content Include="Properties\Resources\Images\DownLoad.png" />
+    <Content Include="Properties\Resources\Images\Enhance.png" />
     <Content Include="Properties\Resources\Images\Jump.png" />
     <Content Include="Properties\Resources\Images\Translate.png" />
     <Content Include="Properties\Resources\Images\User.png" />
+    <Content Include="Properties\Resources\Images\Web.png" />
     <Content Include="Properties\Resources\ShellNew\0.c" />
     <Content Include="Properties\Resources\ShellNew\0.html" />
     <Content Include="Properties\Resources\ShellNew\0.xml" />
@@ -425,12 +459,10 @@
     <Content Include="Properties\Resources\Images\Setting.png" />
     <Content Include="Properties\Resources\Images\Star.png" />
     <Content Include="Properties\Resources\Images\SubItems.png" />
-    <Content Include="Properties\Resources\Images\TurnOff.png" />
-    <Content Include="Properties\Resources\Images\TurnOn.png" />
     <Content Include="Properties\Resources\Images\Type.png" />
     <Content Include="Properties\Resources\Images\Up.png" />
     <Content Include="Properties\Resources\Images\Donate.png" />
-    <Content Include="Properties\Resources\Texts\ThirdRulesDic.xml" />
+    <Content Include="Properties\Resources\Texts\DetailedEditDic.xml" />
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="Properties\Resources.resx">

+ 0 - 598
ContextMenuManager/Controls/AboutApp.cs

@@ -1,598 +0,0 @@
-using BluePointLilac.Controls;
-using BluePointLilac.Methods;
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.IO;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Windows.Forms;
-
-namespace ContextMenuManager.Controls
-{
-    sealed class DonateBox : Panel
-    {
-        public DonateBox()
-        {
-            this.AutoScroll = true;
-            this.Dock = DockStyle.Fill;
-            this.BackColor = Color.White;
-            this.Font = new Font(SystemFonts.MenuFont.FontFamily, 10F);
-            this.Controls.AddRange(new Control[] { lblInfo, picQR, lblList });
-            this.VisibleChanged += (sender, e) => this.SetEnabled(this.Visible);
-            lblList.Click += (sender, e) =>
-            {
-                this.Cursor = Cursors.WaitCursor;
-                Updater.ShowDonateDialog();
-                this.Cursor = Cursors.Default;
-            };
-            picQR.Resize += (sender, e) => this.OnResize(null);
-            picQR.MouseDown += SwitchQR;
-        }
-
-        readonly Label lblInfo = new Label
-        {
-            BorderStyle = BorderStyle.FixedSingle,
-            Text = AppString.Other.Donate,
-            AutoSize = true
-        };
-
-        readonly Label lblList = new Label
-        {
-            ForeColor = Color.FromArgb(85, 145, 215),
-            BorderStyle = BorderStyle.FixedSingle,
-            Text = AppString.Other.DonationList,
-            Cursor = Cursors.Hand,
-            AutoSize = true
-        };
-
-        readonly PictureBox picQR = new PictureBox
-        {
-            SizeMode = PictureBoxSizeMode.AutoSize,
-            BorderStyle = BorderStyle.FixedSingle,
-            Cursor = Cursors.Hand,
-            Image = AllQR,
-        };
-
-        static readonly Image AllQR = Properties.Resources.Donate;
-        static readonly Image WechatQR = GetSingleQR(0);
-        static readonly Image AlipayQR = GetSingleQR(1);
-        static readonly Image QQQR = GetSingleQR(2);
-
-        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;
-            lblList.Left = (this.Width - lblList.Width) / 2;
-            lblInfo.Top = a;
-            picQR.Top = lblInfo.Bottom + a;
-            lblList.Top = picQR.Bottom + a;
-        }
-
-        private static Image GetSingleQR(int index)
-        {
-            Bitmap bitmap = new Bitmap(200, 200);
-            using(Graphics g = Graphics.FromImage(bitmap))
-            {
-                Rectangle destRect = new Rectangle(0, 0, 200, 200);
-                Rectangle srcRect = new Rectangle(index * 200, 0, 200, 200);
-                g.DrawImage(AllQR, destRect, srcRect, GraphicsUnit.Pixel);
-            }
-            return bitmap;
-        }
-
-        private void SwitchQR(object sender, MouseEventArgs e)
-        {
-            if(picQR.Image == AllQR)
-            {
-                if(e.X < 200) picQR.Image = WechatQR;
-                else if(e.X < 400) picQR.Image = AlipayQR;
-                else picQR.Image = QQQR;
-            }
-            else
-            {
-                picQR.Image = AllQR;
-            }
-        }
-    }
-
-    sealed class DictionariesBox : TabControl
-    {
-        public DictionariesBox()
-        {
-            this.Dock = DockStyle.Fill;
-            this.Controls.AddRange(pages);
-            this.Font = new Font(SystemFonts.MenuFont.FontFamily, 10F);
-            cms.Items.AddRange(items);
-            for(int i = 0; i < 6; i++)
-            {
-                boxs[i] = new ReadOnlyRichTextBox { Parent = pages[i] };
-                if(i > 0) boxs[i].ContextMenuStrip = cms;
-            }
-            items[0].Click += (sender, e) => ExternalProgram.OpenNotepadWithText(GetInitialText());
-            items[2].Click += (sender, e) => SaveFile();
-            boxs[0].Controls.Add(btnOpenDir);
-            boxs[0].Text = AppString.Other.Dictionaries;
-            btnOpenDir.Top = boxs[0].Height - btnOpenDir.Height;
-            ToolTipBox.SetToolTip(btnOpenDir, AppString.Menu.FileLocation);
-            btnOpenDir.MouseDown += (sender, e) => ExternalProgram.OpenDirectory(AppConfig.DicsDir);
-            this.SelectedIndexChanged += (sender, e) => LoadText();
-            this.VisibleChanged += (sender, e) => this.SetEnabled(this.Visible);
-        }
-
-        readonly TabPage[] pages = new TabPage[] {
-            new TabPage(AppString.Other.DictionaryDescription),
-            new TabPage(AppString.SideBar.AppLanguage),
-            new TabPage(AppString.Other.GuidInfosDictionary),
-            new TabPage(AppString.SideBar.ThirdRules),
-            new TabPage(AppString.SideBar.EnhanceMenu),
-            new TabPage(AppString.Other.UwpMode)
-        };
-        readonly ReadOnlyRichTextBox[] boxs = new ReadOnlyRichTextBox[6];
-        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),
-            new ToolStripSeparator(),
-            new ToolStripMenuItem(AppString.Menu.Save)
-        };
-
-        private void SaveFile()
-        {
-            using(SaveFileDialog dlg = new SaveFileDialog())
-            {
-                string dirPath = AppConfig.UserDicsDir;
-                switch(SelectedIndex)
-                {
-                    case 1:
-                        dirPath = AppConfig.LangsDir;
-                        dlg.FileName = AppConfig.ZH_CNINI;
-                        break;
-                    case 2:
-                        dlg.FileName = AppConfig.GUIDINFOSDICINI;
-                        break;
-                    case 3:
-                        dlg.FileName = AppConfig.THIRDRULESDICXML;
-                        break;
-                    case 4:
-                        dlg.FileName = AppConfig.ENHANCEMENUSICXML;
-                        break;
-                    case 5:
-                        dlg.FileName = AppConfig.UWPMODEITEMSDICXML;
-                        break;
-                }
-                dlg.Filter = $"{dlg.FileName}|*{Path.GetExtension(dlg.FileName)}";
-                Directory.CreateDirectory(dirPath);
-                dlg.InitialDirectory = dirPath;
-                if(dlg.ShowDialog() == DialogResult.OK)
-                {
-                    File.WriteAllText(dlg.FileName, GetInitialText(), Encoding.Unicode);
-                }
-            }
-        }
-
-        private string GetInitialText()
-        {
-            switch(this.SelectedIndex)
-            {
-                case 0:
-                    return AppString.Other.Dictionaries;
-                case 1:
-                    return Properties.Resources.AppLanguageDic;
-                case 2:
-                    return Properties.Resources.GuidInfosDic;
-                case 3:
-                    return Properties.Resources.ThirdRulesDic;
-                case 4:
-                    return Properties.Resources.EnhanceMenusDic;
-                case 5:
-                    return Properties.Resources.UwpModeItemsDic;
-                default:
-                    return string.Empty;
-            }
-        }
-
-        private void LoadText()
-        {
-            int index = this.SelectedIndex;
-            if(boxs[index].Text.Length > 0) return;
-            Action<string> action = null;
-            switch(index)
-            {
-                case 1:
-                case 2:
-                    action = boxs[index].LoadIni; break;
-                case 3:
-                case 4:
-                case 5:
-                    action = boxs[index].LoadXml; break;
-            }
-            this.BeginInvoke(action, new[] { GetInitialText() });
-        }
-    }
-
-    sealed class LanguagesBox : FlowLayoutPanel
-    {
-        public LanguagesBox()
-        {
-            this.Dock = DockStyle.Fill;
-            this.Font = new Font(SystemFonts.MenuFont.FontFamily, 10F);
-            this.Controls.AddRange(new Control[] { cmbLanguages, btnOpenDir, btnDownLoad, btnTranslate, pnlTranslators });
-            this.VisibleChanged += (sender, e) => this.SetEnabled(this.Visible);
-            pnlTranslators.Controls.AddRange(new[] { lblHeader, lblLanguages, lblTranslators });
-            cmbLanguages.SelectionChangeCommitted += (sender, e) => ChangeLanguage();
-            btnOpenDir.MouseDown += (sender, e) => ExternalProgram.OpenDirectory(AppConfig.LangsDir);
-            btnDownLoad.MouseDown += (sender, e) =>
-            {
-                this.Cursor = Cursors.WaitCursor;
-                if(Updater.ShowLanguageDialog()) LoadLanguages();
-                this.Cursor = Cursors.Default;
-            };
-            btnTranslate.MouseDown += (sender, e) =>
-            {
-                using(TranslateDialog dlg = new TranslateDialog())
-                {
-                    dlg.ShowDialog();
-                }
-            };
-            ToolTipBox.SetToolTip(btnOpenDir, AppString.Menu.FileLocation);
-            ToolTipBox.SetToolTip(btnDownLoad, AppString.Dialog.DownloadLanguages);
-            ToolTipBox.SetToolTip(btnTranslate, AppString.Dialog.TranslateTool);
-            cmbLanguages.AutosizeDropDownWidth();
-            this.OnResize(null);
-        }
-
-        readonly ComboBox cmbLanguages = new ComboBox
-        {
-            Width = 150.DpiZoom(),
-            DropDownStyle = ComboBoxStyle.DropDownList
-        };
-        readonly PictureButton btnOpenDir = new PictureButton(AppImage.Open);
-        readonly PictureButton btnDownLoad = new PictureButton(AppImage.DownLoad);
-        readonly PictureButton btnTranslate = new PictureButton(AppImage.Translate);
-        readonly Panel pnlTranslators = new Panel
-        {
-            BorderStyle = BorderStyle.FixedSingle,
-            AutoScroll = true
-        };
-        readonly Label lblHeader = new Label
-        {
-            Text = AppString.Other.Translators + "\r\n" + new string('-', 75),
-            Dock = DockStyle.Top,
-            AutoSize = true
-        };
-        readonly Label lblLanguages = new Label
-        {
-            AutoSize = true,
-            Left = 0
-        };
-        readonly Label lblTranslators = new Label
-        {
-            AutoSize = true
-        };
-        readonly List<string> languages = new List<string>();
-
-        protected override void OnResize(EventArgs e)
-        {
-            base.OnResize(e);
-            int a = 20.DpiZoom();
-            pnlTranslators.Width = this.ClientSize.Width - 2 * a;
-            pnlTranslators.Height = this.ClientSize.Height - pnlTranslators.Top - a;
-            cmbLanguages.Margin = pnlTranslators.Margin = btnOpenDir.Margin
-                = btnDownLoad.Margin = btnTranslate.Margin = new Padding(a, a, 0, 0);
-        }
-
-        public void LoadLanguages()
-        {
-            cmbLanguages.Items.Clear();
-            cmbLanguages.Items.Add("(default) 简体中文");
-            if(Directory.Exists(AppConfig.LangsDir))
-            {
-                languages.Clear();
-                lblLanguages.Text = lblTranslators.Text = string.Empty;
-                foreach(string fileName in Directory.GetFiles(AppConfig.LangsDir, "*.ini"))
-                {
-                    string langName = Path.GetFileNameWithoutExtension(fileName);
-                    IniWriter reader = new IniWriter(fileName);
-                    string language = reader.GetValue("General", "Language");
-                    if(language.IsNullOrWhiteSpace()) language = langName;
-                    string translator = reader.GetValue("General", "Translator");
-                    translator = translator.Replace("\\r\\n", "\r\n").Replace("\\n", "\r\n");
-                    lblLanguages.Text += language + "\r\n";
-                    lblTranslators.Text += translator + "\r\n";
-                    for(int i = 0; i < Regex.Matches(translator, "\r\n").Count; i++)
-                    {
-                        lblLanguages.Text += "\r\n";
-                    }
-                    cmbLanguages.Items.Add(language);
-                    languages.Add(langName);
-                }
-                lblLanguages.Top = lblTranslators.Top = lblHeader.Bottom;
-                lblTranslators.Left = lblLanguages.Right + 200.DpiZoom();
-            }
-            int index = GetSelectIndex();
-            cmbLanguages.SelectedIndex = index;
-            if(index == 0) AppConfig.Language = "default";
-        }
-
-        private void ChangeLanguage()
-        {
-            string language = "default";
-            int index = GetSelectIndex();
-            if(cmbLanguages.SelectedIndex == index) return;
-            if(cmbLanguages.SelectedIndex > 0) language = languages[cmbLanguages.SelectedIndex - 1];
-            if(MessageBoxEx.Show(AppString.Message.RestartApp, MessageBoxButtons.OKCancel) != DialogResult.OK)
-            {
-                cmbLanguages.SelectedIndex = index;
-            }
-            else
-            {
-                AppConfig.Language = language;
-                SingleInstance.Restart();
-            }
-        }
-
-        private int GetSelectIndex()
-        {
-            string language = AppConfig.Language;
-            for(int i = 0; i < languages.Count; i++)
-            {
-                if(languages[i].Equals(language, StringComparison.OrdinalIgnoreCase)) return i + 1;
-            }
-            return 0;
-        }
-    }
-
-    sealed class AppSettingBox : MyList
-    {
-        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[] { cmbUpdate, lblUpdate });
-            mliRepo.AddCtr(cmbRepo);
-            mliProtect.AddCtr(chkProtect);
-            mliEngine.AddCtr(cmbEngine);
-            mliWinXSortable.AddCtr(chkWinXSortable);
-            mliShowFilePath.AddCtr(chkShowFilePath);
-            mliOpenMoreRegedit.AddCtr(chkOpenMoreRegedit);
-            mliOpenMoreExplorer.AddCtr(chkOpenMoreExplorer);
-            mliHideDisabledItems.AddCtr(chkHideDisabledItems);
-            mliHideSysStoreItems.AddCtr(chkHideSysStoreItems);
-            cmbConfigDir.AutosizeDropDownWidth();
-            cmbEngine.AutosizeDropDownWidth();
-            cmbRepo.AutosizeDropDownWidth();
-            ToolTipBox.SetToolTip(cmbConfigDir, AppString.Tip.ConfigPath);
-            ToolTipBox.SetToolTip(btnConfigDir, AppString.Menu.FileLocation);
-            ToolTipBox.SetToolTip(btnBackupDir, AppString.Menu.FileLocation);
-
-            cmbRepo.Items.AddRange(new[] { "Github", "Gitee" });
-            cmbConfigDir.Items.AddRange(new[] { AppString.Other.AppDataDir, AppString.Other.AppDir });
-            cmbEngine.Items.AddRange(new[] { "Bing", "Baidu", "Google", "DuckDuckGo", "Sogou", "360", AppString.Other.CustomEngine });
-            cmbUpdate.Items.AddRange(new[] { AppString.Other.OnceAWeek, AppString.Other.OnceAMonth, AppString.Other.OnceASeason, AppString.Other.NeverCheck });
-
-            lblUpdate.Click += (sender, e) =>
-            {
-                this.Cursor = Cursors.WaitCursor;
-                Updater.Update(true);
-                this.Cursor = Cursors.Default;
-            };
-            this.VisibleChanged += (sender, e) => this.SetEnabled(this.Visible);
-            btnConfigDir.MouseDown += (sender, e) => ExternalProgram.OpenDirectory(AppConfig.ConfigDir);
-            btnBackupDir.MouseDown += (sender, e) => ExternalProgram.OpenDirectory(AppConfig.BackupDir);
-            chkBackup.CheckChanged += () => AppConfig.AutoBackup = chkBackup.Checked;
-            chkProtect.CheckChanged += () => AppConfig.ProtectOpenItem = chkProtect.Checked;
-            chkWinXSortable.CheckChanged += () => AppConfig.WinXSortable = chkWinXSortable.Checked;
-            chkOpenMoreRegedit.CheckChanged += () => AppConfig.OpenMoreRegedit = chkOpenMoreRegedit.Checked;
-            chkOpenMoreExplorer.CheckChanged += () => AppConfig.OpenMoreExplorer = chkOpenMoreExplorer.Checked;
-            chkHideDisabledItems.CheckChanged += () => AppConfig.HideDisabledItems = chkHideDisabledItems.Checked;
-            chkHideSysStoreItems.CheckChanged += () => AppConfig.HideSysStoreItems = chkHideSysStoreItems.Checked;
-            cmbRepo.SelectionChangeCommitted += (sender, e) => AppConfig.RequestUseGithub = cmbRepo.SelectedIndex == 0;
-            cmbConfigDir.SelectionChangeCommitted += (sender, e) =>
-            {
-                string newPath = (cmbConfigDir.SelectedIndex == 0) ? AppConfig.AppDataConfigDir : AppConfig.AppConfigDir;
-                if(newPath == AppConfig.ConfigDir) return;
-                if(MessageBoxEx.Show(AppString.Message.RestartApp, MessageBoxButtons.OKCancel) != DialogResult.OK)
-                {
-                    cmbConfigDir.SelectedIndex = AppConfig.SaveToAppDir ? 1 : 0;
-                }
-                else
-                {
-                    DirectoryEx.CopyTo(AppConfig.ConfigDir, newPath);
-                    Directory.Delete(AppConfig.ConfigDir, true);
-                    SingleInstance.Restart();
-                }
-            };
-            cmbEngine.SelectionChangeCommitted += (sender, e) =>
-            {
-                if(cmbEngine.SelectedIndex < cmbEngine.Items.Count - 1)
-                {
-                    AppConfig.EngineUrl = AppConfig.EngineUrls[cmbEngine.SelectedIndex];
-                }
-                else
-                {
-                    using(InputDialog dlg = new InputDialog { Title = AppString.Other.SetCustomEngine })
-                    {
-                        dlg.Text = AppConfig.EngineUrl;
-                        if(dlg.ShowDialog() == DialogResult.OK) AppConfig.EngineUrl = dlg.Text;
-                        string url = AppConfig.EngineUrl;
-                        for(int i = 0; i < AppConfig.EngineUrls.Length; i++)
-                        {
-                            if(url.Equals(AppConfig.EngineUrls[i]))
-                            {
-                                cmbEngine.SelectedIndex = i; break;
-                            }
-                        }
-                    }
-                }
-            };
-            cmbUpdate.SelectionChangeCommitted += (sender, e) =>
-            {
-                int day = 30;
-                switch(cmbUpdate.SelectedIndex)
-                {
-                    case 0:
-                        day = 7; break;
-                    case 2:
-                        day = 90; break;
-                    case 3:
-                        day = -1; break;
-                }
-                AppConfig.UpdateFrequency = day;
-            };
-            chkShowFilePath.PreCheckChanging += () =>
-            {
-                return MessageBoxEx.Show(AppString.Message.RestartApp, MessageBoxButtons.OKCancel) == DialogResult.OK;
-            };
-            chkShowFilePath.CheckChanged += () =>
-            {
-                AppConfig.ShowFilePath = chkShowFilePath.Checked;
-                SingleInstance.Restart();
-            };
-        }
-
-        readonly MyListItem mliConfigDir = new MyListItem
-        {
-            Text = AppString.Other.ConfigPath
-        };
-        readonly ComboBox cmbConfigDir = new ComboBox
-        {
-            DropDownStyle = ComboBoxStyle.DropDownList,
-            Width = 120.DpiZoom()
-        };
-        readonly PictureButton btnConfigDir = new PictureButton(AppImage.Open);
-
-        readonly MyListItem mliRepo = new MyListItem
-        {
-            Text = AppString.Other.SetRequestRepo
-        };
-        readonly ComboBox cmbRepo = new ComboBox
-        {
-            DropDownStyle = ComboBoxStyle.DropDownList,
-            Width = 120.DpiZoom()
-        };
-
-        readonly MyListItem mliBackup = new MyListItem
-        {
-            Text = AppString.Other.AutoBackup
-        };
-        readonly MyCheckBox chkBackup = new MyCheckBox();
-        readonly PictureButton btnBackupDir = new PictureButton(AppImage.Open);
-
-        readonly MyListItem mliUpdate = new MyListItem
-        {
-            Text = AppString.Other.SetUpdateFrequency
-        };
-        readonly ComboBox cmbUpdate = new ComboBox
-        {
-            DropDownStyle = ComboBoxStyle.DropDownList,
-            Width = 120.DpiZoom()
-        };
-        readonly Label lblUpdate = new Label
-        {
-            Text = AppString.Other.ImmediatelyCheck,
-            BorderStyle = BorderStyle.FixedSingle,
-            Cursor = Cursors.Hand,
-            AutoSize = true
-        };
-
-        readonly MyListItem mliProtect = new MyListItem
-        {
-            Text = AppString.Other.ProtectOpenItem
-        };
-        readonly MyCheckBox chkProtect = new MyCheckBox();
-
-        readonly MyListItem mliEngine = new MyListItem
-        {
-            Text = AppString.Other.WebSearchEngine
-        };
-        readonly ComboBox cmbEngine = new ComboBox
-        {
-            DropDownStyle = ComboBoxStyle.DropDownList,
-            Width = 120.DpiZoom()
-        };
-
-        readonly MyListItem mliShowFilePath = new MyListItem
-        {
-            Text = AppString.Other.ShowFilePath
-        };
-        readonly MyCheckBox chkShowFilePath = new MyCheckBox();
-
-        readonly MyListItem mliOpenMoreRegedit = new MyListItem
-        {
-            Text = AppString.Other.OpenMoreRegedit
-        };
-        readonly MyCheckBox chkOpenMoreRegedit = new MyCheckBox();
-
-        readonly MyListItem mliOpenMoreExplorer = new MyListItem
-        {
-            Text = AppString.Other.OpenMoreExplorer
-        };
-        readonly MyCheckBox chkOpenMoreExplorer = new MyCheckBox();
-
-        readonly MyListItem mliHideDisabledItems = new MyListItem
-        {
-            Text = AppString.Other.HideDisabledItems
-        };
-        readonly MyCheckBox chkHideDisabledItems = new MyCheckBox();
-
-        readonly MyListItem mliWinXSortable = new MyListItem
-        {
-            Text = AppString.Other.WinXSortable,
-            Visible = WindowsOsVersion.ISAfterOrEqual8
-        };
-        readonly MyCheckBox chkWinXSortable = new MyCheckBox();
-
-        readonly MyListItem mliHideSysStoreItems = new MyListItem
-        {
-            Text = AppString.Other.HideSysStoreItems,
-            Visible = WindowsOsVersion.ISAfterOrEqual7
-        };
-        readonly MyCheckBox chkHideSysStoreItems = new MyCheckBox();
-
-        public void LoadItems()
-        {
-            this.AddItems(new[] { mliUpdate, mliConfigDir, mliRepo, mliEngine, mliBackup, mliProtect, mliShowFilePath,
-                mliOpenMoreRegedit, mliOpenMoreExplorer, mliHideDisabledItems,mliHideSysStoreItems,mliWinXSortable });
-            foreach(MyListItem item in this.Controls) item.HasImage = false;
-            cmbConfigDir.SelectedIndex = AppConfig.SaveToAppDir ? 1 : 0;
-            cmbRepo.SelectedIndex = AppConfig.RequestUseGithub ? 0 : 1;
-            chkBackup.Checked = AppConfig.AutoBackup;
-            chkProtect.Checked = AppConfig.ProtectOpenItem;
-            chkWinXSortable.Checked = AppConfig.WinXSortable;
-            chkShowFilePath.Checked = AppConfig.ShowFilePath;
-            chkOpenMoreRegedit.Checked = AppConfig.OpenMoreRegedit;
-            chkOpenMoreExplorer.Checked = AppConfig.OpenMoreExplorer;
-            chkHideDisabledItems.Checked = AppConfig.HideDisabledItems;
-            chkHideSysStoreItems.Checked = AppConfig.HideSysStoreItems;
-
-            int index = 1;
-            switch(AppConfig.UpdateFrequency)
-            {
-                case 7:
-                    index = 0; break;
-                case 90:
-                    index = 2; break;
-                case -1:
-                    index = 3; break;
-            }
-            cmbUpdate.SelectedIndex = index;
-
-            string url = AppConfig.EngineUrl;
-            for(int i = 0; i <= AppConfig.EngineUrls.Length; i++)
-            {
-                if(i == AppConfig.EngineUrls.Length || url.Equals(AppConfig.EngineUrls[i]))
-                {
-                    cmbEngine.SelectedIndex = i; break;
-                }
-            }
-        }
-    }
-}

+ 258 - 0
ContextMenuManager/Controls/AppSettingBox.cs

@@ -0,0 +1,258 @@
+using BluePointLilac.Controls;
+using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Windows.Forms;
+
+namespace ContextMenuManager.Controls
+{
+    sealed class AppSettingBox : MyList
+    {
+        public AppSettingBox()
+        {
+            this.SuspendLayout();
+            this.Font = SystemFonts.MenuFont;
+            this.Font = new Font(this.Font.FontFamily, this.Font.Size + 1F);
+            mliConfigDir.AddCtrs(new Control[] { cmbConfigDir, btnConfigDir });
+            mliBackup.AddCtrs(new Control[] { chkBackup, btnBackupDir });
+            mliUpdate.AddCtrs(new Control[] { cmbUpdate, btnUpdate });
+            mliRepo.AddCtr(cmbRepo);
+            mliTopMost.AddCtr(chkTopMost);
+            mliProtect.AddCtr(chkProtect);
+            mliEngine.AddCtr(cmbEngine);
+            mliWinXSortable.AddCtr(chkWinXSortable);
+            mliShowFilePath.AddCtr(chkShowFilePath);
+            mliOpenMoreRegedit.AddCtr(chkOpenMoreRegedit);
+            mliOpenMoreExplorer.AddCtr(chkOpenMoreExplorer);
+            mliHideDisabledItems.AddCtr(chkHideDisabledItems);
+            mliHideSysStoreItems.AddCtr(chkHideSysStoreItems);
+
+            ToolTipBox.SetToolTip(btnUpdate, AppString.Tip.ImmediatelyCheck);
+            ToolTipBox.SetToolTip(cmbConfigDir, AppString.Tip.ConfigPath);
+            ToolTipBox.SetToolTip(btnConfigDir, AppString.Menu.FileLocation);
+            ToolTipBox.SetToolTip(btnBackupDir, AppString.Menu.FileLocation);
+
+            cmbRepo.Items.AddRange(new[] { "Github", "Gitee" });
+            cmbConfigDir.Items.AddRange(new[] { AppString.Other.AppDataDir, AppString.Other.AppDir });
+            cmbEngine.Items.AddRange(AppConfig.EngineUrlsDic.Keys.ToArray());
+            cmbEngine.Items.Add(AppString.Other.CustomEngine);
+            cmbUpdate.Items.AddRange(new[] { AppString.Other.OnceAWeek, AppString.Other.OnceAMonth,
+                AppString.Other.OnceASeason, AppString.Other.NeverCheck });
+
+            cmbConfigDir.Width = cmbEngine.Width = cmbUpdate.Width = cmbRepo.Width = 120.DpiZoom();
+            cmbConfigDir.DropDownStyle = cmbEngine.DropDownStyle = cmbUpdate.DropDownStyle
+                = cmbRepo.DropDownStyle = ComboBoxStyle.DropDownList;
+            cmbConfigDir.AutosizeDropDownWidth();
+            cmbEngine.AutosizeDropDownWidth();
+            cmbUpdate.AutosizeDropDownWidth();
+            cmbRepo.AutosizeDropDownWidth();
+
+            btnUpdate.MouseDown += (sender, e) =>
+            {
+                this.Cursor = Cursors.WaitCursor;
+                Updater.Update(true);
+                this.Cursor = Cursors.Default;
+            };
+            btnConfigDir.MouseDown += (sender, e) => ExternalProgram.OpenDirectory(AppConfig.ConfigDir);
+            btnBackupDir.MouseDown += (sender, e) => ExternalProgram.OpenDirectory(AppConfig.BackupDir);
+            chkBackup.CheckChanged += () => AppConfig.AutoBackup = chkBackup.Checked;
+            chkProtect.CheckChanged += () => AppConfig.ProtectOpenItem = chkProtect.Checked;
+            chkWinXSortable.CheckChanged += () => AppConfig.WinXSortable = chkWinXSortable.Checked;
+            chkOpenMoreRegedit.CheckChanged += () => AppConfig.OpenMoreRegedit = chkOpenMoreRegedit.Checked;
+            chkTopMost.CheckChanged += () => AppConfig.TopMost = this.FindForm().TopMost = chkTopMost.Checked;
+            chkOpenMoreExplorer.CheckChanged += () => AppConfig.OpenMoreExplorer = chkOpenMoreExplorer.Checked;
+            chkHideDisabledItems.CheckChanged += () => AppConfig.HideDisabledItems = chkHideDisabledItems.Checked;
+            chkHideSysStoreItems.CheckChanged += () => AppConfig.HideSysStoreItems = chkHideSysStoreItems.Checked;
+            cmbRepo.SelectionChangeCommitted += (sender, e) => AppConfig.RequestUseGithub = cmbRepo.SelectedIndex == 0;
+            chkShowFilePath.CheckChanged += () => AppConfig.ShowFilePath = chkShowFilePath.Checked;
+            cmbUpdate.SelectionChangeCommitted += (sender, e) => ChangeUpdateFrequency();
+            cmbConfigDir.SelectionChangeCommitted += (sender, e) => ChangeConfigDir();
+            cmbEngine.SelectionChangeCommitted += (sender, e) => ChangeEngineUrl();
+            this.ResumeLayout();
+        }
+
+        readonly MyListItem mliConfigDir = new MyListItem
+        {
+            Text = AppString.Other.ConfigPath
+        };
+        readonly ComboBox cmbConfigDir = new ComboBox();
+        readonly PictureButton btnConfigDir = new PictureButton(AppImage.Open);
+
+        readonly MyListItem mliRepo = new MyListItem
+        {
+            Text = AppString.Other.SetRequestRepo
+        };
+        readonly ComboBox cmbRepo = new ComboBox();
+
+        readonly MyListItem mliBackup = new MyListItem
+        {
+            Text = AppString.Other.AutoBackup
+        };
+        readonly MyCheckBox chkBackup = new MyCheckBox();
+        readonly PictureButton btnBackupDir = new PictureButton(AppImage.Open);
+
+        readonly MyListItem mliUpdate = new MyListItem
+        {
+            Text = AppString.Other.SetUpdateFrequency
+        };
+        readonly ComboBox cmbUpdate = new ComboBox();
+        readonly PictureButton btnUpdate = new PictureButton(AppImage.CheckUpdate);
+
+        readonly MyListItem mliTopMost = new MyListItem
+        {
+            Text = AppString.Other.TopMost
+        };
+        readonly MyCheckBox chkTopMost = new MyCheckBox();
+
+        readonly MyListItem mliProtect = new MyListItem
+        {
+            Text = AppString.Other.ProtectOpenItem
+        };
+        readonly MyCheckBox chkProtect = new MyCheckBox();
+
+        readonly MyListItem mliEngine = new MyListItem
+        {
+            Text = AppString.Other.WebSearchEngine
+        };
+        readonly ComboBox cmbEngine = new ComboBox();
+
+        readonly MyListItem mliShowFilePath = new MyListItem
+        {
+            Text = AppString.Other.ShowFilePath
+        };
+        readonly MyCheckBox chkShowFilePath = new MyCheckBox();
+
+        readonly MyListItem mliOpenMoreRegedit = new MyListItem
+        {
+            Text = AppString.Other.OpenMoreRegedit
+        };
+        readonly MyCheckBox chkOpenMoreRegedit = new MyCheckBox();
+
+        readonly MyListItem mliOpenMoreExplorer = new MyListItem
+        {
+            Text = AppString.Other.OpenMoreExplorer
+        };
+        readonly MyCheckBox chkOpenMoreExplorer = new MyCheckBox();
+
+        readonly MyListItem mliHideDisabledItems = new MyListItem
+        {
+            Text = AppString.Other.HideDisabledItems
+        };
+        readonly MyCheckBox chkHideDisabledItems = new MyCheckBox();
+
+        readonly MyListItem mliWinXSortable = new MyListItem
+        {
+            Text = AppString.Other.WinXSortable,
+            Visible = WinOsVersion.Current >= WinOsVersion.Win8
+        };
+        readonly MyCheckBox chkWinXSortable = new MyCheckBox();
+
+        readonly MyListItem mliHideSysStoreItems = new MyListItem
+        {
+            Text = AppString.Other.HideSysStoreItems,
+            Visible = WinOsVersion.Current >= WinOsVersion.Win7
+        };
+        readonly MyCheckBox chkHideSysStoreItems = new MyCheckBox();
+
+        public override void ClearItems()
+        {
+            this.Controls.Clear();
+        }
+
+        public void LoadItems()
+        {
+            this.AddItems(new[] { mliConfigDir, mliUpdate, mliRepo, mliEngine, mliBackup, mliTopMost, mliProtect, mliShowFilePath,
+                mliHideDisabledItems, mliHideSysStoreItems, mliOpenMoreRegedit, mliOpenMoreExplorer, mliWinXSortable });
+            foreach(MyListItem item in this.Controls) item.HasImage = false;
+            cmbConfigDir.SelectedIndex = AppConfig.SaveToAppDir ? 1 : 0;
+            cmbRepo.SelectedIndex = AppConfig.RequestUseGithub ? 0 : 1;
+            cmbUpdate.SelectedIndex = GetUpdateSelectIndex();
+            cmbEngine.SelectedIndex = GetEngineSelectIndex();
+            chkBackup.Checked = AppConfig.AutoBackup;
+            chkTopMost.Checked = this.FindForm().TopMost;
+            chkProtect.Checked = AppConfig.ProtectOpenItem;
+            chkWinXSortable.Checked = AppConfig.WinXSortable;
+            chkShowFilePath.Checked = AppConfig.ShowFilePath;
+            chkOpenMoreRegedit.Checked = AppConfig.OpenMoreRegedit;
+            chkOpenMoreExplorer.Checked = AppConfig.OpenMoreExplorer;
+            chkHideDisabledItems.Checked = AppConfig.HideDisabledItems;
+            chkHideSysStoreItems.Checked = AppConfig.HideSysStoreItems;
+        }
+
+        private void ChangeConfigDir()
+        {
+            string newPath = (cmbConfigDir.SelectedIndex == 0) ? AppConfig.AppDataConfigDir : AppConfig.AppConfigDir;
+            if(newPath == AppConfig.ConfigDir) return;
+            if(AppMessageBox.Show(AppString.Message.RestartApp, MessageBoxButtons.OKCancel) != DialogResult.OK)
+            {
+                cmbConfigDir.SelectedIndex = AppConfig.SaveToAppDir ? 1 : 0;
+            }
+            else
+            {
+                DirectoryEx.CopyTo(AppConfig.ConfigDir, newPath);
+                Directory.Delete(AppConfig.ConfigDir, true);
+                SingleInstance.Restart();
+            }
+        }
+
+        private void ChangeEngineUrl()
+        {
+            if(cmbEngine.SelectedIndex < cmbEngine.Items.Count - 1)
+            {
+                AppConfig.EngineUrl = AppConfig.EngineUrlsDic[cmbEngine.Text];
+            }
+            else
+            {
+                using(InputDialog dlg = new InputDialog())
+                {
+                    dlg.Text = AppConfig.EngineUrl;
+                    dlg.Title = AppString.Other.SetCustomEngine;
+                    if(dlg.ShowDialog() == DialogResult.OK) AppConfig.EngineUrl = dlg.Text;
+                    cmbEngine.SelectedIndex = GetEngineSelectIndex();
+                }
+            }
+        }
+
+        private void ChangeUpdateFrequency()
+        {
+            int day = 30;
+            switch(cmbUpdate.SelectedIndex)
+            {
+                case 0:
+                    day = 7; break;
+                case 2:
+                    day = 90; break;
+                case 3:
+                    day = -1; break;
+            }
+            AppConfig.UpdateFrequency = day;
+        }
+
+        private int GetUpdateSelectIndex()
+        {
+            int index = 1;
+            switch(AppConfig.UpdateFrequency)
+            {
+                case 7:
+                    index = 0; break;
+                case 90:
+                    index = 2; break;
+                case -1:
+                    index = 3; break;
+            }
+            return index;
+        }
+
+        private int GetEngineSelectIndex()
+        {
+            string[] urls = AppConfig.EngineUrlsDic.Values.ToArray();
+            for(int i = 0; i < urls.Length; i++)
+            {
+                if(AppConfig.EngineUrl.Equals(urls[i])) return i;
+            }
+            return cmbEngine.Items.Count - 1;
+        }
+    }
+}

+ 32 - 0
ContextMenuManager/Controls/DetailedEditDialog.cs

@@ -0,0 +1,32 @@
+using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
+using System;
+using System.Windows.Forms;
+
+namespace ContextMenuManager.Controls
+{
+    sealed class DetailedEditDialog : CommonDialog
+    {
+        public Guid GroupGuid { get; set; }
+
+        public override void Reset() { }
+
+        protected override bool RunDialog(IntPtr hwndOwner)
+        {
+            using(SubItemsForm frm = new SubItemsForm())
+            using(DetailedEditList list = new DetailedEditList())
+            {
+                var location = GuidInfo.GetIconLocation(this.GroupGuid);
+                frm.Icon = ResourceIcon.GetIcon(location.IconPath, location.IconIndex);
+                frm.Text = AppString.Dialog.DetailedEdit.Replace("%s", GuidInfo.GetText(this.GroupGuid));
+                frm.TopMost = AppConfig.TopMost;
+                frm.AddList(list);
+                list.GroupGuid = this.GroupGuid;
+                list.UseUserDic = XmlDicHelper.DetailedEditGuidDic[this.GroupGuid];
+                list.LoadItems();
+                frm.ShowDialog();
+            }
+            return false;
+        }
+    }
+}

+ 82 - 87
ContextMenuManager/Controls/ThirdRulesList.cs → ContextMenuManager/Controls/DetailedEditList.cs

@@ -1,86 +1,103 @@
-using BluePointLilac.Controls;
-using BluePointLilac.Methods;
-using ContextMenuManager.Controls.Interfaces;
+using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using Microsoft.Win32;
 using System;
+using System.Collections.Generic;
+using System.Drawing;
 using System.IO;
-using System.Text;
+using System.Windows.Forms;
 using System.Xml;
 
 namespace ContextMenuManager.Controls
 {
-    sealed class ThirdRulesList : MyList
+    sealed class DetailedEditList : SwitchDicList
     {
-        public void LoadItems()
-        {
-            string webPath = AppConfig.WebThirdRulesDic;
-            string userPath = AppConfig.UserThirdRulesDic;
-            string contents = Properties.Resources.ThirdRulesDic;
-            if(!File.Exists(webPath)) File.WriteAllText(webPath, contents, Encoding.Unicode);
-            GroupPathItem webGroupItem = new GroupPathItem(webPath, ObjectPath.PathType.File);
-            GroupPathItem userGroupItem = new GroupPathItem(userPath, ObjectPath.PathType.File);
-            webGroupItem.Text = AppString.SideBar.Dictionaries;
-            userGroupItem.Text = AppString.Other.UserDictionaries;
-            webGroupItem.Image = AppImage.App;
-            userGroupItem.Image = AppImage.User;
-            LoadDocItems(webPath, webGroupItem);
-            LoadDocItems(userPath, userGroupItem);
-        }
+        public Guid GroupGuid { get; set; }
 
-        private void LoadDocItems(string xmlPath, GroupPathItem groupItem)
+        public override void LoadItems()
         {
-            if(!File.Exists(xmlPath)) return;
-            this.AddItem(groupItem);
-            XmlDocument doc = new XmlDocument();
-            try { doc.LoadXml(File.ReadAllText(xmlPath, EncodingType.GetType(xmlPath)).Trim()); }
-            catch(Exception e) { MessageBoxEx.Show(e.Message); return; }
-            foreach(XmlElement groupXE in doc.DocumentElement.ChildNodes)
+            base.LoadItems();
+            int index = this.UseUserDic ? 1 : 0;
+            XmlDocument doc = XmlDicHelper.DetailedEditDic[index];
+            if(doc?.DocumentElement == null) return;
+            foreach(XmlNode groupXN in doc.DocumentElement.ChildNodes)
             {
                 try
                 {
-                    Guid guid = Guid.Empty;
-                    if(groupXE.HasAttribute("Guid"))
+                    List<Guid> guids = new List<Guid>();
+                    XmlNodeList guidList = groupXN.SelectNodes("Guid");
+                    foreach(XmlNode guidXN in guidList)
                     {
-                        if(GuidEx.TryParse(groupXE.GetAttribute("Guid"), out guid))
-                        {
-                            if(!File.Exists(GuidInfo.GetFilePath(guid))) continue;
-                        }
-                        else continue;
+                        if(!GuidEx.TryParse(guidXN.InnerText, out Guid guid)) continue;
+                        if(!File.Exists(GuidInfo.GetFilePath(guid))) continue;
+                        if(this.GroupGuid != Guid.Empty && this.GroupGuid != guid) continue;
+                        guids.Add(guid);
                     }
+                    if(guidList.Count > 0 && guids.Count == 0) continue;
 
-                    SubGroupItem subGroupItem;
-                    bool isIniGroup = groupXE.HasAttribute("IsIniGroup");
+                    FoldGroupItem groupItem;
+                    bool isIniGroup = groupXN.SelectSingleNode("IsIniGroup") != null;
                     string attribute = isIniGroup ? "FilePath" : "RegPath";
                     ObjectPath.PathType pathType = isIniGroup ? ObjectPath.PathType.File : ObjectPath.PathType.Registry;
-                    subGroupItem = new SubGroupItem(groupXE.GetAttribute(attribute), pathType)
+                    groupItem = new FoldGroupItem(groupXN.SelectSingleNode(attribute)?.InnerText, pathType);
+                    foreach(XmlElement textXE in groupXN.SelectNodes("Text"))
                     {
-                        Text = groupXE.GetAttribute("Text"),
-                        Image = GuidInfo.GetImage(guid)
-                    };
-                    if(subGroupItem.Text.IsNullOrWhiteSpace()) subGroupItem.Text = GuidInfo.GetText(guid);
-                    this.AddItem(subGroupItem);
+                        if(XmlDicHelper.JudgeCulture(textXE)) groupItem.Text = ResourceString.GetDirectString(textXE.GetAttribute("Value"));
+                    }
+                    if(guids.Count > 0)
+                    {
+                        groupItem.Tag = guids;
+                        if(groupItem.Text.IsNullOrWhiteSpace()) groupItem.Text = GuidInfo.GetText(guids[0]);
+                        groupItem.Image = GuidInfo.GetImage(guids[0]);
+                        string filePath = GuidInfo.GetFilePath(guids[0]);
+                        string clsidPath = GuidInfo.GetClsidPath(guids[0]);
+                        if(filePath != null || clsidPath != null) groupItem.ContextMenuStrip.Items.Add(new ToolStripSeparator());
+                        if(filePath != null)
+                        {
+                            ToolStripMenuItem tsi = new ToolStripMenuItem(AppString.Menu.FileLocation);
+                            tsi.Click += (sender, e) => ExternalProgram.JumpExplorer(filePath, AppConfig.OpenMoreExplorer);
+                            groupItem.ContextMenuStrip.Items.Add(tsi);
+                        }
+                        if(clsidPath != null)
+                        {
+                            ToolStripMenuItem tsi = new ToolStripMenuItem(AppString.Menu.ClsidLocation);
+                            tsi.Click += (sender, e) => ExternalProgram.JumpRegEdit(clsidPath, null, AppConfig.OpenMoreRegedit);
+                            groupItem.ContextMenuStrip.Items.Add(tsi);
+                        }
+                    }
+                    XmlNode iconXN = groupXN.SelectSingleNode("Icon");
+                    using(Icon icon = ResourceIcon.GetIcon(iconXN?.InnerText))
+                    {
+                        if(icon != null) groupItem.Image = icon.ToBitmap();
+                    }
+                    this.AddItem(groupItem);
 
                     string GetRuleFullRegPath(string regPath)
                     {
-                        if(string.IsNullOrEmpty(regPath)) regPath = subGroupItem.TargetPath;
-                        else if(regPath.StartsWith("\\")) regPath = subGroupItem.TargetPath + regPath;
+                        if(string.IsNullOrEmpty(regPath)) regPath = groupItem.GroupPath;
+                        else if(regPath.StartsWith("\\")) regPath = groupItem.GroupPath + regPath;
                         return regPath;
                     };
 
-                    foreach(XmlElement itemXE in groupXE.ChildNodes)
+                    foreach(XmlElement itemXE in groupXN.SelectNodes("Item"))
                     {
                         try
                         {
-                            if(!EnhanceMenusList.JudgeOSVersion(itemXE)) continue;
+                            if(!XmlDicHelper.JudgeOSVersion(itemXE)) continue;
                             RuleItem ruleItem;
-                            ItemInfo info = new ItemInfo
+                            ItemInfo info = new ItemInfo();
+                            foreach(XmlElement textXE in itemXE.SelectNodes("Text"))
+                            {
+                                if(XmlDicHelper.JudgeCulture(textXE)) info.Text = ResourceString.GetDirectString(textXE.GetAttribute("Value"));
+                            }
+                            foreach(XmlElement tipXE in itemXE.SelectNodes("Tip"))
                             {
-                                Text = itemXE.GetAttribute("Text"),
-                                Tip = itemXE.GetAttribute("Tip"),
-                                RestartExplorer = itemXE.HasAttribute("RestartExplorer"),
-                            };
+                                if(XmlDicHelper.JudgeCulture(tipXE)) info.Tip = ResourceString.GetDirectString(tipXE.GetAttribute("Value"));
+                            }
+                            info.RestartExplorer = itemXE.SelectSingleNode("RestartExplorer") != null;
+
                             int defaultValue = 0, maxValue = 0, minValue = 0;
-                            if(itemXE.HasAttribute("IsNumberItem"))
+                            if(itemXE.SelectSingleNode("IsNumberItem") != null)
                             {
                                 XmlElement ruleXE = (XmlElement)itemXE.SelectSingleNode("Rule");
                                 defaultValue = ruleXE.HasAttribute("Default") ? Convert.ToInt32(ruleXE.GetAttribute("Default")) : 0;
@@ -92,10 +109,10 @@ namespace ContextMenuManager.Controls
                             {
                                 XmlElement ruleXE = (XmlElement)itemXE.SelectSingleNode("Rule");
                                 string iniPath = ruleXE.GetAttribute("FilePath");
-                                if(iniPath.IsNullOrWhiteSpace()) iniPath = subGroupItem.TargetPath;
+                                if(iniPath.IsNullOrWhiteSpace()) iniPath = groupItem.GroupPath;
                                 string section = ruleXE.GetAttribute("Section");
                                 string keyName = ruleXE.GetAttribute("KeyName");
-                                if(itemXE.HasAttribute("IsNumberItem"))
+                                if(itemXE.SelectSingleNode("IsNumberItem") != null)
                                 {
                                     var rule = new NumberIniRuleItem.IniRule
                                     {
@@ -108,7 +125,7 @@ namespace ContextMenuManager.Controls
                                     };
                                     ruleItem = new NumberIniRuleItem(rule, info);
                                 }
-                                else if(itemXE.HasAttribute("IsStringItem"))
+                                else if(itemXE.SelectSingleNode("IsStringItem") != null)
                                 {
                                     var rule = new StringIniRuleItem.IniRule
                                     {
@@ -133,21 +150,21 @@ namespace ContextMenuManager.Controls
                             }
                             else
                             {
-                                if(itemXE.HasAttribute("IsNumberItem"))
+                                if(itemXE.SelectSingleNode("IsNumberItem") != null)
                                 {
                                     XmlElement ruleXE = (XmlElement)itemXE.SelectSingleNode("Rule");
                                     var rule = new NumberRegRuleItem.RegRule
                                     {
                                         RegPath = GetRuleFullRegPath(ruleXE.GetAttribute("RegPath")),
                                         ValueName = ruleXE.GetAttribute("ValueName"),
-                                        ValueKind = GetValueKind(ruleXE.GetAttribute("ValueKind")),
+                                        ValueKind = XmlDicHelper.GetValueKind(ruleXE.GetAttribute("ValueKind"), RegistryValueKind.DWord),
                                         DefaultValue = defaultValue,
                                         MaxValue = maxValue,
                                         MinValue = minValue
                                     };
                                     ruleItem = new NumberRegRuleItem(rule, info);
                                 }
-                                else if(itemXE.HasAttribute("IsStringItem"))
+                                else if(itemXE.SelectSingleNode("IsStringItem") != null)
                                 {
                                     XmlElement ruleXE = (XmlElement)itemXE.SelectSingleNode("Rule");
                                     var rule = new StringRegRuleItem.RegRule
@@ -168,15 +185,15 @@ namespace ContextMenuManager.Controls
                                         {
                                             RegPath = GetRuleFullRegPath(ruleXE.GetAttribute("RegPath")),
                                             ValueName = ruleXE.GetAttribute("ValueName"),
-                                            ValueKind = GetValueKind(ruleXE.GetAttribute("ValueKind"))
+                                            ValueKind = XmlDicHelper.GetValueKind(ruleXE.GetAttribute("ValueKind"), RegistryValueKind.DWord)
                                         };
                                         string turnOn = ruleXE.HasAttribute("On") ? ruleXE.GetAttribute("On") : null;
                                         string turnOff = ruleXE.HasAttribute("Off") ? ruleXE.GetAttribute("Off") : null;
                                         switch(rules[i].ValueKind)
                                         {
                                             case RegistryValueKind.Binary:
-                                                rules[i].TurnOnValue = turnOn != null ? EnhanceMenusList.ConvertToBinary(turnOn) : null;
-                                                rules[i].TurnOffValue = turnOff != null ? EnhanceMenusList.ConvertToBinary(turnOff) : null;
+                                                rules[i].TurnOnValue = turnOn != null ? XmlDicHelper.ConvertToBinary(turnOn) : null;
+                                                rules[i].TurnOffValue = turnOff != null ? XmlDicHelper.ConvertToBinary(turnOff) : null;
                                                 break;
                                             case RegistryValueKind.DWord:
                                                 if(turnOn == null) rules[i].TurnOnValue = null;
@@ -194,38 +211,16 @@ namespace ContextMenuManager.Controls
                                 }
                             }
                             this.AddItem(ruleItem);
-                            ruleItem.FoldGroupItem = subGroupItem;
+                            ruleItem.FoldGroupItem = groupItem;
+                            ruleItem.HasImage = ruleItem.Image != null;
+                            ruleItem.Indent();
                         }
                         catch { continue; }
                     }
-                    subGroupItem.HideWhenNoSubItem();
-                    subGroupItem.FoldGroupItem = groupItem;
+                    groupItem.SetVisibleWithSubItemCount();
                 }
                 catch { continue; }
             }
-            groupItem.IsFold = true;
-            groupItem.HideWhenNoSubItem();
-        }
-
-        private static RegistryValueKind GetValueKind(string data)
-        {
-            switch(data.ToUpper())
-            {
-                case "REG_SZ":
-                    return RegistryValueKind.String;
-                case "REG_BINARY":
-                    return RegistryValueKind.Binary;
-                case "REG_DWORD":
-                    return RegistryValueKind.DWord;
-                case "REG_QWORD":
-                    return RegistryValueKind.QWord;
-                case "REG_MULTI_SZ":
-                    return RegistryValueKind.MultiString;
-                case "REG_EXPAND_SZ":
-                    return RegistryValueKind.ExpandString;
-                default:
-                    return RegistryValueKind.DWord;
-            }
         }
     }
 }

+ 135 - 0
ContextMenuManager/Controls/DictionariesBox.cs

@@ -0,0 +1,135 @@
+using BluePointLilac.Controls;
+using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
+using System;
+using System.Drawing;
+using System.IO;
+using System.Text;
+using System.Windows.Forms;
+
+namespace ContextMenuManager.Controls
+{
+    sealed class DictionariesBox : TabControl
+    {
+        public DictionariesBox()
+        {
+            this.SuspendLayout();
+            this.Dock = DockStyle.Fill;
+            this.Controls.AddRange(pages);
+            this.Font = SystemFonts.MenuFont;
+            this.Font = new Font(this.Font.FontFamily, this.Font.Size + 1F);
+            cms.Items.AddRange(items);
+            for(int i = 0; i < 6; i++)
+            {
+                boxs[i] = new ReadOnlyRichTextBox { Parent = pages[i] };
+                if(i > 0) boxs[i].ContextMenuStrip = cms;
+            }
+            items[0].Click += (sender, e) => ExternalProgram.OpenNotepadWithText(GetInitialText());
+            items[2].Click += (sender, e) => SaveFile();
+            boxs[0].Controls.Add(btnOpenDir);
+            btnOpenDir.Top = boxs[0].Height - btnOpenDir.Height;
+            ToolTipBox.SetToolTip(btnOpenDir, AppString.Menu.FileLocation);
+            btnOpenDir.MouseDown += (sender, e) => ExternalProgram.OpenDirectory(AppConfig.DicsDir);
+            this.SelectedIndexChanged += (sender, e) => LoadText();
+            this.VisibleChanged += (sender, e) => this.SetEnabled(this.Visible);
+            this.ResumeLayout();
+        }
+
+        readonly TabPage[] pages =
+        {
+            new TabPage(AppString.Other.DictionaryDescription),
+            new TabPage(AppString.SideBar.AppLanguage),
+            new TabPage(AppString.Other.GuidInfosDictionary),
+            new TabPage(AppString.SideBar.DetailedEdit),
+            new TabPage(AppString.SideBar.EnhanceMenu),
+            new TabPage(AppString.Other.UwpMode)
+        };
+        readonly ReadOnlyRichTextBox[] boxs = new ReadOnlyRichTextBox[6];
+        readonly PictureButton btnOpenDir = new PictureButton(AppImage.Open)
+        {
+            Anchor = AnchorStyles.Left | AnchorStyles.Bottom,
+            Left = 0
+        };
+        readonly ContextMenuStrip cms = new ContextMenuStrip();
+        readonly ToolStripItem[] items =
+        {
+            new ToolStripMenuItem(AppString.Menu.Edit),
+            new ToolStripSeparator(),
+            new ToolStripMenuItem(AppString.Menu.Save)
+        };
+
+        private void SaveFile()
+        {
+            using(SaveFileDialog dlg = new SaveFileDialog())
+            {
+                string dirPath = AppConfig.UserDicsDir;
+                switch(SelectedIndex)
+                {
+                    case 1:
+                        dirPath = AppConfig.LangsDir;
+                        dlg.FileName = AppConfig.ZH_CNINI;
+                        break;
+                    case 2:
+                        dlg.FileName = AppConfig.GUIDINFOSDICINI;
+                        break;
+                    case 3:
+                        dlg.FileName = AppConfig.DETAILEDEDITDICXML;
+                        break;
+                    case 4:
+                        dlg.FileName = AppConfig.ENHANCEMENUSICXML;
+                        break;
+                    case 5:
+                        dlg.FileName = AppConfig.UWPMODEITEMSDICXML;
+                        break;
+                }
+                dlg.Filter = $"{dlg.FileName}|*{Path.GetExtension(dlg.FileName)}";
+                Directory.CreateDirectory(dirPath);
+                dlg.InitialDirectory = dirPath;
+                if(dlg.ShowDialog() == DialogResult.OK)
+                {
+                    File.WriteAllText(dlg.FileName, GetInitialText(), Encoding.Unicode);
+                }
+            }
+        }
+
+        private string GetInitialText()
+        {
+            switch(this.SelectedIndex)
+            {
+                case 0:
+                    return AppString.Other.Dictionaries;
+                case 1:
+                    return Properties.Resources.AppLanguageDic;
+                case 2:
+                    return Properties.Resources.GuidInfosDic;
+                case 3:
+                    return Properties.Resources.DetailedEditDic;
+                case 4:
+                    return Properties.Resources.EnhanceMenusDic;
+                case 5:
+                    return Properties.Resources.UwpModeItemsDic;
+                default:
+                    return string.Empty;
+            }
+        }
+
+        public void LoadText()
+        {
+            int index = this.SelectedIndex;
+            if(boxs[index].Text.Length > 0) return;
+            Action<string> action = null;
+            switch(index)
+            {
+                case 0:
+                case 1:
+                case 2:
+                    action = boxs[index].LoadIni; break;
+                case 3:
+                case 4:
+                case 5:
+                    action = boxs[index].LoadXml; break;
+            }
+            this.BeginInvoke(action, new[] { GetInitialText() });
+        }
+    }
+}

+ 237 - 0
ContextMenuManager/Controls/DonateBox.cs

@@ -0,0 +1,237 @@
+using BluePointLilac.Controls;
+using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Linq;
+using System.Windows.Forms;
+
+namespace ContextMenuManager.Controls
+{
+    sealed class DonateBox : Panel
+    {
+        public DonateBox()
+        {
+            this.SuspendLayout();
+            this.AutoScroll = true;
+            this.Dock = DockStyle.Fill;
+            this.BackColor = Color.White;
+            this.Font = SystemFonts.MenuFont;
+            this.Font = new Font(this.Font.FontFamily, this.Font.Size + 1F);
+            this.Controls.AddRange(new Control[] { lblInfo, picQR, lblList });
+            this.VisibleChanged += (sender, e) => this.SetEnabled(this.Visible);
+            lblList.Click += (sender, e) => this.ShowDonateDialog();
+            picQR.Resize += (sender, e) => this.OnResize(null);
+            picQR.MouseDown += SwitchQR;
+            this.ResumeLayout();
+        }
+
+        readonly Label lblInfo = new Label
+        {
+            Text = AppString.Other.Donate,
+            AutoSize = true
+        };
+
+        readonly Label lblList = new Label
+        {
+            ForeColor = Color.FromArgb(85, 145, 215),
+            Text = AppString.Other.DonationList,
+            Cursor = Cursors.Hand,
+            AutoSize = true
+        };
+
+        readonly PictureBox picQR = new PictureBox
+        {
+            SizeMode = PictureBoxSizeMode.AutoSize,
+            Cursor = Cursors.Hand,
+            Image = AllQR,
+        };
+
+        static readonly Image AllQR = Properties.Resources.Donate;
+        static readonly Image WechatQR = GetSingleQR(0);
+        static readonly Image AlipayQR = GetSingleQR(1);
+        static readonly Image QQQR = GetSingleQR(2);
+        private static Image GetSingleQR(int index)
+        {
+            Bitmap bitmap = new Bitmap(200, 200);
+            using(Graphics g = Graphics.FromImage(bitmap))
+            {
+                Rectangle destRect = new Rectangle(0, 0, 200, 200);
+                Rectangle srcRect = new Rectangle(index * 200, 0, 200, 200);
+                g.DrawImage(AllQR, destRect, srcRect, GraphicsUnit.Pixel);
+            }
+            return bitmap;
+        }
+
+        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;
+            lblList.Left = (this.Width - lblList.Width) / 2;
+            lblInfo.Top = a;
+            picQR.Top = lblInfo.Bottom + a;
+            lblList.Top = picQR.Bottom + a;
+        }
+
+        private void SwitchQR(object sender, MouseEventArgs e)
+        {
+            if(picQR.Image == AllQR)
+            {
+                if(e.X < 200) picQR.Image = WechatQR;
+                else if(e.X < 400) picQR.Image = AlipayQR;
+                else picQR.Image = QQQR;
+            }
+            else
+            {
+                picQR.Image = AllQR;
+            }
+        }
+
+        private void ShowDonateDialog()
+        {
+            this.Cursor = Cursors.WaitCursor;
+            using(UAWebClient client = new UAWebClient())
+            {
+                string url = AppConfig.RequestUseGithub ? AppConfig.GithubDonateRaw : AppConfig.GiteeDonateRaw;
+                string contents = client.GetWebString(url);
+                //contents = System.IO.File.ReadAllText(@"..\..\..\Donate.md");//用于求和更新Donate.md文件
+                if(contents == null)
+                {
+                    if(AppMessageBox.Show(AppString.Message.WebDataReadFailed + "\r\n"
+                        + AppString.Message.OpenWebUrl, MessageBoxButtons.OKCancel) == DialogResult.OK)
+                    {
+                        url = AppConfig.RequestUseGithub ? AppConfig.GithubDonate : AppConfig.GiteeDonate;
+                        ExternalProgram.OpenWebUrl(url);
+                    }
+                }
+                else
+                {
+                    using(DonateListDialog dlg = new DonateListDialog())
+                    {
+                        dlg.DanateData = contents;
+                        dlg.ShowDialog();
+                    }
+                }
+            }
+            this.Cursor = Cursors.Default;
+        }
+
+        sealed class DonateListDialog : CommonDialog
+        {
+            public string DanateData { get; set; }
+
+            public override void Reset() { }
+
+            protected override bool RunDialog(IntPtr hwndOwner)
+            {
+                using(DonateListForm frm = new DonateListForm())
+                {
+                    frm.ShowDonateList(DanateData);
+                    MainForm mainForm = (MainForm)FromHandle(hwndOwner);
+                    frm.Left = mainForm.Left + (mainForm.Width + mainForm.SideBar.Width - frm.Width) / 2;
+                    frm.Top = mainForm.Top + 150.DpiZoom();
+                    frm.TopMost = AppConfig.TopMost;
+                    frm.ShowDialog();
+                }
+                return true;
+            }
+
+            sealed class DonateListForm : Form
+            {
+                public DonateListForm()
+                {
+                    this.Font = SystemFonts.DialogFont;
+                    this.Text = AppString.Other.DonationList;
+                    this.SizeGripStyle = SizeGripStyle.Hide;
+                    this.StartPosition = FormStartPosition.Manual;
+                    this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
+                    this.MinimizeBox = this.MaximizeBox = this.ShowInTaskbar = false;
+                    this.ClientSize = new Size(520, 350).DpiZoom();
+                    this.MinimumSize = this.Size;
+                    dgvDonate.ColumnHeadersDefaultCellStyle.Alignment
+                        = dgvDonate.RowsDefaultCellStyle.Alignment
+                        = DataGridViewContentAlignment.BottomCenter;
+                    this.Controls.AddRange(new Control[] { lblThank, lblDonate, dgvDonate });
+                    lblThank.MouseEnter += (sender, e) => lblThank.ForeColor = Color.FromArgb(0, 162, 255);
+                    lblThank.MouseLeave += (sender, e) => lblThank.ForeColor = Color.DimGray;
+                    lblDonate.Resize += (sender, e) => this.OnResize(null);
+                    this.AddEscapeButton();
+                }
+
+                readonly DataGridView dgvDonate = new DataGridView
+                {
+                    ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize,
+                    AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells,
+                    SelectionMode = DataGridViewSelectionMode.FullRowSelect,
+                    BackgroundColor = SystemColors.Control,
+                    BorderStyle = BorderStyle.None,
+                    AllowUserToResizeRows = false,
+                    AllowUserToAddRows = false,
+                    RowHeadersVisible = false,
+                    MultiSelect = false,
+                    ReadOnly = true
+                };
+
+                readonly Label lblDonate = new Label { AutoSize = true };
+                readonly Label lblThank = new Label
+                {
+                    Font = new Font("Lucida Handwriting", 15F),
+                    ForeColor = Color.DimGray,
+                    Text = "Thank you!",
+                    AutoSize = true,
+                };
+
+                protected override void OnResize(EventArgs e)
+                {
+                    base.OnResize(e);
+                    int a = 20.DpiZoom();
+                    lblDonate.Location = new Point(a, a);
+                    dgvDonate.Location = new Point(a, lblDonate.Bottom + a);
+                    dgvDonate.Width = this.ClientSize.Width - 2 * a;
+                    dgvDonate.Height = this.ClientSize.Height - 3 * a - lblDonate.Height;
+                    lblThank.Location = new Point(dgvDonate.Right - lblThank.Width, lblDonate.Bottom - lblThank.Height);
+                }
+
+                public void ShowDonateList(string contents)
+                {
+                    string[] lines = contents.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
+                    int index = Array.FindIndex(lines, line => line == "|:--:|:--:|:--:|:--:|:--:");
+                    if(index == -1) return;
+                    string[] heads = lines[index - 1].Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
+                    dgvDonate.ColumnCount = heads.Length;
+                    dgvDonate.Columns[4].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
+                    for(int m = 0; m < heads.Length; m++)
+                    {
+                        dgvDonate.Columns[m].HeaderText = heads[m];
+                    }
+                    for(int n = index + 1; n < lines.Length; n++)
+                    {
+                        string[] strs = lines[n].Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
+                        object[] values = new object[strs.Length];
+                        for(int k = 0; k < strs.Length; k++)
+                        {
+                            switch(k)
+                            {
+                                case 3:
+                                    values[k] = Convert.ToSingle(strs[k]);
+                                    break;
+                                default:
+                                    values[k] = strs[k];
+                                    break;
+                            }
+                        }
+                        dgvDonate.Rows.Add(values);
+                    }
+                    dgvDonate.Sort(dgvDonate.Columns[0], ListSortDirection.Descending);
+                    DateTime date = Convert.ToDateTime(dgvDonate.Rows[0].Cells[0].Value);
+                    float money = dgvDonate.Rows.Cast<DataGridViewRow>().Sum(row => (float)row.Cells[3].Value);
+                    lblDonate.Text = AppString.Dialog.DonateInfo.Replace("%date", date.ToLongDateString())
+                        .Replace("%money", money.ToString()).Replace("%count", dgvDonate.RowCount.ToString());
+                }
+            }
+        }
+    }
+}

+ 0 - 112
ContextMenuManager/Controls/DonateListDialog.cs

@@ -1,112 +0,0 @@
-using BluePointLilac.Methods;
-using System;
-using System.ComponentModel;
-using System.Drawing;
-using System.Linq;
-using System.Windows.Forms;
-
-namespace ContextMenuManager.Controls
-{
-    sealed class DonateListDialog : CommonDialog
-    {
-        public string DanateData { get; set; }
-
-        public override void Reset() { }
-
-        protected override bool RunDialog(IntPtr hwndOwner)
-        {
-            using(DonateListForm frm = new DonateListForm())
-            {
-                frm.ShowDonateList(DanateData);
-                MainForm mainForm = (MainForm)Control.FromHandle(hwndOwner);
-                frm.Left = mainForm.Left + (mainForm.Width + mainForm.GetSideBarWidth() - frm.Width) / 2;
-                frm.Top = mainForm.Top + 150.DpiZoom();
-                frm.ShowDialog();
-            }
-            return true;
-        }
-
-        sealed class DonateListForm : Form
-        {
-            public DonateListForm()
-            {
-                this.Text = AppString.Other.DonationList;
-                this.SizeGripStyle = SizeGripStyle.Hide;
-                this.StartPosition = FormStartPosition.Manual;
-                this.MinimizeBox = this.MaximizeBox = this.ShowInTaskbar = false;
-                this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
-                this.Font = new Font(SystemFonts.DialogFont.FontFamily, 9F);
-                this.ClientSize = new Size(520, 355).DpiZoom();
-                this.MinimumSize = this.Size;
-                dgvDonate.ColumnHeadersDefaultCellStyle.Alignment
-                    = dgvDonate.RowsDefaultCellStyle.Alignment
-                    = DataGridViewContentAlignment.BottomCenter;
-                this.Controls.AddRange(new Control[] { lblDonate, dgvDonate });
-                lblDonate.Resize += (sender, e) => this.OnResize(null);
-            }
-
-            readonly DataGridView dgvDonate = new DataGridView
-            {
-                ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize,
-                AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells,
-                SelectionMode = DataGridViewSelectionMode.FullRowSelect,
-                BackgroundColor = SystemColors.Control,
-                BorderStyle = BorderStyle.None,
-                AllowUserToResizeRows = false,
-                AllowUserToAddRows = false,
-                RowHeadersVisible = false,
-                MultiSelect = false,
-                ReadOnly = true
-            };
-
-            readonly Label lblDonate = new Label { AutoSize = true };
-
-            protected override void OnResize(EventArgs e)
-            {
-                base.OnResize(e);
-                int a = 20.DpiZoom();
-                lblDonate.Location = new Point(a, a);
-                dgvDonate.Location = new Point(a, lblDonate.Bottom + a);
-                dgvDonate.Width = this.ClientSize.Width - 2 * a;
-                dgvDonate.Height = this.ClientSize.Height - 3 * a - lblDonate.Height;
-            }
-
-            public void ShowDonateList(string contents)
-            {
-                string[] lines = contents.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
-                int index = Array.FindIndex(lines, line => line == "|:--:|:--:|:--:|:--:|:--:");
-                if(index == -1) return;
-                string[] heads = lines[index - 1].Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
-                dgvDonate.ColumnCount = heads.Length;
-                dgvDonate.Columns[4].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
-                for(int m = 0; m < heads.Length; m++)
-                {
-                    dgvDonate.Columns[m].HeaderText = heads[m];
-                }
-                for(int n = index + 1; n < lines.Length; n++)
-                {
-                    string[] strs = lines[n].Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
-                    object[] values = new object[strs.Length];
-                    for(int k = 0; k < strs.Length; k++)
-                    {
-                        switch(k)
-                        {
-                            case 3:
-                                values[k] = Convert.ToSingle(strs[k]);
-                                break;
-                            default:
-                                values[k] = strs[k];
-                                break;
-                        }
-                    }
-                    dgvDonate.Rows.Add(values);
-                }
-                dgvDonate.Sort(dgvDonate.Columns[0], ListSortDirection.Descending);
-                DateTime date = Convert.ToDateTime(dgvDonate.Rows[0].Cells[0].Value);
-                float money = dgvDonate.Rows.Cast<DataGridViewRow>().Sum(row => (float)row.Cells[3].Value);
-                lblDonate.Text = AppString.Dialog.DonateInfo.Replace("%date", date.ToLongDateString())
-                    .Replace("%money", money.ToString()).Replace("%count", dgvDonate.RowCount.ToString());
-            }
-        }
-    }
-}

+ 31 - 0
ContextMenuManager/Controls/EnhanceMenusDialog.cs

@@ -0,0 +1,31 @@
+using ContextMenuManager.Methods;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace ContextMenuManager.Controls
+{
+    sealed class EnhanceMenusDialog : CommonDialog
+    {
+        public string ScenePath { get; set; }
+
+        public override void Reset() { }
+
+        protected override bool RunDialog(IntPtr hwndOwner)
+        {
+            using(SubItemsForm frm = new SubItemsForm())
+            using(EnhanceMenusList list = new EnhanceMenusList())
+            {
+                frm.Text = AppString.SideBar.EnhanceMenu;
+                frm.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
+                frm.TopMost = AppConfig.TopMost;
+                frm.AddList(list);
+                list.ScenePath = this.ScenePath;
+                list.UseUserDic = XmlDicHelper.EnhanceMenuPathDic[this.ScenePath];
+                list.LoadItems();
+                frm.ShowDialog();
+            }
+            return false;
+        }
+    }
+}

+ 40 - 24
ContextMenuManager/Controls/EnhanceMenusItem.cs

@@ -1,6 +1,6 @@
-using BluePointLilac.Controls;
-using BluePointLilac.Methods;
+using BluePointLilac.Methods;
 using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using Microsoft.Win32;
 using System;
 using System.Collections.Generic;
@@ -11,12 +11,12 @@ using System.Xml;
 
 namespace ContextMenuManager.Controls
 {
-    sealed class EnhanceShellItem : MyListItem, IFoldSubItem, IChkVisibleItem
+    sealed class EnhanceShellItem : FoldSubItem, IChkVisibleItem
     {
         public string RegPath { get; set; }
         public XmlElement ItemXE { get; set; }
         public VisibleCheckBox ChkVisible { get; set; }
-        public IFoldGroupItem FoldGroupItem { get; set; }
+
         public bool ItemVisible
         {
             get
@@ -34,29 +34,35 @@ namespace ContextMenuManager.Controls
         public EnhanceShellItem()
         {
             ChkVisible = new VisibleCheckBox(this);
+            this.Indent();
         }
 
         private static void WriteAttributesValue(XmlNode valueXN, string regPath)
         {
             if(valueXN == null) return;
-            if(!EnhanceMenusList.JudgeOSVersion((XmlElement)valueXN)) return;
+            if(!XmlDicHelper.FileExists(valueXN)) return;
+            if(!XmlDicHelper.JudgeCulture(valueXN)) return;
+            if(!XmlDicHelper.JudgeOSVersion(valueXN)) return;
             using(RegistryKey key = RegistryEx.GetRegistryKey(regPath, true, true))
             {
                 foreach(XmlNode xn in valueXN.ChildNodes)
                 {
-                    if(!EnhanceMenusList.JudgeOSVersion((XmlElement)xn)) continue;
+                    if(xn is XmlComment) continue;
+                    if(!XmlDicHelper.FileExists(xn)) continue;
+                    if(!XmlDicHelper.JudgeCulture(xn)) continue;
+                    if(!XmlDicHelper.JudgeOSVersion(xn)) continue;
                     foreach(XmlAttribute xa in xn.Attributes)
                     {
                         switch(xn.Name)
                         {
                             case "REG_SZ":
-                                key.SetValue(xa.Name, xa.Value, RegistryValueKind.String);
+                                key.SetValue(xa.Name, Environment.ExpandEnvironmentVariables(xa.Value), RegistryValueKind.String);
                                 break;
                             case "REG_EXPAND_SZ":
                                 key.SetValue(xa.Name, xa.Value, RegistryValueKind.ExpandString);
                                 break;
                             case "REG_BINARY":
-                                key.SetValue(xa.Name, EnhanceMenusList.ConvertToBinary(xa.Value), RegistryValueKind.Binary);
+                                key.SetValue(xa.Name, XmlDicHelper.ConvertToBinary(xa.Value), RegistryValueKind.Binary);
                                 break;
                             case "REG_DWORD":
                                 int num = xa.Value.ToLower().StartsWith("0x") ? 16 : 10;
@@ -68,31 +74,37 @@ namespace ContextMenuManager.Controls
             }
         }
 
-        private static void WriteSubKeysValue(XmlElement keyXE, string regPath)
+        private static void WriteSubKeysValue(XmlNode keyXN, string regPath)
         {
-            if(keyXE == null) return;
-            if(!EnhanceMenusList.JudgeOSVersion(keyXE)) return;
-            string defaultValue = Environment.ExpandEnvironmentVariables(keyXE.GetAttribute("Default"));
+            if(keyXN == null) return;
+            if(!XmlDicHelper.FileExists(keyXN)) return;
+            if(!XmlDicHelper.JudgeCulture(keyXN)) return;
+            if(!XmlDicHelper.JudgeOSVersion(keyXN)) return;
+            string defaultValue = ((XmlElement)keyXN).GetAttribute("Default");
             if(!defaultValue.IsNullOrWhiteSpace())
             {
+                defaultValue = Environment.ExpandEnvironmentVariables(defaultValue);
                 Registry.SetValue(regPath, "", defaultValue);
             }
-            else if(keyXE.Name == "Command")
+            else if(keyXN.Name == "Command")
             {
                 //按照规则Command节点无默认值则创建文件
-                WriteCommandValue(keyXE, regPath);
+                WriteCommandValue(keyXN, regPath);
             }
-            WriteAttributesValue(keyXE.SelectSingleNode("Value"), regPath);
+            WriteAttributesValue(keyXN.SelectSingleNode("Value"), regPath);
 
-            XmlNode subKeyXN = keyXE.SelectSingleNode("SubKey");
+            XmlNode subKeyXN = keyXN.SelectSingleNode("SubKey");
             if(subKeyXN != null)
             {
-                foreach(XmlElement xe in subKeyXN.ChildNodes)
-                    WriteSubKeysValue(xe, $@"{regPath}\{xe.Name}");
+                foreach(XmlNode xn in subKeyXN.ChildNodes)
+                {
+                    if(xn is XmlComment) continue;
+                    WriteSubKeysValue(xn, $@"{regPath}\{xn.Name}");
+                }
             }
         }
 
-        private static void WriteCommandValue(XmlElement cmdXE, string regPath)
+        private static void WriteCommandValue(XmlNode cmdXE, string regPath)
         {
             XmlElement fnXE = (XmlElement)cmdXE.SelectSingleNode("FileName");
             XmlElement argXE = (XmlElement)cmdXE.SelectSingleNode("Arguments");
@@ -105,8 +117,8 @@ namespace ContextMenuManager.Controls
             if(string.IsNullOrEmpty(arguments)) arguments = CreateCommandFile(argXE);
             fileName = Environment.ExpandEnvironmentVariables(fileName);
             arguments = Environment.ExpandEnvironmentVariables(arguments);
-            string prefix = argXE?.GetAttribute("Prefix");
-            string suffix = argXE?.GetAttribute("Suffix");
+            string prefix = argXE?.GetAttribute("Prefix");//参数前缀
+            string suffix = argXE?.GetAttribute("Suffix");//参数后缀
             arguments = prefix + arguments + suffix;
             if(seXE != null)
             {
@@ -123,12 +135,15 @@ namespace ContextMenuManager.Controls
             Registry.SetValue(regPath, "", command);
         }
 
-        private static string CreateCommandFile(XmlElement xe)
+        private static string CreateCommandFile(XmlNode xe)
         {
             string path = string.Empty;
             if(xe == null) return path;
             foreach(XmlElement cfXE in xe.SelectNodes("CreateFile"))
             {
+                if(!XmlDicHelper.FileExists(cfXE)) continue;
+                if(!XmlDicHelper.JudgeCulture(cfXE)) continue;
+                if(!XmlDicHelper.JudgeOSVersion(cfXE)) continue;
                 string fileName = cfXE.GetAttribute("FileName");
                 string content = cfXE.GetAttribute("Content");
                 string extension = Path.GetExtension(fileName).ToLower();
@@ -153,13 +168,13 @@ namespace ContextMenuManager.Controls
         }
     }
 
-    sealed class EnhanceShellExItem : MyListItem, IFoldSubItem, IChkVisibleItem
+    sealed class EnhanceShellExItem : FoldSubItem, IChkVisibleItem
     {
         public string ShellExPath { get; set; }
         public string DefaultKeyName { get; set; }
         public Guid Guid { get; set; }
         public VisibleCheckBox ChkVisible { get; set; }
-        public IFoldGroupItem FoldGroupItem { get; set; }
+
         public bool ItemVisible
         {
             get => ShellExItem.GetPathAndGuids(ShellExPath).Values.Contains(Guid);
@@ -186,6 +201,7 @@ namespace ContextMenuManager.Controls
         public EnhanceShellExItem()
         {
             ChkVisible = new VisibleCheckBox(this);
+            this.Indent();
         }
     }
 }

+ 72 - 180
ContextMenuManager/Controls/EnhanceMenusList.cs

@@ -1,144 +1,78 @@
-using BluePointLilac.Controls;
-using BluePointLilac.Methods;
-using ContextMenuManager.Controls.Interfaces;
+using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.Drawing;
-using System.IO;
-using System.Text;
 using System.Xml;
 
 namespace ContextMenuManager.Controls
 {
-    sealed class EnhanceMenusList : MyList
+    sealed class EnhanceMenusList : SwitchDicList
     {
-        public void LoadItems()
-        {
-            string webPath = AppConfig.WebEnhanceMenusDic;
-            string userPath = AppConfig.UserEnhanceMenusDic;
-            string contents = Properties.Resources.EnhanceMenusDic;
-            if(!File.Exists(webPath)) File.WriteAllText(webPath, contents, Encoding.Unicode);
-            GroupPathItem webGroupItem = new GroupPathItem(webPath, ObjectPath.PathType.File);
-            GroupPathItem userGroupItem = new GroupPathItem(userPath, ObjectPath.PathType.File);
-            webGroupItem.Text = AppString.SideBar.Dictionaries;
-            userGroupItem.Text = AppString.Other.UserDictionaries;
-            webGroupItem.Image = AppImage.App;
-            userGroupItem.Image = AppImage.User;
-            LoadDocItems(webPath, webGroupItem);
-            LoadDocItems(userPath, userGroupItem);
-        }
+        public string ScenePath { get; set; }
 
-        private void LoadDocItems(string xmlPath, GroupPathItem groupItem)
+        public override void LoadItems()
         {
-            if(!File.Exists(xmlPath)) return;
-            this.AddItem(groupItem);
-            XmlDocument doc = new XmlDocument();
-            try { doc.LoadXml(File.ReadAllText(xmlPath, EncodingType.GetType(xmlPath)).Trim()); }
-            catch(Exception e) { MessageBoxEx.Show(e.Message); return; }
+            base.LoadItems();
+            int index = this.UseUserDic ? 1 : 0;
+            XmlDocument doc = XmlDicHelper.EnhanceMenusDic[index];
+            if(doc?.DocumentElement == null) return;
             foreach(XmlNode xn in doc.DocumentElement.ChildNodes)
             {
                 try
                 {
-                    SubGroupItem subGroupItem = GetGroupPathItem(xn);
-                    if(subGroupItem == null) continue;
-                    this.AddItem(subGroupItem);
-                    XmlElement shellXE = (XmlElement)xn.SelectSingleNode("Shell");
-                    XmlElement shellExXE = (XmlElement)xn.SelectSingleNode("ShellEx");
-                    if(shellXE != null) LoadShellItems(shellXE, subGroupItem);
-                    if(shellExXE != null) LoadShellExItems(shellExXE, subGroupItem);
-                    subGroupItem.HideWhenNoSubItem();
-                    subGroupItem.FoldGroupItem = groupItem;
-                }
-                catch { continue; }
-            }
-            groupItem.IsFold = true;
-            groupItem.HideWhenNoSubItem();
-        }
+                    Image image = null;
+                    string text = null;
+                    string path = xn.SelectSingleNode("RegPath")?.InnerText;
+                    foreach(XmlElement textXE in xn.SelectNodes("Text"))
+                    {
+                        if(XmlDicHelper.JudgeCulture(textXE))
+                        {
+                            text = ResourceString.GetDirectString(textXE.GetAttribute("Value"));
+                        }
+                    }
+                    if(string.IsNullOrEmpty(path) || string.IsNullOrEmpty(text)) continue;
+                    if(!string.IsNullOrEmpty(this.ScenePath) && !path.Equals(this.ScenePath, StringComparison.OrdinalIgnoreCase)) continue;
 
-        private SubGroupItem GetGroupPathItem(XmlNode xn)
-        {
-            string path;
-            string text;
-            Image image;
-            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"));
-                    if(string.IsNullOrEmpty(path) || string.IsNullOrEmpty(text)) return null;
-                    using(Icon icon = ResourceIcon.GetIcon(xe.GetAttribute("Icon")))
+                    string iconLocation = xn.SelectSingleNode("Icon")?.InnerText;
+                    using(Icon icon = ResourceIcon.GetIcon(iconLocation))
                     {
-                        if(icon != null) image = icon.ToBitmap();
-                        else image = AppImage.NotFound;
+                        image = icon?.ToBitmap();
+                        image = image ?? AppImage.NotFound;
                     }
-                    break;
+                    FoldGroupItem groupItem = new FoldGroupItem(path, ObjectPath.PathType.Registry)
+                    {
+                        Image = image,
+                        Text = text
+                    };
+                    this.AddItem(groupItem);
+                    XmlNode shellXN = xn.SelectSingleNode("Shell");
+                    XmlNode shellExXN = xn.SelectSingleNode("ShellEx");
+                    if(shellXN != null) LoadShellItems(shellXN, groupItem);
+                    if(shellExXN != null) LoadShellExItems(shellExXN, groupItem);
+                    groupItem.SetVisibleWithSubItemCount();
+                }
+                catch { continue; }
             }
-            return new SubGroupItem(path, ObjectPath.PathType.Registry) { Image = image, Text = text };
         }
 
-        private void LoadShellItems(XmlElement shellXE, SubGroupItem groupItem)
+        private void LoadShellItems(XmlNode shellXN, FoldGroupItem groupItem)
         {
-            foreach(XmlElement itemXE in shellXE.SelectNodes("Item"))
+            foreach(XmlElement itemXE in shellXN.SelectNodes("Item"))
             {
-                if(!JudgeOSVersion(itemXE)) continue;
-                if(!FileExists(itemXE)) continue;
+                if(!XmlDicHelper.FileExists(itemXE)) continue;
+                if(!XmlDicHelper.JudgeCulture(itemXE)) continue;
+                if(!XmlDicHelper.JudgeOSVersion(itemXE)) continue;
                 string keyName = itemXE.GetAttribute("KeyName");
                 if(keyName.IsNullOrWhiteSpace()) continue;
                 EnhanceShellItem item = new EnhanceShellItem()
                 {
-                    RegPath = $@"{groupItem.TargetPath}\shell\{keyName}",
+                    RegPath = $@"{groupItem.GroupPath}\shell\{keyName}",
                     FoldGroupItem = groupItem,
                     ItemXE = itemXE
                 };
                 foreach(XmlElement szXE in itemXE.SelectNodes("Value/REG_SZ"))
                 {
+                    if(!XmlDicHelper.JudgeCulture(szXE)) continue;
                     if(szXE.HasAttribute("MUIVerb")) item.Text = ResourceString.GetDirectString(szXE.GetAttribute("MUIVerb"));
                     if(szXE.HasAttribute("Icon")) item.Image = ResourceIcon.GetIcon(szXE.GetAttribute("Icon"))?.ToBitmap();
                     else if(szXE.HasAttribute("HasLUAShield")) item.Image = AppImage.Shield;
@@ -156,7 +90,7 @@ namespace ContextMenuManager.Controls
                         }
                         else
                         {
-                            XmlElement fileXE = (XmlElement)cmdXE.SelectSingleNode("FileName");
+                            XmlNode fileXE = cmdXE.SelectSingleNode("FileName");
                             if(fileXE != null)
                             {
                                 string filePath = ObjectPath.ExtractFilePath(fileXE.InnerText);
@@ -169,7 +103,11 @@ namespace ContextMenuManager.Controls
                 }
                 if(item.Image == null) item.Image = AppImage.NotFound;
                 if(item.Text.IsNullOrWhiteSpace()) item.Text = keyName;
-                string tip = itemXE.GetAttribute("Tip");
+                string tip = "";
+                foreach(XmlElement tipXE in itemXE.SelectNodes("Tip"))
+                {
+                    if(XmlDicHelper.JudgeCulture(tipXE)) tip = tipXE.GetAttribute("Value");
+                }
                 if(itemXE.GetElementsByTagName("CreateFile").Count > 0)
                 {
                     if(!tip.IsNullOrWhiteSpace()) tip += "\n";
@@ -180,85 +118,39 @@ namespace ContextMenuManager.Controls
             }
         }
 
-        private void LoadShellExItems(XmlElement shellExXE, SubGroupItem groupItem)
+        private void LoadShellExItems(XmlNode shellExXN, FoldGroupItem groupItem)
         {
-            foreach(XmlElement itemXE in shellExXE.SelectNodes("Item"))
+            foreach(XmlNode itemXN in shellExXN.SelectNodes("Item"))
             {
-                if(!JudgeOSVersion(itemXE)) continue;
-                if(!GuidEx.TryParse(itemXE.GetAttribute("Guid"), out Guid guid)) continue;
+                if(!XmlDicHelper.FileExists(itemXN)) continue;
+                if(!XmlDicHelper.JudgeCulture(itemXN)) continue;
+                if(!XmlDicHelper.JudgeOSVersion(itemXN)) continue;
+                if(!GuidEx.TryParse(itemXN.SelectSingleNode("Guid")?.InnerText, out Guid guid)) continue;
                 EnhanceShellExItem item = new EnhanceShellExItem
                 {
                     FoldGroupItem = groupItem,
-                    ShellExPath = $@"{groupItem.TargetPath}\ShellEx",
-                    Image = ResourceIcon.GetIcon(itemXE.GetAttribute("Icon"))?.ToBitmap() ?? AppImage.SystemFile,
-                    Text = ResourceString.GetDirectString(itemXE.GetAttribute("Text")),
-                    DefaultKeyName = itemXE.GetAttribute("KeyName"),
+                    ShellExPath = $@"{groupItem.GroupPath}\ShellEx",
+                    Image = ResourceIcon.GetIcon(itemXN.SelectSingleNode("Icon")?.InnerText)?.ToBitmap() ?? AppImage.SystemFile,
+                    DefaultKeyName = itemXN.SelectSingleNode("KeyName")?.InnerText,
                     Guid = guid
                 };
-                if(item.Text.IsNullOrWhiteSpace()) item.Text = GuidInfo.GetText(guid);
-                if(item.DefaultKeyName.IsNullOrWhiteSpace()) item.DefaultKeyName = guid.ToString("B");
-                ToolTipBox.SetToolTip(item.ChkVisible, itemXE.GetAttribute("Tip"));
-                this.AddItem(item);
-            }
-        }
-
-        public static bool JudgeOSVersion(XmlElement itemXE)
-        {
-            //return true;//测试用
-            bool JudgeOne(XmlElement osXE)
-            {
-                Version ver = new Version(osXE.InnerText);
-                Version osVer = Environment.OSVersion.Version;
-                int compare = osVer.CompareTo(ver);
-                string symbol = osXE.GetAttribute("Compare");
-                switch(symbol)
+                foreach(XmlNode textXE in itemXN.SelectNodes("Text"))
                 {
-                    case ">":
-                        return compare > 0;
-                    case "<":
-                        return compare < 0;
-                    case "=":
-                        return compare == 0;
-                    case ">=":
-                        return compare >= 0;
-                    case "<=":
-                        return compare <= 0;
-                    default:
-                        return true;
+                    if(XmlDicHelper.JudgeCulture(textXE))
+                    {
+                        item.Text = ResourceString.GetDirectString(textXE.InnerText);
+                    }
                 }
-            }
-
-            foreach(XmlElement osXE in itemXE.SelectNodes("OSVersion"))
-            {
-                if(!JudgeOne(osXE)) return false;
-            }
-            return true;
-        }
-
-        private static bool FileExists(XmlElement itemXE)
-        {
-            //return true;//测试用
-            foreach(XmlElement feXE in itemXE.SelectNodes("FileExists"))
-            {
-                string path = Environment.ExpandEnvironmentVariables(feXE.InnerText);
-                if(!File.Exists(path)) return false;
-            }
-            return true;
-        }
-
-        public static byte[] ConvertToBinary(string value)
-        {
-            try
-            {
-                string[] strs = value.Split(' ');
-                byte[] bs = new byte[strs.Length];
-                for(int i = 0; i < strs.Length; i++)
+                if(item.Text.IsNullOrWhiteSpace()) item.Text = GuidInfo.GetText(guid);
+                if(item.DefaultKeyName.IsNullOrWhiteSpace()) item.DefaultKeyName = guid.ToString("B");
+                string tip = "";
+                foreach(XmlElement tipXE in itemXN.SelectNodes("Tip"))
                 {
-                    bs[i] = Convert.ToByte(strs[i], 16);
+                    if(XmlDicHelper.JudgeCulture(tipXE)) tip = tipXE.GetAttribute("Text");
                 }
-                return bs;
+                ToolTipBox.SetToolTip(item.ChkVisible, tip);
+                this.AddItem(item);
             }
-            catch { return null; }
         }
     }
 }

+ 21 - 7
ContextMenuManager/Controls/ExplorerRestarter.cs

@@ -1,35 +1,49 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls
 {
-    public sealed class ExplorerRestarter : MyListItem
+    sealed class ExplorerRestarter : MyListItem
     {
         public ExplorerRestarter()
         {
             this.Visible = false;
+            this.DoubleBuffered = false;
             this.Dock = DockStyle.Bottom;
             this.Image = AppImage.Explorer;
             this.Text = AppString.Other.RestartExplorer;
             ToolTipBox.SetToolTip(BtnRestart, AppString.Tip.RestartExplorer);
             this.AddCtr(BtnRestart);
             this.CanMoveForm();
-            BtnRestart.MouseDown += (sender, e) => { ExternalProgram.RestartExplorer(); this.Visible = false; };
             ShowHandler += () => this.Visible = true;
+            HideHandler += () => this.Visible = false;
+            BtnRestart.MouseDown += (sender, e) =>
+            {
+                ExternalProgram.RestartExplorer();
+                this.Visible = false;
+            };
         }
 
-        protected override void OnVisibleChanged(EventArgs e)
+        public new bool Visible
         {
-            base.OnVisibleChanged(e);
-            if(this.Parent != null) this.Parent.Height += Visible ? Height : -Height;
+            get => base.Visible;
+            set
+            {
+                bool flag = base.Visible != value && this.Parent != null;
+                base.Visible = value;
+                if(flag) this.Parent.Height += value ? Height : -Height;
+            }
         }
 
         private readonly PictureButton BtnRestart = new PictureButton(AppImage.RestartExplorer);
 
-        private static Action ShowHandler { get; set; }
+        private static Action ShowHandler;
+        private static Action HideHandler;
 
-        public static new void Show() { ShowHandler?.Invoke(); }
+        public static new void Show() => ShowHandler?.Invoke();
+        public static new void Hide() => HideHandler?.Invoke();
     }
 }

+ 2 - 1
ContextMenuManager/Controls/FileExtensionDialog.cs

@@ -1,5 +1,6 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.Collections.Generic;
 
@@ -18,7 +19,7 @@ namespace ContextMenuManager.Controls
             this.CanEdit = true;
             this.Title = AppString.Dialog.SelectExtension;
             List<string> items = new List<string>();
-            using(var key = RegistryEx.GetRegistryKey(FileExtension.FileExtsPath))
+            using(var key = RegistryEx.GetRegistryKey(FileExtension.FILEEXTSPATH))
             {
                 if(key != null)
                 {

+ 135 - 0
ContextMenuManager/Controls/FoldSubItem.cs

@@ -0,0 +1,135 @@
+using BluePointLilac.Controls;
+using BluePointLilac.Methods;
+using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
+using System;
+using System.Drawing;
+using System.IO;
+using System.Windows.Forms;
+using static ContextMenuManager.Methods.ObjectPath;
+
+namespace ContextMenuManager.Controls
+{
+    class FoldSubItem : MyListItem
+    {
+        public FoldGroupItem FoldGroupItem { get; set; }
+
+        public void Indent()
+        {
+            int w = 40.DpiZoom();
+            this.Controls["Image"].Left += w;
+            this.Controls["Text"].Left += w;
+        }
+    }
+
+    class FoldGroupItem : MyListItem, IBtnShowMenuItem
+    {
+        private bool isFold;
+        public bool IsFold
+        {
+            get => isFold;
+            set
+            {
+                if(isFold == value) return;
+                isFold = value;
+                FoldMe(value);
+            }
+        }
+
+        public string GroupPath { get; set; }
+        public PathType PathType { get; set; }
+
+        public MenuButton BtnShowMenu { get; set; }
+        readonly PictureButton btnFold;
+        readonly PictureButton btnOpenPath;
+        readonly ToolStripMenuItem tsiFoldAll = new ToolStripMenuItem(AppString.Menu.FoldAll);
+        readonly ToolStripMenuItem tsiUnfoldAll = new ToolStripMenuItem(AppString.Menu.UnfoldAll);
+
+        public FoldGroupItem(string groupPath, PathType pathType)
+        {
+            btnFold = new PictureButton(AppImage.Up);
+            BtnShowMenu = new MenuButton(this);
+            btnOpenPath = new PictureButton(AppImage.Open);
+
+            if(pathType == PathType.File || pathType == PathType.Directory)
+            {
+                groupPath = Environment.ExpandEnvironmentVariables(groupPath);
+            }
+            string tip = null;
+            Action openPath = null;
+            switch(pathType)
+            {
+                case PathType.File:
+                    tip = AppString.Menu.FileLocation;
+                    this.Text = Path.GetFileNameWithoutExtension(groupPath);
+                    this.Image = ResourceIcon.GetExtensionIcon(groupPath).ToBitmap();
+                    openPath = () => ExternalProgram.JumpExplorer(groupPath, AppConfig.OpenMoreExplorer);
+                    break;
+                case PathType.Directory:
+                    tip = AppString.Menu.FileLocation;
+                    this.Text = Path.GetFileNameWithoutExtension(groupPath);
+                    this.Image = ResourceIcon.GetFolderIcon(groupPath).ToBitmap();
+                    openPath = () => ExternalProgram.OpenDirectory(groupPath);
+                    break;
+                case PathType.Registry:
+                    tip = AppString.Menu.RegistryLocation;
+                    openPath = () => ExternalProgram.JumpRegEdit(groupPath, null, AppConfig.OpenMoreRegedit);
+                    break;
+            }
+            this.PathType = pathType;
+            this.GroupPath = groupPath;
+            this.Font = new Font(this.Font, FontStyle.Bold);
+            this.AddCtrs(new[] { btnFold, btnOpenPath });
+            this.ContextMenuStrip.Items.AddRange(new[] { tsiFoldAll, tsiUnfoldAll });
+            this.MouseDown += (sender, e) => Fold();
+            btnFold.MouseDown += (sender, e) =>
+            {
+                Fold();
+                btnFold.Image = btnFold.BaseImage;
+            };
+            tsiFoldAll.Click += (sender, e) => FoldAll(true);
+            tsiUnfoldAll.Click += (sender, e) => FoldAll(false);
+            btnOpenPath.MouseDown += (sender, e) => openPath.Invoke();
+            ToolTipBox.SetToolTip(btnOpenPath, tip);
+        }
+
+        public void SetVisibleWithSubItemCount()
+        {
+            foreach(Control ctr in this.Parent.Controls)
+            {
+                if(ctr is FoldSubItem item && item.FoldGroupItem == this)
+                {
+                    this.Visible = true;
+                    return;
+                }
+            }
+            this.Visible = false;
+        }
+
+        private void Fold()
+        {
+            this.Parent.SuspendLayout();
+            this.IsFold = !this.IsFold;
+            this.Parent.ResumeLayout();
+        }
+
+        private void FoldMe(bool isFold)
+        {
+            btnFold.BaseImage = isFold ? AppImage.Down : AppImage.Up;
+            foreach(Control ctr in this.Parent?.Controls)
+            {
+                if(ctr is FoldSubItem item && item.FoldGroupItem == this) ctr.Visible = !isFold;
+            }
+        }
+
+        private void FoldAll(bool isFold)
+        {
+            this.Parent.SuspendLayout();
+            foreach(Control ctr in this.Parent.Controls)
+            {
+                if(ctr is FoldGroupItem groupItem) groupItem.IsFold = isFold;
+            }
+            this.Parent.ResumeLayout();
+        }
+    }
+}

+ 13 - 18
ContextMenuManager/Controls/GuidBlockedItem.cs

@@ -1,13 +1,14 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
 using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using System;
 using System.Linq;
 using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls
 {
-    class GuidBlockedItem : MyListItem, IBtnDeleteItem, ITsiWebSearchItem, ITsiFilePathItem, ITsiGuidItem, ITsiRegPathItem
+    class GuidBlockedItem : MyListItem, IBtnShowMenuItem, ITsiWebSearchItem, ITsiFilePathItem, ITsiGuidItem, ITsiRegPathItem
     {
         public GuidBlockedItem(string value)
         {
@@ -52,22 +53,16 @@ namespace ContextMenuManager.Controls
             get
             {
                 string text;
-                if(GuidEx.TryParse(Value, out Guid guid))
-                {
-                    text = GuidInfo.GetText(guid);
-                }
-                else
-                {
-                    text = AppString.Message.MalformedGuid;
-                }
+                if(GuidEx.TryParse(Value, out Guid guid)) text = GuidInfo.GetText(guid);
+                else text = AppString.Message.MalformedGuid;
                 text += "\n" + Value;
                 return text;
             }
         }
 
         public string ItemFilePath { get; set; }
-        public DeleteButton BtnDelete { get; set; }
-        public ObjectPathButton BtnOpenPath { get; set; }
+        public MenuButton BtnShowMenu { get; set; }
+        public DetailedEditButton BtnDetailedEdit { get; set; }
         public WebSearchMenuItem TsiSearch { get; set; }
         public FileLocationMenuItem TsiFileLocation { get; set; }
         public FilePropertiesMenuItem TsiFileProperties { get; set; }
@@ -79,8 +74,8 @@ namespace ContextMenuManager.Controls
 
         private void InitializeComponents()
         {
-            BtnDelete = new DeleteButton(this);
-            ContextMenuStrip = new ContextMenuStrip();
+            BtnShowMenu = new MenuButton(this);
+            BtnDetailedEdit = new DetailedEditButton(this);
             TsiSearch = new WebSearchMenuItem(this);
             TsiFileProperties = new FilePropertiesMenuItem(this);
             TsiFileLocation = new FileLocationMenuItem(this);
@@ -92,17 +87,17 @@ namespace ContextMenuManager.Controls
             TsiDetails.DropDownItems.AddRange(new ToolStripItem[] { TsiSearch,
                 new ToolStripSeparator(), TsiFileProperties, TsiFileLocation, TsiRegLocation});
 
-            ToolTipBox.SetToolTip(BtnDelete, AppString.Menu.Delete);
-            TsiDelete.Click += (sender, e) =>
-            {
-                if(MessageBoxEx.Show(AppString.Message.ConfirmDelete, MessageBoxButtons.YesNo) == DialogResult.Yes) DeleteMe();
-            };
+            TsiDelete.Click += (sender, e) => DeleteMe();
         }
 
         public void DeleteMe()
         {
+            if(AppMessageBox.Show(AppString.Message.ConfirmDelete, MessageBoxButtons.YesNo) != DialogResult.Yes) return;
             Array.ForEach(GuidBlockedList.BlockedPaths, path => RegistryEx.DeleteValue(path, this.Value));
             if(!this.Guid.Equals(Guid.Empty)) ExplorerRestarter.Show();
+            int index = this.Parent.Controls.GetChildIndex(this);
+            index -= (index < this.Parent.Controls.Count - 1) ? 0 : 1;
+            this.Parent.Controls[index].Focus();
             this.Dispose();
         }
     }

+ 3 - 2
ContextMenuManager/Controls/GuidBlockedList.cs

@@ -1,5 +1,6 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using Microsoft.Win32;
 using System;
 using System.Collections.Generic;
@@ -56,14 +57,14 @@ namespace ContextMenuManager.Controls
                         {
                             if(((GuidBlockedItem)Controls[i]).Guid.Equals(guid))
                             {
-                                MessageBoxEx.Show(AppString.Message.HasBeenAdded);
+                                AppMessageBox.Show(AppString.Message.HasBeenAdded);
                                 return;
                             }
                         }
                         this.InsertItem(new GuidBlockedItem(value), 1);
                         ExplorerRestarter.Show();
                     }
-                    else MessageBoxEx.Show(AppString.Message.MalformedGuid);
+                    else AppMessageBox.Show(AppString.Message.MalformedGuid);
                 }
             };
         }

+ 2 - 2
ContextMenuManager/Controls/IEItem.cs

@@ -1,6 +1,7 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
 using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using Microsoft.Win32;
 using System;
 using System.Drawing;
@@ -44,7 +45,7 @@ namespace ContextMenuManager.Controls
                 string defaultValue = Registry.GetValue(newPath, "", null)?.ToString();
                 if(!defaultValue.IsNullOrWhiteSpace())
                 {
-                    MessageBoxEx.Show(AppString.Message.HasBeenAdded);
+                    AppMessageBox.Show(AppString.Message.HasBeenAdded);
                 }
                 else
                 {
@@ -115,7 +116,6 @@ namespace ContextMenuManager.Controls
         {
             RegistryEx.DeleteKeyTree(this.RegPath);
             RegistryEx.DeleteKeyTree(this.BackupPath);
-            this.Dispose();
         }
     }
 }

+ 2 - 10
ContextMenuManager/Controls/Interfaces/IBtnDeleteItem.cs

@@ -1,5 +1,5 @@
 using BluePointLilac.Controls;
-using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls.Interfaces
@@ -18,15 +18,7 @@ namespace ContextMenuManager.Controls.Interfaces
             listItem.AddCtr(this);
             this.MouseDown += (sender, e) =>
             {
-                if(MessageBoxEx.Show(AppString.Message.ConfirmDelete,
-                MessageBoxButtons.YesNo) == DialogResult.Yes)
-                {
-                    MyList list = (MyList)listItem.Parent;
-                    int index = list.GetItemIndex(listItem);
-                    index -= (index < list.Controls.Count - 1) ? 0 : 1;
-                    item.DeleteMe();
-                    list.HoveredItem = (MyListItem)list.Controls[index];
-                }
+                if(AppMessageBox.Show(AppString.Message.ConfirmDelete, MessageBoxButtons.YesNo) == DialogResult.Yes) item.DeleteMe();
             };
         }
     }

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

@@ -1,4 +1,5 @@
 using BluePointLilac.Controls;
+using ContextMenuManager.Methods;
 
 namespace ContextMenuManager.Controls.Interfaces
 {

+ 0 - 34
ContextMenuManager/Controls/Interfaces/IBtnOpenPathItem.cs

@@ -1,34 +0,0 @@
-using BluePointLilac.Controls;
-using BluePointLilac.Methods;
-using static BluePointLilac.Methods.ObjectPath;
-
-namespace ContextMenuManager.Controls.Interfaces
-{
-    interface IBtnOpenPathItem
-    {
-        string TargetPath { get; set; }
-        PathType PathType { get; set; }
-        ObjectPathButton BtnOpenPath { get; set; }
-    }
-
-    sealed class ObjectPathButton : PictureButton
-    {
-        public ObjectPathButton(IBtnOpenPathItem item) : base(AppImage.Open)
-        {
-            ((MyListItem)item).AddCtr(this);
-            this.MouseDown += (sender, e) =>
-            {
-                switch(item.PathType)
-                {
-                    case PathType.File:
-                    case PathType.Directory:
-                        ExternalProgram.JumpExplorer(item.TargetPath, AppConfig.OpenMoreExplorer);
-                        break;
-                    case PathType.Registry:
-                        ExternalProgram.JumpRegEdit(item.TargetPath, null, AppConfig.OpenMoreRegedit);
-                        break;
-                }
-            };
-        }
-    }
-}

+ 8 - 1
ContextMenuManager/Controls/Interfaces/IBtnShowMenuItem.cs

@@ -1,4 +1,5 @@
 using BluePointLilac.Controls;
+using ContextMenuManager.Methods;
 using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls.Interfaces
@@ -15,7 +16,13 @@ namespace ContextMenuManager.Controls.Interfaces
         {
             item.ContextMenuStrip = new ContextMenuStrip();
             ((MyListItem)item).AddCtr(this);
-            this.MouseDown += (sender, e) => item.ContextMenuStrip.Show(this, 0, Height);
+            bool isShow = false;
+            this.MouseDown += (sender, e) =>
+            {
+                if(!isShow) item.ContextMenuStrip.Show(this, 0, Height);
+                else item.ContextMenuStrip.Close();
+                isShow = !isShow;
+            };
         }
     }
 }

+ 4 - 3
ContextMenuManager/Controls/Interfaces/IChkVisibleItem.cs

@@ -1,4 +1,5 @@
 using BluePointLilac.Controls;
+using ContextMenuManager.Methods;
 
 namespace ContextMenuManager.Controls.Interfaces
 {
@@ -15,14 +16,14 @@ namespace ContextMenuManager.Controls.Interfaces
             MyListItem listItem = (MyListItem)item;
             listItem.AddCtr(this);
             this.CheckChanged += () => item.ItemVisible = this.Checked;
-            listItem.HandleCreated += (sender, e) => this.Checked = item.ItemVisible;
             listItem.ParentChanged += (sender, e) =>
             {
                 if(listItem.IsDisposed) return;
                 if(listItem.Parent == null) return;
-                if(listItem is IFoldSubItem subItem && subItem.FoldGroupItem != null) return;
+                this.Checked = item.ItemVisible;
+                if(listItem is FoldSubItem subItem && subItem.FoldGroupItem != null) return;
                 if(listItem.FindForm() is ShellStoreDialog.ShellStoreForm) return;
-                if(AppConfig.HideDisabledItems) listItem.Visible = item.ItemVisible;
+                if(AppConfig.HideDisabledItems) listItem.Visible = this.Checked;
             };
         }
     }

+ 0 - 130
ContextMenuManager/Controls/Interfaces/IFoldGroupItem.cs

@@ -1,130 +0,0 @@
-using BluePointLilac.Controls;
-using BluePointLilac.Methods;
-using System;
-using System.Drawing;
-using System.IO;
-using System.Windows.Forms;
-using static BluePointLilac.Methods.ObjectPath;
-
-namespace ContextMenuManager.Controls.Interfaces
-{
-    interface IFoldGroupItem
-    {
-        FoldButton BtnFold { get; set; }
-        bool IsFold { get; set; }
-        string Text { get; set; }
-    }
-
-    interface IFoldSubItem
-    {
-        IFoldGroupItem FoldGroupItem { get; set; }
-    }
-
-    sealed class FoldButton : PictureButton
-    {
-        private bool isFold;
-        public bool IsFold
-        {
-            get => isFold;
-            set
-            {
-                isFold = value;
-                this.BaseImage = ReplaceImage(value);
-                Control list = ((MyListItem)FoldGroup).Parent;
-                if(list == null) return;
-                list.SuspendLayout();
-                foreach(Control ctr in list.Controls)
-                {
-                    if(ctr is IFoldSubItem item1 && item1.FoldGroupItem == FoldGroup) ctr.Visible = !value;
-                    else if(ctr is SubGroupItem item2 && item2.FoldGroupItem == FoldGroup) { item2.IsFold = true; item2.Visible = !value; }
-                }
-                list.ResumeLayout();
-            }
-        }
-
-        private IFoldGroupItem FoldGroup { get; set; }
-
-        static Image ReplaceImage(bool fold) => fold ? AppImage.Up : AppImage.Down;
-
-        public FoldButton(IFoldGroupItem owner, bool fold = false) : base(ReplaceImage(fold))
-        {
-            this.FoldGroup = owner;
-            ((MyListItem)owner).AddCtr(this);
-            this.MouseDown += (sender, e) =>
-            {
-                this.IsFold = !this.IsFold;
-                this.Image = this.BaseImage;
-            };
-        }
-    }
-
-    class GroupPathItem : MyListItem, IFoldGroupItem, IBtnOpenPathItem
-    {
-        public bool IsFold
-        {
-            get => BtnFold.IsFold;
-            set
-            {
-                if(BtnFold.IsFold == value) return;
-                BtnFold.IsFold = value;
-                //IsFoldChanegd?.Invoke();
-            }
-        }
-
-        //public Action IsFoldChanegd;
-        public string TargetPath { get; set; }
-        public PathType PathType { get; set; }
-        public ObjectPathButton BtnOpenPath { get; set; }
-        public FoldButton BtnFold { get; set; }
-        public GroupPathItem(string targetPath, PathType pathType)
-        {
-            BtnFold = new FoldButton(this);
-            BtnOpenPath = new ObjectPathButton(this);
-            this.Font = new Font(base.Font, FontStyle.Bold);
-            if(pathType == PathType.File || pathType == PathType.Directory)
-            {
-                targetPath = Environment.ExpandEnvironmentVariables(targetPath);
-            }
-            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;
-            }
-            ToolTipBox.SetToolTip(BtnOpenPath, tip);
-            this.ImageDoubleClick += () => this.OnDoubleClick(null);
-            this.TextDoubleClick += () => this.OnDoubleClick(null);
-            this.DoubleClick += (sender, e) => this.IsFold = !this.IsFold;
-        }
-
-        public void HideWhenNoSubItem()
-        {
-            int count = 0;
-            foreach(Control ctr in this.Parent.Controls)
-            {
-                if(ctr is IFoldSubItem item1 && item1.FoldGroupItem == this) count++;
-                else if(ctr is SubGroupItem item2 && item2.FoldGroupItem == this) count++;
-            }
-            if(count == 0) this.Visible = false;
-        }
-    }
-
-    class SubGroupItem : GroupPathItem
-    {
-        public SubGroupItem(string targetPath, PathType pathType) : base(targetPath, pathType) { }
-        public GroupPathItem FoldGroupItem { get; set; }
-    }
-}

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

@@ -1,4 +1,5 @@
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System.IO;
 using System.Windows.Forms;
 

+ 3 - 2
ContextMenuManager/Controls/Interfaces/ITsiCommandItem.cs

@@ -1,5 +1,6 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System.Drawing;
 using System.Windows.Forms;
 
@@ -30,11 +31,11 @@ namespace ContextMenuManager.Controls.Interfaces
             {
                 dlg.Text = command;
                 dlg.Title = AppString.Menu.ChangeCommand;
-                dlg.Size = new Size(500, 270).DpiZoom();
+                dlg.Size = new Size(530, 260).DpiZoom();
                 if(dlg.ShowDialog() != DialogResult.OK) return null;
                 if(!CommandCanBeEmpty && string.IsNullOrEmpty(dlg.Text))
                 {
-                    MessageBoxEx.Show(AppString.Message.CommandCannotBeEmpty);
+                    AppMessageBox.Show(AppString.Message.CommandCannotBeEmpty);
                     return ChangeCommand(command);
                 }
                 else return dlg.Text;

+ 16 - 5
ContextMenuManager/Controls/Interfaces/ITsiDeleteItem.cs

@@ -1,5 +1,6 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.IO;
 using System.Windows.Forms;
@@ -26,7 +27,7 @@ namespace ContextMenuManager.Controls.Interfaces
             {
                 if(item is ITsiRegDeleteItem regItem && AppConfig.AutoBackup)
                 {
-                    if(MessageBoxEx.Show(AppString.Message.DeleteButCanRestore,
+                    if(AppMessageBox.Show(AppString.Message.DeleteButCanRestore,
                      MessageBoxButtons.YesNo) != DialogResult.Yes) return;
                     string date = DateTime.Today.ToString("yyyy-MM-dd");
                     string time = DateTime.Now.ToString("HH.mm.ss");
@@ -34,15 +35,25 @@ namespace ContextMenuManager.Controls.Interfaces
                     Directory.CreateDirectory(Path.GetDirectoryName(filePath));
                     ExternalProgram.ExportRegistry(regItem.RegPath, filePath);
                 }
-                else if(MessageBoxEx.Show(AppString.Message.ConfirmDeletePermanently,
+                else if(AppMessageBox.Show(AppString.Message.ConfirmDeletePermanently,
                      MessageBoxButtons.YesNo) != DialogResult.Yes) return;
 
                 MyListItem listItem = (MyListItem)item;
                 MyList list = (MyList)listItem.Parent;
                 int index = list.GetItemIndex(listItem);
-                index -= (index < list.Controls.Count - 1) ? 0 : 1;
-                item.DeleteMe();
-                list.HoveredItem = (MyListItem)list.Controls[index];
+                if(index == list.Controls.Count - 1) index--;
+                try
+                {
+                    item.DeleteMe();
+                }
+                catch
+                {
+                    AppMessageBox.Show(AppString.Message.AuthorityProtection);
+                    return;
+                }
+                list.Controls.Remove(listItem);
+                list.Controls[index].Focus();
+                listItem.Dispose();
             };
         }
     }

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

@@ -1,4 +1,5 @@
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System.IO;
 using System.Windows.Forms;
 

+ 88 - 77
ContextMenuManager/Controls/Interfaces/ITsiGuidItem.cs

@@ -1,5 +1,6 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.Drawing;
 using System.Windows.Forms;
@@ -11,6 +12,7 @@ namespace ContextMenuManager.Controls.Interfaces
         Guid Guid { get; }
         string ItemText { get; }
         HandleGuidMenuItem TsiHandleGuid { get; set; }
+        DetailedEditButton BtnDetailedEdit { get; set; }
     }
 
     sealed class HandleGuidMenuItem : ToolStripMenuItem
@@ -18,32 +20,13 @@ namespace ContextMenuManager.Controls.Interfaces
         public HandleGuidMenuItem(ITsiGuidItem item) : base(AppString.Menu.HandleGuid)
         {
             this.Item = item;
-            this.DropDownItems.AddRange(new ToolStripItem[] {
-                TsiAddGuidDic, new ToolStripSeparator(), TsiCopyGuid });
-            if(item is ShellExItem shellExItem)
-            {
-                this.DropDownItems.AddRange(new ToolStripItem[] { TsiBlockGuid, TsiClsidLocation });
-                shellExItem.ContextMenuStrip.Opening += (sender, e) => TsiClsidLocation.Visible = shellExItem.ClsidPath != null;
-                TsiClsidLocation.Click += (sender, e) => ExternalProgram.JumpRegEdit(shellExItem.ClsidPath);
-            }
+            this.DropDownItems.AddRange(new ToolStripItem[] { TsiAddGuidDic,
+                new ToolStripSeparator(), TsiCopyGuid, TsiBlockGuid, TsiClsidLocation });
             TsiCopyGuid.Click += (sender, e) => CopyGuid();
             TsiBlockGuid.Click += (sender, e) => BlockGuid();
             TsiAddGuidDic.Click += (sender, e) => AddGuidDic();
-            MyListItem listItem = (MyListItem)item;
-            listItem.ImageDoubleClick += () => AddGuidDic();
-            listItem.TextDoubleClick += () => AddGuidDic();
-            listItem.ContextMenuStrip.Opening += (sender, e) =>
-            {
-                TsiBlockGuid.Checked = false;
-                foreach(string path in GuidBlockedList.BlockedPaths)
-                {
-                    if(Microsoft.Win32.Registry.GetValue(path, Item.Guid.ToString("B"), null) != null)
-                    {
-                        TsiBlockGuid.Checked = true;
-                        break;
-                    }
-                }
-            };
+            TsiClsidLocation.Click += (sender, e) => OpenClsidPath();
+            ((MyListItem)item).ContextMenuStrip.Opening += (sender, e) => RefreshMenuItem();
         }
 
         readonly ToolStripMenuItem TsiCopyGuid = new ToolStripMenuItem(AppString.Menu.CopyGuid);
@@ -55,8 +38,9 @@ namespace ContextMenuManager.Controls.Interfaces
 
         private void CopyGuid()
         {
-            Clipboard.SetText(Item.Guid.ToString());
-            MessageBoxEx.Show($"{AppString.Message.CopiedToClipboard}\n{Item.Guid}",
+            string guid = Item.Guid.ToString("B");
+            Clipboard.SetText(guid);
+            AppMessageBox.Show($"{AppString.Message.CopiedToClipboard}\n{guid}",
                 MessageBoxButtons.OK, MessageBoxIcon.Information);
         }
 
@@ -72,7 +56,7 @@ namespace ContextMenuManager.Controls.Interfaces
                 {
                     if(Item.Guid.Equals(ShellExItem.LnkOpenGuid) && AppConfig.ProtectOpenItem)
                     {
-                        if(MessageBoxEx.Show(AppString.Message.PromptIsOpenItem,
+                        if(AppMessageBox.Show(AppString.Message.PromptIsOpenItem,
                             MessageBoxButtons.YesNo) != DialogResult.Yes) return;
                     }
                     Microsoft.Win32.Registry.SetValue(path, Item.Guid.ToString("B"), string.Empty);
@@ -96,59 +80,58 @@ namespace ContextMenuManager.Controls.Interfaces
                     DeleteFileWhenEmpty = true
                 };
                 string section = Item.Guid.ToString();
+                MyListItem listItem = (MyListItem)Item;
                 if(dlg.ShowDialog() != DialogResult.OK)
                 {
                     if(dlg.IsDelete)
                     {
                         writer.DeleteSection(section);
-                        GuidInfo.ItemTextDic.Remove(Item.Guid);
-                        GuidInfo.ItemImageDic.Remove(Item.Guid);
-                        GuidInfo.IconLocationDic.Remove(Item.Guid);
-                        GuidInfo.UserDic.RootDic.Remove(section);
-                        ((MyListItem)Item).Text = Item.ItemText;
-                        ((MyListItem)Item).Image = GuidInfo.GetImage(Item.Guid);
+                        GuidInfo.RemoveDic(Item.Guid);
+                        listItem.Text = Item.ItemText;
+                        listItem.Image = GuidInfo.GetImage(Item.Guid);
                     }
                     return;
                 }
-                string name = ResourceString.GetDirectString(dlg.ItemText);
-                if(!name.IsNullOrWhiteSpace())
+                if(dlg.ItemText.IsNullOrWhiteSpace())
                 {
-                    writer.SetValue(section, "Text", dlg.ItemText);
-                    ((MyListItem)Item).Text = name;
-                    if(GuidInfo.ItemTextDic.ContainsKey(Item.Guid))
-                    {
-                        GuidInfo.ItemTextDic[Item.Guid] = name;
-                    }
-                    else
-                    {
-                        GuidInfo.ItemTextDic.Add(Item.Guid, name);
-                    }
+                    AppMessageBox.Show(AppString.Message.TextCannotBeEmpty);
+                    return;
                 }
-                else
+                dlg.ItemText = ResourceString.GetDirectString(dlg.ItemText);
+                if(dlg.ItemText.IsNullOrWhiteSpace())
                 {
-                    MessageBoxEx.Show(AppString.Message.StringParsingFailed);
+                    AppMessageBox.Show(AppString.Message.StringParsingFailed);
                     return;
                 }
-                if(dlg.ItemIconLocation != null)
+                else
                 {
+                    GuidInfo.RemoveDic(Item.Guid);
+                    writer.SetValue(section, "Text", dlg.ItemText);
                     writer.SetValue(section, "Icon", dlg.ItemIconLocation);
-                    location = new GuidInfo.IconLocation { IconPath = dlg.ItemIconPath, IconIndex = dlg.ItemIconIndex };
-                    if(GuidInfo.IconLocationDic.ContainsKey(Item.Guid))
-                    {
-                        GuidInfo.IconLocationDic[Item.Guid] = location;
-                    }
-                    else
-                    {
-                        GuidInfo.IconLocationDic.Add(Item.Guid, location);
-                    }
-                     ((MyListItem)Item).Image = dlg.ItemIcon;
-                    if(GuidInfo.ItemImageDic.ContainsKey(Item.Guid))
-                    {
-                        GuidInfo.ItemImageDic[Item.Guid] = dlg.ItemIcon;
-                    }
-                    else
+                    listItem.Text = dlg.ItemText;
+                    listItem.Image = dlg.ItemIcon;
+                }
+            }
+        }
+
+        private void OpenClsidPath()
+        {
+            string clsidPath = GuidInfo.GetClsidPath(Item.Guid);
+            ExternalProgram.JumpRegEdit(clsidPath, null, AppConfig.OpenMoreRegedit);
+        }
+
+        private void RefreshMenuItem()
+        {
+            TsiClsidLocation.Visible = GuidInfo.GetClsidPath(Item.Guid) != null;
+            TsiBlockGuid.Visible = TsiBlockGuid.Checked = false;
+            if(Item is ShellExItem)
+            {
+                TsiBlockGuid.Visible = true;
+                foreach(string path in GuidBlockedList.BlockedPaths)
+                {
+                    if(Microsoft.Win32.Registry.GetValue(path, Item.Guid.ToString("B"), null) != null)
                     {
-                        GuidInfo.ItemImageDic.Add(Item.Guid, dlg.ItemIcon);
+                        TsiBlockGuid.Checked = true; break;
                     }
                 }
             }
@@ -180,6 +163,7 @@ namespace ContextMenuManager.Controls.Interfaces
                     frm.ItemIcon = this.ItemIcon;
                     frm.ItemIconPath = this.ItemIconPath;
                     frm.ItemIconIndex = this.ItemIconIndex;
+                    frm.TopMost = AppConfig.TopMost;
                     bool flag = frm.ShowDialog() == DialogResult.OK;
                     if(flag)
                     {
@@ -197,7 +181,7 @@ namespace ContextMenuManager.Controls.Interfaces
             {
                 public AddGuidDicForm()
                 {
-                    this.AcceptButton = btnOk;
+                    this.AcceptButton = btnOK;
                     this.CancelButton = btnCancel;
                     this.Font = SystemFonts.MenuFont;
                     this.Text = AppString.Dialog.AddGuidDic;
@@ -242,15 +226,15 @@ namespace ContextMenuManager.Controls.Interfaces
                     Text = AppString.Dialog.Browse,
                     AutoSize = true
                 };
-                readonly Button btnOk = new Button
+                readonly Button btnOK = new Button
                 {
-                    Text = AppString.Dialog.Ok,
+                    Text = ResourceString.OK,
                     DialogResult = DialogResult.OK,
                     AutoSize = true
                 };
                 readonly Button btnCancel = new Button
                 {
-                    Text = AppString.Dialog.Cancel,
+                    Text = ResourceString.Cancel,
                     DialogResult = DialogResult.Cancel,
                     AutoSize = true
                 };
@@ -263,19 +247,19 @@ namespace ContextMenuManager.Controls.Interfaces
 
                 private void InitializeComponents()
                 {
-                    this.Controls.AddRange(new Control[] { lblName, txtName, lblIcon, picIcon, btnBrowse, btnDelete, btnOk, btnCancel });
+                    this.Controls.AddRange(new Control[] { lblName, txtName, lblIcon, picIcon, btnBrowse, btnDelete, btnOK, btnCancel });
                     int a = 20.DpiZoom();
                     lblName.Left = lblName.Top = lblIcon.Left = btnDelete.Left = txtName.Top = a;
                     txtName.Left = lblName.Right + a;
-                    btnOk.Left = btnDelete.Right + a;
-                    btnCancel.Left = btnOk.Right + a;
+                    btnOK.Left = btnDelete.Right + a;
+                    btnCancel.Left = btnOK.Right + a;
                     txtName.Width = btnCancel.Right - txtName.Left;
                     btnBrowse.Left = btnCancel.Right - btnBrowse.Width;
-                    picIcon.Left = btnOk.Left + (btnOk.Width - picIcon.Width) / 2;
+                    picIcon.Left = btnOK.Left + (btnOK.Width - picIcon.Width) / 2;
                     btnBrowse.Top = txtName.Bottom + a;
                     picIcon.Top = btnBrowse.Top + (btnBrowse.Height - picIcon.Height) / 2;
                     lblIcon.Top = btnBrowse.Top + (btnBrowse.Height - lblIcon.Height) / 2;
-                    btnDelete.Top = btnOk.Top = btnCancel.Top = btnBrowse.Bottom + a;
+                    btnDelete.Top = btnOK.Top = btnCancel.Top = btnBrowse.Bottom + a;
                     this.ClientSize = new Size(btnCancel.Right + a, btnCancel.Bottom + a);
                     ToolTipBox.SetToolTip(btnDelete, AppString.Tip.DeleteGuidDic);
                     btnBrowse.Click += (sender, e) => SelectIcon();
@@ -289,14 +273,41 @@ namespace ContextMenuManager.Controls.Interfaces
                         dlg.IconPath = this.ItemIconPath;
                         dlg.IconIndex = this.ItemIconIndex;
                         if(dlg.ShowDialog() != DialogResult.OK) return;
-                        Image image = ResourceIcon.GetIcon(dlg.IconPath, dlg.IconIndex)?.ToBitmap();
-                        if(image == null) return;
-                        picIcon.Image = image;
-                        ItemIconPath = dlg.IconPath;
-                        ItemIconIndex = dlg.IconIndex;
+                        using(Icon icon = ResourceIcon.GetIcon(dlg.IconPath, dlg.IconIndex))
+                        {
+                            Image image = icon?.ToBitmap();
+                            if(image == null) return;
+                            picIcon.Image = image;
+                            this.ItemIconPath = dlg.IconPath;
+                            this.ItemIconIndex = dlg.IconIndex;
+                        }
                     }
                 }
             }
         }
     }
+
+    sealed class DetailedEditButton : PictureButton
+    {
+        public DetailedEditButton(ITsiGuidItem item) : base(AppImage.SubItems)
+        {
+            MyListItem listItem = (MyListItem)item;
+            listItem.AddCtr(this);
+            ToolTipBox.SetToolTip(this, AppString.SideBar.DetailedEdit);
+            listItem.ParentChanged += (sender, e) =>
+            {
+                if(listItem.IsDisposed) return;
+                if(listItem.Parent == null) return;
+                this.Visible = XmlDicHelper.DetailedEditGuidDic.ContainsKey(item.Guid);
+            };
+            this.MouseDown += (sender, e) =>
+            {
+                using(DetailedEditDialog dlg = new DetailedEditDialog())
+                {
+                    dlg.GroupGuid = item.Guid;
+                    dlg.ShowDialog();
+                }
+            };
+        }
+    }
 }

+ 1 - 7
ContextMenuManager/Controls/Interfaces/ITsiIconItem.cs

@@ -1,5 +1,6 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System.Drawing;
 using System.Windows.Forms;
 
@@ -37,13 +38,6 @@ namespace ContextMenuManager.Controls.Interfaces
                     }
                 }
             };
-            MyListItem listItem = (MyListItem)item;
-            listItem.Disposed += (sender, e) => item.ItemIcon?.Dispose();
-            listItem.ImageDoubleClick += () =>
-            {
-                if(listItem.FindForm() is ShellStoreDialog.ShellStoreForm) return;
-                if(this.Enabled) this.OnClick(null);
-            };
         }
     }
 }

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

@@ -1,4 +1,5 @@
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.IO;
 using System.Windows.Forms;

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

@@ -1,4 +1,5 @@
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls.Interfaces

+ 11 - 13
ContextMenuManager/Controls/Interfaces/ITsiShortcutCommandItem.cs

@@ -1,5 +1,6 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.Drawing;
 using System.Windows.Forms;
@@ -42,19 +43,16 @@ namespace ContextMenuManager.Controls.Interfaces
             public string Command { get; set; }
             public string Arguments { get; set; }
 
-            private static Size LastSize = new Size();
-
             public override void Reset() { }
 
             protected override bool RunDialog(IntPtr hwndOwner)
             {
                 using(CommandForm frm = new CommandForm())
                 {
-                    frm.Size = LastSize;
                     frm.Command = this.Command;
                     frm.Arguments = this.Arguments;
+                    frm.TopMost = AppConfig.TopMost;
                     bool flag = frm.ShowDialog() == DialogResult.OK;
-                    LastSize = frm.Size;
                     if(flag)
                     {
                         this.Command = frm.Command;
@@ -68,7 +66,7 @@ namespace ContextMenuManager.Controls.Interfaces
             {
                 public CommandForm()
                 {
-                    this.AcceptButton = btnOk;
+                    this.AcceptButton = btnOK;
                     this.CancelButton = btnCancel;
                     this.VerticalResizable = false;
                     this.Font = SystemFonts.MessageBoxFont;
@@ -103,31 +101,31 @@ namespace ContextMenuManager.Controls.Interfaces
                 };
                 readonly TextBox txtCommand = new TextBox();
                 readonly TextBox txtArguments = new TextBox();
-                readonly Button btnOk = new Button
+                readonly Button btnOK = new Button
                 {
                     DialogResult = DialogResult.OK,
-                    Text = AppString.Dialog.Ok,
+                    Text = ResourceString.OK,
                     AutoSize = true
                 };
                 readonly Button btnCancel = new Button
                 {
                     DialogResult = DialogResult.Cancel,
-                    Text = AppString.Dialog.Cancel,
+                    Text = ResourceString.Cancel,
                     AutoSize = true
                 };
 
                 private void InitializeComponents()
                 {
-                    this.Controls.AddRange(new Control[] { lblCommand, lblArguments, txtCommand, txtArguments, btnOk, btnCancel });
+                    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;
+                    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;
+                    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;
+                    btnOK.Left = btnCancel.Left - btnOK.Width - a;
                     this.Resize += (sender, e) =>
                     {
                         txtArguments.Width = txtCommand.Width = this.ClientSize.Width - b;

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

@@ -1,5 +1,6 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls.Interfaces
@@ -20,13 +21,6 @@ namespace ContextMenuManager.Controls.Interfaces
                 string name = ChangeText(item.Text);
                 if(name != null) item.ItemText = name;
             };
-            MyListItem listItem = (MyListItem)item;
-            listItem.TextDoubleClick += () =>
-            {
-                if(listItem is IFoldGroupItem) return;
-                if(listItem.FindForm() is ShellStoreDialog.ShellStoreForm) return;
-                if(this.Enabled) this.OnClick(null);
-            };
         }
 
         private string ChangeText(string text)
@@ -36,12 +30,12 @@ namespace ContextMenuManager.Controls.Interfaces
                 if(dlg.ShowDialog() != DialogResult.OK) return null;
                 if(dlg.Text.Length == 0)
                 {
-                    MessageBoxEx.Show(AppString.Message.TextCannotBeEmpty);
+                    AppMessageBox.Show(AppString.Message.TextCannotBeEmpty);
                     return ChangeText(text);
                 }
                 else if(ResourceString.GetDirectString(dlg.Text).Length == 0)
                 {
-                    MessageBoxEx.Show(AppString.Message.StringParsingFailed);
+                    AppMessageBox.Show(AppString.Message.StringParsingFailed);
                     return ChangeText(text);
                 }
                 else return dlg.Text;

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

@@ -1,4 +1,5 @@
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls.Interfaces

+ 485 - 0
ContextMenuManager/Controls/LanguagesBox.cs

@@ -0,0 +1,485 @@
+using BluePointLilac.Controls;
+using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using System.Xml;
+
+namespace ContextMenuManager.Controls
+{
+    sealed class LanguagesBox : FlowLayoutPanel
+    {
+        public LanguagesBox()
+        {
+            this.SuspendLayout();
+            this.Dock = DockStyle.Fill;
+            this.Font = SystemFonts.MenuFont;
+            this.Font = new Font(this.Font.FontFamily, this.Font.Size + 1F);
+            this.Controls.AddRange(new Control[] { cmbLanguages, btnOpenDir, btnDownLoad, btnTranslate, lblThank, pnlTranslators });
+            this.VisibleChanged += (sender, e) => this.SetEnabled(this.Visible);
+            cmbLanguages.SelectionChangeCommitted += (sender, e) => ChangeLanguage();
+            btnOpenDir.MouseDown += (sender, e) => ExternalProgram.OpenDirectory(AppConfig.LangsDir);
+            lblThank.MouseEnter += (sender, e) => lblThank.ForeColor = Color.FromArgb(0, 162, 255);
+            lblThank.MouseLeave += (sender, e) => lblThank.ForeColor = Color.DimGray;
+            btnDownLoad.MouseDown += (sender, e) =>
+            {
+                this.Cursor = Cursors.WaitCursor;
+                this.ShowLanguageDialog();
+                this.Cursor = Cursors.Default;
+            };
+            btnTranslate.MouseDown += (sender, e) =>
+            {
+                using(TranslateDialog dlg = new TranslateDialog())
+                {
+                    dlg.ShowDialog();
+                }
+            };
+            ToolTipBox.SetToolTip(btnOpenDir, AppString.Menu.FileLocation);
+            ToolTipBox.SetToolTip(btnDownLoad, AppString.Dialog.DownloadLanguages);
+            ToolTipBox.SetToolTip(btnTranslate, AppString.Dialog.TranslateTool);
+            lblHeader.Font = new Font(this.Font, FontStyle.Bold);
+            cmbLanguages.AutosizeDropDownWidth();
+            this.OnResize(null);
+            this.ResumeLayout();
+        }
+
+        readonly ComboBox cmbLanguages = new ComboBox
+        {
+            DropDownStyle = ComboBoxStyle.DropDownList,
+            Width = 170.DpiZoom(),
+        };
+        readonly PictureButton btnOpenDir = new PictureButton(AppImage.Open);
+        readonly PictureButton btnDownLoad = new PictureButton(AppImage.DownLoad);
+        readonly PictureButton btnTranslate = new PictureButton(AppImage.Translate);
+        readonly ToolTip toolTip = new ToolTip { InitialDelay = 1 };
+        readonly Panel pnlTranslators = new Panel
+        {
+            BorderStyle = BorderStyle.FixedSingle,
+            AutoScroll = true
+        };
+        readonly Label lblHeader = new Label
+        {
+            Text = AppString.Other.Translators + "\r\n" + new string('-', 96),
+            ForeColor = Color.DarkCyan,
+            Dock = DockStyle.Top,
+            AutoSize = true
+        };
+        readonly Label lblThank = new Label
+        {
+            Font = new Font("Lucida Handwriting", 11F),
+            Text = "Thank you for your translation!",
+            ForeColor = Color.DimGray,
+            AutoSize = true,
+        };
+        readonly List<string> languages = new List<string>();
+
+        protected override void OnResize(EventArgs e)
+        {
+            base.OnResize(e);
+            int a = 20.DpiZoom();
+            pnlTranslators.Width = this.ClientSize.Width - 2 * a;
+            pnlTranslators.Height = this.ClientSize.Height - pnlTranslators.Top - a;
+            cmbLanguages.Margin = pnlTranslators.Margin = lblThank.Margin = btnOpenDir.Margin
+                = btnDownLoad.Margin = btnTranslate.Margin = new Padding(a, a, 0, 0);
+        }
+
+        public void LoadLanguages()
+        {
+            cmbLanguages.Items.Clear();
+            cmbLanguages.Items.Add("(default) 简体中文");
+            languages.Clear();
+            languages.Add("default");
+            pnlTranslators.SuspendLayout();
+            pnlTranslators.Controls.Remove(lblHeader);
+            foreach(Control ctr in pnlTranslators.Controls) ctr.Dispose();
+            pnlTranslators.Controls.Clear();
+            pnlTranslators.Controls.Add(lblHeader);
+            if(Directory.Exists(AppConfig.LangsDir))
+            {
+                Dictionary<Label, Control[]> dic = new Dictionary<Label, Control[]>();
+                foreach(string fileName in Directory.GetFiles(AppConfig.LangsDir, "*.ini"))
+                {
+                    IniWriter writer = new IniWriter(fileName);
+                    string language = writer.GetValue("General", "Language");
+                    string translator = writer.GetValue("General", "Translator");
+                    string translatorUrl = writer.GetValue("General", "TranslatorUrl");
+
+                    string langName = Path.GetFileNameWithoutExtension(fileName);
+                    if(string.IsNullOrEmpty(language)) language = langName;
+                    string[] translators = translator.Split(new[] { "\\r\\n", "\\n" }, StringSplitOptions.RemoveEmptyEntries);
+                    string[] urls = translatorUrl.Split(new[] { "\\r\\n", "\\n" }, StringSplitOptions.RemoveEmptyEntries);
+
+                    Label lblLanguage = new Label
+                    {
+                        ForeColor = Color.DodgerBlue,
+                        Text = language,
+                        AutoSize = true,
+                        Font = this.Font
+                    };
+                    Label[] ctrTranslators = new Label[translators.Length];
+                    for(int i = 0; i < translators.Length; i++)
+                    {
+                        ctrTranslators[i] = new Label
+                        {
+                            AutoSize = true,
+                            Font = this.Font,
+                            Text = translators[i],
+                            ForeColor = Color.DimGray,
+                        };
+                        if(urls.Length > i)
+                        {
+                            string url = urls[i].Trim();
+                            if(url != "null")
+                            {
+                                toolTip.SetToolTip(ctrTranslators[i], url);
+                                ctrTranslators[i].ForeColor = Color.SkyBlue;
+                                ctrTranslators[i].Font = new Font(ctrTranslators[i].Font, FontStyle.Underline);
+                                ctrTranslators[i].Click += (sender, e) => ExternalProgram.OpenWebUrl(url);
+                            }
+                        }
+                    }
+                    dic.Add(lblLanguage, ctrTranslators);
+                    cmbLanguages.Items.Add(language);
+                    languages.Add(langName);
+                }
+                int left = 0;
+                dic.Keys.ToList().ForEach(lbl => left = Math.Max(left, lbl.Width));
+                left += 250.DpiZoom();
+                int top = lblHeader.Bottom + 10.DpiZoom();
+                foreach(var item in dic)
+                {
+                    item.Key.Top = top;
+                    pnlTranslators.Controls.Add(item.Key);
+                    foreach(var ctr in item.Value)
+                    {
+                        ctr.Location = new Point(left, top);
+                        pnlTranslators.Controls.Add(ctr);
+                        top += ctr.Height + 10.DpiZoom();
+                    }
+                }
+            }
+            pnlTranslators.ResumeLayout();
+            cmbLanguages.SelectedIndex = GetSelectIndex();
+        }
+
+        private void ChangeLanguage()
+        {
+            int index = GetSelectIndex();
+            if(cmbLanguages.SelectedIndex == index) return;
+            string language = languages[cmbLanguages.SelectedIndex];
+            string msg = "";
+            if(cmbLanguages.SelectedIndex != 0)
+            {
+                string langPath = $@"{AppConfig.LangsDir}\{language}.ini";
+                msg = new IniWriter(langPath).GetValue("Message", "RestartApp");
+            }
+            if(msg == "") msg = AppString.Message.RestartApp;
+            if(AppMessageBox.Show(msg, MessageBoxButtons.OKCancel) != DialogResult.OK)
+            {
+                cmbLanguages.SelectedIndex = index;
+            }
+            else
+            {
+                if(language == CultureInfo.CurrentUICulture.Name) language = "";
+                AppConfig.Language = language;
+                SingleInstance.Restart();
+            }
+        }
+
+        private int GetSelectIndex()
+        {
+            int index = languages.FindIndex(language => language.Equals(AppConfig.Language, StringComparison.OrdinalIgnoreCase));
+            if(index == -1) index = 0;
+            return index;
+        }
+
+        public void ShowLanguageDialog()
+        {
+            using(UAWebClient client = new UAWebClient())
+            {
+                string apiUrl = AppConfig.RequestUseGithub ? AppConfig.GithubLangsApi : AppConfig.GiteeLangsApi;
+                XmlDocument doc = client.GetWebJsonToXml(apiUrl);
+                if(doc == null)
+                {
+                    AppMessageBox.Show(AppString.Message.WebDataReadFailed);
+                    return;
+                }
+                XmlNodeList list = doc.FirstChild.ChildNodes;
+                string[] langs = new string[list.Count];
+                for(int i = 0; i < list.Count; i++)
+                {
+                    XmlNode nameXN = list.Item(i).SelectSingleNode("name");
+                    langs[i] = Path.GetFileNameWithoutExtension(nameXN.InnerText);
+                }
+                if(langs.Length == 0)
+                {
+                    AppMessageBox.Show(AppString.Message.WebDataReadFailed);
+                    return;
+                }
+                using(SelectDialog dlg = new SelectDialog())
+                {
+                    dlg.Items = langs;
+                    dlg.Title = AppString.Dialog.DownloadLanguages;
+                    string lang = CultureInfo.CurrentUICulture.Name;
+                    if(dlg.Items.Contains(lang)) dlg.Selected = lang;
+                    else dlg.SelectedIndex = 0;
+                    if(dlg.ShowDialog() == DialogResult.OK)
+                    {
+                        string fileName = $"{dlg.Selected}.ini";
+                        string filePath = $@"{AppConfig.LangsDir}\{fileName}";
+                        string dirUrl = AppConfig.RequestUseGithub ? AppConfig.GithubLangsRawDir : AppConfig.GiteeLangsRawDir;
+                        string fileUrl = $"{dirUrl}/{fileName}";
+                        bool flag = client.WebStringToFile(filePath, fileUrl);
+                        if(!flag)
+                        {
+                            if(AppMessageBox.Show(AppString.Message.WebDataReadFailed + "\r\n ● " + fileName + "\r\n"
+                                + AppString.Message.OpenWebUrl, MessageBoxButtons.YesNo) == DialogResult.Yes)
+                            {
+                                ExternalProgram.OpenWebUrl(fileUrl);
+                            }
+                        }
+                        else
+                        {
+                            this.LoadLanguages();
+                            string language = new IniWriter(filePath).GetValue("General", "Language");
+                            if(language == "") language = dlg.Selected;
+                            cmbLanguages.Text = language;
+                            ChangeLanguage();
+                        }
+                    }
+                }
+            }
+        }
+
+        sealed class TranslateDialog : CommonDialog
+        {
+            public override void Reset() { }
+
+            protected override bool RunDialog(IntPtr hwndOwner)
+            {
+                using(TranslateForm frm = new TranslateForm())
+                {
+                    frm.TopMost = AppConfig.TopMost;
+                    return frm.ShowDialog() == DialogResult.OK;
+                }
+            }
+
+            sealed class TranslateForm : Form
+            {
+                public TranslateForm()
+                {
+                    this.SuspendLayout();
+                    this.CancelButton = btnCancel;
+                    this.Font = SystemFonts.MessageBoxFont;
+                    this.SizeGripStyle = SizeGripStyle.Hide;
+                    this.Text = AppString.Dialog.TranslateTool;
+                    this.ShowInTaskbar = this.MinimizeBox = false;
+                    this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
+                    this.StartPosition = FormStartPosition.CenterParent;
+                    this.InitializeComponents();
+                    this.ResumeLayout();
+                }
+
+                readonly Label lblSections = new Label
+                {
+                    AutoSize = true,
+                    Text = "Section"
+                };
+                readonly Label lblKeys = new Label
+                {
+                    AutoSize = true,
+                    Text = "Key"
+                };
+                readonly Label lblDefault = new Label
+                {
+                    Text = AppString.Dialog.DefaultText,
+                    AutoSize = true
+                };
+                readonly Label lblOld = new Label
+                {
+                    Text = AppString.Dialog.OldTranslation,
+                    AutoSize = true
+                };
+                readonly Label lblNew = new Label
+                {
+                    Text = AppString.Dialog.NewTranslation,
+                    AutoSize = true
+                };
+                readonly TextBox txtDefault = new TextBox
+                {
+                    Multiline = true,
+                    ReadOnly = true
+                };
+                readonly TextBox txtOld = new TextBox
+                {
+                    Multiline = true,
+                    ReadOnly = true
+                };
+                readonly TextBox txtNew = new TextBox
+                {
+                    Multiline = true
+                };
+                readonly ComboBox cmbSections = new ComboBox
+                {
+                    DropDownStyle = ComboBoxStyle.DropDownList
+                };
+                readonly ComboBox cmbKeys = new ComboBox
+                {
+                    DropDownStyle = ComboBoxStyle.DropDownList
+                };
+                readonly Button btnBrowse = new Button
+                {
+                    Text = AppString.Dialog.Browse,
+                    AutoSize = true
+                };
+                readonly Button btnSave = new Button
+                {
+                    Text = AppString.Menu.Save,
+                    AutoSize = true
+                };
+                readonly Button btnCancel = new Button
+                {
+                    DialogResult = DialogResult.Cancel,
+                    Text = ResourceString.Cancel,
+                    AutoSize = true
+                };
+
+                static TranslateForm()
+                {
+                    foreach(string section in AppString.DefLangReader.Sections)
+                    {
+                        var dic = new Dictionary<string, string>();
+                        foreach(string key in AppString.DefLangReader.GetSectionKeys(section))
+                        {
+                            dic.Add(key, string.Empty);
+                        }
+                        EditingDic.Add(section, dic);
+                    }
+                }
+
+                static readonly Dictionary<string, Dictionary<string, string>> EditingDic
+                    = new Dictionary<string, Dictionary<string, string>>();
+
+                static readonly IniWriter ReferentialWirter = new IniWriter();
+
+                private string Section => cmbSections.Text;
+                private string Key => cmbKeys.Text;
+
+                private void InitializeComponents()
+                {
+                    this.Controls.AddRange(new Control[] { lblSections, cmbSections, lblKeys,
+                    cmbKeys, lblDefault, txtDefault, lblOld, txtOld, lblNew,
+                    txtNew, btnBrowse, btnSave, btnCancel });
+
+                    txtDefault.SetAutoShowScroll(ScrollBars.Vertical);
+                    txtOld.SetAutoShowScroll(ScrollBars.Vertical);
+                    txtNew.SetAutoShowScroll(ScrollBars.Vertical);
+                    txtDefault.CanSelectAllWhenReadOnly();
+                    txtOld.CanSelectAllWhenReadOnly();
+                    cmbSections.AutosizeDropDownWidth();
+                    cmbKeys.AutosizeDropDownWidth();
+
+                    int a = 20.DpiZoom();
+
+                    lblSections.Top = lblSections.Left = cmbSections.Top = lblKeys.Left
+                        = lblDefault.Left = lblOld.Left = lblNew.Left = btnBrowse.Left = a;
+
+                    lblKeys.Top = cmbKeys.Top = cmbSections.Bottom + a;
+                    lblDefault.Top = txtDefault.Top = cmbKeys.Bottom + a;
+                    txtDefault.Height = txtOld.Height = txtNew.Height = 4 * a;
+                    cmbSections.Width = cmbKeys.Width = txtDefault.Width = txtOld.Width = txtNew.Width = 20 * a;
+
+                    int h = cmbSections.Height + cmbKeys.Height + btnBrowse.Height;
+                    int[] ws = { lblSections.Width, lblKeys.Width, lblDefault.Width, lblOld.Width, lblNew.Width };
+                    int w = ws.Max();
+
+                    cmbSections.Left = cmbKeys.Left = txtDefault.Left = txtOld.Left = txtNew.Left = w + 2 * a;
+
+                    this.Resize += (sender, e) =>
+                    {
+                        txtDefault.Height = txtOld.Height = txtNew.Height
+                            = (this.ClientSize.Height - h - 7 * a) / 3;
+
+                        lblOld.Top = txtOld.Top = txtDefault.Bottom + a;
+                        lblNew.Top = txtNew.Top = txtOld.Bottom + a;
+                        btnBrowse.Top = btnSave.Top = btnCancel.Top = txtNew.Bottom + a;
+
+                        cmbSections.Width = cmbKeys.Width = txtDefault.Width = txtOld.Width = txtNew.Width
+                            = this.ClientSize.Width - (w + 3 * a);
+
+                        btnCancel.Left = this.ClientSize.Width - btnCancel.Width - a;
+                        btnSave.Left = btnCancel.Left - btnSave.Width - a;
+                        btnBrowse.Left = btnSave.Left - btnBrowse.Width - a;
+                    };
+                    this.ClientSize = new Size(w + 23 * a, h + 3 * 4 * a + 7 * a);
+                    this.MinimumSize = this.Size;
+
+                    cmbSections.Items.AddRange(AppString.DefLangReader.Sections);
+                    cmbSections.SelectedIndexChanged += (sender, e) =>
+                    {
+                        cmbKeys.Items.Clear();
+                        cmbKeys.Items.AddRange(AppString.DefLangReader.GetSectionKeys(Section));
+                        cmbKeys.SelectedIndex = 0;
+                    };
+                    cmbKeys.SelectedIndexChanged += (sender, e) =>
+                    {
+                        txtDefault.Text = AppString.DefLangReader.GetValue(Section, Key).Replace("\\r", "\r").Replace("\\n", "\n");
+                        txtOld.Text = ReferentialWirter.GetValue(Section, Key).Replace("\\r", "\r").Replace("\\n", "\n");
+                        txtNew.Text = EditingDic[Section][Key].Replace("\\r", "\r").Replace("\\n", "\n");
+                    };
+                    cmbSections.SelectedIndex = 0;
+
+                    txtOld.TextChanged += (sender, e) => { if(txtNew.Text == string.Empty) txtNew.Text = txtOld.Text; };
+                    txtNew.TextChanged += (sender, e) => EditingDic[Section][Key] = txtNew.Text.Replace("\n", "\\n").Replace("\r", "\\r");
+                    btnBrowse.Click += (sender, e) => SelectFile();
+                    btnSave.Click += (sender, e) => Save();
+                }
+
+                private void SelectFile()
+                {
+                    using(OpenFileDialog dlg = new OpenFileDialog())
+                    {
+                        dlg.InitialDirectory = AppConfig.LangsDir;
+                        dlg.Filter = $"{AppString.SideBar.AppLanguage}|*.ini";
+                        if(dlg.ShowDialog() != DialogResult.OK) return;
+                        ReferentialWirter.FilePath = dlg.FileName;
+                        txtOld.Text = ReferentialWirter.GetValue(Section, Key).Replace("\\r", "\r").Replace("\\n", "\n");
+                    }
+                }
+
+                private void Save()
+                {
+                    using(SaveFileDialog dlg = new SaveFileDialog())
+                    {
+                        string language = EditingDic["General"]["Language"];
+                        int index = language.IndexOf(' ');
+                        if(index > 0) language = language.Substring(0, index);
+                        dlg.FileName = $"{language}.ini";
+                        dlg.InitialDirectory = AppConfig.LangsDir;
+                        dlg.Filter = $"{AppString.SideBar.AppLanguage}|*.ini";
+                        if(dlg.ShowDialog() != DialogResult.OK) return;
+
+                        string contents = string.Empty;
+                        foreach(string section in EditingDic.Keys)
+                        {
+                            contents += $"[{section}]" + "\r\n";
+                            foreach(string key in EditingDic[section].Keys)
+                            {
+                                string value = EditingDic[section][key];
+                                contents += $"{key} = {value}" + "\r\n";
+                            }
+                            contents += "\r\n";
+                        }
+                        File.WriteAllText(dlg.FileName, contents, Encoding.Unicode);
+                    }
+                }
+            }
+        }
+    }
+}

+ 5 - 3
ContextMenuManager/Controls/NewIEDialog.cs

@@ -1,4 +1,5 @@
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.IO;
 using System.Windows.Forms;
@@ -14,6 +15,7 @@ namespace ContextMenuManager.Controls
         {
             using(NewIEForm frm = new NewIEForm())
             {
+                frm.TopMost = AppConfig.TopMost;
                 bool flag = frm.ShowDialog() == DialogResult.OK;
                 if(flag) this.RegPath = frm.RegPath;
                 return flag;
@@ -27,16 +29,16 @@ namespace ContextMenuManager.Controls
             protected override void InitializeComponents()
             {
                 base.InitializeComponents();
-                btnOk.Click += (sender, e) =>
+                btnOK.Click += (sender, e) =>
                 {
                     if(ItemText.IsNullOrWhiteSpace())
                     {
-                        MessageBoxEx.Show(AppString.Message.TextCannotBeEmpty);
+                        AppMessageBox.Show(AppString.Message.TextCannotBeEmpty);
                         return;
                     }
                     if(ItemCommand.IsNullOrWhiteSpace())
                     {
-                        MessageBoxEx.Show(AppString.Message.CommandCannotBeEmpty);
+                        AppMessageBox.Show(AppString.Message.CommandCannotBeEmpty);
                         return;
                     }
                     AddNewItem();

+ 3 - 3
ContextMenuManager/Controls/NewItem.cs

@@ -1,5 +1,6 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 
 namespace ContextMenuManager.Controls
@@ -15,11 +16,10 @@ namespace ContextMenuManager.Controls
             this.AddCtr(BtnAddNewItem);
             ToolTipBox.SetToolTip(BtnAddNewItem, text);
             BtnAddNewItem.MouseDown += (sender, e) => AddNewItem?.Invoke();
-            this.ImageDoubleClick += () => AddNewItem?.Invoke();
-            this.TextDoubleClick += () => AddNewItem?.Invoke();
+            this.MouseDoubleClick += (sender, e) => AddNewItem?.Invoke();
 
         }
-        public Action AddNewItem { get; set; }
+        public Action AddNewItem;
         readonly PictureButton BtnAddNewItem = new PictureButton(AppImage.AddNewItem);
     }
 }

+ 17 - 17
ContextMenuManager/Controls/NewItemForm.cs

@@ -1,5 +1,6 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.Drawing;
 using System.Windows.Forms;
@@ -10,7 +11,7 @@ namespace ContextMenuManager.Controls
     {
         public NewItemForm()
         {
-            this.AcceptButton = btnOk;
+            this.AcceptButton = btnOK;
             this.CancelButton = btnCancel;
             this.Text = AppString.Other.NewItem;
             this.Font = SystemFonts.MenuFont;
@@ -29,10 +30,13 @@ namespace ContextMenuManager.Controls
         {
             get
             {
-                if(Arguments.IsNullOrWhiteSpace()) return ItemFilePath;
-                if(ItemFilePath.IsNullOrWhiteSpace()) return Arguments;
-                if(Arguments.StartsWith("\"") && Arguments.EndsWith("\"")) return $"\"{ItemFilePath}\" {Arguments}";
-                return $"\"{ItemFilePath}\" \"{Arguments}\"";
+                string filePath = ItemFilePath;
+                string arguments = Arguments;
+                if(arguments.IsNullOrWhiteSpace()) return filePath;
+                if(filePath.IsNullOrWhiteSpace()) return arguments;
+                if(filePath.Contains(" ")) filePath = $"\"{filePath}\"";
+                if(!arguments.Contains("\"")) arguments = $"\"{arguments}\"";
+                return $"{filePath} {arguments}";
             }
         }
 
@@ -59,42 +63,38 @@ namespace ContextMenuManager.Controls
             Text = AppString.Dialog.Browse,
             AutoSize = true
         };
-        protected readonly Button btnOk = new Button
+        protected readonly Button btnOK = new Button
         {
-            Text = AppString.Dialog.Ok,
+            Text = ResourceString.OK,
             AutoSize = true
         };
         protected readonly Button btnCancel = new Button
         {
             DialogResult = DialogResult.Cancel,
-            Text = AppString.Dialog.Cancel,
+            Text = ResourceString.Cancel,
             AutoSize = true
         };
 
-        private static Size LastSize = new Size();
-
         protected virtual void InitializeComponents()
         {
             this.Controls.AddRange(new Control[] { lblText, lblCommand, lblArguments,
-                txtText, txtFilePath, txtArguments, btnBrowse, btnOk, btnCancel });
+                txtText, txtFilePath, txtArguments, btnBrowse, btnOK, btnCancel });
             int a = 20.DpiZoom();
-            btnBrowse.Anchor = btnOk.Anchor = btnCancel.Anchor = AnchorStyles.Right | AnchorStyles.Top;
+            btnBrowse.Anchor = btnOK.Anchor = btnCancel.Anchor = AnchorStyles.Right | AnchorStyles.Top;
             txtText.Top = lblText.Top = lblText.Left = lblCommand.Left = lblArguments.Left = a;
             btnBrowse.Top = txtFilePath.Top = lblCommand.Top = txtText.Bottom + a;
             lblArguments.Top = txtArguments.Top = txtFilePath.Bottom + a;
-            btnOk.Top = btnCancel.Top = txtArguments.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;
+            btnOK.Left = btnCancel.Left - btnOK.Width - a;
             int b = Math.Max(Math.Max(lblText.Width, lblCommand.Width), lblArguments.Width) + btnBrowse.Width + 4 * a;
-            this.ClientSize = new Size(320.DpiZoom() + b, btnOk.Bottom + a);
+            this.ClientSize = new Size(320.DpiZoom() + b, btnOK.Bottom + a);
             this.MinimumSize = this.Size;
             this.Resize += (sender, e) =>
             {
                 txtText.Width = txtFilePath.Width = txtArguments.Width = this.ClientSize.Width - b;
                 txtText.Left = txtFilePath.Left = txtArguments.Left = btnBrowse.Left - txtFilePath.Width - a;
-                LastSize = this.Size;
             };
-            if(LastSize != null) this.Size = LastSize;
             this.OnResize(null);
         }
     }

+ 8 - 6
ContextMenuManager/Controls/NewLnkFileDialog.cs

@@ -1,4 +1,5 @@
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.IO;
 using System.Windows.Forms;
@@ -18,6 +19,7 @@ namespace ContextMenuManager.Controls
             using(NewLnkForm frm = new NewLnkForm())
             {
                 frm.FileFilter = this.FileFilter;
+                frm.TopMost = AppConfig.TopMost;
                 bool flag = frm.ShowDialog() == DialogResult.OK;
                 if(flag)
                 {
@@ -49,7 +51,7 @@ namespace ContextMenuManager.Controls
             {
                 base.InitializeComponents();
                 this.Controls.AddRange(new Control[] { rdoFile, rdoFolder });
-                rdoFile.Top = rdoFolder.Top = btnOk.Top;
+                rdoFile.Top = rdoFolder.Top = btnOK.Top + (btnOK.Height - rdoFile.Height) / 2;
                 rdoFile.Left = lblCommand.Left;
                 rdoFolder.Left = rdoFile.Right + 20.DpiZoom();
 
@@ -59,23 +61,23 @@ namespace ContextMenuManager.Controls
                     else BrowseFolder();
                 };
 
-                btnOk.Click += (sender, e) =>
+                btnOK.Click += (sender, e) =>
                 {
                     if(ItemText.IsNullOrWhiteSpace())
                     {
-                        MessageBoxEx.Show(AppString.Message.TextCannotBeEmpty);
+                        AppMessageBox.Show(AppString.Message.TextCannotBeEmpty);
                     }
                     else if(ItemFilePath.IsNullOrWhiteSpace())
                     {
-                        MessageBoxEx.Show(AppString.Message.CommandCannotBeEmpty);
+                        AppMessageBox.Show(AppString.Message.CommandCannotBeEmpty);
                     }
                     else if(rdoFile.Checked && !ObjectPath.GetFullFilePath(ItemFilePath, out _))
                     {
-                        MessageBoxEx.Show(AppString.Message.FileNotExists);
+                        AppMessageBox.Show(AppString.Message.FileNotExists);
                     }
                     else if(rdoFolder.Checked && !Directory.Exists(ItemFilePath))
                     {
-                        MessageBoxEx.Show(AppString.Message.FolderNotExists);
+                        AppMessageBox.Show(AppString.Message.FolderNotExists);
                     }
                     else DialogResult = DialogResult.OK;
                 };

+ 8 - 6
ContextMenuManager/Controls/NewOpenWithDialog.cs

@@ -1,4 +1,5 @@
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.Diagnostics;
 using System.IO;
@@ -15,6 +16,7 @@ namespace ContextMenuManager.Controls
         {
             using(NewOpenWithForm frm = new NewOpenWithForm())
             {
+                frm.TopMost = AppConfig.TopMost;
                 bool flag = frm.ShowDialog() == DialogResult.OK;
                 if(flag) this.RegPath = frm.RegPath;
                 return flag;
@@ -27,23 +29,23 @@ namespace ContextMenuManager.Controls
 
             private string FilePath;
             private string FileName => Path.GetFileName(FilePath);
-            private string AppRegPath => $@"{RegistryEx.CLASSESROOT}\Applications\{FileName}";
+            private string AppRegPath => $@"{RegistryEx.CLASSES_ROOT}\Applications\{FileName}";
             private string CommandPath => $@"{AppRegPath}\shell\open\command";
 
             protected override void InitializeComponents()
             {
                 base.InitializeComponents();
                 btnBrowse.Click += (sender, e) => BrowseFile();
-                btnOk.Click += (sender, e) =>
+                btnOK.Click += (sender, e) =>
                 {
                     if(string.IsNullOrEmpty(ItemText))
                     {
-                        MessageBoxEx.Show(AppString.Message.TextCannotBeEmpty);
+                        AppMessageBox.Show(AppString.Message.TextCannotBeEmpty);
                         return;
                     }
                     if(ItemCommand.IsNullOrWhiteSpace())
                     {
-                        MessageBoxEx.Show(AppString.Message.CommandCannotBeEmpty);
+                        AppMessageBox.Show(AppString.Message.CommandCannotBeEmpty);
                         return;
                     }
                     FilePath = ObjectPath.ExtractFilePath(base.ItemFilePath);
@@ -53,12 +55,12 @@ namespace ContextMenuManager.Controls
                         string name = Path.GetFileName(path);
                         if(FilePath != null && FilePath.Equals(path, StringComparison.OrdinalIgnoreCase))
                         {
-                            MessageBoxEx.Show(AppString.Message.HasBeenAdded);
+                            AppMessageBox.Show(AppString.Message.HasBeenAdded);
                             return;
                         }
                         if(FileName == null || FileName.Equals(name, StringComparison.OrdinalIgnoreCase))
                         {
-                            MessageBoxEx.Show(AppString.Message.UnsupportedFilename);
+                            AppMessageBox.Show(AppString.Message.UnsupportedFilename);
                             return;
                         }
                     }

+ 9 - 9
ContextMenuManager/Controls/NewShellDialog.cs

@@ -1,4 +1,5 @@
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.IO;
 using System.Windows.Forms;
@@ -22,6 +23,7 @@ namespace ContextMenuManager.Controls
                 ShellPath = this.ShellPath
             })
             {
+                frm.TopMost = AppConfig.TopMost;
                 bool flag = frm.ShowDialog() == DialogResult.OK;
                 if(flag) this.NewItemRegPath = frm.NewItemRegPath;
                 return flag;
@@ -64,21 +66,19 @@ namespace ContextMenuManager.Controls
             {
                 base.InitializeComponents();
                 this.Controls.AddRange(new Control[] { rdoSingle, rdoMulti, chkSE });
-                rdoSingle.Top = rdoMulti.Top = btnOk.Top;
+                rdoSingle.Top = rdoMulti.Top = chkSE.Top = btnOK.Top + (btnOK.Height - rdoSingle.Height) / 2;
                 rdoSingle.Left = lblCommand.Left;
                 rdoMulti.Left = rdoSingle.Right + 20.DpiZoom();
-                chkSE.Top = txtArguments.Top + (txtArguments.Height - chkSE.Height) / 2;
-                this.Resize += (sender, e) => chkSE.Left = txtArguments.Right + 20.DpiZoom();
-                this.OnResize(null);
+                chkSE.Left = rdoMulti.Right + 20.DpiZoom();
 
                 rdoMulti.CheckedChanged += (sender, e) =>
                 {
                     if(rdoMulti.Checked)
                     {
                         chkSE.Checked = false;
-                        if(WindowsOsVersion.IsEqualVista)
+                        if(WinOsVersion.Current == WinOsVersion.Vista)
                         {
-                            MessageBoxEx.Show(AppString.Message.VistaUnsupportedMulti);
+                            AppMessageBox.Show(AppString.Message.VistaUnsupportedMulti);
                             rdoSingle.Checked = true;
                             return;
                         }
@@ -89,11 +89,11 @@ namespace ContextMenuManager.Controls
 
                 btnBrowse.Click += (sender, e) => BrowseFile();
 
-                btnOk.Click += (sender, e) =>
+                btnOK.Click += (sender, e) =>
                 {
                     if(txtText.Text.IsNullOrWhiteSpace())
                     {
-                        MessageBoxEx.Show(AppString.Message.TextCannotBeEmpty);
+                        AppMessageBox.Show(AppString.Message.TextCannotBeEmpty);
                     }
                     else
                     {
@@ -123,7 +123,7 @@ namespace ContextMenuManager.Controls
                             extension = Path.GetExtension(filePath);
                         }
                     }
-                    string exePath = FileExtension.GetExecutablePath(extension);
+                    string exePath = FileExtension.GetExtentionInfo(FileExtension.AssocStr.Executable, extension);
                     if(File.Exists(exePath))
                     {
                         ItemFilePath = exePath;

+ 2 - 2
ContextMenuManager/Controls/OpenWithItem.cs

@@ -1,6 +1,7 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
 using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using Microsoft.Win32;
 using System;
 using System.Diagnostics;
@@ -66,7 +67,7 @@ namespace ContextMenuManager.Controls
             {
                 if(ObjectPath.ExtractFilePath(value) != ItemFilePath)
                 {
-                    MessageBoxEx.Show(AppString.Message.CannotChangePath);
+                    AppMessageBox.Show(AppString.Message.CannotChangePath);
                 }
                 else Registry.SetValue(RegPath, "", value);
             }
@@ -127,7 +128,6 @@ namespace ContextMenuManager.Controls
             {
                 if(key.GetSubKeyNames().Length == 0) RegistryEx.DeleteKeyTree(this.AppPath);
             }
-            this.Dispose();
         }
     }
 }

+ 3 - 2
ContextMenuManager/Controls/OpenWithList.cs

@@ -1,5 +1,6 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using Microsoft.Win32;
 using System;
 using System.Collections.Generic;
@@ -17,8 +18,8 @@ namespace ContextMenuManager.Controls
             this.AddNewItem();
             VisibleRegRuleItem storeItem = new VisibleRegRuleItem(VisibleRegRuleItem.UseStoreOpenWith)
             {
-                //Win8、Win8.1、Win10才有在应用商店中查找应用
-                Visible = WindowsOsVersion.ISAfterOrEqual8
+                //Win8及以上版本系统才有在应用商店中查找应用
+                Visible = WinOsVersion.Current >= WinOsVersion.Win8
             };
             this.InsertItem(storeItem, 1);
         }

+ 37 - 30
ContextMenuManager/Controls/RuleItem.cs

@@ -1,6 +1,7 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
 using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using Microsoft.Win32;
 using System;
 using System.Drawing;
@@ -8,7 +9,7 @@ using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls
 {
-    class RuleItem : MyListItem, IFoldSubItem, IBtnShowMenuItem, ITsiWebSearchItem
+    class RuleItem : FoldSubItem, IBtnShowMenuItem, ITsiWebSearchItem
     {
         public RuleItem(ItemInfo info)
         {
@@ -21,7 +22,6 @@ namespace ContextMenuManager.Controls
             this.ContextMenuStrip.Items.Add(TsiSearch);
         }
 
-        public IFoldGroupItem FoldGroupItem { get; set; }
         public WebSearchMenuItem TsiSearch { get; set; }
         public MenuButton BtnShowMenu { get; set; }
 
@@ -86,16 +86,7 @@ namespace ContextMenuManager.Controls
         public VisibleRegRuleItem(RuleAndInfo ruleAndInfo)
             : this(ruleAndInfo.Rules, ruleAndInfo.ItemInfo) { }
 
-        private RegRule[] _Rules;
-        public RegRule[] Rules
-        {
-            get => _Rules;
-            set
-            {
-                _Rules = value;
-                //ChkVisible.Checked = ItemVisible;
-            }
-        }
+        public RegRule[] Rules { get; set; }
 
         public VisibleCheckBox ChkVisible { get; set; }
         public RegLocationMenuItem TsiRegLocation { get; set; }
@@ -150,7 +141,7 @@ namespace ContextMenuManager.Controls
         const string LM_SPMWE = @"HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Explorer";
         const string CU_SPMWE = @"HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\Explorer";
 
-        public static RuleAndInfo CustomFolder = new RuleAndInfo
+        public static readonly RuleAndInfo CustomFolder = new RuleAndInfo
         {
             Rules = new[] {
                 new RegRule(LM_SMWCPE, "NoCustomizeThisFolder", null, 1),
@@ -167,7 +158,7 @@ namespace ContextMenuManager.Controls
             }
         };
 
-        public static RuleAndInfo NetworkDrive = new RuleAndInfo
+        public static readonly RuleAndInfo NetworkDrive = new RuleAndInfo
         {
             Rules = new[] {
                 new RegRule(LM_SMWCPE, "NoNetConnectDisconnect", null, 1),
@@ -175,13 +166,13 @@ namespace ContextMenuManager.Controls
             },
             ItemInfo = new ItemInfo
             {
-                Text = $"{AppString.Other.MapNetworkDrive} && {AppString.Other.DisconnectNetworkDrive}",
+                Text = $"{ResourceString.GetDirectString("@AppResolver.dll,-8556")} && {ResourceString.GetDirectString("@AppResolver.dll,-8557")}",
                 Image = AppImage.NetworkDrive,
                 RestartExplorer = true
             }
         };
 
-        public static RuleAndInfo RecycleBinProperties = new RuleAndInfo
+        public static readonly RuleAndInfo RecycleBinProperties = new RuleAndInfo
         {
             Rules = new[] {
                 new RegRule(LM_SMWCPE, "NoPropertiesRecycleBin", null, 1),
@@ -189,13 +180,13 @@ namespace ContextMenuManager.Controls
             },
             ItemInfo = new ItemInfo
             {
-                Text = AppString.Other.RecycleBinProperties,
+                Text = ResourceString.GetDirectString("@AppResolver.dll,-8553"),
                 Image = AppImage.RecycleBin,
                 RestartExplorer = true
             }
         };
 
-        public static RuleAndInfo SendToDrive = new RuleAndInfo
+        public static readonly RuleAndInfo SendToDrive = new RuleAndInfo
         {
             Rules = new[] {
                 new RegRule(LM_SMWCPE, "NoDrivesInSendToMenu", null, 1),
@@ -203,14 +194,14 @@ namespace ContextMenuManager.Controls
             },
             ItemInfo = new ItemInfo
             {
-                Text = AppString.Other.RemovableDrive,
+                Text = ResourceString.GetDirectString("@shell32.dll,-9309"),
                 Image = AppImage.Drive,
                 Tip = AppString.Tip.SendToDrive,
                 RestartExplorer = true
             }
         };
 
-        public static RuleAndInfo DeferBuildSendTo = new RuleAndInfo
+        public static readonly RuleAndInfo DeferBuildSendTo = new RuleAndInfo
         {
             Rules = new[] {
                 new RegRule(LM_SMWCE, "DelaySendToMenuBuild", null, 1),
@@ -224,7 +215,7 @@ namespace ContextMenuManager.Controls
             }
         };
 
-        public static RuleAndInfo UseStoreOpenWith = new RuleAndInfo
+        public static readonly RuleAndInfo UseStoreOpenWith = new RuleAndInfo
         {
             Rules = new[] {
                 new RegRule(LM_SPMWE, "NoUseStoreOpenWith", null, 1),
@@ -232,7 +223,7 @@ namespace ContextMenuManager.Controls
             },
             ItemInfo = new ItemInfo
             {
-                Text = AppString.Other.UseStoreOpenWith,
+                Text = ResourceString.GetDirectString("@shell32.dll,-5383"),
                 Image = AppImage.MicrosoftStore
             }
         };
@@ -252,7 +243,6 @@ namespace ContextMenuManager.Controls
 
         readonly NumericUpDown NudValue = new NumericUpDown
         {
-            Font = new Font(SystemFonts.MenuFont.FontFamily, 12F),
             TextAlign = HorizontalAlignment.Center,
             Width = 80.DpiZoom()
         };
@@ -267,6 +257,7 @@ namespace ContextMenuManager.Controls
             this.Rule = rule;
             NudValue.Maximum = rule.MaxValue;
             NudValue.Minimum = rule.MinValue;
+            NudValue.Font = new Font(this.Font.FontFamily, this.Font.Size + 3F);
             NudValue.ValueChanged += (sender, e) =>
             {
                 if(NudValue.Value == Rule.DefaultValue)
@@ -302,6 +293,7 @@ namespace ContextMenuManager.Controls
             set
             {
                 Registry.SetValue(Rule.RegPath, Rule.ValueName, value, Rule.ValueKind);
+                if(RestartExplorer) ExplorerRestarter.Show();
             }
         }
     }
@@ -316,8 +308,8 @@ namespace ContextMenuManager.Controls
 
         readonly Label LblValue = new Label
         {
-            Font = new Font(SystemFonts.MenuFont.FontFamily, 12F),
             BorderStyle = BorderStyle.FixedSingle,
+            ForeColor = Color.FromArgb(80, 80, 80),
             Cursor = Cursors.Hand,
             AutoSize = true
         };
@@ -332,6 +324,7 @@ namespace ContextMenuManager.Controls
             this.ContextMenuStrip.Items.AddRange(new ToolStripItem[] { new ToolStripSeparator(), TsiRegLocation });
             this.Rule = rule;
             LblValue.Text = ItemValue;
+            LblValue.Font = new Font(this.Font.FontFamily, this.Font.Size + 3F);
             LblValue.MouseDown += (sender, e) =>
             {
                 using(InputDialog dlg = new InputDialog())
@@ -352,7 +345,11 @@ namespace ContextMenuManager.Controls
         public string ItemValue
         {
             get => Registry.GetValue(Rule.RegPath, Rule.ValueName, null)?.ToString();
-            set => Registry.SetValue(Rule.RegPath, Rule.ValueName, value);
+            set
+            {
+                Registry.SetValue(Rule.RegPath, Rule.ValueName, value);
+                if(RestartExplorer) ExplorerRestarter.Show();
+            }
         }
     }
 
@@ -371,7 +368,7 @@ namespace ContextMenuManager.Controls
         {
             this.Rule = rule;
             this.IniWriter = new IniWriter(rule.IniPath);
-            ChkVisible = new VisibleCheckBox(this);// { Checked = ItemVisible };
+            ChkVisible = new VisibleCheckBox(this);
             ToolTipBox.SetToolTip(ChkVisible, info.Tip);
         }
 
@@ -381,7 +378,11 @@ namespace ContextMenuManager.Controls
         public bool ItemVisible
         {
             get => IniWriter.GetValue(Rule.Section, Rule.KeyName) == Rule.TurnOnValue;
-            set => IniWriter.SetValue(Rule.Section, Rule.KeyName, value ? Rule.TurnOnValue : Rule.TurnOffValue);
+            set
+            {
+                IniWriter.SetValue(Rule.Section, Rule.KeyName, value ? Rule.TurnOnValue : Rule.TurnOffValue);
+                if(RestartExplorer) ExplorerRestarter.Show();
+            }
         }
     }
 
@@ -405,6 +406,7 @@ namespace ContextMenuManager.Controls
             ToolTipBox.SetToolTip(NudValue, info.Tip);
             NudValue.Maximum = rule.MaxValue;
             NudValue.Minimum = rule.MinValue;
+            NudValue.Font = new Font(this.Font.FontFamily, this.Font.Size + 3F);
             NudValue.ValueChanged += (sender, e) =>
             {
                 if(NudValue.Value == Rule.DefaultValue)
@@ -427,7 +429,6 @@ namespace ContextMenuManager.Controls
 
         readonly NumericUpDown NudValue = new NumericUpDown
         {
-            Font = new Font(SystemFonts.MenuFont.FontFamily, 12F),
             TextAlign = HorizontalAlignment.Center,
             Width = 80.DpiZoom()
         };
@@ -446,6 +447,7 @@ namespace ContextMenuManager.Controls
             set
             {
                 IniWriter.SetValue(Rule.Section, Rule.KeyName, value);
+                if(RestartExplorer) ExplorerRestarter.Show();
             }
         }
     }
@@ -462,8 +464,8 @@ namespace ContextMenuManager.Controls
 
         readonly Label LblValue = new Label
         {
-            Font = new Font(SystemFonts.MenuFont.FontFamily, 12F),
             BorderStyle = BorderStyle.FixedSingle,
+            ForeColor = Color.FromArgb(80, 80, 80),
             Cursor = Cursors.Hand,
             AutoSize = true
         };
@@ -475,6 +477,7 @@ namespace ContextMenuManager.Controls
             this.AddCtr(LblValue);
             ToolTipBox.SetToolTip(LblValue, info.Tip);
             LblValue.Text = ItemValue;
+            LblValue.Font = new Font(this.Font.FontFamily, this.Font.Size + 3F);
             LblValue.MouseDown += (sender, e) =>
             {
                 using(InputDialog dlg = new InputDialog())
@@ -494,7 +497,11 @@ namespace ContextMenuManager.Controls
         public string ItemValue
         {
             get => IniWriter.GetValue(Rule.Secation, Rule.KeyName);
-            set => IniWriter.SetValue(Rule.Secation, Rule.KeyName, value);
+            set
+            {
+                IniWriter.SetValue(Rule.Secation, Rule.KeyName, value);
+                if(RestartExplorer) ExplorerRestarter.Show();
+            }
         }
     }
 }

+ 5 - 4
ContextMenuManager/Controls/SendToItem.cs

@@ -1,6 +1,7 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
 using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using Microsoft.Win32;
 using System.Drawing;
 using System.IO;
@@ -26,7 +27,7 @@ namespace ContextMenuManager.Controls
                 filePath = value;
                 if(IsShortcut) this.ShellLink = new ShellLink(value);
                 this.Text = this.ItemText;
-                this.Image = this.ItemIcon.ToBitmap();
+                this.Image = this.ItemImage;
             }
         }
 
@@ -34,6 +35,7 @@ namespace ContextMenuManager.Controls
         private string FileExtension => Path.GetExtension(FilePath);
         private bool IsShortcut => FileExtension.ToLower() == ".lnk";
         public string SearchText => $"{AppString.SideBar.SendTo} {Text}";
+        private Image ItemImage => ItemIcon?.ToBitmap() ?? AppImage.NotFound;
 
         public string ItemFilePath
         {
@@ -209,7 +211,7 @@ namespace ContextMenuManager.Controls
             {
                 if(TsiChangeCommand.ChangeCommand(ShellLink))
                 {
-                    Image = ItemIcon.ToBitmap();
+                    Image = this.ItemImage;
                 }
             };
         }
@@ -218,8 +220,7 @@ namespace ContextMenuManager.Controls
         {
             File.Delete(this.FilePath);
             DesktopIni.DeleteLocalizedFileNames(FilePath);
-            this.ShellLink.Dispose();
-            this.Dispose();
+            this.ShellLink?.Dispose();
         }
     }
 }

+ 23 - 0
ContextMenuManager/Controls/SendToList.cs

@@ -1,5 +1,6 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.IO;
 using System.Windows.Forms;
@@ -9,6 +10,7 @@ namespace ContextMenuManager.Controls
     sealed class SendToList : MyList
     {
         private static readonly string SendToPath = Environment.ExpandEnvironmentVariables(@"%AppData%\Microsoft\Windows\SendTo");
+        private static readonly string DefaultSendToPath = Environment.ExpandEnvironmentVariables(@"%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\SendTo");
 
         public void LoadItems()
         {
@@ -61,6 +63,27 @@ namespace ContextMenuManager.Controls
             btnPath.MouseDown += (sender, e) => ExternalProgram.OpenDirectory(SendToPath);
             item.AddCtr(btnPath);
             this.InsertItem(item, 1);
+            item.ContextMenuStrip = new ContextMenuStrip();
+            ToolStripMenuItem tsiRestoreDefault = new ToolStripMenuItem(AppString.Menu.RestoreDefault);
+            item.ContextMenuStrip.Items.Add(tsiRestoreDefault);
+            tsiRestoreDefault.Enabled = Directory.Exists(DefaultSendToPath);
+            tsiRestoreDefault.Click += (sender, e) =>
+            {
+                if(AppMessageBox.Show(AppString.Message.RestoreDefault, MessageBoxButtons.OKCancel) == DialogResult.OK)
+                {
+                    File.SetAttributes(SendToPath, FileAttributes.Normal);
+                    Directory.Delete(SendToPath, true);
+                    Directory.CreateDirectory(SendToPath);
+                    File.SetAttributes(SendToPath, File.GetAttributes(DefaultSendToPath));
+                    foreach(string srcPath in Directory.GetFiles(DefaultSendToPath))
+                    {
+                        string dstPath = $@"{SendToPath}\{Path.GetFileName(srcPath)}";
+                        File.Copy(srcPath, dstPath);
+                    }
+                    this.ClearItems();
+                    this.LoadItems();
+                }
+            };
         }
     }
 }

+ 11 - 20
ContextMenuManager/Controls/ShellExItem.cs

@@ -1,6 +1,6 @@
-using BluePointLilac.Controls;
-using BluePointLilac.Methods;
+using BluePointLilac.Methods;
 using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using Microsoft.Win32;
 using System;
 using System.Collections.Generic;
@@ -8,7 +8,7 @@ using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls
 {
-    sealed class ShellExItem : MyListItem, IChkVisibleItem, IBtnShowMenuItem, IFoldSubItem, ITsiGuidItem,
+    sealed class ShellExItem : FoldSubItem, IChkVisibleItem, IBtnShowMenuItem, ITsiGuidItem,
         ITsiWebSearchItem, ITsiFilePathItem, ITsiRegPathItem, ITsiRegDeleteItem, ITsiRegExportItem, IProtectOpenItem
     {
         public static Dictionary<string, Guid> GetPathAndGuids(string shellExPath, bool isDragDrop = false)
@@ -65,7 +65,6 @@ namespace ContextMenuManager.Controls
         public Guid Guid { get; set; }
         public string ValueName => null;
         public string SearchText => Text;
-        public string ClsidPath => GuidInfo.GetClsidPath(Guid);
         public string ItemFilePath => GuidInfo.GetFilePath(Guid);
         private string KeyName => RegistryEx.GetKeyName(RegPath);
         private string ParentPath => RegistryEx.GetParentPath(RegPath);
@@ -99,22 +98,22 @@ namespace ContextMenuManager.Controls
                 }
                 catch
                 {
-                    MessageBoxEx.Show(AppString.Message.AuthorityProtection);
+                    AppMessageBox.Show(AppString.Message.AuthorityProtection);
                     return;
                 }
                 RegPath = BackupPath;
             }
         }
 
-        public VisibleCheckBox ChkVisible { get; set; }
         public MenuButton BtnShowMenu { get; set; }
+        public VisibleCheckBox ChkVisible { get; set; }
+        public DetailedEditButton BtnDetailedEdit { get; set; }
         public WebSearchMenuItem TsiSearch { get; set; }
         public FilePropertiesMenuItem TsiFileProperties { get; set; }
         public FileLocationMenuItem TsiFileLocation { get; set; }
         public RegLocationMenuItem TsiRegLocation { get; set; }
         public DeleteMeMenuItem TsiDeleteMe { get; set; }
         public RegExportMenuItem TsiRegExport { get; set; }
-        public IFoldGroupItem FoldGroupItem { get; set; }
         public HandleGuidMenuItem TsiHandleGuid { get; set; }
 
         readonly ToolStripMenuItem TsiDetails = new ToolStripMenuItem(AppString.Menu.Details);
@@ -123,13 +122,14 @@ namespace ContextMenuManager.Controls
         {
             BtnShowMenu = new MenuButton(this);
             ChkVisible = new VisibleCheckBox(this);
+            BtnDetailedEdit = new DetailedEditButton(this);
+            TsiHandleGuid = new HandleGuidMenuItem(this);
             TsiSearch = new WebSearchMenuItem(this);
             TsiFileLocation = new FileLocationMenuItem(this);
             TsiFileProperties = new FilePropertiesMenuItem(this);
             TsiRegLocation = new RegLocationMenuItem(this);
             TsiRegExport = new RegExportMenuItem(this);
             TsiDeleteMe = new DeleteMeMenuItem(this);
-            TsiHandleGuid = new HandleGuidMenuItem(this);
 
             ContextMenuStrip.Items.AddRange(new ToolStripItem[] { TsiHandleGuid, new ToolStripSeparator(),
                 TsiDetails, new ToolStripSeparator(), TsiDeleteMe });
@@ -144,22 +144,13 @@ namespace ContextMenuManager.Controls
         public bool TryProtectOpenItem()
         {
             if(!ChkVisible.Checked || !Guid.Equals(LnkOpenGuid) || !AppConfig.ProtectOpenItem) return true;
-            return MessageBoxEx.Show(AppString.Message.PromptIsOpenItem, MessageBoxButtons.YesNo) == DialogResult.Yes;
+            return AppMessageBox.Show(AppString.Message.PromptIsOpenItem, MessageBoxButtons.YesNo) == DialogResult.Yes;
         }
 
         public void DeleteMe()
         {
-            try
-            {
-                RegistryEx.DeleteKeyTree(this.RegPath, true);
-                RegistryEx.DeleteKeyTree(this.BackupPath);
-            }
-            catch
-            {
-                MessageBoxEx.Show(AppString.Message.AuthorityProtection);
-                return;
-            }
-            this.Dispose();
+            RegistryEx.DeleteKeyTree(this.RegPath, true);
+            RegistryEx.DeleteKeyTree(this.BackupPath);
         }
     }
 }

+ 19 - 12
ContextMenuManager/Controls/ShellExecuteDialog.cs

@@ -1,4 +1,5 @@
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.Drawing;
 using System.IO;
@@ -16,6 +17,7 @@ namespace ContextMenuManager.Controls
         {
             using(ShellExecuteForm frm = new ShellExecuteForm())
             {
+                frm.TopMost = AppConfig.TopMost;
                 bool flag = frm.ShowDialog() == DialogResult.OK;
                 if(flag)
                 {
@@ -40,18 +42,22 @@ namespace ContextMenuManager.Controls
 
         sealed class ShellExecuteForm : Form
         {
-            private const string ApiInfoUrl = "https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutea";
+            private const string ApiInfoUrl = "https://docs.microsoft.com/windows/win32/api/shellapi/nf-shellapi-shellexecutea";
             private static readonly string[] Verbs = new[] { "open", "runas", "edit", "print", "find", "explore" };
             public ShellExecuteForm()
             {
+                this.SuspendLayout();
+                this.HelpButton = true;
                 this.Text = "ShellExecute";
+                this.AcceptButton = btnOK;
+                this.CancelButton = btnCancel;
                 this.Font = SystemFonts.MenuFont;
                 this.FormBorderStyle = FormBorderStyle.FixedSingle;
                 this.StartPosition = FormStartPosition.CenterParent;
                 this.ShowIcon = ShowInTaskbar = MaximizeBox = MinimizeBox = false;
-                this.HelpButton = true;
                 this.HelpButtonClicked += (sender, e) => ExternalProgram.OpenWebUrl(ApiInfoUrl);
                 this.InitializeComponents();
+                this.ResumeLayout();
             }
             public string Verb { get; set; }
             public int WindowStyle { get; set; }
@@ -71,22 +77,22 @@ namespace ContextMenuManager.Controls
                 Minimum = 0,
                 Value = 1
             };
-            readonly Button btnOk = new Button
+            readonly Button btnOK = new Button
             {
-                Text = AppString.Dialog.Ok,
+                Text = ResourceString.OK,
                 DialogResult = DialogResult.OK,
                 AutoSize = true
             };
             readonly Button btnCancel = new Button
             {
-                Text = AppString.Dialog.Cancel,
+                Text = ResourceString.Cancel,
                 DialogResult = DialogResult.Cancel,
                 AutoSize = true
             };
 
             private void InitializeComponents()
             {
-                this.Controls.AddRange(new Control[] { grpVerb, lblStyle, nudStyle, btnOk, btnCancel });
+                this.Controls.AddRange(new Control[] { grpVerb, lblStyle, nudStyle, btnOK, btnCancel });
                 int a = 10.DpiZoom();
                 int b = 2 * a;
                 for(int i = 0; i < 6; i++)
@@ -104,12 +110,12 @@ namespace ContextMenuManager.Controls
                 grpVerb.Width = rdoVerbs[5].Right + a;
                 grpVerb.Height = rdoVerbs[5].Bottom + b;
                 lblStyle.Left = grpVerb.Left = grpVerb.Top = b;
-                btnOk.Top = btnCancel.Top = lblStyle.Top = nudStyle.Top = grpVerb.Bottom + b;
+                btnOK.Top = btnCancel.Top = lblStyle.Top = nudStyle.Top = grpVerb.Bottom + b;
                 nudStyle.Left = lblStyle.Right + b;
                 btnCancel.Left = grpVerb.Right - btnCancel.Width;
-                btnOk.Left = btnCancel.Left - btnOk.Width - b;
+                btnOK.Left = btnCancel.Left - btnOK.Width - b;
                 this.ClientSize = new Size(btnCancel.Right + b, btnCancel.Bottom + b);
-                btnOk.Click += (sender, e) =>
+                btnOK.Click += (sender, e) =>
                 {
                     for(int i = 0; i < 6; i++)
                     {
@@ -131,13 +137,14 @@ namespace ContextMenuManager.Controls
         {
             this.Text = "ShellExecute";
             this.AutoSize = true;
-            this.Font = new Font(SystemFonts.DialogFont.FontFamily, 8F).DpiZoom();
+            //this.Font = SystemFonts.DialogFont;
+            //this.Font = new Font(this.Font.FontFamily, this.Font.Size - 1F);
         }
 
         public string Verb { get; set; }
         public int WindowStyle { get; set; }
 
-        readonly ToolTip ttpInfo = new ToolTip();
+        readonly ToolTip ttpInfo = new ToolTip { InitialDelay = 1 };
 
         protected override void OnClick(EventArgs e)
         {
@@ -154,7 +161,7 @@ namespace ContextMenuManager.Controls
                     this.Verb = dlg.Verb;
                     this.WindowStyle = dlg.WindowStyle;
                     this.Checked = true;
-                    ttpInfo.SetToolTip(this, $"Verb = {Verb}\nWindowStyle = {WindowStyle}");
+                    ttpInfo.SetToolTip(this, $"Verb: \"{Verb}\"\nWindowStyle: {WindowStyle}");
                 }
             }
         }

+ 41 - 38
ContextMenuManager/Controls/ShellItem.cs

@@ -1,6 +1,7 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
 using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using Microsoft.Win32;
 using System;
 using System.Collections.Generic;
@@ -19,13 +20,13 @@ namespace ContextMenuManager.Controls
         private const string OpenInNewWindowPath = @"HKEY_CLASSES_ROOT\Folder\shell\opennewwindow";
 
         /// <summary>Shell类型菜单特殊注册表项名默认名称</summary>
-        private static readonly Dictionary<string, string> DefaultNames
-            = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) {
-            {"open", AppString.Other.Open }, {"edit", AppString.Other.Edit }, {"print", AppString.Other.Print },
-            {"find", AppString.Other.Find }, {"play", AppString.Other.Play }, {"runas", AppString.Other.Runas },
-            //Win10为“浏览(&X)”,Win10之前为“资源管理器(&X)”
-            {"explore", WindowsOsVersion.IsBefore10 ? AppString.Other.ExploreOld : AppString.Other.Explore }
-        };
+        /// <remarks>字符串资源在windows.storage.dll里面</remarks>
+        private static readonly Dictionary<string, int> DefaultNameIndexs
+            = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
+            {
+                { "open", 8496 }, { "edit", 8516 }, { "print", 8497 }, { "find", 8503 },
+                { "play", 8498 }, { "runas", 8505 }, { "explore", 8502 }, { "preview", 8499 }
+            };
 
         /// <summary>菜单项目在菜单中出现的位置</summary>
         enum Positions { Default, Top, Bottom }
@@ -169,7 +170,7 @@ namespace ContextMenuManager.Controls
         {
             get
             {
-                if(WindowsOsVersion.IsAfterOrEqualWin10_1703)
+                if(WinOsVersion.Current >= WinOsVersion.Win10_1703)
                 {
                     //HideBasedOnVelocityId键值仅适用于Win10系统1703以上版本
                     if(Convert.ToInt32(Registry.GetValue(RegPath, "HideBasedOnVelocityId", 0)) == 0x639bc8) return false;
@@ -180,7 +181,7 @@ namespace ContextMenuManager.Controls
                     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;
+                    if(WinOsVersion.Current > WinOsVersion.Vista && Convert.ToInt32(Registry.GetValue(RegPath, "CommandFlags", 0)) % 16 >= 8) return false;
                 }
                 return true;
             }
@@ -192,7 +193,7 @@ namespace ContextMenuManager.Controls
                     {
                         RegistryEx.DeleteValue(RegPath, "LegacyDisable");
                         RegistryEx.DeleteValue(RegPath, "ProgrammaticAccessOnly");
-                        if(WindowsOsVersion.IsAfterVista && Convert.ToInt32(Registry.GetValue(RegPath, "CommandFlags", 0)) % 16 >= 8)
+                        if(WinOsVersion.Current > WinOsVersion.Vista && Convert.ToInt32(Registry.GetValue(RegPath, "CommandFlags", 0)) % 16 >= 8)
                         {
                             RegistryEx.DeleteValue(RegPath, "CommandFlags");
                         }
@@ -205,7 +206,7 @@ namespace ContextMenuManager.Controls
                     }
                     else
                     {
-                        if(WindowsOsVersion.IsAfterOrEqualWin10_1703)
+                        if(WinOsVersion.Current >= WinOsVersion.Win10_1703)
                         {
                             Registry.SetValue(RegPath, "HideBasedOnVelocityId", 0x639bc8);
                         }
@@ -213,7 +214,7 @@ namespace ContextMenuManager.Controls
                         {
                             if(IsSubItem)
                             {
-                                MessageBoxEx.Show(AppString.Message.CannotHideSubItem);
+                                AppMessageBox.Show(AppString.Message.CannotHideSubItem);
                                 return;
                             }
                         }
@@ -232,7 +233,7 @@ namespace ContextMenuManager.Controls
                 }
                 catch
                 {
-                    MessageBoxEx.Show(AppString.Message.AuthorityProtection);
+                    AppMessageBox.Show(AppString.Message.AuthorityProtection);
                 }
             }
         }
@@ -251,15 +252,20 @@ namespace ContextMenuManager.Controls
                     name = ResourceString.GetDirectString(name);
                     if(!string.IsNullOrEmpty(name)) return name;
                 }
-                if(DefaultNames.TryGetValue(KeyName, out name)) return name;
-                else return KeyName;
+                if(DefaultNameIndexs.TryGetValue(KeyName, out int index))
+                {
+                    name = $"@windows.storage.dll,-{index}";
+                    name = ResourceString.GetDirectString(name);
+                    if(!string.IsNullOrEmpty(name)) return name;
+                }
+                return KeyName;
             }
             set
             {
                 //MUIVerb长度不可超过80,超过80系统会隐藏该菜单项目
                 if(ResourceString.GetDirectString(value).Length >= 80)
                 {
-                    MessageBoxEx.Show(AppString.Message.TextLengthCannotExceed80);
+                    AppMessageBox.Show(AppString.Message.TextLengthCannotExceed80);
                 }
                 else
                 {
@@ -336,13 +342,18 @@ namespace ContextMenuManager.Controls
         {
             get
             {
-                string value = Registry.GetValue(CommandPath, "DelegateExecute", null)?.ToString();
-                if(!GuidEx.TryParse(value, out Guid guid))
+                Dictionary<string, string> keyValues = new Dictionary<string, string>
+                {
+                    { CommandPath , "DelegateExecute" },
+                    { $@"{RegPath}\DropTarget" , "CLSID" },
+                    { RegPath , "ExplorerCommandHandler" },
+                };
+                foreach(var item in keyValues)
                 {
-                    value = Registry.GetValue($@"{RegPath}\DropTarget", "CLSID", null)?.ToString();
-                    GuidEx.TryParse(value, out guid);
+                    string value = Registry.GetValue(item.Key, item.Value, null)?.ToString();
+                    if(GuidEx.TryParse(value, out Guid guid)) return guid;
                 }
-                return guid;
+                return Guid.Empty;
             }
         }
 
@@ -411,7 +422,7 @@ namespace ContextMenuManager.Controls
             TsiNoWorkDir.Click += (sender, e) => this.NoWorkingDirectory = !TsiNoWorkDir.Checked;
             TsiNeverDefault.Click += (sender, e) => this.NeverDefault = !TsiNeverDefault.Checked;
             TsiShowAsDisabled.Click += (sender, e) => this.ShowAsDisabledIfHidden = !TsiShowAsDisabled.Checked;
-            TsiClsidLocation.Click += (sender, e) => ExternalProgram.JumpRegEdit(GuidInfo.GetClsidPath(Guid));
+            TsiClsidLocation.Click += (sender, e) => ExternalProgram.JumpRegEdit(GuidInfo.GetClsidPath(Guid), null, AppConfig.OpenMoreRegedit);
             ChkVisible.PreCheckChanging += () => !ChkVisible.Checked || TryProtectOpenItem();
             ContextMenuStrip.Opening += (sender, e) => RefreshMenuItem();
             BtnSubItems.MouseDown += (sender, e) => ShowSubItems();
@@ -450,13 +461,13 @@ namespace ContextMenuManager.Controls
             TsiOnlyWithShift.Visible = !IsSubItem;
             TsiDeleteMe.Enabled = !(IsOpenItem && AppConfig.ProtectOpenItem);
             TsiNoWorkDir.Checked = this.NoWorkingDirectory;
-            TsiShowAsDisabled.Visible = WindowsOsVersion.IsAfterOrEqualWin10_1703;
+            TsiShowAsDisabled.Visible = WinOsVersion.Current >= WinOsVersion.Win10_1703;
             TsiShowAsDisabled.Checked = this.ShowAsDisabledIfHidden;
             TsiChangeCommand.Visible = !IsMultiItem && Guid.Equals(Guid.Empty);
             TsiClsidLocation.Visible = GuidInfo.GetClsidPath(Guid) != null;
             if(!this.IsSubItem) TsiOnlyWithShift.Checked = this.OnlyWithShift;
 
-            if(WindowsOsVersion.IsAfterVista)
+            if(WinOsVersion.Current >= WinOsVersion.Vista)
             {
                 TsiItemIcon.Visible = true;
                 TsiPosition.Visible = !IsSubItem;
@@ -504,16 +515,17 @@ namespace ContextMenuManager.Controls
 
         private void ShowSubItems()
         {
-            if(WindowsOsVersion.IsEqualVista)
+            if(WinOsVersion.Current == WinOsVersion.Vista)
             {
-                MessageBoxEx.Show(AppString.Message.VistaUnsupportedMulti);
+                AppMessageBox.Show(AppString.Message.VistaUnsupportedMulti);
                 return;
             }
             using(ShellSubMenuDialog dlg = new ShellSubMenuDialog())
             {
                 dlg.Text = AppString.Dialog.EditSubItems.Replace("%s", this.Text);
                 dlg.Icon = ResourceIcon.GetIcon(IconPath, IconIndex);
-                dlg.ShowDialog(this.RegPath);
+                dlg.ParentPath = this.RegPath;
+                dlg.ShowDialog();
             }
         }
 
@@ -521,21 +533,12 @@ namespace ContextMenuManager.Controls
         {
             if(!IsOpenItem) return true;
             if(!AppConfig.ProtectOpenItem) return true;
-            return MessageBoxEx.Show(AppString.Message.PromptIsOpenItem, MessageBoxButtons.YesNo) == DialogResult.Yes;
+            return AppMessageBox.Show(AppString.Message.PromptIsOpenItem, MessageBoxButtons.YesNo) == DialogResult.Yes;
         }
 
         public virtual void DeleteMe()
         {
-            try
-            {
-                RegistryEx.DeleteKeyTree(this.RegPath, true);
-            }
-            catch
-            {
-                MessageBoxEx.Show(AppString.Message.AuthorityProtection);
-                return;
-            }
-            this.Dispose();
+            RegistryEx.DeleteKeyTree(this.RegPath, true);
         }
     }
 }

+ 132 - 123
ContextMenuManager/Controls/ShellList.cs

@@ -1,6 +1,6 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
-using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using Microsoft.Win32;
 using System;
 using System.Collections.Generic;
@@ -8,7 +8,6 @@ using System.Diagnostics;
 using System.Drawing;
 using System.IO;
 using System.Linq;
-using System.Text;
 using System.Windows.Forms;
 using System.Xml;
 
@@ -40,20 +39,15 @@ namespace ContextMenuManager.Controls
             CommandStore, DragDrop, CustomRegPath, MenuAnalysis, CustomExtensionPerceivedType
         }
 
-        private static readonly string[] DirectoryTypes =
+        private static readonly List<string> DirectoryTypes = new List<string>
         {
             "Document", "Image", "Video", "Audio"
         };
-        private static readonly string[] PerceivedTypes =
+        private static readonly List<string> PerceivedTypes = new List<string>
         {
             null, "Text", "Document", "Image",
             "Video", "Audio", "Compressed", "System"
         };
-        private static readonly string[] FileObjectTypes =
-        {
-            AppString.SideBar.File,
-            AppString.SideBar.Directory
-        };
         private static readonly string[] PerceivedTypeNames =
         {
             AppString.Dialog.NoPerceivedType, AppString.Dialog.TextFile, AppString.Dialog.DocumentFile, AppString.Dialog.ImageFile,
@@ -67,29 +61,17 @@ namespace ContextMenuManager.Controls
 
         private static string GetDirectoryTypeName(string directoryType)
         {
-            if(directoryType != null)
-            {
-                for(int i = 0; i < DirectoryTypes.Length; i++)
-                {
-                    if(directoryType.Equals(DirectoryTypes[i], StringComparison.OrdinalIgnoreCase))
-                    {
-                        return DirectoryTypeNames[i];
-                    }
-                }
-            }
-            return null;
+            if(directoryType == null) return null;
+            int index = DirectoryTypes.FindIndex(type => directoryType.Equals(type, StringComparison.OrdinalIgnoreCase));
+            if(index >= 0) return DirectoryTypeNames[index];
+            else return null;
         }
 
         private static string GetPerceivedTypeName(string perceivedType)
         {
             int index = 0;
-            if(perceivedType != null)
-            {
-                for(int i = 1; i < PerceivedTypes.Length; i++)
-                {
-                    if(perceivedType.Equals(PerceivedTypes[i], StringComparison.OrdinalIgnoreCase)) index = i;
-                }
-            }
+            if(perceivedType != null) index = PerceivedTypes.FindIndex(type => perceivedType.Equals(type, StringComparison.OrdinalIgnoreCase));
+            if(index == -1) index = 0;
             return PerceivedTypeNames[index];
         }
 
@@ -172,19 +154,21 @@ namespace ContextMenuManager.Controls
 
         private static string CurrentExtensionPerceivedType
         {
-            get => Registry.GetValue(CurrentExtensionPath, "PerceivedType", null)?.ToString();
+            get => GetPerceivedType(CurrentExtension);
             set
             {
-                if(value == null) RegistryEx.DeleteValue(CurrentExtensionPath, "PerceivedType");
-                else Registry.SetValue(CurrentExtensionPath, "PerceivedType", value, RegistryValueKind.String);
+                string path = $@"{RegistryEx.CLASSES_ROOT}\{CurrentExtension}";
+                if(value == null) RegistryEx.DeleteValue(path, "PerceivedType");
+                else Registry.SetValue(path, "PerceivedType", value, RegistryValueKind.String);
             }
         }
 
         private static string GetShellPath(string scenePath) => $@"{scenePath}\shell";
         private static string GetShellExPath(string scenePath) => $@"{scenePath}\ShellEx";
         private static string GetSysAssExtPath(string typeName) => typeName != null ? $@"{SYSFILEASSPATH}\{typeName}" : null;
-        private static string GetOpenModePath(string extension) => extension != null ? $@"{RegistryEx.CLASSESROOT}\{FileExtension.GetOpenMode(extension)}" : null;
-        private static string CurrentExtensionPath => $@"{RegistryEx.CLASSESROOT}\{CurrentExtension}";
+        private static string GetOpenMode(string extension) => FileExtension.GetOpenMode(extension);
+        private static string GetOpenModePath(string extension) => extension != null ? $@"{RegistryEx.CLASSES_ROOT}\{GetOpenMode(extension)}" : null;
+        private static string GetPerceivedType(string extension) => Registry.GetValue($@"{RegistryEx.CLASSES_ROOT}\{extension}", "PerceivedType", null)?.ToString();
 
         public Scenes Scene { get; set; }
 
@@ -203,7 +187,7 @@ namespace ContextMenuManager.Controls
                     scenePath = MENUPATH_BACKGROUND; break;
                 case Scenes.Desktop:
                     //Vista系统没有这一项
-                    if(WindowsOsVersion.IsEqualVista) return;
+                    if(WinOsVersion.Current == WinOsVersion.Vista) return;
                     scenePath = MENUPATH_DESKTOP; break;
                 case Scenes.Drive:
                     scenePath = MENUPATH_DRIVE; break;
@@ -215,13 +199,13 @@ namespace ContextMenuManager.Controls
                     scenePath = MENUPATH_RECYCLEBIN; break;
                 case Scenes.Library:
                     //Vista系统没有这一项
-                    if(WindowsOsVersion.IsEqualVista) return;
+                    if(WinOsVersion.Current == WinOsVersion.Vista) return;
                     scenePath = MENUPATH_LIBRARY; break;
                 case Scenes.LnkFile:
                     scenePath = GetOpenModePath(".lnk"); break;
                 case Scenes.UwpLnk:
                     //Win8之前没有Uwp
-                    if(WindowsOsVersion.IsBefore8) return;
+                    if(WinOsVersion.Current < WinOsVersion.Win8) return;
                     scenePath = MENUPATH_UWPLNK; break;
                 case Scenes.ExeFile:
                     scenePath = GetSysAssExtPath(".exe"); break;
@@ -245,7 +229,7 @@ namespace ContextMenuManager.Controls
                     scenePath = CurrentCustomRegPath; break;
                 case Scenes.CommandStore:
                     //Vista系统没有这一项
-                    if(WindowsOsVersion.IsEqualVista) return;
+                    if(WinOsVersion.Current == WinOsVersion.Vista) return;
                     this.AddNewItem(RegistryEx.GetParentPath(ShellItem.CommandStorePath));
                     this.LoadStoreItems();
                     return;
@@ -260,14 +244,9 @@ namespace ContextMenuManager.Controls
             }
             this.AddNewItem(scenePath);
             this.LoadItems(scenePath);
-            if(WindowsOsVersion.ISAfterOrEqual10)
+            if(WinOsVersion.Current >= WinOsVersion.Win10)
             {
-                string webPath = AppConfig.WebUwpModeItemsDic;
-                string userPath = AppConfig.UserUwpModeItemsDic;
-                string contents = Properties.Resources.UwpModeItemsDic;
-                if(!File.Exists(webPath)) File.WriteAllText(webPath, contents, Encoding.Unicode);
-                this.LoadUwpModeItem(webPath);
-                this.LoadUwpModeItem(userPath);
+                this.LoadUwpModeItem();
             }
             switch(Scene)
             {
@@ -331,7 +310,7 @@ namespace ContextMenuManager.Controls
                 bool isDragDrop = Scene == Scenes.DragDrop;
                 RegTrustedInstaller.TakeRegTreeOwnerShip(shellExKey.Name);
                 Dictionary<string, Guid> dic = ShellExItem.GetPathAndGuids(shellExPath, isDragDrop);
-                GroupPathItem groupItem = null;
+                FoldGroupItem groupItem = null;
                 if(isDragDrop)
                 {
                     groupItem = GetDragDropGroupItem(shellExPath);
@@ -343,16 +322,20 @@ namespace ContextMenuManager.Controls
                     if(!names.Contains(keyName))
                     {
                         ShellExItem item = new ShellExItem(dic[path], path);
-                        if(groupItem != null) item.FoldGroupItem = groupItem;
+                        if(groupItem != null)
+                        {
+                            item.FoldGroupItem = groupItem;
+                            item.Indent();
+                        }
                         this.AddItem(item);
                         names.Add(keyName);
                     }
                 }
-                if(groupItem != null) groupItem.IsFold = true;
+                groupItem?.SetVisibleWithSubItemCount();
             }
         }
 
-        private GroupPathItem GetDragDropGroupItem(string shellExPath)
+        private FoldGroupItem GetDragDropGroupItem(string shellExPath)
         {
             string text = null;
             Image image = null;
@@ -376,18 +359,33 @@ namespace ContextMenuManager.Controls
                     image = AppImage.AllObjects;
                     break;
             }
-            return new GroupPathItem(shellExPath, ObjectPath.PathType.Registry) { Text = text, Image = image };
+            return new FoldGroupItem(shellExPath, ObjectPath.PathType.Registry) { Text = text, Image = image };
         }
 
         private void AddNewItem(string scenePath)
         {
+            if(scenePath == null) return;
             string shellPath = GetShellPath(scenePath);
-            NewItem newItem = new NewItem { Visible = scenePath != null };
+            NewItem newItem = new NewItem();
             PictureButton btnAddExisting = new PictureButton(AppImage.AddExisting);
+            PictureButton btnEnhanceMenu = new PictureButton(AppImage.Enhance);
             ToolTipBox.SetToolTip(btnAddExisting, AppString.Tip.AddFromPublic);
-            btnAddExisting.Visible = Scene != Scenes.DragDrop && !string.Equals(shellPath, ShellItem.CommandStorePath, StringComparison.OrdinalIgnoreCase);
-            newItem.AddCtr(btnAddExisting);
+            ToolTipBox.SetToolTip(btnEnhanceMenu, AppString.StatusBar.EnhanceMenu);
+            if(Scene == Scenes.DragDrop || ShellItem.CommandStorePath.Equals(shellPath,
+                StringComparison.OrdinalIgnoreCase)) btnAddExisting.Visible = false;
+            else
+            {
+                using(RegistryKey key = RegistryEx.GetRegistryKey(ShellItem.CommandStorePath))
+                {
+                    List<string> subKeyNames = key.GetSubKeyNames().ToList();
+                    if(AppConfig.HideSysStoreItems) subKeyNames.RemoveAll(name => name.StartsWith("Windows.", StringComparison.OrdinalIgnoreCase));
+                    if(subKeyNames.Count == 0) btnAddExisting.Visible = false;
+                }
+            }
+            if(!XmlDicHelper.EnhanceMenuPathDic.ContainsKey(scenePath)) btnEnhanceMenu.Visible = false;
+            newItem.AddCtrs(new[] { btnAddExisting, btnEnhanceMenu });
             this.AddItem(newItem);
+
             newItem.AddNewItem += () =>
             {
                 bool isShell;
@@ -406,6 +404,7 @@ namespace ContextMenuManager.Controls
                 if(isShell) this.AddNewShellItem(scenePath);
                 else this.AddNewShellExItem(scenePath);
             };
+
             btnAddExisting.MouseDown += (sender, e) =>
             {
                 using(ShellStoreDialog dlg = new ShellStoreDialog())
@@ -425,6 +424,28 @@ namespace ContextMenuManager.Controls
                     }
                 }
             };
+
+            btnEnhanceMenu.MouseDown += (sender, e) =>
+            {
+                string tempPath1 = Path.GetTempFileName();
+                string tempPath2 = Path.GetTempFileName();
+                ExternalProgram.ExportRegistry(scenePath, tempPath1);
+                using(EnhanceMenusDialog dlg = new EnhanceMenusDialog())
+                {
+                    dlg.ScenePath = scenePath;
+                    dlg.ShowDialog();
+                }
+                ExternalProgram.ExportRegistry(scenePath, tempPath2);
+                string str1 = File.ReadAllText(tempPath1);
+                string str2 = File.ReadAllText(tempPath2);
+                File.Delete(tempPath1);
+                File.Delete(tempPath2);
+                if(!str1.Equals(str2))
+                {
+                    MainForm mainForm = (MainForm)this.FindForm();
+                    mainForm.JumpItem(mainForm.ToolBar.SelectedIndex, mainForm.SideBar.SelectedIndex);
+                }
+            };
         }
 
         private void AddNewShellItem(string scenePath)
@@ -482,7 +503,7 @@ namespace ContextMenuManager.Controls
                     string shellExPath = GetShellExPath(scenePath);
                     if(ShellExItem.GetPathAndGuids(shellExPath, isDragDrop).Values.Contains(guid))
                     {
-                        MessageBoxEx.Show(AppString.Message.HasBeenAdded);
+                        AppMessageBox.Show(AppString.Message.HasBeenAdded);
                     }
                     else
                     {
@@ -494,13 +515,15 @@ namespace ContextMenuManager.Controls
                         {
                             if(isDragDrop)
                             {
-                                if(this.Controls[i] is GroupPathItem groupItem)
+                                if(this.Controls[i] is FoldGroupItem groupItem)
                                 {
-                                    if(groupItem.TargetPath.Equals(shellExPath, StringComparison.OrdinalIgnoreCase))
+                                    if(groupItem.GroupPath.Equals(shellExPath, StringComparison.OrdinalIgnoreCase))
                                     {
                                         this.InsertItem(item, i + 1);
                                         item.FoldGroupItem = groupItem;
+                                        groupItem.SetVisibleWithSubItemCount();
                                         item.Visible = !groupItem.IsFold;
+                                        item.Indent();
                                         break;
                                     }
                                 }
@@ -518,7 +541,7 @@ namespace ContextMenuManager.Controls
                 }
                 else
                 {
-                    MessageBoxEx.Show(AppString.Message.MalformedGuid);
+                    AppMessageBox.Show(AppString.Message.MalformedGuid);
                 }
             }
         }
@@ -527,37 +550,35 @@ namespace ContextMenuManager.Controls
         {
             using(RegistryKey shellKey = RegistryEx.GetRegistryKey(ShellItem.CommandStorePath))
             {
-                bool flag = AppConfig.HideSysStoreItems;
                 foreach(string itemName in shellKey.GetSubKeyNames())
                 {
-                    if(flag && itemName.StartsWith("Windows.", StringComparison.OrdinalIgnoreCase)) continue;
+                    if(AppConfig.HideSysStoreItems && itemName.StartsWith("Windows.", StringComparison.OrdinalIgnoreCase)) continue;
                     this.AddItem(new StoreShellItem($@"{ShellItem.CommandStorePath}\{itemName}", true, false));
                 }
             }
         }
 
-        private void LoadUwpModeItem(string xmlPath)
+        private void LoadUwpModeItem()
         {
-            XmlDocument doc = new XmlDocument();
-            try { doc.LoadXml(File.ReadAllText(xmlPath, EncodingType.GetType(xmlPath)).Trim()); }
-            catch { return; }
-            foreach(XmlElement sceneXE in doc.DocumentElement.ChildNodes)
+            foreach(XmlDocument doc in XmlDicHelper.UwpModeItemsDic)
             {
-                if(sceneXE.Name == Scene.ToString())
+                if(doc?.DocumentElement == null) continue;
+                foreach(XmlNode sceneXN in doc.DocumentElement.ChildNodes)
                 {
-                    foreach(XmlElement itemXE in sceneXE.ChildNodes)
+                    if(sceneXN.Name == Scene.ToString())
                     {
-                        if(GuidEx.TryParse(itemXE.GetAttribute("Guid"), out Guid guid))
+                        foreach(XmlElement itemXE in sceneXN.ChildNodes)
                         {
-                            bool isAdded = false;
-                            foreach(Control ctr in this.Controls)
-                            {
-                                if(ctr is UwpModeItem item && item.Guid == guid) { isAdded = true; break; }
-                            }
-                            if(isAdded) continue;
-                            string uwpName = GuidInfo.GetUwpName(guid);
-                            if(!string.IsNullOrEmpty(uwpName))
+                            if(GuidEx.TryParse(itemXE.GetAttribute("Guid"), out Guid guid))
                             {
+                                bool isAdded = false;
+                                foreach(Control ctr in this.Controls)
+                                {
+                                    if(ctr is UwpModeItem item && item.Guid == guid) { isAdded = true; break; }
+                                }
+                                if(isAdded) continue;
+                                if(GuidInfo.GetFilePath(guid) == null) continue;
+                                string uwpName = GuidInfo.GetUwpName(guid);
                                 this.AddItem(new UwpModeItem(uwpName, guid));
                             }
                         }
@@ -574,9 +595,8 @@ namespace ContextMenuManager.Controls
             {
                 string extension = Path.GetExtension(filePath).ToLower();
                 if(extension == string.Empty) extension = ".";
-                string perceivedType = Registry.GetValue($@"{RegistryEx.CLASSESROOT}\{extension}", "PerceivedType", null)?.ToString();
+                string perceivedType = GetPerceivedType(extension);
                 string perceivedTypeName = GetPerceivedTypeName(perceivedType);
-                string openMode = FileExtension.GetOpenMode(extension);
                 JumpItem.TargetPath = filePath;
                 JumpItem.Extension = extension;
                 JumpItem.PerceivedType = perceivedType;
@@ -584,7 +604,7 @@ namespace ContextMenuManager.Controls
                 this.AddItem(new JumpItem(Scenes.AllObjects));
                 if(extension == ".exe") this.AddItem(new JumpItem(Scenes.ExeFile));
                 else this.AddItem(new JumpItem(Scenes.CustomExtension));
-                if(openMode == null) this.AddItem(new JumpItem(Scenes.UnknownType));
+                if(GetOpenMode(extension) == null) this.AddItem(new JumpItem(Scenes.UnknownType));
                 if(perceivedType != null) this.AddItem(new JumpItem(Scenes.PerceivedType));
             }
 
@@ -599,6 +619,7 @@ namespace ContextMenuManager.Controls
                 }
                 else
                 {
+                    this.AddItem(new JumpItem(Scenes.Folder));
                     this.AddItem(new JumpItem(Scenes.Drive));
                 }
             }
@@ -608,32 +629,20 @@ namespace ContextMenuManager.Controls
                 string extension = Path.GetExtension(CurrentFileObjectPath).ToLower();
                 if(extension == ".lnk")
                 {
-                    this.AddItem(new JumpItem(Scenes.LnkFile));
                     using(ShellLink shellLink = new ShellLink(CurrentFileObjectPath))
                     {
                         string targetPath = shellLink.TargetPath;
-                        if(File.Exists(targetPath))
-                        {
-                            AddFileItems(targetPath);
-                        }
-                        else if(Directory.Exists(targetPath))
-                        {
-                            AddDirItems(targetPath);
-                        }
+                        if(File.Exists(targetPath)) AddFileItems(targetPath);
+                        else if(Directory.Exists(targetPath)) AddDirItems(targetPath);
                     }
+                    this.AddItem(new JumpItem(Scenes.LnkFile));
                 }
-                else
-                {
-                    AddFileItems(CurrentFileObjectPath);
-                }
-            }
-            else if(Directory.Exists(CurrentFileObjectPath))
-            {
-                AddDirItems(CurrentFileObjectPath);
+                else AddFileItems(CurrentFileObjectPath);
             }
+            else if(Directory.Exists(CurrentFileObjectPath)) AddDirItems(CurrentFileObjectPath);
         }
 
-        public sealed class SelectItem : MyListItem
+        sealed class SelectItem : MyListItem
         {
             public SelectItem(Scenes scene)
             {
@@ -642,13 +651,13 @@ namespace ContextMenuManager.Controls
                 this.SetTextAndTip();
                 this.SetImage();
                 BtnSelect.MouseDown += (sender, e) => ShowSelectDialog();
-                this.ImageDoubleClick += () => ShowSelectDialog();
-                this.TextDoubleClick += () => ShowSelectDialog();
+                this.MouseDoubleClick += (sender, e) => ShowSelectDialog();
             }
 
             readonly PictureButton BtnSelect = new PictureButton(AppImage.Select);
 
             public Scenes Scene { get; private set; }
+            public string SelectedPath { get; set; }
 
             private void SetTextAndTip()
             {
@@ -672,23 +681,25 @@ namespace ContextMenuManager.Controls
                         else text = AppString.Other.CurrentDirectoryType.Replace("%s", GetDirectoryTypeName(CurrentDirectoryType));
                         break;
                     case Scenes.CustomRegPath:
+                        this.SelectedPath = CurrentCustomRegPath;
                         tip = AppString.Other.SelectRegPath;
-                        if(CurrentCustomRegPath == null) text = tip;
-                        else text = AppString.Other.CurrentRegPath + "\n" + CurrentCustomRegPath;
+                        if(this.SelectedPath == null) text = tip;
+                        else text = AppString.Other.CurrentRegPath + "\n" + this.SelectedPath;
                         break;
                     case Scenes.MenuAnalysis:
+                        this.SelectedPath = CurrentFileObjectPath;
                         tip = AppString.Tip.DropOrSelectObject;
-                        if(CurrentFileObjectPath == null) text = tip;
-                        else text = AppString.Other.CurrentFilePath + "\n" + CurrentFileObjectPath;
+                        if(this.SelectedPath == null) text = tip;
+                        else text = AppString.Other.CurrentFilePath + "\n" + this.SelectedPath;
                         break;
                     case Scenes.DragDrop:
+                        this.SelectedPath = GetDropEffectName();
                         tip = AppString.Dialog.SelectDropEffect;
-                        text = AppString.Other.SetDefaultDropEffect + " " + GetDropEffectName();
+                        text = AppString.Other.SetDefaultDropEffect + " " + this.SelectedPath;
                         break;
                     case Scenes.CustomExtensionPerceivedType:
                         tip = AppString.Dialog.SelectPerceivedType;
-                        text = AppString.Other.SetPerceivedType.Replace("%s", CurrentExtension)
-                            + " " + GetPerceivedTypeName(CurrentExtensionPerceivedType);
+                        text = AppString.Other.SetPerceivedType.Replace("%s", CurrentExtension) + " " + GetPerceivedTypeName(CurrentExtensionPerceivedType);
                         break;
                 }
                 ToolTipBox.SetToolTip(BtnSelect, tip);
@@ -753,12 +764,12 @@ namespace ContextMenuManager.Controls
                     case Scenes.MenuAnalysis:
                         dlg = new SelectDialog
                         {
-                            Items = FileObjectTypes,
+                            Items = new[] { AppString.SideBar.File, AppString.SideBar.Directory },
                             Title = AppString.Dialog.SelectObjectType,
                         };
                         break;
                     case Scenes.CustomRegPath:
-                        if(MessageBoxEx.Show(AppString.Message.SelectRegPath,
+                        if(AppMessageBox.Show(AppString.Message.SelectRegPath,
                             MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) return;
                         Form frm = this.FindForm();
                         frm.Hide();
@@ -804,8 +815,7 @@ namespace ContextMenuManager.Controls
                     case Scenes.CustomExtensionPerceivedType:
                         string selected = PerceivedTypes[dlg.SelectedIndex];
                         CurrentExtensionPerceivedType = selected;
-                        this.Text = AppString.Other.SetPerceivedType.Replace("%s", CurrentExtension)
-                            + " " + GetPerceivedTypeName(selected);
+                        this.Text = AppString.Other.SetPerceivedType.Replace("%s", CurrentExtension) + " " + GetPerceivedTypeName(selected);
                         break;
                     case Scenes.DragDrop:
                         switch(dlg.SelectedIndex)
@@ -853,73 +863,73 @@ namespace ContextMenuManager.Controls
             public JumpItem(Scenes scene)
             {
                 this.AddCtr(btnJump);
-                string text = "";
                 Image image = null;
                 int index1 = 0;
                 int index2 = 0;
+                string[] txts = null;
                 switch(scene)
                 {
                     case Scenes.File:
-                        text = $"[ {AppString.ToolBar.Home} ]  ▶  [ {AppString.SideBar.File} ]";
+                        txts = new[] { AppString.ToolBar.Home, AppString.SideBar.File };
                         image = AppImage.File;
                         break;
                     case Scenes.Folder:
-                        text = $"[ {AppString.ToolBar.Home} ]  ▶  [ {AppString.SideBar.Folder} ]";
+                        txts = new[] { AppString.ToolBar.Home, AppString.SideBar.Folder };
                         image = AppImage.Folder;
                         index2 = 1;
                         break;
                     case Scenes.Directory:
-                        text = $"[ {AppString.ToolBar.Home} ]  ▶  [ {AppString.SideBar.Directory} ]";
+                        txts = new[] { AppString.ToolBar.Home, AppString.SideBar.Directory };
                         image = AppImage.Directory;
                         index2 = 2;
                         break;
                     case Scenes.Drive:
-                        text = $"[ {AppString.ToolBar.Home} ]  ▶  [ {AppString.SideBar.Drive} ]";
+                        txts = new[] { AppString.ToolBar.Home, AppString.SideBar.Drive };
                         image = AppImage.Drive;
                         index2 = 5;
                         break;
                     case Scenes.AllObjects:
-                        text = $"[ {AppString.ToolBar.Home} ]  ▶  [ {AppString.SideBar.AllObjects} ]";
+                        txts = new[] { AppString.ToolBar.Home, AppString.SideBar.AllObjects };
                         image = AppImage.AllObjects;
                         index2 = 6;
                         break;
                     case Scenes.LnkFile:
-                        text = $"[ {AppString.ToolBar.Type} ]  ▶  [ {AppString.SideBar.LnkFile} ]";
+                        txts = new[] { AppString.ToolBar.Type, AppString.SideBar.LnkFile };
                         image = AppImage.LnkFile;
                         index1 = 1;
                         break;
                     case Scenes.ExeFile:
-                        text = $"[ {AppString.ToolBar.Type} ]  ▶  [ {AppString.SideBar.ExeFile} ]";
+                        txts = new[] { AppString.ToolBar.Type, AppString.SideBar.ExeFile };
                         using(Icon icon = ResourceIcon.GetExtensionIcon(TargetPath)) image = icon.ToBitmap();
                         index1 = 1;
                         index2 = 2;
                         break;
                     case Scenes.UnknownType:
-                        text = $"[ {AppString.ToolBar.Type} ]  ▶  [ {AppString.SideBar.UnknownType} ]";
+                        txts = new[] { AppString.ToolBar.Type, AppString.SideBar.UnknownType };
                         image = AppImage.NotFound;
                         index1 = 1;
                         index2 = 8;
                         break;
                     case Scenes.CustomExtension:
-                        text = $"[ {AppString.ToolBar.Type} ]  ▶  [ {AppString.SideBar.CustomExtension} ]  ▶  [ {Extension} ]";
+                        txts = new[] { AppString.ToolBar.Type, AppString.SideBar.CustomExtension, Extension };
                         using(Icon icon = ResourceIcon.GetExtensionIcon(Extension)) image = icon.ToBitmap();
                         index1 = 1;
                         index2 = 4;
                         break;
                     case Scenes.PerceivedType:
-                        text = $"[ {AppString.ToolBar.Type} ]  ▶  [ {AppString.SideBar.PerceivedType} ]  ▶  [ {GetPerceivedTypeName(PerceivedType)} ]";
+                        txts = new[] { AppString.ToolBar.Type, AppString.SideBar.PerceivedType, GetPerceivedTypeName(PerceivedType) };
                         image = AppImage.File;
                         index1 = 1;
                         index2 = 5;
                         break;
                     case Scenes.DirectoryType:
-                        text = $"[ {AppString.ToolBar.Type} ]  ▶  [ {AppString.SideBar.DirectoryType} ]";
+                        txts = new[] { AppString.ToolBar.Type, AppString.SideBar.DirectoryType };
                         image = AppImage.Directory;
                         index1 = 1;
                         index2 = 6;
                         break;
                 }
-                this.Text = text;
+                this.Text = "[ " + string.Join(" ]  ▶  [ ", txts) + " ]";
                 this.Image = image;
                 void SwitchTab()
                 {
@@ -930,11 +940,10 @@ namespace ContextMenuManager.Controls
                         case Scenes.PerceivedType:
                             CurrentPerceivedType = PerceivedType; break;
                     }
-                    ((MainForm)this.FindForm()).SwitchTab(index1, index2);
+                    ((MainForm)this.FindForm()).JumpItem(index1, index2);
                 };
                 btnJump.MouseDown += (sender, e) => SwitchTab();
-                this.ImageDoubleClick += () => SwitchTab();
-                this.TextDoubleClick += () => SwitchTab();
+                this.DoubleClick += (sender, e) => SwitchTab();
             }
 
             readonly PictureButton btnJump = new PictureButton(AppImage.Jump);

+ 41 - 18
ContextMenuManager/Controls/ShellNewItem.cs

@@ -1,6 +1,7 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
 using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using Microsoft.Win32;
 using System;
 using System.Drawing;
@@ -10,12 +11,29 @@ using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls
 {
-    /* 新建菜单项成立条件与相关规则:
-     * 1.有关联打开方式,优先为HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\<扩展名>\UserChoice的ProgId键值(以下简称<OpenMode>)
-     * 再次为HKCR\<扩展名>的默认键值(以下简称<DefaultOpenMode>)
-     * 2.<DefaultOpenMode>不能为空,HKCR\<DefaultOpenMode>项需存在,<DefaultOpenMode>不一定为关联打开方式,
-     * 但当ShellNew项中不存在合法的MenuText键值时,菜单名称取HKCR\<DefaultOpenMode>的FriendlyTypeName键值或者默认值,后两个键值都为空时也不成立
-     * 3.ShellNew项中存在"NullFile", "Data", "FileName", "Directory", "Command"中的一个或多个键值*/
+    /* 新建菜单项成立条件与相关规则:(恶心的关联方式,反复研究了好久)
+     * 
+     * 1.① 扩展名的关联打开方式(以下简称[OpenMode],对应路径简称[OpenModePath])
+     *   ② HKCR默认值打开方式(以下简称[DefaultOpenMode],对应路径简称[DefaultOpenModePath])
+     *   以上两个打开方式不一定相同
+     * 
+     * 2.① [DefaultOpenMode]不能为空,[DefaultOpenModePath]必须存在
+     *   ② 菜单文本也不可为空
+     *   ③ ShellNew项中必须存在 NullFile、Data、FileName、Directory、Command 中的一个或多个键值
+     *   以上三个条件缺一不可,否则菜单不成立
+     *   
+     * 3.菜单名称取值优先级:
+     *   ① ShellNew项的 MenuText 键值(必须为带@的资源文件字符串)
+     *   ② [DefaultOpenModePath] 的 FriendlyTypeName 键值
+     *   ③ [DefaultOpenModePath] 的默认键值
+     *   ④ ②和③虽然不是第一优先级,但至少得存在一个,否则菜单不成立
+     *   
+     * 4.菜单图标取值优先级:
+     *   ① ShellNew项的 IconPath 键值
+     *   ② [OpenModePath]\DefaultIcon 的默认键值
+     *   ③ 关联程序图标
+     */
+
     sealed class ShellNewItem : MyListItem, IChkVisibleItem, ITsiTextItem, IBtnShowMenuItem, IBtnMoveUpDownItem,
          ITsiIconItem, ITsiWebSearchItem, ITsiFilePathItem, ITsiRegPathItem, ITsiRegDeleteItem, ITsiRegExportItem, ITsiCommandItem
     {
@@ -52,10 +70,9 @@ namespace ContextMenuManager.Controls
         private string SnKeyName => RegistryEx.GetKeyName(RegPath);
         private string BackupPath => $@"{RegistryEx.GetParentPath(RegPath)}\{(ItemVisible ? SnParts[1] : SnParts[0])}";
         private string OpenMode => FileExtension.GetOpenMode(Extension);//关联打开方式
-        private string OpenModePath => $@"{RegistryEx.CLASSESROOT}\{OpenMode}";//关联打开方式注册表路径
-        private string DefaultOpenMode => Registry.GetValue($@"{RegistryEx.CLASSESROOT}\{Extension}", "", null)?.ToString();//默认关联打开方式
-        private string DefaultOpenModePath => $@"{RegistryEx.CLASSESROOT}\{DefaultOpenMode}";//默认关联打开方式注册表路径
-        private string ConfigPath => $@"{RegPath}\Config";
+        private string OpenModePath => $@"{RegistryEx.CLASSES_ROOT}\{OpenMode}";//关联打开方式注册表路径
+        private string DefaultOpenMode => Registry.GetValue($@"{RegistryEx.CLASSES_ROOT}\{Extension}", "", null)?.ToString();//HKCR默认值打开方式
+        private string DefaultOpenModePath => $@"{RegistryEx.CLASSES_ROOT}\{DefaultOpenMode}";//HKCR默认值打开方式路径
         public bool CanSort => !UnableSortExtensions.Contains(Extension, StringComparer.OrdinalIgnoreCase);//能够排序的
         private bool CanEditData => UnableEditDataValues.All(value => Registry.GetValue(RegPath, value, null) == null);//能够编辑初始数据的
         private bool CanChangeCommand => UnableChangeCommandValues.All(value => Registry.GetValue(RegPath, value, null) == null);//能够更改菜单命令的
@@ -65,7 +82,7 @@ namespace ContextMenuManager.Controls
         {
             get
             {
-                string filePath = FileExtension.GetExecutablePath(Extension);
+                string filePath = FileExtension.GetExtentionInfo(FileExtension.AssocStr.Executable, Extension);
                 if(File.Exists(filePath)) return filePath;
                 using(RegistryKey oKey = RegistryEx.GetRegistryKey(OpenModePath))
                 {
@@ -103,8 +120,11 @@ namespace ContextMenuManager.Controls
             get
             {
                 string name = Registry.GetValue(RegPath, "MenuText", null)?.ToString();
-                name = ResourceString.GetDirectString(name);
-                if(!string.IsNullOrEmpty(name)) return name;
+                if(name!=null&&name.StartsWith("@"))
+                {
+                    name = ResourceString.GetDirectString(name);
+                    if(!string.IsNullOrEmpty(name)) return name;
+                }
                 name = Registry.GetValue(DefaultOpenModePath, "FriendlyTypeName", null)?.ToString();
                 name = ResourceString.GetDirectString(name);
                 if(!string.IsNullOrEmpty(name)) return name;
@@ -138,7 +158,10 @@ namespace ContextMenuManager.Controls
             get
             {
                 string location = IconLocation;
-                if(location == null || location.StartsWith("@")) return ResourceIcon.GetExtensionIcon(Extension);
+                if(location == null || location.StartsWith("@"))
+                {
+                    return ResourceIcon.GetExtensionIcon(Extension);
+                } 
                 Icon icon = ResourceIcon.GetIcon(location, out string path, out int index);
                 if(icon == null) icon = ResourceIcon.GetIcon(path = "imageres.dll", index = -2);
                 IconPath = path; IconIndex = index;
@@ -179,13 +202,13 @@ namespace ContextMenuManager.Controls
             get
             {
                 if(DefaultBeforeSeparator) return true;
-                else return Registry.GetValue(ConfigPath, "BeforeSeparator", null) != null;
+                else return Registry.GetValue($@"{RegPath}\Config", "BeforeSeparator", null) != null;
             }
             set
             {
                 if(value)
                 {
-                    Registry.SetValue(ConfigPath, "BeforeSeparator", "");
+                    Registry.SetValue($@"{RegPath}\Config", "BeforeSeparator", "");
                 }
                 else
                 {
@@ -264,7 +287,7 @@ namespace ContextMenuManager.Controls
 
         private void EditInitialData()
         {
-            if(MessageBoxEx.Show(AppString.Message.EditInitialData,
+            if(AppMessageBox.Show(AppString.Message.EditInitialData,
                 MessageBoxButtons.YesNo) != DialogResult.Yes) return;
             using(InputDialog dlg = new InputDialog
             {
@@ -294,7 +317,7 @@ namespace ContextMenuManager.Controls
         {
             RegistryEx.DeleteKeyTree(this.RegPath);
             RegistryEx.DeleteKeyTree(this.BackupPath);
-            this.Dispose();
+            this.Parent.Controls.Remove(this);
             if(ShellNewList.ShellNewLockItem.IsLocked) Owner.SaveSorting();
         }
     }

+ 35 - 6
ContextMenuManager/Controls/ShellNewList.cs

@@ -1,13 +1,16 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
 using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using Microsoft.Win32;
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Security.AccessControl;
 using System.Security.Principal;
 using System.Windows.Forms;
+using System.Xml;
 
 namespace ContextMenuManager.Controls
 {
@@ -34,7 +37,7 @@ namespace ContextMenuManager.Controls
             using(RegistryKey root = Registry.ClassesRoot)
             {
                 extensions.AddRange(Array.FindAll(root.GetSubKeyNames(), keyName => keyName.StartsWith(".")));
-                if(WindowsOsVersion.IsBefore10) extensions.Add("Briefcase");//公文包(Win10没有)
+                if(WinOsVersion.Current < WinOsVersion.Win10) extensions.Add("Briefcase");//公文包(Win10没有)
                 this.LoadItems(extensions);
             }
         }
@@ -63,7 +66,7 @@ namespace ContextMenuManager.Controls
                     using(RegistryKey extKey = root.OpenSubKey(extension))
                     {
                         string defalutOpenMode = extKey?.GetValue("")?.ToString();
-                        if(string.IsNullOrEmpty(defalutOpenMode)) continue;
+                        if(string.IsNullOrEmpty(defalutOpenMode) || defalutOpenMode.Length > 255) continue;
                         using(RegistryKey openModeKey = root.OpenSubKey(defalutOpenMode))
                         {
                             if(openModeKey == null) continue;
@@ -144,7 +147,7 @@ namespace ContextMenuManager.Controls
                     string openMode = FileExtension.GetOpenMode(extension);
                     if(string.IsNullOrEmpty(openMode))
                     {
-                        if(MessageBoxEx.Show(AppString.Message.NoOpenModeExtension,
+                        if(AppMessageBox.Show(AppString.Message.NoOpenModeExtension,
                             MessageBoxButtons.OKCancel) == DialogResult.OK)
                         {
                             ExternalProgram.ShowOpenWithDialog(extension);
@@ -157,7 +160,7 @@ namespace ContextMenuManager.Controls
                         {
                             if(item.Extension.Equals(extension, StringComparison.OrdinalIgnoreCase))
                             {
-                                MessageBoxEx.Show(AppString.Message.HasBeenAdded);
+                                AppMessageBox.Show(AppString.Message.HasBeenAdded);
                                 return;
                             }
                         }
@@ -170,7 +173,7 @@ namespace ContextMenuManager.Controls
                         string defaultOpenMode = exKey.GetValue("")?.ToString();
                         if(string.IsNullOrEmpty(defaultOpenMode)) exKey.SetValue("", openMode);
 
-                        byte[] bytes = Updater.GetShellNewData(extension);
+                        byte[] bytes = GetWebShellNewData(extension);
                         if(bytes != null) snKey.SetValue("Data", bytes, RegistryValueKind.Binary);
                         else snKey.SetValue("NullFile", "", RegistryValueKind.String);
 
@@ -179,7 +182,7 @@ namespace ContextMenuManager.Controls
                         item.Focus();
                         if(item.ItemText.IsNullOrWhiteSpace())
                         {
-                            item.ItemText = FileExtension.GetFriendlyDocName(extension);
+                            item.ItemText = FileExtension.GetExtentionInfo(FileExtension.AssocStr.FriendlyDocName, extension);
                         }
                         if(ShellNewLockItem.IsLocked) this.SaveSorting();
                     }
@@ -187,6 +190,32 @@ namespace ContextMenuManager.Controls
             };
         }
 
+        private static byte[] GetWebShellNewData(string extension)
+        {
+            string apiUrl = AppConfig.RequestUseGithub ? AppConfig.GithubShellNewApi : AppConfig.GiteeShellNewApi;
+            using(UAWebClient client = new UAWebClient())
+            {
+                XmlDocument doc = client.GetWebJsonToXml(apiUrl);
+                if(doc == null) return null;
+                foreach(XmlNode node in doc.FirstChild.ChildNodes)
+                {
+                    XmlNode nameXN = node.SelectSingleNode("name");
+                    string str = Path.GetExtension(nameXN.InnerText);
+                    if(string.Equals(str, extension, StringComparison.OrdinalIgnoreCase))
+                    {
+                        try
+                        {
+                            string dirUrl = AppConfig.RequestUseGithub ? AppConfig.GithubShellNewRawDir : AppConfig.GiteeShellNewRawDir;
+                            string fileUrl = $"{dirUrl}/{nameXN.InnerText}";
+                            return client.DownloadData(fileUrl);
+                        }
+                        catch { return null; }
+                    }
+                }
+                return null;
+            }
+        }
+
         public sealed class ShellNewLockItem : MyListItem, IChkVisibleItem, IBtnShowMenuItem, ITsiWebSearchItem, ITsiRegPathItem
         {
             public ShellNewLockItem(ShellNewList list)

+ 17 - 15
ContextMenuManager/Controls/ShellStoreDialog.cs

@@ -1,5 +1,6 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.Collections.Generic;
 using System.Drawing;
@@ -20,6 +21,7 @@ namespace ContextMenuManager.Controls
         {
             using(ShellStoreForm frm = new ShellStoreForm(this.ShellPath, this.Filter, this.IsReference))
             {
+                frm.TopMost = AppConfig.TopMost;
                 bool flag = frm.ShowDialog() == DialogResult.OK;
                 if(flag) this.SelectedKeyNames = frm.SelectedKeyNames;
                 return flag;
@@ -34,18 +36,19 @@ namespace ContextMenuManager.Controls
 
             public ShellStoreForm(string shellPath, Func<string, bool> filter, bool isReference)
             {
+                this.SuspendLayout();
                 this.Filter = filter;
                 this.ShellPath = shellPath;
-                this.AcceptButton = btnOk;
+                this.AcceptButton = btnOK;
                 this.CancelButton = btnCancel;
                 this.Font = SystemFonts.MessageBoxFont;
                 this.SizeGripStyle = SizeGripStyle.Hide;
                 this.ShowIcon = this.ShowInTaskbar = false;
-                this.MinimizeBox =this.MaximizeBox = false;
+                this.MinimizeBox = this.MaximizeBox = false;
                 this.StartPosition = FormStartPosition.CenterParent;
-                this.MinimumSize = this.Size = new Size(652, 425).DpiZoom();
+                this.MinimumSize = this.Size = new Size(652, 422).DpiZoom();
                 this.Text = isReference ? AppString.Dialog.CheckReference : AppString.Dialog.CheckCopy;
-                btnOk.Click += (sender, e) => GetSelectedItems();
+                btnOK.Click += (sender, e) => GetSelectedItems();
                 chkSelectAll.Click += (sender, e) =>
                 {
                     bool flag = chkSelectAll.Checked;
@@ -57,6 +60,7 @@ namespace ContextMenuManager.Controls
                 list.Owner = listBox;
                 InitializeComponents();
                 LoadItems(isReference);
+                this.ResumeLayout();
             }
 
             readonly MyList list = new MyList();
@@ -65,18 +69,18 @@ namespace ContextMenuManager.Controls
             {
                 BackColor = Color.FromArgb(200, 200, 200)
             };
-            readonly Button btnOk = new Button
+            readonly Button btnOK = new Button
             {
                 Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
                 DialogResult = DialogResult.OK,
-                Text = AppString.Dialog.Ok,
+                Text = ResourceString.OK,
                 AutoSize = true
             };
             readonly Button btnCancel = new Button
             {
                 Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
                 DialogResult = DialogResult.Cancel,
-                Text = AppString.Dialog.Cancel,
+                Text = ResourceString.Cancel,
                 AutoSize = true
             };
             readonly CheckBox chkSelectAll = new CheckBox
@@ -89,13 +93,13 @@ namespace ContextMenuManager.Controls
 
             private void InitializeComponents()
             {
-                this.Controls.AddRange(new Control[] { listBox, pnlBorder, btnOk, btnCancel, chkSelectAll });
+                this.Controls.AddRange(new Control[] { listBox, pnlBorder, btnOK, btnCancel, chkSelectAll });
                 int a = 20.DpiZoom();
                 listBox.Location = new Point(a, a);
                 pnlBorder.Location = new Point(a - 1, a - 1);
-                chkSelectAll.Top = btnOk.Top = btnCancel.Top = this.ClientSize.Height - btnCancel.Height - a;
+                chkSelectAll.Top = 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;
+                btnOK.Left = btnCancel.Left - btnOK.Width - a;
                 chkSelectAll.Left = a;
                 this.OnResize(null);
             }
@@ -104,7 +108,7 @@ namespace ContextMenuManager.Controls
             {
                 base.OnResize(e);
                 listBox.Width = ClientSize.Width - 2 * listBox.Left;
-                listBox.Height = btnOk.Top - 2 * listBox.Top;
+                listBox.Height = btnOK.Top - 2 * listBox.Top;
                 pnlBorder.Width = listBox.Width + 2;
                 pnlBorder.Height = listBox.Height + 2;
             }
@@ -157,8 +161,6 @@ namespace ContextMenuManager.Controls
                 ChkVisible.Visible = BtnShowMenu.Visible = BtnSubItems.Visible = false;
                 this.MouseClick += (sender, e) => chkSelected.Checked = !chkSelected.Checked;
                 chkSelected.CheckedChanged += (sender, e) => SelectedChanged?.Invoke();
-                ImageDoubleClick += () => OnMouseClick(null);
-                TextDoubleClick += () => OnMouseClick(null);
             }
             RegTrustedInstaller.TakeRegTreeOwnerShip(regPath);
         }
@@ -176,11 +178,11 @@ namespace ContextMenuManager.Controls
             AutoSize = true
         };
 
-        public Action SelectedChanged { get; set; }
+        public Action SelectedChanged;
 
         public override void DeleteMe()
         {
-            if(IsPublic && MessageBoxEx.Show(AppString.Message.ConfirmDeleteReferenced,
+            if(IsPublic && AppMessageBox.Show(AppString.Message.ConfirmDeleteReferenced,
                 MessageBoxButtons.YesNo) != DialogResult.Yes) return;
             base.DeleteMe();
         }

+ 383 - 476
ContextMenuManager/Controls/ShellSubMenuDialog.cs

@@ -1,13 +1,12 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
 using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using System;
 using System.Collections.Generic;
 using System.Drawing;
-using System.IO;
 using System.Reflection;
 using System.Windows.Forms;
-using static Microsoft.Win32.Registry;
 
 namespace ContextMenuManager.Controls
 {
@@ -15,605 +14,513 @@ namespace ContextMenuManager.Controls
     {
         public Icon Icon { get; set; }
         public string Text { get; set; }
+        /// <summary>子菜单的父菜单的注册表路径</summary>
+        public string ParentPath { get; set; }
         public override void Reset() { }
-        protected override bool RunDialog(IntPtr hwndOwner) { return false; }
 
-        /// <param name="parentPath">子菜单的父菜单的注册表路径</param>
-        public void ShowDialog(string parentPath)
+        protected override bool RunDialog(IntPtr hwndOwner)
         {
-            using(ShellSubMenuForm frm = new ShellSubMenuForm())
+            bool isPublic = true;
+            string value = Microsoft.Win32.Registry.GetValue(this.ParentPath, "SubCommands", null)?.ToString();
+            if(value == null) isPublic = false;
+            else if(value.IsNullOrWhiteSpace())
             {
-                frm.Text = this.Text;
-                frm.Icon = this.Icon;
-                frm.ParentPath = parentPath;
-                frm.ShowDialog();
-            }
-        }
-
-        sealed class ShellSubMenuForm : Form
-        {
-            public ShellSubMenuForm()
-            {
-                this.StartPosition = FormStartPosition.CenterParent;
-                this.ShowInTaskbar = this.MaximizeBox = this.MinimizeBox = false;
-                this.MinimumSize = this.Size = new Size(646, 369).DpiZoom();
-                this.Controls.AddRange(new Control[] { MlbSubItems, StatusBar });
-                StatusBar.CanMoveForm();
-                this.OnResize(null);
-            }
-
-            /// <summary>子菜单的父菜单的注册表路径</summary>
-            public string ParentPath { get; set; }
-            readonly MyListBox MlbSubItems = new MyListBox { Dock = DockStyle.Fill };
-            readonly MyStatusBar StatusBar = new MyStatusBar();
-            private MyList LstSubItems;
-
-            protected override void OnLoad(EventArgs e)
-            {
-                base.OnLoad(e);
-                bool isPublic = true;
-                string value = GetValue(ParentPath, "SubCommands", null)?.ToString();
-                if(value == null) isPublic = false;
-                else if(value.IsNullOrWhiteSpace())
+                using(var shellKey = RegistryEx.GetRegistryKey($@"{ParentPath}\shell"))
                 {
-                    using(var shellKey = RegistryEx.GetRegistryKey($@"{ParentPath}\shell"))
+                    if(shellKey != null && shellKey.GetSubKeyNames().Length > 0) isPublic = false;
+                    else
                     {
-                        if(shellKey != null && shellKey.GetSubKeyNames().Length > 0) isPublic = false;
-                        else
-                        {
-                            using(SubMenuModeForm frm = new SubMenuModeForm())
-                            {
-                                frm.ShowDialog();
-                                switch(frm.Mode)
-                                {
-                                    case SubMenuModeForm.SubMode.Public:
-                                        isPublic = true; break;
-                                    case SubMenuModeForm.SubMode.Private:
-                                        isPublic = false; break;
-                                    case SubMenuModeForm.SubMode.None:
-                                        this.Dispose(); return;
-                                }
-                            }
-                        }
+                        string[] modes = new[] { ResourceString.Cancel, AppString.Dialog.Private, AppString.Dialog.Public };
+                        string mode = MessageBoxEx.Show(AppString.Message.SelectSubMenuMode, AppString.General.AppName,
+                            modes, MessageBoxImage.Question, null, modes[1]);
+                        if(mode == modes[2]) isPublic = true;
+                        else if(mode == modes[1]) isPublic = false;
+                        else return false;
                     }
                 }
+            }
+
+            using(SubItemsForm frm = new SubItemsForm())
+            {
+                frm.Text = this.Text;
+                frm.Icon = this.Icon;
+                frm.TopMost = AppConfig.TopMost;
+
                 if(isPublic)
                 {
-                    LstSubItems = new PulicMultiItemsList(MlbSubItems);
-                    ((PulicMultiItemsList)LstSubItems).LoadItems(ParentPath);
-                    this.Text += $"({AppString.Dialog.Public})";
+                    frm.Text += $"({AppString.Dialog.Public})";
+                    PulicMultiItemsList list = new PulicMultiItemsList();
+                    frm.AddList(list);
+                    list.ParentPath = this.ParentPath;
+                    list.LoadItems();
                 }
                 else
                 {
-                    LstSubItems = new PrivateMultiItemsList(MlbSubItems);
-                    ((PrivateMultiItemsList)LstSubItems).LoadItems(ParentPath);
-                    this.Text += $"({AppString.Dialog.Private})";
+                    frm.Text += $"({AppString.Dialog.Private})";
+                    PrivateMultiItemsList list = new PrivateMultiItemsList();
+                    frm.AddList(list);
+                    list.ParentPath = this.ParentPath;
+                    list.LoadItems();
                 }
-                LstSubItems.HoveredItemChanged += () =>
-                {
-                    if(!AppConfig.ShowFilePath) return;
-                    MyListItem item = LstSubItems.HoveredItem;
-                    if(item is ITsiFilePathItem pathItem1)
-                    {
-                        string path = pathItem1.ItemFilePath;
-                        if(File.Exists(path)) { StatusBar.Text = path; return; }
-                    }
-                    if(item is ITsiRegPathItem pathItem2)
-                    {
-                        StatusBar.Text = pathItem2.RegPath; return;
-                    }
-                    StatusBar.Text = item.Text;
-                };
+
+                frm.ShowDialog();
             }
+            return false;
+        }
 
-            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[] { pnlInfo, btnPrivate, btnPublic });
-                    pnlInfo.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);
-                    pnlInfo.Height = lblInfo.Bottom + a;
-                    btnPrivate.Top = btnPublic.Top = pnlInfo.Bottom + a / 2;
-                    btnPublic.Left = pnlInfo.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;
-                }
+        sealed class PulicMultiItemsList : MyList
+        {
+            readonly List<string> SubKeyNames = new List<string>();
+            /// <summary>子菜单的父菜单的注册表路径</summary>
+            public string ParentPath { get; set; }
+            /// <summary>菜单所处环境注册表路径</summary>
+            private string ScenePath => RegistryEx.GetParentPath(RegistryEx.GetParentPath(ParentPath));
 
-                public enum SubMode { Public, Private, None }
-                public SubMode Mode { get; private set; } = SubMode.None;
+            readonly SubNewItem subNewItem = new SubNewItem(true);
 
-                readonly Label lblInfo = new Label
-                {
-                    Text = AppString.Dialog.SelectSubMenuMode,
-                    AutoSize = true
-                };
-                readonly Panel pnlInfo = new Panel
-                {
-                    BackColor = Color.White,
-                    Dock = DockStyle.Top
-                };
-                readonly Button btnPrivate = new Button
-                {
-                    Text = AppString.Dialog.Private,
-                    DialogResult = DialogResult.OK,
-                    AutoSize = true
-                };
-                readonly Button btnPublic = new Button
-                {
-                    Text = AppString.Dialog.Public,
-                    DialogResult = DialogResult.OK,
-                    AutoSize = true
-                };
-            }
-
-            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
-            sealed class PulicMultiItemsList : MyList
+            /// <param name="parentPath">子菜单的父菜单的注册表路径</param>
+            public void LoadItems()
             {
-                readonly List<string> SubKeyNames = new List<string>();
-                /// <summary>子菜单的父菜单的注册表路径</summary>
-                private string ParentPath { get; set; }
-                /// <summary>菜单所处环境注册表路径</summary>
-                private string ScenePath => RegistryEx.GetParentPath(RegistryEx.GetParentPath(ParentPath));
+                this.AddItem(subNewItem);
+                subNewItem.AddNewItem += () => AddNewItem();
+                subNewItem.AddExisting += () => AddReference();
+                subNewItem.AddSeparator += () => AddSeparator();
 
-                readonly SubNewItem subNewItem = new SubNewItem(true);
+                string value = Microsoft.Win32.Registry.GetValue(ParentPath, "SubCommands", null)?.ToString();
+                Array.ForEach(value.Split(';'), cmd => SubKeyNames.Add(cmd.TrimStart()));
+                SubKeyNames.RemoveAll(string.IsNullOrEmpty);
 
-                public PulicMultiItemsList(MyListBox owner) : base(owner)
+                using(var shellKey = RegistryEx.GetRegistryKey(ShellItem.CommandStorePath, false, true))
                 {
-                    this.AddItem(subNewItem);
-                    subNewItem.AddNewItem += () => AddNewItem();
-                    subNewItem.AddExisting += () => AddReference();
-                    subNewItem.AddSeparator += () => AddSeparator();
-                }
-
-                /// <param name="parentPath">子菜单的父菜单的注册表路径</param>
-                public void LoadItems(string parentPath)
-                {
-                    this.ParentPath = parentPath;
-                    string value = GetValue(ParentPath, "SubCommands", null)?.ToString();
-                    Array.ForEach(value.Split(';'), cmd => SubKeyNames.Add(cmd.TrimStart()));
-                    SubKeyNames.RemoveAll(string.IsNullOrEmpty);
-
-                    using(var shellKey = RegistryEx.GetRegistryKey(ShellItem.CommandStorePath, false, true))
+                    foreach(string keyName in SubKeyNames)
                     {
-                        foreach(string keyName in SubKeyNames)
+                        using(var key = shellKey.OpenSubKey(keyName))
                         {
-                            using(var key = shellKey.OpenSubKey(keyName))
-                            {
-                                MyListItem item;
-                                if(key != null) item = new SubShellItem(this, keyName);
-                                else if(keyName == "|") item = new SeparatorItem(this);
-                                else item = new InvalidItem(this, keyName);
-                                this.AddItem(item);
-                            }
+                            MyListItem item;
+                            if(key != null) item = new SubShellItem(this, keyName);
+                            else if(keyName == "|") item = new SeparatorItem(this);
+                            else item = new InvalidItem(this, keyName);
+                            this.AddItem(item);
                         }
                     }
                 }
+            }
 
-                private void AddNewItem()
+            private void AddNewItem()
+            {
+                if(!SubShellTypeItem.CanAddMore(this)) return;
+                using(NewShellDialog dlg = new NewShellDialog())
                 {
-                    if(!SubShellTypeItem.CanAddMore(this)) return;
-                    using(NewShellDialog dlg = new NewShellDialog())
-                    {
-                        dlg.ScenePath = this.ScenePath;
-                        dlg.ShellPath = ShellItem.CommandStorePath;
-                        if(dlg.ShowDialog() != DialogResult.OK) return;
-                        SubKeyNames.Add(dlg.NewItemKeyName);
-                        SaveSorting();
-                        this.AddItem(new SubShellItem(this, dlg.NewItemKeyName));
-                    }
+                    dlg.ScenePath = this.ScenePath;
+                    dlg.ShellPath = ShellItem.CommandStorePath;
+                    if(dlg.ShowDialog() != DialogResult.OK) return;
+                    SubKeyNames.Add(dlg.NewItemKeyName);
+                    this.SaveSorting();
+                    this.AddItem(new SubShellItem(this, dlg.NewItemKeyName));
                 }
+            }
 
-                private void AddReference()
-                {
-                    if(!SubShellTypeItem.CanAddMore(this)) return;
-                    using(ShellStoreDialog dlg = new ShellStoreDialog())
+            private void AddReference()
+            {
+                if(!SubShellTypeItem.CanAddMore(this)) return;
+                using(ShellStoreDialog dlg = new ShellStoreDialog())
+                {
+                    dlg.IsReference = true;
+                    dlg.ShellPath = ShellItem.CommandStorePath;
+                    dlg.Filter = new Func<string, bool>(itemName => !(AppConfig.HideSysStoreItems
+                        && itemName.StartsWith("Windows.", StringComparison.OrdinalIgnoreCase)));
+                    if(dlg.ShowDialog() != DialogResult.OK) return;
+                    foreach(string keyName in dlg.SelectedKeyNames)
                     {
-                        dlg.IsReference = true;
-                        dlg.ShellPath = ShellItem.CommandStorePath;
-                        dlg.Filter = new Func<string, bool>(itemName => !(AppConfig.HideSysStoreItems
-                            && itemName.StartsWith("Windows.", StringComparison.OrdinalIgnoreCase)));
-                        if(dlg.ShowDialog() != DialogResult.OK) return;
-                        foreach(string keyName in dlg.SelectedKeyNames)
-                        {
-                            if(!SubShellTypeItem.CanAddMore(this)) return;
-                            this.AddItem(new SubShellItem(this, keyName));
-                            this.SubKeyNames.Add(keyName);
-                            SaveSorting();
-                        }
+                        if(!SubShellTypeItem.CanAddMore(this)) return;
+                        this.AddItem(new SubShellItem(this, keyName));
+                        this.SubKeyNames.Add(keyName);
+                        this.SaveSorting();
                     }
                 }
+            }
 
-                private void AddSeparator()
-                {
-                    this.SubKeyNames.Add("|");
-                    SaveSorting();
-                    this.AddItem(new SeparatorItem(this));
-                }
+            private void AddSeparator()
+            {
+                if(this.Controls[this.Controls.Count - 1] is SeparatorItem) return;
+                this.SubKeyNames.Add("|");
+                this.SaveSorting();
+                this.AddItem(new SeparatorItem(this));
+            }
 
-                private void SaveSorting()
-                {
-                    SetValue(ParentPath, "SubCommands", string.Join(";", SubKeyNames.ToArray()));
-                }
+            private void SaveSorting()
+            {
+                Microsoft.Win32.Registry.SetValue(ParentPath, "SubCommands", string.Join(";", SubKeyNames.ToArray()));
+            }
 
-                private void MoveItem(MyListItem item, bool isUp)
+            private void MoveItem(MyListItem item, bool isUp)
+            {
+                int index = this.GetItemIndex(item);
+                if(isUp)
                 {
-                    int index = this.GetItemIndex(item);
-                    if(isUp)
+                    if(index > 1)
                     {
-                        if(index > 1)
-                        {
-                            this.SetItemIndex(item, index - 1);
-                            this.SubKeyNames.Reverse(index - 2, 2);
-                        }
+                        this.SetItemIndex(item, index - 1);
+                        this.SubKeyNames.Reverse(index - 2, 2);
                     }
-                    else
-                    {
-                        if(index < this.Controls.Count - 1)
-                        {
-                            this.SetItemIndex(item, index + 1);
-                            this.SubKeyNames.Reverse(index - 1, 2);
-                        }
-                    }
-                    this.SaveSorting();
                 }
-
-                private void DeleteItem(MyListItem item)
-                {
-                    int index = this.GetItemIndex(item);
-                    this.Controls.Remove(item);
-                    this.Controls[index - 1].Focus();
-                    this.SubKeyNames.RemoveAt(index - 1);
-                    this.SaveSorting();
-                    item.Dispose();
-                }
-
-                sealed class SubShellItem : SubShellTypeItem
+                else
                 {
-                    public SubShellItem(PulicMultiItemsList list, string keyName) : base($@"{CommandStorePath}\{keyName}")
+                    if(index < this.Controls.Count - 1)
                     {
-                        this.Owner = list;
-                        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();
+                        this.SetItemIndex(item, index + 1);
+                        this.SubKeyNames.Reverse(index - 1, 2);
                     }
+                }
+                this.SaveSorting();
+            }
 
-                    readonly ToolStripMenuItem TsiDeleteRef = new ToolStripMenuItem(AppString.Menu.DeleteReference);
-                    public PulicMultiItemsList Owner { get; private set; }
+            private void DeleteItem(MyListItem item)
+            {
+                int index = this.GetItemIndex(item);
+                this.SubKeyNames.RemoveAt(index - 1);
+                if(index == this.Controls.Count - 1) index--;
+                this.Controls.Remove(item);
+                this.Controls[index].Focus();
+                this.SaveSorting();
+                item.Dispose();
+            }
 
-                    private void DeleteReference()
-                    {
-                        if(MessageBoxEx.Show(AppString.Message.ConfirmDeleteReference,
-                            MessageBoxButtons.YesNo) == DialogResult.Yes)
-                        {
-                            Owner.DeleteItem(this);
-                        }
-                    }
+            sealed class SubShellItem : SubShellTypeItem
+            {
+                public SubShellItem(PulicMultiItemsList list, string keyName) : base($@"{CommandStorePath}\{keyName}")
+                {
+                    this.Owner = list;
+                    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();
                 }
 
-                sealed class SeparatorItem : SubSeparatorItem
-                {
-                    public SeparatorItem(PulicMultiItemsList list) : base()
-                    {
-                        this.Owner = list;
-                        BtnMoveUp.MouseDown += (sender, e) => Owner.MoveItem(this, true);
-                        BtnMoveDown.MouseDown += (sender, e) => Owner.MoveItem(this, false);
-                    }
-
-                    public PulicMultiItemsList Owner { get; private set; }
+                readonly ToolStripMenuItem TsiDeleteRef = new ToolStripMenuItem(AppString.Menu.DeleteReference);
+                public PulicMultiItemsList Owner { get; private set; }
 
-                    public override void DeleteMe()
+                private void DeleteReference()
+                {
+                    if(AppMessageBox.Show(AppString.Message.ConfirmDeleteReference, MessageBoxButtons.YesNo) == DialogResult.Yes)
                     {
                         Owner.DeleteItem(this);
                     }
                 }
+            }
 
-                sealed class InvalidItem : MyListItem, IBtnDeleteItem, IBtnMoveUpDownItem
+            sealed class SeparatorItem : SubSeparatorItem
+            {
+                public SeparatorItem(PulicMultiItemsList list) : base()
                 {
-                    public InvalidItem(PulicMultiItemsList list, string keyName)
-                    {
-                        this.Owner = list;
-                        this.Text = $"{AppString.Other.InvalidItem} {keyName}";
-                        this.Image = AppImage.NotFound.ToTransparent();
-                        BtnDelete = new DeleteButton(this);
-                        BtnMoveDown = new MoveButton(this, false);
-                        BtnMoveUp = new MoveButton(this, true);
-                        BtnMoveUp.MouseDown += (sender, e) => Owner.MoveItem(this, true);
-                        BtnMoveDown.MouseDown += (sender, e) => Owner.MoveItem(this, false);
-                        ToolTipBox.SetToolTip(this, AppString.Tip.InvalidItem);
-                        ToolTipBox.SetToolTip(BtnDelete, AppString.Menu.Delete);
-                    }
+                    this.Owner = list;
+                    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 MoveButton BtnMoveUp { get; set; }
-                    public MoveButton BtnMoveDown { get; set; }
+                public PulicMultiItemsList Owner { get; private set; }
 
-                    public void DeleteMe()
-                    {
-                        Owner.DeleteItem(this);
-                    }
+                public override void DeleteMe()
+                {
+                    Owner.DeleteItem(this);
                 }
             }
 
-            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
-            sealed class PrivateMultiItemsList : MyList
+            sealed class InvalidItem : MyListItem, IBtnDeleteItem, IBtnMoveUpDownItem
             {
-                public PrivateMultiItemsList(MyListBox owner) : base(owner)
+                public InvalidItem(PulicMultiItemsList list, string keyName)
                 {
-                    this.AddItem(subNewItem);
-                    subNewItem.AddNewItem += () => AddNewItem();
-                    subNewItem.AddSeparator += () => AddSeparator();
-                    subNewItem.AddExisting += () => AddFromParentMenu();
+                    this.Owner = list;
+                    this.Text = $"{AppString.Other.InvalidItem} {keyName}";
+                    this.Image = AppImage.NotFound.ToTransparent();
+                    BtnDelete = new DeleteButton(this);
+                    BtnMoveDown = new MoveButton(this, false);
+                    BtnMoveUp = new MoveButton(this, true);
+                    BtnMoveUp.MouseDown += (sender, e) => Owner.MoveItem(this, true);
+                    BtnMoveDown.MouseDown += (sender, e) => Owner.MoveItem(this, false);
+                    ToolTipBox.SetToolTip(this, AppString.Tip.InvalidItem);
+                    ToolTipBox.SetToolTip(BtnDelete, AppString.Menu.Delete);
                 }
 
-                readonly SubNewItem subNewItem = new SubNewItem(false);
+                public DeleteButton BtnDelete { get; set; }
+                public PulicMultiItemsList Owner { get; private set; }
+                public MoveButton BtnMoveUp { get; set; }
+                public MoveButton BtnMoveDown { get; set; }
 
-                /// <summary>父菜单的注册表路径</summary>
-                public string ParentPath { get; set; }
-                /// <summary>子菜单的Shell项注册表路径</summary>
-                private string ShellPath { get; set; }
-                /// <summary>父菜单的Shell项注册表路径</summary>
-                private string ParentShellPath => RegistryEx.GetParentPath(ParentPath);
-                /// <summary>菜单所处环境注册表路径</summary>
-                private string ScenePath => RegistryEx.GetParentPath(ParentShellPath);
-                /// <summary>父菜单的项名</summary>
-                private string ParentKeyName => RegistryEx.GetKeyName(ParentPath);
+                public void DeleteMe()
+                {
+                    Owner.DeleteItem(this);
+                }
+            }
+        }
 
-                public void LoadItems(string parentPath)
+        sealed class PrivateMultiItemsList : MyList
+        {
+            readonly SubNewItem subNewItem = new SubNewItem(false);
+
+            /// <summary>父菜单的注册表路径</summary>
+            public string ParentPath { get; set; }
+            /// <summary>子菜单的Shell项注册表路径</summary>
+            private string ShellPath { get; set; }
+            /// <summary>父菜单的Shell项注册表路径</summary>
+            private string ParentShellPath => RegistryEx.GetParentPath(ParentPath);
+            /// <summary>菜单所处环境注册表路径</summary>
+            private string ScenePath => RegistryEx.GetParentPath(ParentShellPath);
+            /// <summary>父菜单的项名</summary>
+            private string ParentKeyName => RegistryEx.GetKeyName(ParentPath);
+
+            public void LoadItems()
+            {
+                this.AddItem(subNewItem);
+                subNewItem.AddNewItem += () => AddNewItem();
+                subNewItem.AddSeparator += () => AddSeparator();
+                subNewItem.AddExisting += () => AddFromParentMenu();
+
+                string sckValue = Microsoft.Win32.Registry.GetValue(this.ParentPath, "ExtendedSubCommandsKey", null)?.ToString();
+                if(!sckValue.IsNullOrWhiteSpace())
                 {
-                    this.ParentPath = parentPath;
-                    string sckValue = GetValue(parentPath, "ExtendedSubCommandsKey", null)?.ToString();
-                    if(!sckValue.IsNullOrWhiteSpace())
-                    {
-                        this.ShellPath = $@"{RegistryEx.CLASSESROOT}\{sckValue}\shell";
-                    }
-                    else
-                    {
-                        this.ShellPath = $@"{parentPath}\shell";
-                    }
-                    using(var shellKey = RegistryEx.GetRegistryKey(ShellPath))
+                    this.ShellPath = $@"{RegistryEx.CLASSES_ROOT}\{sckValue}\shell";
+                }
+                else
+                {
+                    this.ShellPath = $@"{this.ParentPath}\shell";
+                }
+                using(var shellKey = RegistryEx.GetRegistryKey(ShellPath))
+                {
+                    if(shellKey == null) return;
+                    RegTrustedInstaller.TakeRegTreeOwnerShip(shellKey.Name);
+                    foreach(string keyName in shellKey.GetSubKeyNames())
                     {
-                        if(shellKey == null) return;
-                        RegTrustedInstaller.TakeRegTreeOwnerShip(shellKey.Name);
-                        foreach(string keyName in shellKey.GetSubKeyNames())
+                        string regPath = $@"{ShellPath}\{keyName}";
+                        int value = Convert.ToInt32(Microsoft.Win32.Registry.GetValue(regPath, "CommandFlags", 0));
+                        if(value % 16 >= 8)
                         {
-                            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));
-                            }
+                            this.AddItem(new SeparatorItem(this, regPath));
+                        }
+                        else
+                        {
+                            this.AddItem(new SubShellItem(this, regPath));
                         }
                     }
                 }
+            }
 
-                private void AddNewItem()
+            private void AddNewItem()
+            {
+                if(!SubShellTypeItem.CanAddMore(this)) return;
+                using(NewShellDialog dlg = new NewShellDialog
                 {
-                    if(!SubShellTypeItem.CanAddMore(this)) return;
-                    using(NewShellDialog dlg = new NewShellDialog
-                    {
-                        ScenePath = this.ScenePath,
-                        ShellPath = this.ShellPath
-                    })
-                    {
-                        if(dlg.ShowDialog() != DialogResult.OK) return;
-                        this.AddItem(new SubShellItem(this, dlg.NewItemRegPath));
-                    }
+                    ScenePath = this.ScenePath,
+                    ShellPath = this.ShellPath
+                })
+                {
+                    if(dlg.ShowDialog() != DialogResult.OK) return;
+                    this.AddItem(new SubShellItem(this, dlg.NewItemRegPath));
                 }
+            }
 
-                private void AddSeparator()
+            private void AddSeparator()
+            {
+                if(this.Controls[this.Controls.Count - 1] is SeparatorItem) return;
+                string regPath;
+                if(this.Controls.Count > 1)
                 {
-                    string regPath;
-                    if(this.Controls.Count > 1)
-                    {
-                        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));
+                    regPath = GetItemRegPath((MyListItem)Controls[Controls.Count - 1]);
                 }
-
-                private void AddFromParentMenu()
+                else
                 {
-                    if(!SubShellTypeItem.CanAddMore(this)) return;
-                    using(ShellStoreDialog dlg = new ShellStoreDialog())
+                    regPath = $@"{ShellPath}\Item";
+                }
+                regPath = ObjectPath.GetNewPathWithIndex(regPath, ObjectPath.PathType.Registry);
+                Microsoft.Win32.Registry.SetValue(regPath, "CommandFlags", 0x8);
+                this.AddItem(new SeparatorItem(this, regPath));
+            }
+
+            private void AddFromParentMenu()
+            {
+                if(!SubShellTypeItem.CanAddMore(this)) return;
+                using(ShellStoreDialog dlg = new ShellStoreDialog())
+                {
+                    dlg.IsReference = false;
+                    dlg.ShellPath = this.ParentShellPath;
+                    dlg.Filter = new Func<string, bool>(itemName => !itemName.Equals(this.ParentKeyName, StringComparison.OrdinalIgnoreCase));
+                    if(dlg.ShowDialog() != DialogResult.OK) return;
+                    foreach(string keyName in dlg.SelectedKeyNames)
                     {
-                        dlg.IsReference = false;
-                        dlg.ShellPath = this.ParentShellPath;
-                        dlg.Filter = new Func<string, bool>(itemName => !itemName.Equals(this.ParentKeyName, StringComparison.OrdinalIgnoreCase));
-                        if(dlg.ShowDialog() != DialogResult.OK) return;
-                        foreach(string keyName in dlg.SelectedKeyNames)
-                        {
-                            if(!SubShellTypeItem.CanAddMore(this)) return;
-                            string srcPath = $@"{dlg.ShellPath}\{keyName}";
-                            string dstPath = ObjectPath.GetNewPathWithIndex($@"{ShellPath}\{keyName}", ObjectPath.PathType.Registry);
+                        if(!SubShellTypeItem.CanAddMore(this)) return;
+                        string srcPath = $@"{dlg.ShellPath}\{keyName}";
+                        string dstPath = ObjectPath.GetNewPathWithIndex($@"{ShellPath}\{keyName}", ObjectPath.PathType.Registry);
 
-                            RegistryEx.CopyTo(srcPath, dstPath);
-                            this.AddItem(new SubShellItem(this, dstPath));
-                        }
+                        RegistryEx.CopyTo(srcPath, dstPath);
+                        this.AddItem(new SubShellItem(this, dstPath));
                     }
                 }
+            }
 
-                public void MoveItem(MyListItem item, bool isUp)
+            public void MoveItem(MyListItem item, bool isUp)
+            {
+                int index = this.GetItemIndex(item);
+                MyListItem otherItem = null;
+                if(isUp)
                 {
-                    int index = this.GetItemIndex(item);
-                    MyListItem otherItem = null;
-                    if(isUp)
-                    {
-                        if(index > 1)
-                        {
-                            otherItem = (MyListItem)this.Controls[index - 1];
-                            this.SetItemIndex(item, index - 1);
-                        }
-                    }
-                    else
+                    if(index > 1)
                     {
-                        if(index < this.Controls.Count - 1)
-                        {
-                            otherItem = (MyListItem)this.Controls[index + 1];
-                            this.SetItemIndex(item, index + 1);
-                        }
+                        otherItem = (MyListItem)this.Controls[index - 1];
+                        this.SetItemIndex(item, index - 1);
                     }
-                    if(otherItem != null)
+                }
+                else
+                {
+                    if(index < this.Controls.Count - 1)
                     {
-                        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);
+                        otherItem = (MyListItem)this.Controls[index + 1];
+                        this.SetItemIndex(item, index + 1);
                     }
                 }
-
-                private string GetItemRegPath(MyListItem item)
-                {
-                    PropertyInfo pi = item.GetType().GetProperty("RegPath");
-                    return pi.GetValue(item, null).ToString();
+                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 void SetItemRegPath(MyListItem item, string regPath)
-                {
-                    PropertyInfo pi = item.GetType().GetProperty("RegPath");
-                    pi.SetValue(item, regPath, null);
-                }
+            private string GetItemRegPath(MyListItem item)
+            {
+                PropertyInfo pi = item.GetType().GetProperty("RegPath");
+                return pi.GetValue(item, null).ToString();
+            }
 
-                sealed class SubShellItem : SubShellTypeItem
+            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)
                 {
-                    public SubShellItem(PrivateMultiItemsList list, string regPath) : base(regPath)
-                    {
-                        this.Owner = list;
-                        BtnMoveUp.MouseDown += (sender, e) => Owner.MoveItem(this, true);
-                        BtnMoveDown.MouseDown += (sender, e) => Owner.MoveItem(this, false);
-                        SetItemTextValue();
-                    }
+                    this.Owner = list;
+                    BtnMoveUp.MouseDown += (sender, e) => Owner.MoveItem(this, true);
+                    BtnMoveDown.MouseDown += (sender, e) => Owner.MoveItem(this, false);
+                    SetItemTextValue();
+                }
 
-                    public PrivateMultiItemsList Owner { get; private set; }
+                public PrivateMultiItemsList Owner { get; private set; }
 
-                    private void SetItemTextValue()
+                private void SetItemTextValue()
+                {
+                    using(var key = RegistryEx.GetRegistryKey(this.RegPath, true))
                     {
-                        using(var key = RegistryEx.GetRegistryKey(this.RegPath, true))
+                        bool hasValue = false;
+                        foreach(string valueName in new[] { "MUIVerb", "" })
                         {
-                            bool hasValue = false;
-                            foreach(string valueName in new[] { "MUIVerb", "" })
+                            if(key.GetValue(valueName) != null)
                             {
-                                if(key.GetValue(valueName) != null)
-                                {
-                                    hasValue = true; break;
-                                }
+                                hasValue = true; break;
                             }
-                            if(!hasValue) key.SetValue("MUIVerb", this.ItemText);
                         }
-
+                        if(!hasValue) key.SetValue("MUIVerb", this.ItemText);
                     }
+
                 }
+            }
 
-                sealed class SeparatorItem : SubSeparatorItem
+            sealed class SeparatorItem : SubSeparatorItem
+            {
+                public SeparatorItem(PrivateMultiItemsList list, string regPath)
                 {
-                    public SeparatorItem(PrivateMultiItemsList list, string regPath)
-                    {
-                        this.Owner = list;
-                        this.RegPath = regPath;
-                        BtnMoveUp.MouseDown += (sender, e) => Owner.MoveItem(this, true);
-                        BtnMoveDown.MouseDown += (sender, e) => Owner.MoveItem(this, false);
-                    }
+                    this.Owner = list;
+                    this.RegPath = regPath;
+                    BtnMoveUp.MouseDown += (sender, e) => Owner.MoveItem(this, true);
+                    BtnMoveDown.MouseDown += (sender, e) => Owner.MoveItem(this, false);
+                }
 
-                    public PrivateMultiItemsList Owner { get; private set; }
-                    public string RegPath { get; private set; }
+                public PrivateMultiItemsList Owner { get; private set; }
+                public string RegPath { get; private set; }
 
-                    public override void DeleteMe()
-                    {
-                        RegistryEx.DeleteKeyTree(this.RegPath);
-                        this.Dispose();
-                    }
+                public override void DeleteMe()
+                {
+                    RegistryEx.DeleteKeyTree(this.RegPath);
+                    int index = this.Parent.Controls.GetChildIndex(this);
+                    if(index == this.Parent.Controls.Count - 1) index--;
+                    this.Parent.Controls[index].Focus();
+                    this.Parent.Controls.Remove(this);
+                    this.Dispose();
                 }
             }
+        }
 
-            class SubSeparatorItem : MyListItem, IBtnDeleteItem, IBtnMoveUpDownItem
+        class SubSeparatorItem : MyListItem, IBtnDeleteItem, IBtnMoveUpDownItem
+        {
+            public SubSeparatorItem()
             {
-                public SubSeparatorItem()
-                {
-                    this.Text = AppString.Other.Separator;
-                    this.HasImage = false;
-                    BtnDelete = new DeleteButton(this);
-                    BtnMoveDown = new MoveButton(this, false);
-                    BtnMoveUp = new MoveButton(this, true);
-                    ToolTipBox.SetToolTip(BtnDelete, AppString.Menu.Delete);
-                }
+                this.Text = AppString.Other.Separator;
+                this.HasImage = false;
+                BtnDelete = new DeleteButton(this);
+                BtnMoveDown = new MoveButton(this, false);
+                BtnMoveUp = new MoveButton(this, true);
+                ToolTipBox.SetToolTip(BtnDelete, AppString.Menu.Delete);
+            }
 
-                public DeleteButton BtnDelete { get; set; }
-                public MoveButton BtnMoveUp { get; set; }
-                public MoveButton BtnMoveDown { get; set; }
+            public DeleteButton BtnDelete { get; set; }
+            public MoveButton BtnMoveUp { get; set; }
+            public MoveButton BtnMoveDown { get; set; }
 
-                public virtual void DeleteMe() { }
-            }
+            public virtual void DeleteMe() { }
+        }
 
-            class SubShellTypeItem : ShellItem, IBtnMoveUpDownItem
+        class SubShellTypeItem : ShellItem, IBtnMoveUpDownItem
+        {
+            public SubShellTypeItem(string regPath) : base(regPath)
             {
-                public SubShellTypeItem(string regPath) : base(regPath)
-                {
-                    BtnMoveDown = new MoveButton(this, false);
-                    BtnMoveUp = new MoveButton(this, true);
-                    this.SetCtrIndex(BtnMoveDown, 1);
-                    this.SetCtrIndex(BtnMoveUp, 2);
-                }
+                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; }
+            public MoveButton BtnMoveUp { get; set; }
+            public MoveButton BtnMoveDown { get; set; }
 
-                protected override bool IsSubItem => true;
+            protected override bool IsSubItem => true;
 
-                public static bool CanAddMore(MyList list)
+            public static bool CanAddMore(MyList list)
+            {
+                int count = 0;
+                foreach(Control item in list.Controls)
                 {
-                    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.Message.CannotAddNewItem);
-                    return flag;
+                    if(item.GetType().BaseType == typeof(SubShellTypeItem)) count++;
                 }
+                bool flag = count < 16;
+                if(!flag) AppMessageBox.Show(AppString.Message.CannotAddNewItem);
+                return flag;
             }
+        }
 
-            sealed class SubNewItem : NewItem
+        sealed class SubNewItem : NewItem
+        {
+            public SubNewItem(bool isPublic)
             {
-                public SubNewItem(bool isPublic)
-                {
-                    this.AddCtrs(new[] { btnAddExisting, btnAddSeparator });
-                    ToolTipBox.SetToolTip(btnAddExisting, isPublic ? AppString.Tip.AddReference : AppString.Tip.AddFromParentMenu);
-                    ToolTipBox.SetToolTip(btnAddSeparator, AppString.Tip.AddSeparator);
-                    btnAddExisting.MouseDown += (sender, e) => AddExisting?.Invoke();
-                    btnAddSeparator.MouseDown += (sender, e) => AddSeparator?.Invoke();
-                }
+                this.AddCtrs(new[] { btnAddExisting, btnAddSeparator });
+                ToolTipBox.SetToolTip(btnAddExisting, isPublic ? AppString.Tip.AddReference : AppString.Tip.AddFromParentMenu);
+                ToolTipBox.SetToolTip(btnAddSeparator, AppString.Tip.AddSeparator);
+                btnAddExisting.MouseDown += (sender, e) => AddExisting?.Invoke();
+                btnAddSeparator.MouseDown += (sender, e) => AddSeparator?.Invoke();
+            }
 
-                readonly PictureButton btnAddExisting = new PictureButton(AppImage.AddExisting);
-                readonly PictureButton btnAddSeparator = new PictureButton(AppImage.AddSeparator);
+            readonly PictureButton btnAddExisting = new PictureButton(AppImage.AddExisting);
+            readonly PictureButton btnAddSeparator = new PictureButton(AppImage.AddSeparator);
 
-                public Action AddExisting { get; set; }
-                public Action AddSeparator { get; set; }
-            }
+            public Action AddExisting;
+            public Action AddSeparator;
         }
     }
 }

+ 42 - 0
ContextMenuManager/Controls/SubItemsForm.cs

@@ -0,0 +1,42 @@
+using BluePointLilac.Controls;
+using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace ContextMenuManager.Controls
+{
+    sealed class SubItemsForm : Form
+    {
+        public SubItemsForm()
+        {
+            this.SuspendLayout();
+            this.StartPosition = FormStartPosition.CenterParent;
+            this.ShowInTaskbar = this.MaximizeBox = this.MinimizeBox = false;
+            this.MinimumSize = this.Size = new Size(646, 419).DpiZoom();
+            this.Controls.AddRange(new Control[] { listBox, statusBar });
+            statusBar.CanMoveForm();
+            this.AddEscapeButton();
+            this.ResumeLayout();
+        }
+
+        readonly MyListBox listBox = new MyListBox { Dock = DockStyle.Fill };
+        readonly MyStatusBar statusBar = new MyStatusBar();
+
+        public void AddList(MyList myList)
+        {
+            myList.Owner = listBox;
+            myList.HoveredItemChanged += (sender, e) =>
+            {
+                if(!AppConfig.ShowFilePath) return;
+                MyListItem item = myList.HoveredItem;
+                foreach(string prop in new[] { "ItemFilePath", "RegPath", "GroupPath" })
+                {
+                    string path = item.GetType().GetProperty(prop)?.GetValue(item, null)?.ToString();
+                    if(!path.IsNullOrWhiteSpace()) { statusBar.Text = path; return; }
+                }
+                statusBar.Text = item.Text;
+            };
+        }
+    }
+}

+ 71 - 0
ContextMenuManager/Controls/SwitchDicList.cs

@@ -0,0 +1,71 @@
+using BluePointLilac.Controls;
+using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace ContextMenuManager.Controls
+{
+    class SwitchDicList : MyList
+    {
+        public bool UseUserDic { get; set; }
+
+        public virtual void LoadItems()
+        {
+            this.AddSwitchItem();
+        }
+
+        public void AddSwitchItem()
+        {
+            SwitchDicItem item = new SwitchDicItem { UseUserDic = this.UseUserDic };
+            item.UseDicChanged += () =>
+            {
+                this.UseUserDic = item.UseUserDic;
+                this.ClearItems();
+                this.LoadItems();
+            };
+            this.AddItem(item);
+        }
+    }
+
+    sealed class SwitchDicItem : MyListItem
+    {
+        public SwitchDicItem()
+        {
+            this.Text = AppString.Other.SwitchDictionaries;
+            this.AddCtr(cmbDic);
+            cmbDic.AutosizeDropDownWidth();
+            cmbDic.Font = new Font(this.Font.FontFamily, this.Font.Size + 1F);
+            cmbDic.Items.AddRange(new[] { AppString.Other.WebDictionaries, AppString.Other.UserDictionaries });
+            cmbDic.SelectionChangeCommitted += (sender, e) =>
+            {
+                this.Focus();
+                this.UseUserDic = cmbDic.SelectedIndex == 1;
+            };
+        }
+
+        private bool? useUserDic = null;
+        public bool UseUserDic
+        {
+            get => useUserDic == true;
+            set
+            {
+                if(useUserDic == value) return;
+                bool flag = useUserDic == null;
+                useUserDic = value;
+                this.Image = this.UseUserDic ? AppImage.User : AppImage.Web;
+                cmbDic.SelectedIndex = value ? 1 : 0;
+                if(!flag) UseDicChanged?.Invoke();
+            }
+        }
+
+        public Action UseDicChanged;
+
+        readonly ComboBox cmbDic = new ComboBox
+        {
+            DropDownStyle = ComboBoxStyle.DropDownList,
+            Width = 120.DpiZoom()
+        };
+    }
+}

+ 0 - 233
ContextMenuManager/Controls/TranslateDialog.cs

@@ -1,233 +0,0 @@
-using BluePointLilac.Methods;
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Windows.Forms;
-
-namespace ContextMenuManager.Controls
-{
-    sealed class TranslateDialog : CommonDialog
-    {
-        public override void Reset() { }
-
-        protected override bool RunDialog(IntPtr hwndOwner)
-        {
-            using(TranslateForm frm = new TranslateForm())
-            {
-                return frm.ShowDialog() == DialogResult.OK;
-            }
-        }
-
-        sealed class TranslateForm : Form
-        {
-            public TranslateForm()
-            {
-                this.SizeGripStyle = SizeGripStyle.Hide;
-                this.Text = AppString.Dialog.TranslateTool;
-                this.StartPosition = FormStartPosition.CenterParent;
-                this.ShowIcon = this.ShowInTaskbar = this.MinimizeBox = false;
-                this.Font = new Font(SystemFonts.MessageBoxFont.FontFamily, 10F);
-                this.InitializeComponents();
-            }
-
-            readonly Label lblSections = new Label
-            {
-                AutoSize = true,
-                Text = "Section"
-            };
-            readonly Label lblKeys = new Label
-            {
-                AutoSize = true,
-                Text = "Key"
-            };
-            readonly Label lblDefault = new Label
-            {
-                Text = AppString.Dialog.DefaultText,
-                AutoSize = true
-            };
-            readonly Label lblOld = new Label
-            {
-                Text = AppString.Dialog.OldTranslation,
-                AutoSize = true
-            };
-            readonly Label lblNew = new Label
-            {
-                Text = AppString.Dialog.NewTranslation,
-                AutoSize = true
-            };
-            readonly TextBox txtDefault = new TextBox
-            {
-                Multiline = true,
-                ReadOnly = true
-            };
-            readonly TextBox txtOld = new TextBox
-            {
-                Multiline = true,
-                ReadOnly = true
-            };
-            readonly TextBox txtNew = new TextBox
-            {
-                Multiline = true
-            };
-            readonly ComboBox cmbSections = new ComboBox
-            {
-                DropDownStyle = ComboBoxStyle.DropDownList
-            };
-            readonly ComboBox cmbKeys = new ComboBox
-            {
-                DropDownStyle = ComboBoxStyle.DropDownList
-            };
-            readonly Button btnBrowse = new Button
-            {
-                Text = AppString.Dialog.Browse,
-                AutoSize = true
-            };
-            readonly Button btnSave = new Button
-            {
-                Text = AppString.Menu.Save,
-                AutoSize = true
-            };
-            readonly Button btnCancel = new Button
-            {
-                DialogResult = DialogResult.Cancel,
-                Text = AppString.Dialog.Cancel,
-                AutoSize = true
-            };
-
-            static TranslateForm()
-            {
-                foreach(string section in DefaultDic.Keys)
-                {
-                    var dic = new Dictionary<string, string>();
-                    foreach(string key in DefaultDic[section].Keys)
-                    {
-                        dic.Add(key, string.Empty);
-                    }
-                    EditingDic.Add(section, dic);
-                }
-            }
-
-            static readonly Dictionary<string, Dictionary<string, string>> EditingDic
-                = new Dictionary<string, Dictionary<string, string>>();
-            static readonly Dictionary<string, Dictionary<string, string>> DefaultDic
-                = AppString.DefaultLanguage.RootDic;
-
-            static readonly IniWriter ReferentialWirter = new IniWriter();
-
-            private string Section => cmbSections.Text;
-            private string Key => cmbKeys.Text;
-
-            private void InitializeComponents()
-            {
-                this.Controls.AddRange(new Control[] { lblSections, cmbSections, lblKeys,
-                    cmbKeys, lblDefault, txtDefault, lblOld, txtOld, lblNew,
-                    txtNew, btnBrowse, btnSave, btnCancel });
-
-                txtDefault.SetAutoShowScroll(ScrollBars.Vertical);
-                txtOld.SetAutoShowScroll(ScrollBars.Vertical);
-                txtNew.SetAutoShowScroll(ScrollBars.Vertical);
-                txtDefault.CanSelectAllWhenReadOnly();
-                txtOld.CanSelectAllWhenReadOnly();
-                cmbSections.AutosizeDropDownWidth();
-                cmbKeys.AutosizeDropDownWidth();
-
-                int a = 20.DpiZoom();
-
-                lblSections.Top = lblSections.Left = cmbSections.Top = lblKeys.Left
-                    = lblDefault.Left = lblOld.Left = lblNew.Left = btnBrowse.Left = a;
-
-                lblKeys.Top = cmbKeys.Top = cmbSections.Bottom + a;
-                lblDefault.Top = txtDefault.Top = cmbKeys.Bottom + a;
-                txtDefault.Height = txtOld.Height = txtNew.Height = 4 * a;
-                cmbSections.Width = cmbKeys.Width = txtDefault.Width = txtOld.Width = txtNew.Width = 20 * a;
-
-                int h = cmbSections.Height + cmbKeys.Height + btnBrowse.Height;
-                int[] ws = { lblSections.Width, lblKeys.Width, lblDefault.Width, lblOld.Width, lblNew.Width };
-                int w = ws.Max();
-
-                cmbSections.Left = cmbKeys.Left = txtDefault.Left = txtOld.Left = txtNew.Left = w + 2 * a;
-
-                this.Resize += (sender, e) =>
-                {
-                    txtDefault.Height = txtOld.Height = txtNew.Height
-                        = (this.ClientSize.Height - h - 7 * a) / 3;
-
-                    lblOld.Top = txtOld.Top = txtDefault.Bottom + a;
-                    lblNew.Top = txtNew.Top = txtOld.Bottom + a;
-                    btnBrowse.Top = btnSave.Top = btnCancel.Top = txtNew.Bottom + a;
-
-                    cmbSections.Width = cmbKeys.Width = txtDefault.Width = txtOld.Width = txtNew.Width
-                        = this.ClientSize.Width - (w + 3 * a);
-
-                    btnCancel.Left = this.ClientSize.Width - btnCancel.Width - a;
-                    btnSave.Left = btnCancel.Left - btnSave.Width - a;
-                    btnBrowse.Left = btnSave.Left - btnBrowse.Width - a;
-                };
-                this.ClientSize = new Size(w + 23 * a, h + 3 * 4 * a + 7 * a);
-                this.MinimumSize = this.Size;
-
-                cmbSections.Items.AddRange(DefaultDic.Keys.ToArray());
-                cmbSections.SelectedIndexChanged += (sender, e) =>
-                {
-                    cmbKeys.Items.Clear();
-                    cmbKeys.Items.AddRange(DefaultDic[Section].Keys.ToArray());
-                    cmbKeys.SelectedIndex = 0;
-                };
-                cmbKeys.SelectedIndexChanged += (sender, e) =>
-                {
-                    txtNew.Text = EditingDic[Section][Key].Replace("\\n", Environment.NewLine);
-                    txtDefault.Text = DefaultDic[Section][Key].Replace("\\n", Environment.NewLine);
-                    txtOld.Text = ReferentialWirter.GetValue(Section, Key).Replace("\\n", Environment.NewLine);
-                };
-                cmbSections.SelectedIndex = 0;
-
-                txtOld.TextChanged += (sender, e) => { if(txtNew.Text == string.Empty) txtNew.Text = txtOld.Text; };
-                txtNew.TextChanged += (sender, e) => EditingDic[Section][Key] = txtNew.Text.Replace(Environment.NewLine, "\\n");
-                btnBrowse.Click += (sender, e) => SelectFile();
-                btnSave.Click += (sender, e) => Save();
-            }
-
-            private void SelectFile()
-            {
-                using(OpenFileDialog dlg = new OpenFileDialog())
-                {
-                    dlg.InitialDirectory = AppConfig.LangsDir;
-                    dlg.Filter = $"{AppString.SideBar.AppLanguage}|*.ini";
-                    if(dlg.ShowDialog() != DialogResult.OK) return;
-                    ReferentialWirter.FilePath = dlg.FileName;
-                    txtOld.Text = ReferentialWirter.GetValue(Section, Key).Replace("\\n", "\n");
-                }
-            }
-
-            private void Save()
-            {
-                using(SaveFileDialog dlg = new SaveFileDialog())
-                {
-                    string language = EditingDic["General"]["Language"];
-                    int index = language.IndexOf(' ');
-                    if(index > 0) language = language.Substring(0, index);
-                    dlg.FileName = $"{language}.ini";
-                    dlg.InitialDirectory = AppConfig.LangsDir;
-                    dlg.Filter = $"{AppString.SideBar.AppLanguage}|*.ini";
-                    if(dlg.ShowDialog() != DialogResult.OK) return;
-
-                    string contents = string.Empty;
-                    foreach(string section in EditingDic.Keys)
-                    {
-                        contents += $"[{section}]" + Environment.NewLine;
-                        foreach(string key in EditingDic[section].Keys)
-                        {
-                            string value = EditingDic[section][key];
-                            contents += $"{key} = {value}" + Environment.NewLine;
-                        }
-                        contents += Environment.NewLine;
-                    }
-                    File.WriteAllText(dlg.FileName, contents, Encoding.Unicode);
-                }
-            }
-        }
-    }
-}

+ 8 - 55
ContextMenuManager/Controls/UwpModeItem.cs

@@ -1,9 +1,9 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
 using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using Microsoft.Win32;
 using System;
-using System.IO;
 using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls
@@ -11,16 +11,12 @@ namespace ContextMenuManager.Controls
     sealed class UwpModeItem : MyListItem, IChkVisibleItem, ITsiRegPathItem, ITsiFilePathItem,
         IBtnShowMenuItem, ITsiWebSearchItem, ITsiRegExportItem, ITsiRegDeleteItem, ITsiGuidItem
     {
-        private const string PackageRegPath = @"HKEY_CLASSES_ROOT\PackagedCom\Package";
-        private const string PackagesRegPath = @"HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\PackageRepository\Packages";
-
         public UwpModeItem(string uwpName, Guid guid)
         {
             this.Guid = guid;
             this.UwpName = uwpName;
             this.InitializeComponents();
-            //ChkVisible.Checked = ItemVisible;
-            this.Visible = GetPackageName(uwpName) != null;
+            this.Visible = UwpHelper.GetPackageName(uwpName) != null;
             this.Image = GuidInfo.GetImage(guid);
             this.Text = this.ItemText;
         }
@@ -60,59 +56,14 @@ namespace ContextMenuManager.Controls
         }
 
         public string ItemText => GuidInfo.GetText(Guid);
-        public string RegPath => GetGuidRegPath(UwpName, Guid);
-        public string ItemFilePath => GetFilePath(UwpName, Guid);
-
-        public static string GetPackageName(string uwpName)
-        {
-            using(RegistryKey packageKey = RegistryEx.GetRegistryKey(PackageRegPath))
-            {
-                if(packageKey == null) return null;
-                foreach(string packageName in packageKey.GetSubKeyNames())
-                {
-                    if(packageName.StartsWith(uwpName, StringComparison.OrdinalIgnoreCase))
-                    {
-                        return packageName;
-                    }
-                }
-            }
-            return null;
-        }
-
-        public static string GetGuidRegPath(string uwpName, Guid guid)
-        {
-            string packageName = GetPackageName(uwpName);
-            if(packageName == null) return null;
-            else return $@"{PackageRegPath}\{packageName}\Class\{guid:B}";
-        }
-
-        public static string GetFilePath(string uwpName, Guid guid)
-        {
-            string regPath = GetGuidRegPath(uwpName, guid);
-            if(regPath == null) return null;
-            string packageName = GetPackageName(uwpName);
-            using(RegistryKey pKey = RegistryEx.GetRegistryKey($@"{PackagesRegPath}\{packageName}"))
-            {
-                if(pKey == null) return null;
-                string dirPath = pKey.GetValue("Path")?.ToString();
-                string dllPath = Registry.GetValue(regPath, "DllPath", null)?.ToString();
-                string filePath = $@"{dirPath}\{dllPath}";
-                if(File.Exists(filePath)) return filePath;
-                string[] names = pKey.GetSubKeyNames();
-                if(names.Length == 1)
-                {
-                    filePath = "shell:AppsFolder\\" + names[0];
-                    return filePath;
-                }
-                if(Directory.Exists(dirPath)) return dirPath;
-                return null;
-            }
-        }
+        public string RegPath => UwpHelper.GetRegPath(UwpName, Guid);
+        public string ItemFilePath => UwpHelper.GetFilePath(UwpName, Guid);
 
         public string SearchText => Text;
         public string ValueName => "DllPath";
         public MenuButton BtnShowMenu { get; set; }
         public VisibleCheckBox ChkVisible { get; set; }
+        public DetailedEditButton BtnDetailedEdit { get; set; }
         public RegLocationMenuItem TsiRegLocation { get; set; }
         public FileLocationMenuItem TsiFileLocation { get; set; }
         public FilePropertiesMenuItem TsiFileProperties { get; set; }
@@ -120,12 +71,14 @@ namespace ContextMenuManager.Controls
         public DeleteMeMenuItem TsiDeleteMe { get; set; }
         public RegExportMenuItem TsiRegExport { get; set; }
         public HandleGuidMenuItem TsiHandleGuid { get; set; }
+
         readonly ToolStripMenuItem TsiDetails = new ToolStripMenuItem(AppString.Menu.Details);
 
         private void InitializeComponents()
         {
             BtnShowMenu = new MenuButton(this);
             ChkVisible = new VisibleCheckBox(this);
+            BtnDetailedEdit = new DetailedEditButton(this);
             TsiSearch = new WebSearchMenuItem(this);
             TsiFileLocation = new FileLocationMenuItem(this);
             TsiFileProperties = new FilePropertiesMenuItem(this);
@@ -133,6 +86,7 @@ namespace ContextMenuManager.Controls
             TsiDeleteMe = new DeleteMeMenuItem(this);
             TsiRegExport = new RegExportMenuItem(this);
             TsiHandleGuid = new HandleGuidMenuItem(this);
+
             this.ContextMenuStrip.Items.AddRange(new ToolStripItem[] { TsiHandleGuid,
                 new ToolStripSeparator(), TsiDetails, new ToolStripSeparator(), TsiDeleteMe });
             TsiDetails.DropDownItems.AddRange(new ToolStripItem[] { TsiSearch, new ToolStripSeparator(),
@@ -142,7 +96,6 @@ namespace ContextMenuManager.Controls
         public void DeleteMe()
         {
             RegistryEx.DeleteKeyTree(this.RegPath);
-            this.Dispose();
         }
     }
 }

+ 22 - 36
ContextMenuManager/Controls/WinXGroupItem.cs

@@ -1,50 +1,38 @@
-using BluePointLilac.Methods;
-using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using System.IO;
 using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls
 {
-    sealed class WinXGroupItem : GroupPathItem, IChkVisibleItem, ITsiDeleteItem, ITsiTextItem
+    sealed class WinXGroupItem : FoldGroupItem, IChkVisibleItem, ITsiDeleteItem, ITsiTextItem
     {
         public WinXGroupItem(string groupPath) : base(groupPath, ObjectPath.PathType.Directory)
         {
             InitializeComponents();
-            this.TargetPath = groupPath;
-        }
-
-        public new string TargetPath
-        {
-            get => base.TargetPath;
-            set
-            {
-                base.TargetPath = value;
-                this.Text = Path.GetFileNameWithoutExtension(value);
-                this.Image = ResourceIcon.GetFolderIcon(value).ToBitmap();
-            }
         }
 
         public bool ItemVisible
         {
-            get => (File.GetAttributes(TargetPath) & FileAttributes.Hidden) != FileAttributes.Hidden;
+            get => (File.GetAttributes(GroupPath) & FileAttributes.Hidden) != FileAttributes.Hidden;
             set
             {
-                FileAttributes attributes = File.GetAttributes(TargetPath);
+                FileAttributes attributes = File.GetAttributes(GroupPath);
                 if(value) attributes &= ~FileAttributes.Hidden;
                 else attributes |= FileAttributes.Hidden;
-                File.SetAttributes(TargetPath, attributes);
-                if(Directory.GetFiles(TargetPath).Length > 0) ExplorerRestarter.Show();
+                File.SetAttributes(GroupPath, attributes);
+                if(Directory.GetFiles(GroupPath).Length > 0) ExplorerRestarter.Show();
             }
         }
 
         public string ItemText
         {
-            get => Path.GetFileNameWithoutExtension(TargetPath);
+            get => Path.GetFileNameWithoutExtension(GroupPath);
             set
             {
                 string newPath = $@"{WinXList.WinXPath}\{ObjectPath.RemoveIllegalChars(value)}";
-                Directory.Move(TargetPath, newPath);
-                this.TargetPath = newPath;
+                Directory.Move(GroupPath, newPath);
+                this.GroupPath = newPath;
                 ExplorerRestarter.Show();
             }
         }
@@ -62,24 +50,23 @@ namespace ContextMenuManager.Controls
             this.SetCtrIndex(ChkVisible, 1);
             TsiDeleteMe = new DeleteMeMenuItem(this);
             TsiChangeText = new ChangeTextMenuItem(this);
-            this.ContextMenuStrip = new ContextMenuStrip();
-            this.ContextMenuStrip.Items.AddRange(new ToolStripItem[] { TsiChangeText,
-                new ToolStripSeparator(), TsiRestoreDefault, new ToolStripSeparator(), TsiDeleteMe });
+            this.ContextMenuStrip.Items.AddRange(new ToolStripItem[] { new ToolStripSeparator(),
+                TsiChangeText, TsiRestoreDefault, new ToolStripSeparator(), TsiDeleteMe });
             this.ContextMenuStrip.Opening += (sender, e) => TsiRestoreDefault.Enabled = Directory.Exists(DefaultGroupPath);
             TsiRestoreDefault.Click += (sender, e) => RestoreDefault();
         }
 
         private void RestoreDefault()
         {
-            if(MessageBoxEx.Show(AppString.Message.RestoreDefault, MessageBoxButtons.OKCancel) == DialogResult.OK)
+            if(AppMessageBox.Show(AppString.Message.RestoreDefault, MessageBoxButtons.OKCancel) == DialogResult.OK)
             {
-                File.SetAttributes(TargetPath, FileAttributes.Normal);
-                Directory.Delete(TargetPath, true);
-                Directory.CreateDirectory(TargetPath);
-                File.SetAttributes(TargetPath, File.GetAttributes(DefaultGroupPath));
+                File.SetAttributes(GroupPath, FileAttributes.Normal);
+                Directory.Delete(GroupPath, true);
+                Directory.CreateDirectory(GroupPath);
+                File.SetAttributes(GroupPath, File.GetAttributes(DefaultGroupPath));
                 foreach(string srcPath in Directory.GetFiles(DefaultGroupPath))
                 {
-                    string dstPath = $@"{TargetPath}\{Path.GetFileName(srcPath)}";
+                    string dstPath = $@"{GroupPath}\{Path.GetFileName(srcPath)}";
                     File.Copy(srcPath, dstPath);
                 }
                 WinXList list = (WinXList)this.Parent;
@@ -91,10 +78,10 @@ namespace ContextMenuManager.Controls
 
         public void DeleteMe()
         {
-            bool flag = Directory.GetFiles(TargetPath, "*.lnk").Length > 0;
-            if(flag && MessageBoxEx.Show(AppString.Message.DeleteGroup, MessageBoxButtons.OKCancel) != DialogResult.OK) return;
-            File.SetAttributes(TargetPath, FileAttributes.Normal);
-            Directory.Delete(TargetPath, true);
+            bool flag = Directory.GetFiles(GroupPath, "*.lnk").Length > 0;
+            if(flag && AppMessageBox.Show(AppString.Message.DeleteGroup, MessageBoxButtons.OKCancel) != DialogResult.OK) return;
+            File.SetAttributes(GroupPath, FileAttributes.Normal);
+            Directory.Delete(GroupPath, true);
             if(flag)
             {
                 WinXList list = (WinXList)this.Parent;
@@ -102,7 +89,6 @@ namespace ContextMenuManager.Controls
                 list.LoadItems();
                 ExplorerRestarter.Show();
             }
-            else this.Dispose();
         }
     }
 }

+ 11 - 7
ContextMenuManager/Controls/WinXItem.cs

@@ -1,20 +1,22 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
 using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using System.Drawing;
 using System.IO;
 using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls
 {
-    sealed class WinXItem : MyListItem, IChkVisibleItem, IBtnShowMenuItem, IBtnMoveUpDownItem, ITsiAdministratorItem,
-        ITsiTextItem, ITsiWebSearchItem, ITsiFilePathItem, ITsiDeleteItem, IFoldSubItem, ITsiShortcutCommandItem
+    sealed class WinXItem : FoldSubItem, IChkVisibleItem, IBtnShowMenuItem, IBtnMoveUpDownItem, ITsiAdministratorItem,
+        ITsiTextItem, ITsiWebSearchItem, ITsiFilePathItem, ITsiDeleteItem, ITsiShortcutCommandItem
     {
-        public WinXItem(string filePath, IFoldGroupItem group)
+        public WinXItem(string filePath, FoldGroupItem group)
         {
             InitializeComponents();
             this.FoldGroupItem = group;
             this.FilePath = filePath;
+            this.Indent();
         }
 
         private string filePath;
@@ -26,7 +28,7 @@ namespace ContextMenuManager.Controls
                 filePath = value;
                 this.ShellLink = new ShellLink(value);
                 this.Text = this.ItemText;
-                this.Image = this.ItemIcon.ToBitmap();
+                this.Image = this.ItemImage;
             }
         }
 
@@ -43,6 +45,7 @@ namespace ContextMenuManager.Controls
             {
                 ShellLink.Description = value;
                 ShellLink.Save();
+                DesktopIni.SetLocalizedFileNames(FilePath, value);
                 this.Text = ResourceString.GetDirectString(value);
                 ExplorerRestarter.Show();
             }
@@ -57,6 +60,7 @@ namespace ContextMenuManager.Controls
                 if(value) attributes &= ~FileAttributes.Hidden;
                 else attributes |= FileAttributes.Hidden;
                 File.SetAttributes(FilePath, attributes);
+                if(value) WinXHasher.HashLnk(FilePath);
                 ExplorerRestarter.Show();
             }
         }
@@ -93,8 +97,8 @@ namespace ContextMenuManager.Controls
         public ShellLink ShellLink { get; private set; }
         public string SearchText => $"{AppString.SideBar.WinX} {Text}";
         private string FileName => Path.GetFileName(FilePath);
+        private Image ItemImage => ItemIcon?.ToBitmap() ?? AppImage.NotFound;
 
-        public IFoldGroupItem FoldGroupItem { get; set; }
         public VisibleCheckBox ChkVisible { get; set; }
         public MenuButton BtnShowMenu { get; set; }
         public ChangeTextMenuItem TsiChangeText { get; set; }
@@ -109,6 +113,7 @@ namespace ContextMenuManager.Controls
 
         readonly ToolStripMenuItem TsiDetails = new ToolStripMenuItem(AppString.Menu.Details);
         readonly ToolStripMenuItem TsiChangeGroup = new ToolStripMenuItem(AppString.Menu.ChangeGroup);
+
         private void InitializeComponents()
         {
             BtnShowMenu = new MenuButton(this);
@@ -137,7 +142,7 @@ namespace ContextMenuManager.Controls
             {
                 if(TsiChangeCommand.ChangeCommand(ShellLink))
                 {
-                    Image = ItemIcon.ToBitmap();
+                    Image = this.ItemImage;
                     WinXHasher.HashLnk(FilePath);
                     ExplorerRestarter.Show();
                 }
@@ -219,7 +224,6 @@ namespace ContextMenuManager.Controls
             DesktopIni.DeleteLocalizedFileNames(FilePath);
             ExplorerRestarter.Show();
             this.ShellLink.Dispose();
-            this.Dispose();
         }
     }
 }

+ 22 - 10
ContextMenuManager/Controls/WinXList.cs

@@ -1,5 +1,6 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
+using ContextMenuManager.Methods;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -11,11 +12,11 @@ namespace ContextMenuManager.Controls
     sealed class WinXList : MyList
     {
         public static readonly string WinXPath = Environment.ExpandEnvironmentVariables(@"%LocalAppData%\Microsoft\Windows\WinX");
-        public static readonly string DefaultWinXPath = Environment.ExpandEnvironmentVariables(@"%HOMEDRIVE%\Users\Default\AppData\Local\Microsoft\Windows\WinX");
+        public static readonly string DefaultWinXPath = Environment.ExpandEnvironmentVariables(@"%SystemDrive%\Users\Default\AppData\Local\Microsoft\Windows\WinX");
 
         public void LoadItems()
         {
-            if(WindowsOsVersion.ISAfterOrEqual8)
+            if(WinOsVersion.Current >= WinOsVersion.Win8)
             {
                 this.AddNewItem();
                 this.LoadWinXItems();
@@ -26,14 +27,13 @@ namespace ContextMenuManager.Controls
         {
             string[] dirPaths = Directory.GetDirectories(WinXPath);
             Array.Reverse(dirPaths);
-            bool sortable = AppConfig.WinXSortable;
             bool sorted = false;
             foreach(string dirPath in dirPaths)
             {
                 WinXGroupItem groupItem = new WinXGroupItem(dirPath);
                 this.AddItem(groupItem);
                 string[] lnkPaths;
-                if(sortable)
+                if(AppConfig.WinXSortable)
                 {
                     lnkPaths = GetSortedPaths(dirPath, out bool flag);
                     if(flag) sorted = true;
@@ -46,15 +46,14 @@ namespace ContextMenuManager.Controls
                 foreach(string path in lnkPaths)
                 {
                     WinXItem winXItem = new WinXItem(path, groupItem);
-                    winXItem.BtnMoveDown.Visible = winXItem.BtnMoveUp.Visible = sortable;
+                    winXItem.BtnMoveDown.Visible = winXItem.BtnMoveUp.Visible = AppConfig.WinXSortable;
                     this.AddItem(winXItem);
                 }
-                groupItem.IsFold = true;
             }
             if(sorted)
             {
                 ExplorerRestarter.Show();
-                MessageBoxEx.Show(AppString.Message.WinXSorted);
+                AppMessageBox.Show(AppString.Message.WinXSorted);
             }
         }
 
@@ -156,12 +155,25 @@ namespace ContextMenuManager.Controls
                 {
                     sortedPaths.Add(srcPath); continue;
                 }
-                string dstPath = $@"{groupPath}\{(i + 1).ToString().PadLeft(2, '0')} - {name.Substring(index + 3)}";
+                if(index >= 0) name = name.Substring(index + 3);
+                string dstPath = $@"{groupPath}\{(i + 1).ToString().PadLeft(2, '0')} - {name}";
                 dstPath = ObjectPath.GetNewPathWithIndex(dstPath, ObjectPath.PathType.File);
-                string value = DesktopIni.GetLocalizedFileNames(srcPath);
+
+                string value;
+                using(ShellLink srcLnk = new ShellLink(srcPath))
+                {
+                    value = srcLnk.Description?.Trim();
+                }
+                if(string.IsNullOrEmpty(value)) value = DesktopIni.GetLocalizedFileNames(srcPath);
+                if(string.IsNullOrEmpty(value)) value = Path.GetFileNameWithoutExtension(name);
                 DesktopIni.DeleteLocalizedFileNames(srcPath);
-                if(value != string.Empty) DesktopIni.SetLocalizedFileNames(dstPath, value);
+                DesktopIni.SetLocalizedFileNames(dstPath, value);
                 File.Move(srcPath, dstPath);
+                using(ShellLink dstLnk = new ShellLink(dstPath))
+                {
+                    dstLnk.Description = value;
+                    dstLnk.Save();
+                }
                 sortedPaths.Add(dstPath);
                 sorted = true;
             }

+ 248 - 111
ContextMenuManager/MainForm.cs

@@ -1,10 +1,10 @@
 using BluePointLilac.Controls;
 using BluePointLilac.Methods;
 using ContextMenuManager.Controls;
-using ContextMenuManager.Controls.Interfaces;
+using ContextMenuManager.Methods;
 using System;
-using System.Drawing;
-using System.IO;
+using System.Collections.Generic;
+using System.Globalization;
 using System.Linq;
 using System.Windows.Forms;
 
@@ -14,56 +14,62 @@ namespace ContextMenuManager
     {
         public MainForm()
         {
-            SideBar.Width = GetSideBarWidth();
+            this.TopMost = AppConfig.TopMost;
+            this.Size = AppConfig.MainFormSize;
             this.Text = AppString.General.AppName;
-            this.ForeColor = Color.FromArgb(80, 80, 80);
-            this.Controls.Add(new ExplorerRestarter());
-            donateBox.Parent = aboutMeBox.Parent = dictionariesBox.Parent
-                = languagesBox.Parent = appSettingBox.Owner = shellList.Owner
-                = shellNewList.Owner = sendToList.Owner = openWithList.Owner
-                = winXList.Owner = guidBlockedList.Owner = enhanceMenusList.Owner
-                = thirdRuleList.Owner = iEList.Owner = MainBody;
-            ToolBar.SelectedButtonChanged += () => SwitchTab(ToolBar.SelectedIndex);
-            SideBar.HoverIndexChanged += () => ShowItemInfo();
-            SideBar.SelectIndexChanged += () => SwitchItem();
-            ToolBarButtons[3].MouseDown += (sender, e) => SwitchItem();
+            this.Controls.Add(explorerRestarter);
             ToolBar.AddButtons(ToolBarButtons);
-            ToolBar.SelectedIndex = 0;
-            if(AppConfig.ShowFilePath) ShowFilePath();
-            var droper = new ElevatedFileDroper(this);
-            droper.DragDrop += () =>
-            {
-                ShellList.CurrentFileObjectPath = droper.DropFilePaths[0];
-                SwitchTab(1, 9);
-            };
+            MainBody.Controls.AddRange(MainControls);
+            ToolBarButtons[3].CanBeSelected = false;
+            ToolBarButtons[3].MouseDown += (sender, e) => RefreshApp();
+            ToolBar.SelectedButtonChanged += (sender, e) => SwitchTab();
+            SideBar.HoverIndexChanged += (sender, e) => ShowItemInfo();
+            SideBar.SelectIndexChanged += (sender, e) => SwitchItem();
+            this.Shown += (sender, e) => FirstRunDownloadLanguage();
+            this.FormClosing += (sender, e) => CloseMainForm();
+            HoveredToShowItemPath();
+            DragDropToAnalysis();
+            AddContextMenus();
+            ResizeSideBar();
+            JumpItem(0, 0);
         }
 
-        readonly MyToolBarButton[] ToolBarButtons = new MyToolBarButton[] {
+        readonly MyToolBarButton[] ToolBarButtons =
+        {
             new MyToolBarButton(AppImage.Home, AppString.ToolBar.Home),
             new MyToolBarButton(AppImage.Type, AppString.ToolBar.Type),
             new MyToolBarButton(AppImage.Star, AppString.ToolBar.Rule),
-            new MyToolBarButton(AppImage.Refresh,AppString.ToolBar.Refresh){ CanBeSelected = false },
+            new MyToolBarButton(AppImage.Refresh, AppString.ToolBar.Refresh),
             new MyToolBarButton(AppImage.About, AppString.ToolBar.About)
         };
+
+        private Control[] MainControls => new Control[]
+        {
+            shellList, shellNewList, sendToList, openWithList, winXList,
+            enhanceMenusList, detailedEditList, guidBlockedList, iEList,
+            appSettingBox, languagesBox, dictionariesBox, aboutMeBox, donateBox
+        };
+
         readonly ShellList shellList = new ShellList();
         readonly ShellNewList shellNewList = new ShellNewList();
         readonly SendToList sendToList = new SendToList();
         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 DetailedEditList detailedEditList = new DetailedEditList();
+        readonly GuidBlockedList guidBlockedList = new GuidBlockedList();
         readonly IEList iEList = new IEList();
-        readonly ReadOnlyRichTextBox aboutMeBox = new ReadOnlyRichTextBox
-        {
-            Text = AppString.Other.AboutApp
-        };
-        readonly DonateBox donateBox = new DonateBox();
+
+        readonly AppSettingBox appSettingBox = new AppSettingBox();
         readonly LanguagesBox languagesBox = new LanguagesBox();
         readonly DictionariesBox dictionariesBox = new DictionariesBox();
-        readonly AppSettingBox appSettingBox = new AppSettingBox();
+        readonly ReadOnlyRichTextBox aboutMeBox = new ReadOnlyRichTextBox();
+        readonly DonateBox donateBox = new DonateBox();
+        readonly ExplorerRestarter explorerRestarter = new ExplorerRestarter();
 
-        static readonly string[] GeneralItems = {
+        static readonly string[] GeneralItems =
+        {
             AppString.SideBar.File,
             AppString.SideBar.Folder,
             AppString.SideBar.Directory,
@@ -81,7 +87,8 @@ namespace ContextMenuManager
             null,
             AppString.SideBar.WinX
         };
-        static readonly string[] GeneralItemInfos = {
+        static readonly string[] GeneralItemInfos =
+        {
             AppString.StatusBar.File,
             AppString.StatusBar.Folder,
             AppString.StatusBar.Directory,
@@ -100,7 +107,8 @@ namespace ContextMenuManager
             AppString.StatusBar.WinX
         };
 
-        static readonly string[] TypeItems = {
+        static readonly string[] TypeItems =
+        {
             AppString.SideBar.LnkFile,
             AppString.SideBar.UwpLnk,
             AppString.SideBar.ExeFile,
@@ -112,7 +120,8 @@ namespace ContextMenuManager
             AppString.SideBar.UnknownType,
             AppString.SideBar.MenuAnalysis
         };
-        static readonly string[] TypeItemInfos = {
+        static readonly string[] TypeItemInfos =
+        {
             AppString.StatusBar.LnkFile,
             AppString.StatusBar.UwpLnk,
             AppString.StatusBar.ExeFile,
@@ -125,30 +134,33 @@ namespace ContextMenuManager
             AppString.StatusBar.MenuAnalysis
         };
 
-        static readonly string[] OtherRuleItems = {
+        static readonly string[] OtherRuleItems =
+        {
             AppString.SideBar.EnhanceMenu,
-            AppString.SideBar.ThirdRules,
+            AppString.SideBar.DetailedEdit,
             null,
             AppString.SideBar.DragDrop,
             AppString.SideBar.PublicReferences,
             AppString.SideBar.CustomRegPath,
             null,
             AppString.SideBar.GuidBlocked,
-            AppString.SideBar.IEMenu,
+            AppString.SideBar.IEMenu
         };
-        static readonly string[] OtherRuleItemInfos = {
+        static readonly string[] OtherRuleItemInfos =
+        {
             AppString.StatusBar.EnhanceMenu,
-            AppString.StatusBar.ThirdRules,
+            AppString.StatusBar.DetailedEdit,
             null,
             AppString.StatusBar.DragDrop,
             AppString.StatusBar.PublicReferences,
             AppString.StatusBar.CustomRegPath,
             null,
             AppString.StatusBar.GuidBlocked,
-            AppString.StatusBar.IEMenu,
+            AppString.StatusBar.IEMenu
         };
 
-        static readonly string[] AboutItems = {
+        static readonly string[] AboutItems =
+        {
             AppString.SideBar.AppSetting,
             AppString.SideBar.AppLanguage,
             AppString.SideBar.Dictionaries,
@@ -156,6 +168,17 @@ namespace ContextMenuManager
             AppString.SideBar.Donate
         };
 
+        static readonly string[] SettingItems =
+        {
+            AppString.Other.TopMost,
+            null,
+            AppString.Other.ShowFilePath,
+            AppString.Other.HideDisabledItems,
+            null,
+            AppString.Other.OpenMoreRegedit,
+            AppString.Other.OpenMoreExplorer,
+        };
+
         static readonly ShellList.Scenes[] GeneralShellScenes =
         {
             ShellList.Scenes.File,
@@ -184,10 +207,35 @@ namespace ContextMenuManager
             ShellList.Scenes.MenuAnalysis
         };
 
-        public void SwitchTab(int toolbarIndex, int sidebarIndex = 0)
+        readonly int[] lastItemIndex = new int[5];
+
+        public void JumpItem(int toolBarIndex, int sideBarIndex)
         {
-            ToolBar.SelectedIndex = toolbarIndex;
-            switch(toolbarIndex)
+            bool flag1 = ToolBar.SelectedIndex == toolBarIndex;
+            bool flag2 = SideBar.SelectedIndex == sideBarIndex;
+            lastItemIndex[toolBarIndex] = sideBarIndex;
+            ToolBar.SelectedIndex = toolBarIndex;
+            if(flag1 || flag2)
+            {
+                SideBar.SelectedIndex = sideBarIndex;
+                SwitchItem();
+            }
+        }
+
+        private void RefreshApp()
+        {
+            this.Cursor = Cursors.WaitCursor;
+            ObjectPath.FilePathDic.Clear();
+            AppConfig.ReloadConfig();
+            GuidInfo.ReloadDics();
+            XmlDicHelper.ReloadDics();
+            this.SwitchItem();
+            this.Cursor = Cursors.Default;
+        }
+
+        private void SwitchTab()
+        {
+            switch(ToolBar.SelectedIndex)
             {
                 case 0:
                     SideBar.ItemNames = GeneralItems; break;
@@ -198,17 +246,17 @@ namespace ContextMenuManager
                 case 4:
                     SideBar.ItemNames = AboutItems; break;
             }
-            SideBar.SelectIndex = sidebarIndex;
+            SideBar.SelectedIndex = lastItemIndex[ToolBar.SelectedIndex];
         }
 
         private void SwitchItem()
         {
-            foreach(Control ctr in MainBody.Controls)
+            foreach(Control ctr in MainControls)
             {
                 ctr.Visible = false;
-                if(ctr is MyList list && list != appSettingBox) list.ClearItems();
+                if(ctr is MyList list) list.ClearItems();
             }
-            if(SideBar.SelectIndex == -1) return;
+            if(SideBar.SelectedIndex == -1) return;
             switch(ToolBar.SelectedIndex)
             {
                 case 0:
@@ -220,13 +268,15 @@ namespace ContextMenuManager
                 case 4:
                     SwitchAboutItem(); break;
             }
+            lastItemIndex[ToolBar.SelectedIndex] = SideBar.SelectedIndex;
+            this.SuspendMainBodyWhenMove = MainControls.ToList().Any(ctr => ctr.Controls.Count > 50);
         }
 
         private void ShowItemInfo()
         {
-            if(SideBar.HoverIndex >= 0)
+            if(SideBar.HoveredIndex >= 0)
             {
-                int i = SideBar.HoverIndex;
+                int i = SideBar.HoveredIndex;
                 switch(ToolBar.SelectedIndex)
                 {
                     case 0:
@@ -240,48 +290,40 @@ namespace ContextMenuManager
             StatusBar.Text = MyStatusBar.DefaultText;
         }
 
-        private void ShowFilePath()
+        private void HoveredToShowItemPath()
         {
-            foreach(MyList list in new MyList[] { shellList, shellNewList, sendToList, openWithList, winXList, guidBlockedList, iEList })
+            foreach(Control ctr in MainBody.Controls)
             {
-                list.HoveredItemChanged += () =>
+                if(ctr is MyList list && list != appSettingBox)
                 {
-                    MyListItem item = list.HoveredItem;
-                    if(item is ITsiFilePathItem pathItem)
-                    {
-                        string path = pathItem.ItemFilePath;
-                        if(path != null)
-                        {
-                            if(File.Exists(path) || path.StartsWith("shell:AppsFolder"))
-                            {
-                                StatusBar.Text = path; return;
-                            }
-                        }
-                    }
-                    if(item is GuidBlockedItem guidItem)
-                    {
-                        StatusBar.Text = guidItem.Value; return;
-                    }
-                    else if(item is ShellList.SelectItem selectItem)
+                    list.HoveredItemChanged += (sender, e) =>
                     {
-                        switch(shellList.Scene)
+                        if(!AppConfig.ShowFilePath) return;
+                        MyListItem item = list.HoveredItem;
+                        foreach(string prop in new[] { "ItemFilePath", "RegPath", "GroupPath", "SelectedPath" })
                         {
-                            case ShellList.Scenes.CustomRegPath:
-                                StatusBar.Text = ShellList.CurrentCustomRegPath ?? item.Text; return;
-                            case ShellList.Scenes.MenuAnalysis:
-                                StatusBar.Text = ShellList.CurrentFileObjectPath ?? item.Text; return;
+                            string path = item.GetType().GetProperty(prop)?.GetValue(item, null)?.ToString();
+                            if(!path.IsNullOrWhiteSpace()) { StatusBar.Text = path; return; }
                         }
-                    }
-                    string regPath = item.GetType().GetProperty("RegPath")?.GetValue(item, null)?.ToString();
-                    if(regPath != null) StatusBar.Text = regPath;
-                    else StatusBar.Text = item.Text;
-                };
+                        StatusBar.Text = item.Text;
+                    };
+                }
             }
         }
 
+        private void DragDropToAnalysis()
+        {
+            var droper = new ElevatedFileDroper(this);
+            droper.DragDrop += (sender, e) =>
+            {
+                ShellList.CurrentFileObjectPath = droper.DropFilePaths[0];
+                JumpItem(1, 9);
+            };
+        }
+
         private void SwitchGeneralItem()
         {
-            switch(SideBar.SelectIndex)
+            switch(SideBar.SelectedIndex)
             {
                 case 11:
                     shellNewList.LoadItems(); shellNewList.Visible = true; break;
@@ -292,31 +334,26 @@ namespace ContextMenuManager
                 case 15:
                     winXList.LoadItems(); winXList.Visible = true; break;
                 default:
-                    if(SideBar.SelectIndex <= 9)
-                    {
-                        shellList.Scene = GeneralShellScenes[SideBar.SelectIndex];
-                        shellList.LoadItems();
-                        shellList.Visible = true;
-                    }
-                    break;
+                    shellList.Scene = GeneralShellScenes[SideBar.SelectedIndex];
+                    shellList.LoadItems(); shellList.Visible = true; break;
             }
         }
 
         private void SwitchTypeItem()
         {
-            shellList.Scene = (ShellList.Scenes)TypeShellScenes[SideBar.SelectIndex];
+            shellList.Scene = (ShellList.Scenes)TypeShellScenes[SideBar.SelectedIndex];
             shellList.LoadItems();
             shellList.Visible = true;
         }
 
         private void SwitchOtherRuleItem()
         {
-            switch(SideBar.SelectIndex)
+            switch(SideBar.SelectedIndex)
             {
                 case 0:
-                    enhanceMenusList.LoadItems(); enhanceMenusList.Visible = true; break;
+                    enhanceMenusList.ScenePath = null; enhanceMenusList.LoadItems(); enhanceMenusList.Visible = true; break;
                 case 1:
-                    thirdRuleList.LoadItems(); thirdRuleList.Visible = true; break;
+                    detailedEditList.GroupGuid = Guid.Empty; detailedEditList.LoadItems(); detailedEditList.Visible = true; break;
                 case 3:
                     shellList.Scene = ShellList.Scenes.DragDrop; shellList.LoadItems(); shellList.Visible = true; break;
                 case 4:
@@ -327,41 +364,141 @@ namespace ContextMenuManager
                     guidBlockedList.LoadItems(); guidBlockedList.Visible = true; break;
                 case 8:
                     iEList.LoadItems(); iEList.Visible = true; break;
-                case 9:
-                    break;
             }
         }
 
         private void SwitchAboutItem()
         {
-            switch(SideBar.SelectIndex)
+            switch(SideBar.SelectedIndex)
             {
                 case 0:
-                    appSettingBox.LoadItems();
-                    appSettingBox.Visible = true;
+                    appSettingBox.LoadItems(); appSettingBox.Visible = true;
                     break;
                 case 1:
-                    languagesBox.LoadLanguages();
-                    languagesBox.Visible = true;
+                    languagesBox.LoadLanguages(); languagesBox.Visible = true;
                     break;
                 case 2:
-                    dictionariesBox.Visible = true;
+                    dictionariesBox.LoadText(); dictionariesBox.Visible = true;
                     break;
                 case 3:
-                    aboutMeBox.Visible = true;
-                    break;
+                    if(aboutMeBox.TextLength == 0) aboutMeBox.LoadIni(AppString.Other.AboutApp);
+                    aboutMeBox.Visible = true; break;
                 case 4:
-                    donateBox.Visible = true;
-                    break;
+                    donateBox.Visible = true; break;
             }
         }
 
-        public int GetSideBarWidth()
+        private void ResizeSideBar()
         {
-            int maxWidth = 0;
+            SideBar.Width = 0;
             string[] strs = GeneralItems.Concat(TypeItems).Concat(OtherRuleItems).Concat(AboutItems).ToArray();
-            Array.ForEach(strs, str => maxWidth = Math.Max(maxWidth, SideBar.GetItemWidth(str)));
-            return maxWidth;
+            Array.ForEach(strs, str => SideBar.Width = Math.Max(SideBar.Width, SideBar.GetItemWidth(str)));
+        }
+
+        private void AddContextMenus()
+        {
+            var dic = new Dictionary<MyToolBarButton, string[]>
+            {
+                { ToolBarButtons[0], GeneralItems },
+                { ToolBarButtons[1], TypeItems },
+                { ToolBarButtons[2], OtherRuleItems },
+                { ToolBarButtons[4], SettingItems }
+            };
+
+            foreach(var item in dic)
+            {
+                ContextMenuStrip cms = new ContextMenuStrip();
+                cms.MouseEnter += (sender, e) =>
+                {
+                    if(item.Key != ToolBar.SelectedButton) item.Key.Opacity = 0.2F;
+                };
+                cms.Closed += (sender, e) =>
+                {
+                    if(item.Key != ToolBar.SelectedButton) item.Key.Opacity = 0;
+                };
+                item.Key.MouseDown += (sender, e) =>
+                {
+                    if(e.Button != MouseButtons.Right) return;
+                    if(sender == ToolBar.SelectedButton) return;
+                    cms.Show(item.Key, e.Location);
+                };
+                for(int i = 0; i < item.Value.Length; i++)
+                {
+                    if(item.Value[i] == null) cms.Items.Add(new ToolStripSeparator());
+                    else
+                    {
+                        ToolStripMenuItem tsi = new ToolStripMenuItem(item.Value[i]);
+                        cms.Items.Add(tsi);
+                        int toolBarIndex = ToolBar.Controls.GetChildIndex(item.Key);
+                        int index = i;
+                        if(toolBarIndex != 4)
+                        {
+                            tsi.Click += (sender, e) => JumpItem(toolBarIndex, index);
+                            cms.Opening += (sender, e) => tsi.Checked = lastItemIndex[toolBarIndex] == index;
+                        }
+                        else
+                        {
+                            tsi.Click += (sender, e) =>
+                            {
+                                switch(index)
+                                {
+                                    case 0:
+                                        AppConfig.TopMost = this.TopMost = !tsi.Checked; break;
+                                    case 2:
+                                        AppConfig.ShowFilePath = !tsi.Checked; break;
+                                    case 3:
+                                        AppConfig.HideDisabledItems = !tsi.Checked; SwitchItem(); break;
+                                    case 5:
+                                        AppConfig.OpenMoreRegedit = !tsi.Checked; break;
+                                    case 6:
+                                        AppConfig.OpenMoreExplorer = !tsi.Checked; break;
+                                }
+                            };
+                            cms.Opening += (sender, e) =>
+                            {
+                                switch(index)
+                                {
+                                    case 0:
+                                        tsi.Checked = this.TopMost; break;
+                                    case 2:
+                                        tsi.Checked = AppConfig.ShowFilePath; break;
+                                    case 3:
+                                        tsi.Checked = AppConfig.HideDisabledItems; break;
+                                    case 5:
+                                        tsi.Checked = AppConfig.OpenMoreRegedit; break;
+                                    case 6:
+                                        tsi.Checked = AppConfig.OpenMoreExplorer; break;
+                                }
+                            };
+                        }
+                    }
+                }
+            }
+        }
+
+        private void FirstRunDownloadLanguage()
+        {
+            if(AppConfig.IsFirstRun && CultureInfo.CurrentUICulture.Name != "zh-CN")
+            {
+                if(AppMessageBox.Show("It is detected that you may be running this program for the first time,\n" +
+                    "and your system display language is not simplified Chinese (zh-CN),\n" +
+                    "do you need to download another language?",
+                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
+                {
+                    JumpItem(4, 1);
+                    languagesBox.ShowLanguageDialog();
+                }
+            }
+        }
+
+        private void CloseMainForm()
+        {
+            if(explorerRestarter.Visible && AppMessageBox.Show(explorerRestarter.Text,
+                MessageBoxButtons.OKCancel) == DialogResult.OK) ExternalProgram.RestartExplorer();
+            this.Opacity = 0;
+            this.WindowState = FormWindowState.Normal;
+            explorerRestarter.Visible = false;
+            AppConfig.MainFormSize = this.Size;
         }
     }
 }

+ 278 - 0
ContextMenuManager/Methods/AppConfig.cs

@@ -0,0 +1,278 @@
+using BluePointLilac.Methods;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Windows.Forms;
+
+namespace ContextMenuManager.Methods
+{
+    static class AppConfig
+    {
+        static AppConfig()
+        {
+            CreateDirectory();
+            ReloadConfig();
+            LoadLanguage();
+        }
+
+        public const string GithubLatest = "https://github.com/BluePointLilac/ContextMenuManager/releases/latest";
+        public const string GithubLatestApi = "https://api.github.com/repos/BluePointLilac/ContextMenuManager/releases/latest";
+        public const string GithubLangsApi = "https://api.github.com/repos/BluePointLilac/ContextMenuManager/contents/languages";
+        public const string GithubLangsRawDir = "https://raw.githubusercontent.com/BluePointLilac/ContextMenuManager/master/languages";
+        public const string GithubShellNewApi = "https://api.github.com/repos/BluePointLilac/ContextMenuManager/contents/ContextMenuManager/Properties/Resources/ShellNew";
+        public const string GithubShellNewRawDir = "https://raw.githubusercontent.com/BluePointLilac/ContextMenuManager/master/ContextMenuManager/Properties/Resources/ShellNew";
+        public const string GithubTexts = "https://raw.githubusercontent.com/BluePointLilac/ContextMenuManager/master/ContextMenuManager/Properties/Resources/Texts";
+        public const string GithubDonateRaw = "https://raw.githubusercontent.com/BluePointLilac/ContextMenuManager/master/Donate.md";
+        public const string GithubDonate = "https://github.com/BluePointLilac/ContextMenuManager/blob/master/Donate.md";
+
+        public const string GiteeReleases = "https://gitee.com/BluePointLilac/ContextMenuManager/releases";
+        public const string GiteeLatestApi = "https://gitee.com/api/v5/repos/BluePointLilac/ContextMenuManager/releases/latest";
+        public const string GiteeLangsApi = "https://gitee.com/api/v5/repos/BluePointLilac/ContextMenuManager/contents/languages";
+        public const string GiteeLangsRawDir = "https://gitee.com/BluePointLilac/ContextMenuManager/raw/master/languages";
+        public const string GiteeShellNewApi = "https://gitee.com/api/v5/repos/BluePointLilac/ContextMenuManager/contents/ContextMenuManager/Properties/Resources/ShellNew";
+        public const string GiteeShellNewRawDir = "https://gitee.com/BluePointLilac/ContextMenuManager/raw/master/ContextMenuManager/Properties/Resources/ShellNew";
+        public const string GiteeTexts = "https://gitee.com/BluePointLilac/ContextMenuManager/raw/master/ContextMenuManager/Properties/Resources/Texts";
+        public const string GiteeDonateRaw = "https://gitee.com/BluePointLilac/ContextMenuManager/raw/master/Donate.md";
+        public const string GiteeDonate = "https://gitee.com/BluePointLilac/ContextMenuManager/blob/master/Donate.md";
+
+        public static readonly string AppConfigDir = $@"{Application.StartupPath}\Config";
+        public static readonly string AppDataDir = Environment.ExpandEnvironmentVariables(@"%AppData%\ContextMenuManager");
+        public static readonly string AppDataConfigDir = $@"{AppDataDir}\Config";
+        public static readonly string ConfigDir = Directory.Exists(AppConfigDir) ? AppConfigDir : AppDataConfigDir;
+        public static readonly bool SaveToAppDir = ConfigDir == AppConfigDir;
+        public static readonly bool IsFirstRun = !Directory.Exists(ConfigDir);
+        public static string ConfigIni = $@"{ConfigDir}\Config.ini";
+        public static string BackupDir = $@"{ConfigDir}\Backup";
+        public static string LangsDir = $@"{ConfigDir}\Languages";
+        public static string ProgramsDir = $@"{ConfigDir}\Programs";
+        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 WebDetailedEditDic = $@"{WebDicsDir}\{DETAILEDEDITDICXML}";
+        public static string WebEnhanceMenusDic = $@"{WebDicsDir}\{ENHANCEMENUSICXML}";
+        public static string WebUwpModeItemsDic = $@"{WebDicsDir}\{UWPMODEITEMSDICXML}";
+
+        public static string UserGuidInfosDic = $@"{UserDicsDir}\{GUIDINFOSDICINI}";
+        public static string UserDetailedEditDic = $@"{UserDicsDir}\{DETAILEDEDITDICXML}";
+        public static string UserEnhanceMenusDic = $@"{UserDicsDir}\{ENHANCEMENUSICXML}";
+        public static string UserUwpModeItemsDic = $@"{UserDicsDir}\{UWPMODEITEMSDICXML}";
+
+        public const string ZH_CNINI = "zh-CN.ini";
+        public const string GUIDINFOSDICINI = "GuidInfosDic.ini";
+        public const string DETAILEDEDITDICXML = "DetailedEditDic.xml";
+        public const string ENHANCEMENUSICXML = "EnhanceMenusDic.xml";
+        public const string UWPMODEITEMSDICXML = "UwpModeItemsDic.xml";
+
+        public static readonly Dictionary<string, string> EngineUrlsDic = new Dictionary<string, string>
+        {
+            { "Bing", "https://www.bing.com/search?q=%s" },
+            { "Baidu", "https://www.baidu.com/s?wd=%s" },
+            { "Google", "https://www.google.com/search?q=%s" },
+            { "Yandex", "https://yandex.com/search/?text=%s" },
+            { "DuckDuckGo", "https://duckduckgo.com/?q=%s" },
+            { "Sogou", "https://www.sogou.com/web?query=%s" },
+            { "360", "https://www.so.com/s?q=%s" },
+        };
+
+        private static readonly IniReader ConfigReader = new IniReader(ConfigIni);
+        private static readonly IniWriter ConfigWriter = new IniWriter(ConfigIni);
+
+        private static string GetGeneralValue(string key)
+        {
+            return ConfigReader.GetValue("General", key);
+        }
+
+        private static void SetGeneralValue(string key, object value)
+        {
+            ConfigWriter.SetValue("General", key, value);
+            ReloadConfig();
+        }
+
+        private static string GetWindowValue(string key)
+        {
+            return ConfigReader.GetValue("Window", key);
+        }
+
+        private static void SetWindowValue(string key, object value)
+        {
+            ConfigWriter.SetValue("Window", key, value);
+            ReloadConfig();
+        }
+
+        public static void ReloadConfig()
+        {
+            ConfigReader.LoadFile(ConfigIni);
+        }
+
+        private static void CreateDirectory()
+        {
+            foreach(string dirPath in new[] { AppDataDir, ConfigDir, ProgramsDir, BackupDir, LangsDir, DicsDir, WebDicsDir, UserDicsDir })
+            {
+                Directory.CreateDirectory(dirPath);
+                Application.ApplicationExit += (sender, e) =>
+                {
+                    if(Directory.Exists(dirPath) && Directory.GetFileSystemEntries(dirPath).Length == 0)
+                    {
+                        Directory.Delete(dirPath);
+                    }
+                };
+            }
+        }
+
+        private static void LoadLanguage()
+        {
+            language = GetGeneralValue("Language");
+            if(language.ToLower() == "default")
+            {
+                LanguageIniPath = "";
+                return;
+            }
+            if(language == "") language = CultureInfo.CurrentUICulture.Name;
+            LanguageIniPath = $@"{LangsDir}\{language}.ini";
+            if(!File.Exists(LanguageIniPath))
+            {
+                LanguageIniPath = "";
+                Language = "";
+            }
+        }
+
+        public static string LanguageIniPath { get; private set; }
+
+        private static string language;
+        public static string Language
+        {
+            get => language;
+            set => SetGeneralValue("Language", value);
+        }
+
+        public static bool AutoBackup
+        {
+            get => GetGeneralValue("AutoBackup") != "0";
+            set => SetGeneralValue("AutoBackup", value ? 1 : 0);
+        }
+
+        public static DateTime LastCheckUpdateTime
+        {
+            get
+            {
+                try
+                {
+                    string time = GetGeneralValue("LastCheckUpdateTime");
+                    //二进制数据时间不会受系统时间格式影响
+                    return DateTime.FromBinary(Convert.ToInt64(time));
+                }
+                catch
+                {
+                    //返回文件上次修改时间
+                    return new FileInfo(Application.ExecutablePath).LastWriteTime;
+                }
+            }
+            set => SetGeneralValue("LastCheckUpdateTime", value.ToBinary());
+        }
+
+        public static bool ProtectOpenItem
+        {
+            get => GetGeneralValue("ProtectOpenItem") != "0";
+            set => SetGeneralValue("ProtectOpenItem", value ? 1 : 0);
+        }
+
+        public static string EngineUrl
+        {
+            get
+            {
+                string url = GetGeneralValue("EngineUrl");
+                if(string.IsNullOrEmpty(url)) url = EngineUrlsDic.Values.ToArray()[0];
+                return url;
+            }
+            set => SetGeneralValue("EngineUrl", value);
+        }
+
+        public static bool ShowFilePath
+        {
+            get => GetGeneralValue("ShowFilePath") == "1";
+            set => SetGeneralValue("ShowFilePath", value ? 1 : 0);
+        }
+
+        public static bool WinXSortable
+        {
+            get => GetGeneralValue("WinXSortable") == "1";
+            set => SetGeneralValue("WinXSortable", value ? 1 : 0);
+        }
+
+        public static bool OpenMoreRegedit
+        {
+            get => GetGeneralValue("OpenMoreRegedit") == "1";
+            set => SetGeneralValue("OpenMoreRegedit", value ? 1 : 0);
+        }
+
+        public static bool OpenMoreExplorer
+        {
+            get => GetGeneralValue("OpenMoreExplorer") == "1";
+            set => SetGeneralValue("OpenMoreExplorer", value ? 1 : 0);
+        }
+
+        public static bool HideDisabledItems
+        {
+            get => GetGeneralValue("HideDisabledItems") == "1";
+            set => SetGeneralValue("HideDisabledItems", value ? 1 : 0);
+        }
+
+        public static bool HideSysStoreItems
+        {
+            get => GetGeneralValue("HideSysStoreItems") != "0";
+            set => SetGeneralValue("HideSysStoreItems", value ? 1 : 0);
+        }
+
+        public static bool RequestUseGithub
+        {
+            get
+            {
+                string value = GetGeneralValue("RequestUseGithub");
+                if(!string.IsNullOrEmpty(value)) return value == "1";
+                if(CultureInfo.CurrentCulture.Name == "zh-CN") return false;
+                return true;
+            }
+            set => SetGeneralValue("RequestUseGithub", value ? 1 : 0);
+        }
+
+        public static int UpdateFrequency
+        {
+            get
+            {
+                string value = GetGeneralValue("UpdateFrequency");
+                if(int.TryParse(value, out int day))
+                {
+                    if(day == -1 || day == 7 || day == 90) return day;
+                }
+                return 30;
+            }
+            set => SetGeneralValue("UpdateFrequency", value);
+        }
+
+        public static bool TopMost
+        {
+            get => GetWindowValue("TopMost") == "1";
+            set => SetWindowValue("TopMost", value ? 1 : 0);
+        }
+
+        public static Size MainFormSize
+        {
+            get
+            {
+                string str = GetWindowValue("MainFormSize");
+                int index = str.IndexOf(',');
+                if(index == -1) return Size.Empty;
+                if(int.TryParse(str.Substring(0, index), out int x))
+                    if(int.TryParse(str.Substring(index + 1), out int y))
+                        return new Size(x, y);
+                return Size.Empty;
+            }
+            set => SetWindowValue("MainFormSize", value.Width + "," + value.Height);
+        }
+    }
+}

+ 8 - 16
ContextMenuManager/AppImage.cs → ContextMenuManager/Methods/AppImage.cs

@@ -3,9 +3,9 @@ using ContextMenuManager.Properties;
 using System.Drawing;
 using System.Windows.Forms;
 
-namespace ContextMenuManager
+namespace ContextMenuManager.Methods
 {
-    public static class AppImage
+    static class AppImage
     {
         private static readonly double Scale = HighDpi.DpiScale / 1.5;
         ///<summary>主页</summary>
@@ -20,10 +20,6 @@ namespace ContextMenuManager
         public static readonly Image About = Resources.About.ResizeImage(Scale);
         ///<summary>设置按钮</summary>
         public static readonly Image Setting = Resources.Setting.ResizeImage(Scale);
-        ///<summary>开关打开状态</summary>
-        public static readonly Image TurnOn = Resources.TurnOn.ResizeImage(Scale);
-        ///<summary>开关关闭状态</summary>
-        public static readonly Image TurnOff = Resources.TurnOff.ResizeImage(Scale);
         ///<summary>编辑子项</summary>
         public static readonly Image SubItems = Resources.SubItems.ResizeImage(Scale);
         ///<summary>删除</summary>
@@ -34,12 +30,16 @@ namespace ContextMenuManager
         public static readonly Image AddExisting = Resources.AddExisting.ResizeImage(Scale);
         ///<summary>添加分割线</summary>
         public static readonly Image AddSeparator = Resources.AddSeparator.ResizeImage(Scale);
+        ///<summary>添加增强菜单</summary>
+        public static readonly Image Enhance = Resources.Enhance.ResizeImage(Scale);
         ///<summary>打开</summary>
         public static readonly Image Open = Resources.Open.ResizeImage(Scale);
         ///<summary>下载</summary>
         public static readonly Image DownLoad = Resources.DownLoad.ResizeImage(Scale);
         ///<summary>翻译</summary>
         public static readonly Image Translate = Resources.Translate.ResizeImage(Scale);
+        ///<summary>检查更新</summary>
+        public static readonly Image CheckUpdate = Resources.CheckUpdate.ResizeImage(Scale);
         ///<summary>上</summary>
         public static readonly Image Up = Resources.Up.ResizeImage(Scale);
         ///<summary>下</summary>
@@ -58,8 +58,8 @@ namespace ContextMenuManager
         public static readonly Image MicrosoftStore = Resources.MicrosoftStore.ResizeImage(Scale);
         ///<summary>用户</summary>
         public static readonly Image User = Resources.User.ResizeImage(Scale);
-        ///<summary>程序图标</summary>
-        public static readonly Image App = Icon.ExtractAssociatedIcon(Application.ExecutablePath).ToBitmap();
+        ///<summary>网络</summary>
+        public static readonly Image Web = Resources.Web.ResizeImage(Scale);
         ///<summary>系统文件</summary>
         public static readonly Image SystemFile = GetIconImage("imageres.dll", -67);
         ///<summary>资源不存在</summary>
@@ -68,8 +68,6 @@ namespace ContextMenuManager
         public static readonly Image Shield = GetIconImage("imageres.dll", -78);
         ///<summary>资源管理器</summary>
         public static readonly Image Explorer = GetIconImage("explorer.exe", 0);
-        ///<summary>命令提示符</summary>
-        public static readonly Image Cmd = GetIconImage("cmd.exe", 0);
         ///<summary>重启Explorer</summary>
         public static readonly Image RestartExplorer = GetIconImage("shell32.dll", 238);
         ///<summary>网络驱动器</summary>
@@ -78,8 +76,6 @@ namespace ContextMenuManager
         public static readonly Image SendTo = GetIconImage("imageres.dll", -185);
         ///<summary>回收站</summary>
         public static readonly Image RecycleBin = GetIconImage("imageres.dll", -55);
-        ///<summary>此电脑</summary>
-        public static readonly Image Computer = GetIconImage("imageres.dll", -109);
         ///<summary>磁盘</summary>
         public static readonly Image Drive = GetIconImage("imageres.dll", -30);
         ///<summary>文件</summary>
@@ -88,10 +84,6 @@ namespace ContextMenuManager
         public static readonly Image Folder = GetIconImage("imageres.dll", -3);
         ///<summary>目录</summary>
         public static readonly Image Directory = GetIconImage("imageres.dll", -162);
-        ///<summary目录背景</summary>
-        public static readonly Image Background = GetIconImage("imageres.dll", 0);
-        ///<summary>桌面</summary>
-        public static readonly Image Desktop = GetIconImage("imageres.dll", -183);
         ///<summary>所有对象</summary>
         public static readonly Image AllObjects = GetIconImage("imageres.dll", -117);
         ///<summary>锁定</summary>

+ 14 - 0
ContextMenuManager/Methods/AppMessageBox.cs

@@ -0,0 +1,14 @@
+using BluePointLilac.Methods;
+using System.Windows.Forms;
+
+namespace ContextMenuManager.Methods
+{
+    public static class AppMessageBox
+    {
+        public static DialogResult Show(string text, MessageBoxButtons buttons = MessageBoxButtons.OK,
+            MessageBoxIcon icon = MessageBoxIcon.Warning, string caption = null)
+        {
+            return MessageBoxEx.Show(text, caption ?? AppString.General.AppName, buttons, icon);
+        }
+    }
+}

+ 333 - 0
ContextMenuManager/Methods/AppString.cs

@@ -0,0 +1,333 @@
+using BluePointLilac.Methods;
+using System;
+using System.Reflection;
+using System.Text;
+
+namespace ContextMenuManager.Methods
+{
+    static class AppString
+    {
+        private static readonly IniReader UserLangReader = new IniReader(AppConfig.LanguageIniPath);
+        public static readonly IniReader DefLangReader = new IniReader(new StringBuilder(Properties.Resources.AppLanguageDic));
+
+        private static string GetValue(string section, string key)
+        {
+            string value = UserLangReader.GetValue(section, key);
+            if(string.IsNullOrEmpty(value)) value = DefLangReader.GetValue(section, key);
+            return value.Replace("\\r", "\r").Replace("\\n", "\n");
+        }
+
+        /// <summary>加载语言</summary>
+        public static void LoadStrings()
+        {
+            foreach(Type type in typeof(AppString).GetNestedTypes())
+            {
+                foreach(PropertyInfo pi in type.GetProperties())
+                {
+                    pi.SetValue(type, GetValue(type.Name, pi.Name), null);
+                }
+            }
+        }
+
+        /// <summary>常规</summary>
+        public static class General
+        {
+            public static string AppName { get; set; }
+        }
+
+        /// <summary>工具栏</summary>
+        public static class ToolBar
+        {
+            public static string Home { get; set; }
+            public static string Type { get; set; }
+            public static string Rule { get; set; }
+            public static string Refresh { get; set; }
+            public static string About { get; set; }
+        }
+
+        /// <summary>侧边栏</summary>
+        public static class SideBar
+        {
+            public static string File { get; set; }
+            public static string Folder { get; set; }
+            public static string Directory { get; set; }
+            public static string Background { get; set; }
+            public static string Desktop { get; set; }
+            public static string Drive { get; set; }
+            public static string AllObjects { get; set; }
+            public static string Computer { get; set; }
+            public static string RecycleBin { get; set; }
+            public static string Library { get; set; }
+            public static string New { get; set; }
+            public static string SendTo { get; set; }
+            public static string OpenWith { get; set; }
+            public static string WinX { get; set; }
+            public static string LnkFile { get; set; }
+            public static string UwpLnk { get; set; }
+            public static string ExeFile { get; set; }
+            public static string UnknownType { get; set; }
+            public static string MenuAnalysis { get; set; }
+            public static string CustomExtension { get; set; }
+            public static string PerceivedType { get; set; }
+            public static string DirectoryType { get; set; }
+            public static string EnhanceMenu { get; set; }
+            public static string DetailedEdit { get; set; }
+            public static string GuidBlocked { get; set; }
+            public static string DragDrop { get; set; }
+            public static string PublicReferences { get; set; }
+            public static string CustomRegPath { get; set; }
+            public static string IEMenu { get; set; }
+            public static string AppSetting { get; set; }
+            public static string AboutApp { get; set; }
+            public static string Dictionaries { get; set; }
+            public static string AppLanguage { get; set; }
+            public static string Donate { get; set; }
+        }
+
+        /// <summary>状态栏</summary>
+        public static class StatusBar
+        {
+            public static string File { get; set; }
+            public static string Folder { get; set; }
+            public static string Directory { get; set; }
+            public static string Background { get; set; }
+            public static string Desktop { get; set; }
+            public static string Drive { get; set; }
+            public static string AllObjects { get; set; }
+            public static string Computer { get; set; }
+            public static string RecycleBin { get; set; }
+            public static string Library { get; set; }
+            public static string New { get; set; }
+            public static string SendTo { get; set; }
+            public static string OpenWith { get; set; }
+            public static string WinX { get; set; }
+            public static string LnkFile { get; set; }
+            public static string UwpLnk { get; set; }
+            public static string ExeFile { get; set; }
+            public static string UnknownType { get; set; }
+            public static string MenuAnalysis { get; set; }
+            public static string CustomExtension { get; set; }
+            public static string PerceivedType { get; set; }
+            public static string DirectoryType { get; set; }
+            public static string EnhanceMenu { get; set; }
+            public static string DetailedEdit { get; set; }
+            public static string GuidBlocked { get; set; }
+            public static string DragDrop { get; set; }
+            public static string PublicReferences { get; set; }
+            public static string CustomRegPath { get; set; }
+            public static string IEMenu { get; set; }
+        }
+
+        /// <summary>程序内右键菜单</summary>
+        public static class Menu
+        {
+            public static string ChangeText { get; set; }
+            public static string ItemIcon { get; set; }
+            public static string ChangeIcon { get; set; }
+            public static string AddIcon { get; set; }
+            public static string DeleteIcon { get; set; }
+            public static string ShieldIcon { get; set; }
+            public static string ItemPosition { get; set; }
+            public static string SetDefault { get; set; }
+            public static string SetTop { get; set; }
+            public static string SetBottom { get; set; }
+            public static string OtherAttributes { get; set; }
+            public static string OnlyWithShift { get; set; }
+            public static string OnlyInExplorer { get; set; }
+            public static string NoWorkingDirectory { get; set; }
+            public static string NeverDefault { get; set; }
+            public static string ShowAsDisabledIfHidden { get; set; }
+            public static string Details { get; set; }
+            public static string WebSearch { get; set; }
+            public static string ChangeCommand { get; set; }
+            public static string RunAsAdministrator { get; set; }
+            public static string FileProperties { get; set; }
+            public static string FileLocation { get; set; }
+            public static string RegistryLocation { get; set; }
+            public static string ExportRegistry { get; set; }
+            public static string Delete { get; set; }
+            public static string DeleteReference { get; set; }
+            public static string HandleGuid { get; set; }
+            public static string CopyGuid { get; set; }
+            public static string BlockGuid { get; set; }
+            public static string AddGuidDic { get; set; }
+            public static string ClsidLocation { get; set; }
+            public static string InitialData { get; set; }
+            public static string BeforeSeparator { get; set; }
+            public static string ChangeGroup { get; set; }
+            public static string RestoreDefault { get; set; }
+            public static string Edit { get; set; }
+            public static string Save { get; set; }
+            public static string FoldAll { get; set; }
+            public static string UnfoldAll { get; set; }
+        }
+
+        /// <summary>对话框子窗口</summary>
+        public static class Dialog
+        {
+            public static string Browse { get; set; }
+            public static string Program { get; set; }
+            public static string AllFiles { get; set; }
+            public static string RegistryFile { get; set; }
+            public static string ItemText { get; set; }
+            public static string ItemCommand { get; set; }
+            public static string CommandArguments { get; set; }
+            public static string SingleMenu { get; set; }
+            public static string MultiMenu { get; set; }
+            public static string Public { get; set; }
+            public static string Private { get; set; }
+            public static string SelectAll { get; set; }
+            public static string InputGuid { get; set; }
+            public static string AddGuidDic { get; set; }
+            public static string DeleteGuidDic { get; set; }
+            public static string NoPerceivedType { get; set; }
+            public static string TextFile { get; set; }
+            public static string DocumentFile { get; set; }
+            public static string ImageFile { get; set; }
+            public static string VideoFile { get; set; }
+            public static string AudioFile { get; set; }
+            public static string CompressedFile { get; set; }
+            public static string SystemFile { get; set; }
+            public static string DocumentDirectory { get; set; }
+            public static string ImageDirectory { get; set; }
+            public static string VideoDirectory { get; set; }
+            public static string AudioDirectory { get; set; }
+            public static string EditSubItems { get; set; }
+            public static string DetailedEdit { get; set; }
+            public static string CheckReference { get; set; }
+            public static string CheckCopy { get; set; }
+            public static string SelectExtension { get; set; }
+            public static string SelectPerceivedType { get; set; }
+            public static string SelectDirectoryType { get; set; }
+            public static string SelectNewItemType { get; set; }
+            public static string SelectGroup { get; set; }
+            public static string SelectObjectType { get; set; }
+            public static string SelectDropEffect { get; set; }
+            public static string DefaultDropEffect { get; set; }
+            public static string CopyDropEffect { get; set; }
+            public static string MoveDropEffect { get; set; }
+            public static string CreateLinkDropEffect { get; set; }
+            public static string DownloadLanguages { get; set; }
+            public static string TranslateTool { get; set; }
+            public static string DefaultText { get; set; }
+            public static string OldTranslation { get; set; }
+            public static string NewTranslation { get; set; }
+            public static string DonateInfo { get; set; }
+        }
+
+        /// <summary>消息</summary>
+        public static class Message
+        {
+            public static string TextCannotBeEmpty { get; set; }
+            public static string CommandCannotBeEmpty { get; set; }
+            public static string StringParsingFailed { get; set; }
+            public static string TextLengthCannotExceed80 { get; set; }
+            public static string ConfirmDeletePermanently { get; set; }
+            public static string DeleteButCanRestore { get; set; }
+            public static string ConfirmDeleteReference { get; set; }
+            public static string ConfirmDelete { get; set; }
+            public static string ConfirmDeleteReferenced { get; set; }
+            public static string CannotAddNewItem { get; set; }
+            public static string VistaUnsupportedMulti { get; set; }
+            public static string CannotHideSubItem { get; set; }
+            public static string UnsupportedFilename { get; set; }
+            public static string NoOpenModeExtension { get; set; }
+            public static string CannotChangePath { get; set; }
+            public static string CopiedToClipboard { get; set; }
+            public static string MalformedGuid { get; set; }
+            public static string HasBeenAdded { get; set; }
+            public static string EditInitialData { get; set; }
+            public static string PromptIsOpenItem { get; set; }
+            public static string SelectRegPath { get; set; }
+            public static string RestartApp { get; set; }
+            public static string UpdateInfo { get; set; }
+            public static string UpdateSucceeded { get; set; }
+            public static string DicUpdateSucceeded { get; set; }
+            public static string FileNotExists { get; set; }
+            public static string FolderNotExists { get; set; }
+            public static string VersionIsLatest { get; set; }
+            public static string AuthorityProtection { get; set; }
+            public static string WinXSorted { get; set; }
+            public static string RestoreDefault { get; set; }
+            public static string DeleteGroup { get; set; }
+            public static string WebDataReadFailed { get; set; }
+            public static string OpenWebUrl { get; set; }
+            public static string SelectSubMenuMode { get; set; }
+        }
+
+        /// <summary>提示文本</summary>
+        public static class Tip
+        {
+            public static string RestartExplorer { get; set; }
+            public static string CustomFolder { get; set; }
+            public static string SendToDrive { get; set; }
+            public static string BuildSendtoMenu { get; set; }
+            public static string EditSubItems { get; set; }
+            public static string InvalidItem { get; set; }
+            public static string AddSeparator { get; set; }
+            public static string AddReference { get; set; }
+            public static string AddFromPublic { get; set; }
+            public static string AddFromParentMenu { get; set; }
+            public static string DeleteGuidDic { get; set; }
+            public static string LockNewMenu { get; set; }
+            public static string ConfigPath { get; set; }
+            public static string CommandFiles { get; set; }
+            public static string CreateGroup { get; set; }
+            public static string DropOrSelectObject { get; set; }
+            public static string ImmediatelyCheck { get; set; }
+        }
+
+        /// <summary>其他文本</summary>
+        public static class Other
+        {
+            public static string CustomFolder { get; set; }
+            public static string BuildSendtoMenu { get; set; }
+            public static string NewItem { get; set; }
+            public static string AddGuidBlockedItem { get; set; }
+            public static string CurrentExtension { get; set; }
+            public static string CurrentPerceivedType { get; set; }
+            public static string CurrentDirectoryType { get; set; }
+            public static string CurrentFilePath { get; set; }
+            public static string CurrentRegPath { get; set; }
+            public static string SelectRegPath { get; set; }
+            public static string InvalidItem { get; set; }
+            public static string Separator { get; set; }
+            public static string LockNewMenu { get; set; }
+            public static string RestartExplorer { get; set; }
+            public static string WebDictionaries { get; set; }
+            public static string SwitchDictionaries { get; set; }
+            public static string UserDictionaries { get; set; }
+            public static string DictionaryDescription { get; set; }
+            public static string GuidInfosDictionary { get; set; }
+            public static string UwpMode { get; set; }
+            public static string Translators { get; set; }
+            public static string AboutApp { get; set; }
+            public static string Dictionaries { get; set; }
+            public static string Donate { get; set; }
+            public static string DonationList { get; set; }
+            public static string ConfigPath { get; set; }
+            public static string AppDataDir { get; set; }
+            public static string AppDir { get; set; }
+            public static string AutoBackup { get; set; }
+            public static string SetUpdateFrequency { get; set; }
+            public static string OnceAWeek { get; set; }
+            public static string OnceAMonth { get; set; }
+            public static string OnceASeason { get; set; }
+            public static string NeverCheck { get; set; }
+            public static string SetRequestRepo { get; set; }
+            public static string ProtectOpenItem { get; set; }
+            public static string WebSearchEngine { get; set; }
+            public static string CustomEngine { get; set; }
+            public static string SetCustomEngine { get; set; }
+            public static string WinXSortable { get; set; }
+            public static string ShowFilePath { get; set; }
+            public static string OpenMoreRegedit { get; set; }
+            public static string OpenMoreExplorer { get; set; }
+            public static string HideDisabledItems { get; set; }
+            public static string HideSysStoreItems { get; set; }
+            public static string SetPerceivedType { get; set; }
+            public static string SetDefaultDropEffect { get; set; }
+            public static string TopMost { get; set; }
+        }
+    }
+}

+ 8 - 7
ContextMenuManager/BluePointLilac.Methods/DesktopIni.cs → ContextMenuManager/Methods/DesktopIni.cs

@@ -1,30 +1,31 @@
-using System.IO;
+using BluePointLilac.Methods;
+using System.IO;
 
-namespace BluePointLilac.Methods
+namespace ContextMenuManager.Methods
 {
-    public static class DesktopIni
+    static class DesktopIni
     {
         private const string LocalizedFileNames = "LocalizedFileNames";
 
-        private static string GetIniPath(string filePath) => $@"{Path.GetDirectoryName(filePath)}\desktop.ini";
+        public static string GetDesktopIniPath(string filePath) => $@"{Path.GetDirectoryName(filePath)}\desktop.ini";
 
         public static void DeleteLocalizedFileNames(string filePath)
         {
-            IniWriter writer = new IniWriter(GetIniPath(filePath));
+            IniWriter writer = new IniWriter(GetDesktopIniPath(filePath));
             string fileName = Path.GetFileName(filePath);
             writer.DeleteKey(LocalizedFileNames, fileName);
         }
 
         public static void SetLocalizedFileNames(string filePath, string name)
         {
-            IniWriter writer = new IniWriter(GetIniPath(filePath));
+            IniWriter writer = new IniWriter(GetDesktopIniPath(filePath));
             string fileName = Path.GetFileName(filePath);
             writer.SetValue(LocalizedFileNames, fileName, name);
         }
 
         public static string GetLocalizedFileNames(string filePath, bool translate = false)
         {
-            IniWriter writer = new IniWriter(GetIniPath(filePath));
+            IniWriter writer = new IniWriter(GetDesktopIniPath(filePath));
             string fileName = Path.GetFileName(filePath);
             string name = writer.GetValue(LocalizedFileNames, fileName);
             if(translate) name = ResourceString.GetDirectString(name);

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