فهرست منبع

优化代码逻辑,修复Bug

蓝点lilac 4 سال پیش
والد
کامیت
a62ae2ed9e
59فایلهای تغییر یافته به همراه614 افزوده شده و 341 حذف شده
  1. 16 3
      ContextMenuManager/AppConfig.cs
  2. 4 0
      ContextMenuManager/AppString.cs
  3. 45 5
      ContextMenuManager/BluePointLilac.Controls/MyCheckBox.cs
  4. 9 12
      ContextMenuManager/BluePointLilac.Controls/MyListBox.cs
  5. 4 4
      ContextMenuManager/BluePointLilac.Controls/MySideBar.cs
  6. 12 7
      ContextMenuManager/BluePointLilac.Controls/MyToolBar.cs
  7. 1 1
      ContextMenuManager/BluePointLilac.Controls/ReadOnlyTextBox.cs
  8. 1 1
      ContextMenuManager/BluePointLilac.Controls/ResizeLimitedForm.cs
  9. 19 15
      ContextMenuManager/BluePointLilac.Methods/ControlExtension.cs
  10. 3 3
      ContextMenuManager/BluePointLilac.Methods/ElevatedFileDroper.cs
  11. 24 19
      ContextMenuManager/BluePointLilac.Methods/EncodingType.cs
  12. 70 10
      ContextMenuManager/BluePointLilac.Methods/ExternalProgram.cs
  13. 8 0
      ContextMenuManager/BluePointLilac.Methods/HighDpi.cs
  14. 2 2
      ContextMenuManager/BluePointLilac.Methods/ImageExtension.cs
  15. 0 7
      ContextMenuManager/BluePointLilac.Methods/RegistryEx.cs
  16. 1 0
      ContextMenuManager/BluePointLilac.Methods/TextBoxExtension.cs
  17. 4 5
      ContextMenuManager/BluePointLilac.Methods/ToolTipBox.cs
  18. 8 6
      ContextMenuManager/ContextMenuManager.csproj
  19. 104 47
      ContextMenuManager/Controls/AboutApp.cs
  20. 22 20
      ContextMenuManager/Controls/EnhanceMenusItem.cs
  21. 21 15
      ContextMenuManager/Controls/EnhanceMenusList.cs
  22. 4 4
      ContextMenuManager/Controls/ExplorerRestarter.cs
  23. 1 1
      ContextMenuManager/Controls/GuidBlockedItem.cs
  24. 1 1
      ContextMenuManager/Controls/GuidBlockedList.cs
  25. 0 1
      ContextMenuManager/Controls/IEItem.cs
  26. 1 1
      ContextMenuManager/Controls/IEList.cs
  27. 1 1
      ContextMenuManager/Controls/Interfaces/IBtnOpenPathItem.cs
  28. 2 9
      ContextMenuManager/Controls/Interfaces/IChkVisibleItem.cs
  29. 6 6
      ContextMenuManager/Controls/Interfaces/IFoldGroupItem.cs
  30. 8 0
      ContextMenuManager/Controls/Interfaces/IProtectOpenItem.cs
  31. 1 1
      ContextMenuManager/Controls/Interfaces/ITsiDeleteItem.cs
  32. 2 4
      ContextMenuManager/Controls/Interfaces/ITsiFilePathItem.cs
  33. 11 4
      ContextMenuManager/Controls/Interfaces/ITsiGuidItem.cs
  34. 7 5
      ContextMenuManager/Controls/Interfaces/ITsiIconItem.cs
  35. 1 1
      ContextMenuManager/Controls/Interfaces/ITsiRegExportItem.cs
  36. 1 1
      ContextMenuManager/Controls/Interfaces/ITsiShortcutCommandItem.cs
  37. 1 1
      ContextMenuManager/Controls/Interfaces/ITsiTextItem.cs
  38. 1 1
      ContextMenuManager/Controls/Interfaces/ITsiWebSearchItem.cs
  39. 6 5
      ContextMenuManager/Controls/NewItem.cs
  40. 2 2
      ContextMenuManager/Controls/NewItemForm.cs
  41. 0 1
      ContextMenuManager/Controls/OpenWithItem.cs
  42. 2 2
      ContextMenuManager/Controls/OpenWithList.cs
  43. 8 8
      ContextMenuManager/Controls/RuleItem.cs
  44. 1 2
      ContextMenuManager/Controls/SendToItem.cs
  45. 3 3
      ContextMenuManager/Controls/SendToList.cs
  46. 7 10
      ContextMenuManager/Controls/ShellExItem.cs
  47. 2 2
      ContextMenuManager/Controls/ShellExecuteDialog.cs
  48. 13 11
      ContextMenuManager/Controls/ShellItem.cs
  49. 8 8
      ContextMenuManager/Controls/ShellList.cs
  50. 0 1
      ContextMenuManager/Controls/ShellNewItem.cs
  51. 2 2
      ContextMenuManager/Controls/ShellNewList.cs
  52. 52 9
      ContextMenuManager/Controls/ShellStoreDialog.cs
  53. 22 18
      ContextMenuManager/Controls/ShellSubMenuDialog.cs
  54. 1 1
      ContextMenuManager/Controls/UwpModeItem.cs
  55. 0 1
      ContextMenuManager/Controls/WinXGroupItem.cs
  56. 0 1
      ContextMenuManager/Controls/WinXItem.cs
  57. 2 2
      ContextMenuManager/Controls/WinXList.cs
  58. 9 7
      ContextMenuManager/MainForm.cs
  59. 47 21
      ContextMenuManager/Updater.cs

+ 16 - 3
ContextMenuManager/AppConfig.cs

@@ -10,14 +10,22 @@ namespace ContextMenuManager
     {
         static AppConfig()
         {
-            foreach(string dirPath in new[] { ConfigDir, ProgramsDir, BackupDir, LangsDir, DicsDir, WebDicsDir, UserDicsDir })
+            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 AppDataConfigDir = Environment.ExpandEnvironmentVariables(@"%AppData%\ContextMenuManager\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";
@@ -50,7 +58,6 @@ namespace ContextMenuManager
             "https://www.baidu.com/s?wd=%s",          //百度搜索
             "https://www.google.com/search?q=%s",     //谷歌搜索
             "https://duckduckgo.com/?q=%s",           //DuckDuckGo
-            "https://www.dogedoge.com/results?q=%s",  //多吉搜索
             "https://www.sogou.com/web?query=%s",     //搜狗搜索
             "https://www.so.com/s?q=%s",              //360搜索
         };
@@ -138,6 +145,12 @@ namespace ContextMenuManager
             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";

+ 4 - 0
ContextMenuManager/AppString.cs

@@ -170,6 +170,7 @@ namespace ContextMenuManager
             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");
@@ -236,6 +237,7 @@ namespace ContextMenuManager
             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");
@@ -244,6 +246,7 @@ namespace ContextMenuManager
             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>
@@ -304,6 +307,7 @@ namespace ContextMenuManager
             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");

+ 45 - 5
ContextMenuManager/BluePointLilac.Controls/MyCheckBox.cs

@@ -1,26 +1,66 @@
 using ContextMenuManager;
+using System;
+using System.Drawing;
 using System.Windows.Forms;
 
 namespace BluePointLilac.Controls
 {
     public class MyCheckBox : PictureBox
     {
-        private bool _Checked;
+        private bool? _Checked = null;
         public bool Checked
         {
-            get => _Checked;
+            get => _Checked == true;
             set
             {
-                _Checked = value;
-                Image = value ? AppImage.TurnOn : AppImage.TurnOff;
+                if(_Checked == value) return;
+                bool notFirst = _Checked != null;
+                this.Image = SwitchImage(value);
+                if(_Checked == null)
+                {
+                    _Checked = value;
+                    return;
+                }
+                if(PreCheckChanging != null && !PreCheckChanging.Invoke())
+                {
+                    this.Image = SwitchImage(!value);
+                    return;
+                }
+                else CheckChanging?.Invoke();
+                if(PreCheckChanged != null && !PreCheckChanged.Invoke())
+                {
+                    this.Image = SwitchImage(!value);
+                    return;
+                }
+                else
+                {
+                    _Checked = value;
+                    CheckChanged?.Invoke();
+                }
             }
         }
 
         public MyCheckBox()
         {
-            this.Checked = false;
+            this.Image = SwitchImage(false);
             this.Cursor = Cursors.Hand;
             this.SizeMode = PictureBoxSizeMode.AutoSize;
         }
+
+        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)
+        {
+            return value ? AppImage.TurnOn : AppImage.TurnOff;
+        }
     }
 }

+ 9 - 12
ContextMenuManager/BluePointLilac.Controls/MyListBox.cs

@@ -58,11 +58,11 @@ namespace BluePointLilac.Controls
                 value.ForeColor = Color.FromArgb(0, 138, 217);
                 //value.BackColor = Color.FromArgb(200, 230, 250);
                 value.Focus();
-                HoveredItemChanged?.Invoke(null, null);
+                HoveredItemChanged?.Invoke();
             }
         }
 
-        public event EventHandler HoveredItemChanged;
+        public Action HoveredItemChanged;
 
         public void AddItem(MyListItem item)
         {
@@ -91,7 +91,7 @@ namespace BluePointLilac.Controls
 
         public int GetItemIndex(MyListItem item)
         {
-            return this.Controls.GetChildIndex(item);
+            return Controls.GetChildIndex(item);
         }
 
         public void InsertItem(MyListItem item, int index)
@@ -142,8 +142,9 @@ 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(null, null);
-            lblText.DoubleClick += (sender, e) => TextDoubleClick?.Invoke(null, null);
+            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);
             CenterControl(lblText);
@@ -154,11 +155,7 @@ namespace BluePointLilac.Controls
         public Image Image
         {
             get => picImage.Image;
-            set
-            {
-                picImage.Image = value;
-                picImage.Visible = value != null;
-            }
+            set => picImage.Image = value;
         }
         public new string Text
         {
@@ -188,8 +185,8 @@ namespace BluePointLilac.Controls
             }
         }
 
-        public event EventHandler TextDoubleClick;
-        public event EventHandler ImageDoubleClick;
+        public Action TextDoubleClick { get; set; }
+        public Action ImageDoubleClick { get; set; }
 
         private readonly Label lblText = new Label
         {

+ 4 - 4
ContextMenuManager/BluePointLilac.Controls/MySideBar.cs

@@ -181,9 +181,9 @@ namespace BluePointLilac.Controls
             HoverIndex = SelectIndex;
         }
 
-        public event EventHandler SelectIndexChanged;
+        public Action SelectIndexChanged { get; set; }
 
-        public event EventHandler HoverIndexChanged;
+        public Action HoverIndexChanged { get; set; }
 
         private int selectIndex;
         public int SelectIndex
@@ -194,7 +194,7 @@ namespace BluePointLilac.Controls
                 HoverIndex = value;
                 RefreshItem(PnlSelected, value);
                 selectIndex = value;
-                SelectIndexChanged?.Invoke(null, null);
+                SelectIndexChanged?.Invoke();
             }
         }
 
@@ -207,7 +207,7 @@ namespace BluePointLilac.Controls
                 if(hoverIndex == value) return;
                 RefreshItem(PnlHovered, value);
                 hoverIndex = value;
-                HoverIndexChanged?.Invoke(null, null);
+                HoverIndexChanged?.Invoke();
             }
         }
     }

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

@@ -22,14 +22,19 @@ namespace BluePointLilac.Controls
             set
             {
                 if(selectedButton == value) return;
-                if(selectedButton != null) selectedButton.Opacity = 0;
+                if(selectedButton != null)
+                {
+                    selectedButton.Opacity = 0;
+                    selectedButton.Cursor = Cursors.Hand;
+                }
                 selectedButton = value;
-                value.Opacity = 0.4F;
-                SelectedButtonChanged?.Invoke(null, null);
+                selectedButton.Opacity = 0.4F;
+                selectedButton.Cursor = Cursors.Default;
+                SelectedButtonChanged?.Invoke();
             }
         }
 
-        public event EventHandler SelectedButtonChanged;
+        public Action SelectedButtonChanged { get; set; }
 
         public int SelectedIndex
         {
@@ -40,14 +45,14 @@ namespace BluePointLilac.Controls
         public void AddButton(MyToolBarButton button)
         {
             button.Parent = this;
-            button.Margin = new Padding(12.DpiZoom(), 4.DpiZoom(), 0, 0);
+            button.Margin = new Padding(12, 4, 0, 0).DpiZoom();
             button.MouseDown += (sender, e) =>
             {
-                if(button.CanBeSelected) { SelectedButton = button; button.Cursor = Cursors.Default; }
+                if(button.CanBeSelected) SelectedButton = button;
             };
             button.MouseEnter += (sender, e) =>
             {
-                if(button != SelectedButton) { button.Opacity = 0.2F; button.Cursor = Cursors.Hand; }
+                if(button != SelectedButton) button.Opacity = 0.2F;
             };
             button.MouseLeave += (sender, e) =>
             {

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

@@ -56,7 +56,7 @@ namespace BluePointLilac.Controls
 
         protected override void OnLinkClicked(LinkClickedEventArgs e)
         {
-            base.OnLinkClicked(e); ExternalProgram.OpenUrl(e.LinkText);
+            base.OnLinkClicked(e); ExternalProgram.OpenWebUrl(e.LinkText);
         }
     }
 }

+ 1 - 1
ContextMenuManager/BluePointLilac.Controls/ResizbleForm.cs → ContextMenuManager/BluePointLilac.Controls/ResizeLimitedForm.cs

@@ -4,7 +4,7 @@ using System.Windows.Forms;
 namespace BluePointLilac.Controls
 {
     /// <summary>限制水平、竖直方向调整大小的窗体</summary>
-    public class ResizbleForm : Form
+    public class ResizeLimitedForm : Form
     {
         /// <summary>水平方向可调整大小</summary>
         public bool HorizontalResizable { get; set; } = true;

+ 19 - 15
ContextMenuManager/BluePointLilac.Methods/ControlExtension.cs

@@ -11,6 +11,7 @@ namespace BluePointLilac.Methods
 
         [DllImport("user32.dll")]
         private static extern bool ReleaseCapture();
+
         private const int WM_NCLBUTTONDOWN = 0xA1;
         private const int HT_CAPTION = 0x2;
 
@@ -18,29 +19,30 @@ namespace BluePointLilac.Methods
         /// <param name="ctr">目标控件</param>
         public static void CanMoveForm(this Control ctr)
         {
+            bool isDown = false;
             DateTime downTime = DateTime.MinValue;
-            DateTime upTime = DateTime.MinValue;
-            ctr.MouseDown += (sender, e) => downTime = DateTime.Now;
-            ctr.MouseUp += (sender, e) => upTime = DateTime.Now;
+            ctr.MouseDown += (sender, e) =>
+            {
+                isDown = e.Button == MouseButtons.Left;
+                downTime = DateTime.Now;
+            };
+            ctr.MouseUp += (sender, e) => isDown = false;
             ctr.MouseMove += (sender, e) =>
             {
-                foreach(DateTime time in new[] { downTime, upTime })
-                {
-                    //避免ReleaseCapture影响控件的其他鼠标事件
-                    if((DateTime.Now - time).TotalMilliseconds < 20) return;
-                }
-                if(e.Button == MouseButtons.Left)
-                {
-                    ReleaseCapture();
-                    SendMessage(ctr.FindForm().Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
-                }
+                if(e.Button != MouseButtons.Left) return;
+                //避免ReleaseCapture影响控件的其他鼠标事件
+                if((DateTime.Now - downTime).TotalMilliseconds < 20) return;
+                ReleaseCapture();
+                SendMessage(ctr.FindForm().Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
             };
         }
 
         [DllImport("user32.dll")]
         private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int wndproc);
+
         [DllImport("user32.dll")]
         private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
+
         private const int GWL_STYLE = -16;
         private const int WS_DISABLED = 0x8000000;
 
@@ -50,8 +52,10 @@ namespace BluePointLilac.Methods
         /// <param name="enabled">启用为true,禁用为false</param>
         public static void SetEnabled(this Control ctr, bool enabled)
         {
-            if(enabled) { SetWindowLong(ctr.Handle, GWL_STYLE, (~WS_DISABLED) & GetWindowLong(ctr.Handle, GWL_STYLE)); }
-            else { SetWindowLong(ctr.Handle, GWL_STYLE, WS_DISABLED | GetWindowLong(ctr.Handle, GWL_STYLE)); }
+            int value = GetWindowLong(ctr.Handle, GWL_STYLE);
+            if(enabled) value &= ~WS_DISABLED;
+            else value |= WS_DISABLED;
+            SetWindowLong(ctr.Handle, GWL_STYLE, value);
         }
     }
 }

+ 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 += (sender, e) => MessageBox.Show(droper.DropFilePaths[0]);
+    /// droper.DragDrop += () => 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 event EventHandler DragDrop;
+        public Action DragDrop { get; set; }
         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(null, null);
+            DragDrop?.Invoke();
             return true;
         }
     }

+ 24 - 19
ContextMenuManager/BluePointLilac.Methods/EncodingType.cs

@@ -1,34 +1,39 @@
-using System.IO;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
 using System.Text;
 
 namespace BluePointLilac.Methods
 {
     /* 获取文本文件编码类型
-     * 代码参考:https://www.cnblogs.com/guyun/p/4262587.html (Napoléon)
-
-     * 各种带BOM的编码BOM值
-     * UTF-7 : 2B 2F 76
-     * UTF-8 : EF BB BF
-     * UTF-16LE : FF FE
-     * UTF-16BE : FE FF
-     * UTF-32LE : FF FE 00 00
-     * UTF-32BE : 00 00 FE FF
-     */
+     * 代码参考:https://www.cnblogs.com/guyun/p/4262587.html (Napoléon)*/
     public static class EncodingType
     {
+        /// <summary>各种带BOM的编码BOM值</summary>
+        private static readonly Dictionary<byte[], Encoding> EncodingBomBytes = new Dictionary<byte[], Encoding>
+        {
+            { new byte[] { 0xEF, 0xBB, 0xBF }, Encoding.UTF8 },                         //UTF-8         EF BB BF
+            { new byte[] { 0xFF, 0xFE, 0x00, 0x00 }, Encoding.UTF32 },                  //UTF-32LE      FF FE 00 00
+            { new byte[] { 0xFF, 0xFE }, Encoding.Unicode },                            //UTF-16LE      FF FE
+            { new byte[] { 0xFE, 0xFF }, Encoding.BigEndianUnicode },                   //UTF-16BE      FE FF
+            { new byte[] { 0x2B, 0x2F, 0x76 }, Encoding.UTF7 },                         //UTF-7         2B 2F 76
+            { new byte[] { 0x00, 0x00, 0xFE, 0xFF }, new UTF32Encoding(true, true) },   //UTF-32BE      00 00 FE FF
+        };
+
         /// <summary>获取给定的文件的编码类型</summary> 
         /// <param name=“filePath“>文件路径</param> 
         /// <returns>文件的编码类型</returns> 
         public static Encoding GetType(string filePath)
         {
-            byte[] bytes = File.ReadAllBytes(filePath);
-            if(bytes.Length >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) return Encoding.UTF8;//UTF-8
-            else if(bytes.Length >= 4 && bytes[0] == 0xFF && bytes[1] == 0xFE && bytes[2] == 0x00 && bytes[3] == 0x00) return Encoding.UTF32;//UTF-32LE
-            else if(bytes.Length >= 2 && bytes[0] == 0xFF && bytes[1] == 0xFE) return Encoding.Unicode; //UTF-16LE
-            else if(bytes.Length >= 2 && bytes[0] == 0xFE && bytes[1] == 0xFF) return Encoding.BigEndianUnicode; //UTF-16BE
-            else if(bytes.Length >= 3 && bytes[0] == 0x2B && bytes[1] == 0x2F && bytes[2] == 0x76) return Encoding.UTF7; //UTF-7
-            else if(bytes.Length >= 4 && bytes[0] == 0x00 && bytes[1] == 0x00 && bytes[2] == 0xFE && bytes[3] == 0xFF) return new UTF32Encoding(true, true);//UTF-32BE
-            else if(IsUTF8Bytes(bytes)) return Encoding.UTF8; //不带BOM的UTF-8
+            byte[] fs = File.ReadAllBytes(filePath);
+            foreach(var kv in EncodingBomBytes)
+            {
+                if(fs.Length < kv.Key.Length) continue;
+                int i = -1;
+                bool flag = kv.Key.All(s => { i++; return s == fs[i]; });
+                if(flag) return kv.Value;
+            }
+            if(IsUTF8Bytes(fs)) return Encoding.UTF8; //不带BOM的UTF-8
             return Encoding.Default;
         }
 

+ 70 - 10
ContextMenuManager/BluePointLilac.Methods/ExternalProgram.cs

@@ -8,10 +8,19 @@ using System.Threading;
 
 namespace BluePointLilac.Methods
 {
+    /// <summary>外部程序</summary>
     public static class ExternalProgram
     {
+        /// <summary>在Regedit中跳转指定路径并定位指定键名</summary>
+        /// <param name="regPath">注册表项路径</param>
+        /// <param name="valueName">注册表键名</param>
+        /// <param name="moreOpen">窗口是否多开</param>
         public static void JumpRegEdit(string regPath, string valueName = null, bool moreOpen = false)
         {
+            //还有一种方法,修改HKCU\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit
+            //中的LastKey键值(记录上次关闭注册表编辑器时的注册表路径)为要跳转的注册表项路径regPath,
+            //再使用Process.Start("regedit.exe", "-m")打开注册表编辑器
+            //优点:代码少、不会有Bug。缺点:不能定位具体键,没有展开效果
             if(regPath == null) return;
             Process process;
             IntPtr hMain = FindWindow("RegEdit_RegEdit", null);
@@ -22,6 +31,7 @@ namespace BluePointLilac.Methods
             }
             else
             {
+                //注册表编辑器窗口多开
                 process = Process.Start("regedit.exe", "-m");
                 process.WaitForInputIdle();
                 hMain = process.MainWindowHandle;
@@ -71,25 +81,44 @@ namespace BluePointLilac.Methods
             process.Dispose();
         }
 
-        public static void JumpExplorer(string filePath)
+        /// <summary>在Explorer中选中指定文件或文件夹</summary>
+        /// <param name="filePath">文件或文件夹路径</param>
+        /// <param name="moreOpen">窗口是否多开</param>
+        public static void JumpExplorer(string filePath, bool moreOpen = false)
         {
             if(filePath == null) return;
-            using(Process process = new Process())
+            if(!moreOpen)
+            {
+                IntPtr pidlList = ILCreateFromPathW(filePath);
+                if(pidlList == IntPtr.Zero) return;
+                SHOpenFolderAndSelectItems(pidlList, 0, IntPtr.Zero, 0);
+                ILFree(pidlList);
+            }
+            else
             {
-                if(File.Exists(filePath) || filePath.StartsWith("shell:AppsFolder", StringComparison.OrdinalIgnoreCase))
+                using(Process process = new Process())
                 {
                     process.StartInfo.FileName = "explorer.exe";
                     process.StartInfo.Arguments = $"/select, {filePath}";
                     process.Start();
                 }
-                if(Directory.Exists(filePath))
-                {
-                    process.StartInfo.FileName = filePath;
-                    process.Start();
-                }
             }
         }
 
+        /// <summary>在Explorer中打开指定目录</summary>
+        /// <param name="dirPath">目录路径</param>
+        public static void OpenDirectory(string dirPath)
+        {
+            if(!Directory.Exists(dirPath)) return;
+            using(Process process = new Process())
+            {
+                process.StartInfo.FileName = dirPath;
+                process.Start();
+            }
+        }
+
+        /// <summary>打开文件或文件夹的属性对话框</summary>
+        /// <param name="filePath">文件或文件夹路径</param>
         public static bool ShowPropertiesDialog(string filePath)
         {
             SHELLEXECUTEINFO info = new SHELLEXECUTEINFO
@@ -104,6 +133,8 @@ namespace BluePointLilac.Methods
             return ShellExecuteEx(ref info);
         }
 
+        /// <summary>打开指定未关联打开方式的扩展名的打开方式对话框</summary>
+        /// <param name="extension">文件扩展名</param>
         public static void ShowOpenWithDialog(string extension)
         {
             //Win10 调用 SHOpenWithDialog API 或调用 OpenWith.exe -override "%1"
@@ -125,8 +156,10 @@ namespace BluePointLilac.Methods
             File.Delete(tempPath);
         }
 
+        /// <summary>重启Explorer</summary>
         public static void RestartExplorer()
         {
+            //有些系统有tskill.exe可以直接调用tskill explorer命令
             using(Process process = new Process())
             {
                 process.StartInfo = new ProcessStartInfo
@@ -142,19 +175,37 @@ namespace BluePointLilac.Methods
             }
         }
 
-        public static void OpenUrl(string url)
+        /// <summary>调用默认浏览器打开指定网址</summary>
+        /// <param name="url">网址</param>
+        public static void OpenWebUrl(string url)
         {
+            if(url == null) return;
             //替换网址转义符
             url = url.Replace("%", "%25").Replace("#", "%23").Replace("&", "%26").Replace("+", "%2B");
             using(Process process = new Process())
             {
-                //通过explorer来调用浏览器打开链接,避免管理员权限影响
+                //通过explorer来调用默认浏览器打开链接,避免管理员权限影响
                 process.StartInfo.FileName = "explorer.exe";
                 process.StartInfo.Arguments = $"\"{url}\"";
                 process.Start();
             }
         }
 
+        /// <summary>导出指定注册表项的.reg文件</summary>
+        /// <param name="regPath">注册表项路径</param>
+        /// <param name="filePath">.reg文件保存路径</param>
+        public static void ExportRegistry(string regPath, string filePath)
+        {
+            using(Process process = new Process())
+            {
+                process.StartInfo.FileName = "regedit.exe";
+                process.StartInfo.Arguments = $"/e \"{filePath}\" \"{regPath}\"";
+                process.WaitForExit();
+            }
+        }
+
+        /// <summary>打开记事本显示指定文本</summary>
+        /// <param name="text">要显示的文本</param>
         public static void OpenNotepadWithText(string text)
         {
             using(Process process = Process.Start("notepad.exe"))
@@ -195,6 +246,15 @@ namespace BluePointLilac.Methods
         [DllImport("user32.dll")]
         private static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
 
+        [DllImport("shell32.dll", ExactSpelling = true)]
+        private static extern void ILFree(IntPtr pidlList);
+
+        [DllImport("shell32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
+        private static extern IntPtr ILCreateFromPathW(string pszPath);
+
+        [DllImport("shell32.dll", ExactSpelling = true)]
+        private static extern IntPtr SHOpenFolderAndSelectItems(IntPtr pidlList, uint cild, IntPtr children, uint dwFlags);
+
         [DllImport("shell32.dll", CharSet = CharSet.Auto)]
         private static extern bool ShellExecuteEx(ref SHELLEXECUTEINFO lpExecInfo);
 

+ 8 - 0
ContextMenuManager/BluePointLilac.Methods/HighDpi.cs

@@ -4,8 +4,14 @@ using System.Windows.Forms;
 
 namespace BluePointLilac.Methods
 {
+    /// <summary>处理不同DPI缩放比下的像素绘制和字体显示问题</summary>
+    /// <remarks>Font为矢量类型,Point、Size、Rectangle、Padding等为像素类型。
+    /// 在不同DPI缩放下,矢量类型等比缩放,像素类型保持不变,故会出现排版显示问题。
+    /// 解决方案一:项目中所有用到的像素类型实例值都取与缩放比之积,矢量类型不变。
+    /// 解决方案二:项目中所有用到的矢量类型实例都取与缩放比之商,像素类型不变</remarks>
     public static class HighDpi
     {
+        /// <summary>DPI缩放比</summary>
         public static readonly double DpiScale = Screen.PrimaryScreen.Bounds.Width / SystemParameters.PrimaryScreenWidth;
 
         public static Point DpiZoom(this Point point) => new Point(DpiZoom(point.X), DpiZoom(point.Y));
@@ -22,6 +28,8 @@ 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 int DpiZoom(this int num) => (int)(num * DpiScale);
 
         public static float DpiZoom(this float num) => (float)(num * DpiScale);

+ 2 - 2
ContextMenuManager/BluePointLilac.Methods/ImageExtension.cs

@@ -29,10 +29,10 @@ namespace BluePointLilac.Methods
             using(Graphics g = Graphics.FromImage(destImage))
             {
                 g.CompositingMode = CompositingMode.SourceCopy;
-                g.CompositingQuality = CompositingQuality.HighQuality;
                 g.InterpolationMode = InterpolationMode.HighQualityBicubic;
-                g.SmoothingMode = SmoothingMode.HighQuality;
+                g.CompositingQuality = CompositingQuality.HighQuality;
                 g.PixelOffsetMode = PixelOffsetMode.HighQuality;
+                g.SmoothingMode = SmoothingMode.HighQuality;
 
                 using(ImageAttributes attributes = new ImageAttributes())
                 {

+ 0 - 7
ContextMenuManager/BluePointLilac.Methods/RegistryEx.cs

@@ -156,12 +156,5 @@ namespace BluePointLilac.Methods
             GetRootAndSubRegPath(regPath, out RegistryKey root, out string keyPath);
             using(root) return root.OpenSubKey(keyPath, check, rights);
         }
-
-        public static void Export(string regPath, string filePath)
-        {
-            File.Delete(filePath);
-            using(Process process = Process.Start("regedit.exe", $"/e \"{filePath}\" \"{regPath}\""))
-                process.WaitForExit();
-        }
     }
 }

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

@@ -54,6 +54,7 @@ namespace BluePointLilac.Methods
             box.ClientSizeChanged += (sender, e) => SetScrollVisible();
         }
 
+        /// <summary>TextBox只读时可以使用Ctrl+A全选快捷键</summary>
         public static void CanSelectAllWhenReadOnly(this TextBox box)
         {
             box.KeyDown += (sender, e) =>

+ 4 - 5
ContextMenuManager/BluePointLilac.Controls/MyToolTip.cs → ContextMenuManager/BluePointLilac.Methods/ToolTipBox.cs

@@ -1,14 +1,13 @@
-using BluePointLilac.Methods;
-using System.Windows.Forms;
+using System.Windows.Forms;
 
-namespace BluePointLilac.Controls
+namespace BluePointLilac.Methods
 {
-    public static class MyToolTip
+    public static class ToolTipBox
     {
         public static void SetToolTip(Control ctr, string tip)
         {
             if(tip.IsNullOrWhiteSpace()) return;
-            ToolTip toolTip = new ToolTip();
+            ToolTip toolTip = new ToolTip { InitialDelay = 1 };
             toolTip.SetToolTip(ctr, tip);
             ctr.Disposed += (sender, e) => toolTip.Dispose();
         }

+ 8 - 6
ContextMenuManager/ContextMenuManager.csproj

@@ -32,18 +32,19 @@
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
+    <DebugSymbols>false</DebugSymbols>
+    <DebugType>none</DebugType>
+    <Optimize>true</Optimize>
     <OutputPath>bin\Debug\</OutputPath>
     <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
+    <ErrorReport>queue</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <Prefer32Bit>false</Prefer32Bit>
     <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
     <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
     <DocumentationFile>
     </DocumentationFile>
+    <FileAlignment>4096</FileAlignment>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <PlatformTarget>AnyCPU</PlatformTarget>
@@ -127,11 +128,11 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="AppConfig.cs" />
-    <Compile Include="BluePointLilac.Controls\MyToolTip.cs" />
+    <Compile Include="BluePointLilac.Methods\ToolTipBox.cs" />
     <Compile Include="BluePointLilac.Controls\ReadOnlyTextBox.cs">
       <SubType>Component</SubType>
     </Compile>
-    <Compile Include="BluePointLilac.Controls\ResizbleForm.cs">
+    <Compile Include="BluePointLilac.Controls\ResizeLimitedForm.cs">
       <SubType>Form</SubType>
     </Compile>
     <Compile Include="BluePointLilac.Controls\MyToolBar.cs">
@@ -181,6 +182,7 @@
     <Compile Include="Controls\Interfaces\IBtnMoveUpDownItem.cs">
       <SubType>Component</SubType>
     </Compile>
+    <Compile Include="Controls\Interfaces\IProtectOpenItem.cs" />
     <Compile Include="Controls\Interfaces\ITsiAdministratorItem.cs">
       <SubType>Component</SubType>
     </Compile>

+ 104 - 47
ContextMenuManager/Controls/AboutApp.cs

@@ -5,6 +5,7 @@ using System.Collections.Generic;
 using System.Drawing;
 using System.IO;
 using System.Text;
+using System.Text.RegularExpressions;
 using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls
@@ -18,7 +19,13 @@ namespace ContextMenuManager.Controls
             this.BackColor = Color.White;
             this.Font = new Font(SystemFonts.MenuFont.FontFamily, 10F);
             this.Controls.AddRange(new Control[] { lblInfo, picQR, lblList });
-            lblList.Click += (sender, e) => Updater.ShowDonateDialog();
+            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;
         }
@@ -109,9 +116,10 @@ namespace ContextMenuManager.Controls
             boxs[0].Controls.Add(btnOpenDir);
             boxs[0].Text = AppString.Other.Dictionaries;
             btnOpenDir.Top = boxs[0].Height - btnOpenDir.Height;
-            MyToolTip.SetToolTip(btnOpenDir, AppString.Menu.FileLocation);
-            btnOpenDir.MouseDown += (sender, e) => ExternalProgram.JumpExplorer(AppConfig.DicsDir);
+            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[] {
@@ -215,15 +223,27 @@ namespace ContextMenuManager.Controls
         {
             this.Dock = DockStyle.Fill;
             this.Font = new Font(SystemFonts.MenuFont.FontFamily, 10F);
-            this.Controls.AddRange(new Control[] { cmbLanguages, btnOpenDir, btnDownLoad, btnTranslate, txtTranslators });
+            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();
-            btnDownLoad.MouseDown += (sender, e) => { if(Updater.ShowLanguageDialog()) LoadLanguages(); };
-            btnOpenDir.MouseDown += (sender, e) => ExternalProgram.JumpExplorer(AppConfig.LangsDir);
-            btnTranslate.MouseDown += (sender, e) => new TranslateDialog().ShowDialog();
-            MyToolTip.SetToolTip(btnOpenDir, AppString.Menu.FileLocation);
-            MyToolTip.SetToolTip(btnDownLoad, AppString.Dialog.DownloadLanguages);
-            MyToolTip.SetToolTip(btnTranslate, AppString.Dialog.TranslateTool);
-            txtTranslators.SetAutoShowScroll(ScrollBars.Vertical);
+            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);
         }
@@ -233,20 +253,38 @@ namespace ContextMenuManager.Controls
             Width = 150.DpiZoom(),
             DropDownStyle = ComboBoxStyle.DropDownList
         };
-
-        readonly ReadOnlyTextBox txtTranslators = new ReadOnlyTextBox();
         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();
-            txtTranslators.Width = this.ClientSize.Width - 2 * a;
-            txtTranslators.Height = this.ClientSize.Height - txtTranslators.Top - a;
-            cmbLanguages.Margin = txtTranslators.Margin = btnOpenDir.Margin
+            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);
         }
 
@@ -254,10 +292,10 @@ namespace ContextMenuManager.Controls
         {
             cmbLanguages.Items.Clear();
             cmbLanguages.Items.Add("(default) 简体中文");
-            string str = AppString.Other.Translators + Environment.NewLine + new string('-', 74);
             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);
@@ -265,13 +303,22 @@ namespace ContextMenuManager.Controls
                     string language = reader.GetValue("General", "Language");
                     if(language.IsNullOrWhiteSpace()) language = langName;
                     string translator = reader.GetValue("General", "Translator");
-                    str += Environment.NewLine + language + new string('\t', 5) + 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();
             }
-            txtTranslators.Text = str;
-            cmbLanguages.SelectedIndex = GetSelectIndex();
+            int index = GetSelectIndex();
+            cmbLanguages.SelectedIndex = index;
+            if(index == 0) AppConfig.Language = "default";
         }
 
         private void ChangeLanguage()
@@ -316,31 +363,38 @@ namespace ContextMenuManager.Controls
             mliWinXSortable.AddCtr(chkWinXSortable);
             mliShowFilePath.AddCtr(chkShowFilePath);
             mliOpenMoreRegedit.AddCtr(chkOpenMoreRegedit);
+            mliOpenMoreExplorer.AddCtr(chkOpenMoreExplorer);
             mliHideDisabledItems.AddCtr(chkHideDisabledItems);
             mliHideSysStoreItems.AddCtr(chkHideSysStoreItems);
             cmbConfigDir.AutosizeDropDownWidth();
             cmbEngine.AutosizeDropDownWidth();
             cmbRepo.AutosizeDropDownWidth();
-            MyToolTip.SetToolTip(cmbConfigDir, AppString.Tip.ConfigPath);
-            MyToolTip.SetToolTip(btnConfigDir, AppString.Menu.FileLocation);
-            MyToolTip.SetToolTip(btnBackupDir, AppString.Menu.FileLocation);
+            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", "DogeDoge", "Sogou", "360", AppString.Other.CustomEngine });
+            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) => Updater.Update(true);
-            this.VisibleChanged += (sender, e) => this.Enabled = this.Visible;
-            btnConfigDir.MouseDown += (sender, e) => ExternalProgram.JumpExplorer(AppConfig.ConfigDir);
-            btnBackupDir.MouseDown += (sender, e) => ExternalProgram.JumpExplorer(AppConfig.BackupDir);
+            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;
-            chkBackup.MouseDown += (sender, e) => AppConfig.AutoBackup = chkBackup.Checked = !chkBackup.Checked;
-            chkProtect.MouseDown += (sender, e) => AppConfig.ProtectOpenItem = chkProtect.Checked = !chkProtect.Checked;
-            chkWinXSortable.MouseDown += (sender, e) => AppConfig.WinXSortable = chkWinXSortable.Checked = !chkWinXSortable.Checked;
-            chkOpenMoreRegedit.MouseDown += (sender, e) => AppConfig.OpenMoreRegedit = chkOpenMoreRegedit.Checked = !chkOpenMoreRegedit.Checked;
-            chkHideDisabledItems.MouseDown += (sender, e) => AppConfig.HideDisabledItems = chkHideDisabledItems.Checked = !chkHideDisabledItems.Checked;
-            chkHideSysStoreItems.MouseDown += (sender, e) => AppConfig.HideSysStoreItems = chkHideSysStoreItems.Checked = !chkHideSysStoreItems.Checked;
             cmbConfigDir.SelectionChangeCommitted += (sender, e) =>
             {
                 string newPath = (cmbConfigDir.SelectedIndex == 0) ? AppConfig.AppDataConfigDir : AppConfig.AppConfigDir;
@@ -393,18 +447,14 @@ namespace ContextMenuManager.Controls
                 }
                 AppConfig.UpdateFrequency = day;
             };
-            chkShowFilePath.MouseDown += (sender, e) =>
+            chkShowFilePath.PreCheckChanging += () =>
             {
-                chkShowFilePath.Checked = !chkShowFilePath.Checked;
-                if(MessageBoxEx.Show(AppString.Message.RestartApp, MessageBoxButtons.OKCancel) == DialogResult.OK)
-                {
-                    AppConfig.ShowFilePath = chkShowFilePath.Checked;
-                    SingleInstance.Restart();
-                }
-                else
-                {
-                    chkShowFilePath.Checked = !chkShowFilePath.Checked;
-                }
+                return MessageBoxEx.Show(AppString.Message.RestartApp, MessageBoxButtons.OKCancel) == DialogResult.OK;
+            };
+            chkShowFilePath.CheckChanged += () =>
+            {
+                AppConfig.ShowFilePath = chkShowFilePath.Checked;
+                SingleInstance.Restart();
             };
         }
 
@@ -481,6 +531,12 @@ namespace ContextMenuManager.Controls
         };
         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
@@ -503,8 +559,8 @@ namespace ContextMenuManager.Controls
 
         public void LoadItems()
         {
-            this.AddItems(new[] { mliUpdate, mliConfigDir, mliRepo, mliEngine, mliBackup, mliProtect,
-                mliShowFilePath, mliOpenMoreRegedit, mliHideDisabledItems,mliHideSysStoreItems,mliWinXSortable });
+            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;
@@ -513,6 +569,7 @@ namespace ContextMenuManager.Controls
             chkWinXSortable.Checked = AppConfig.WinXSortable;
             chkShowFilePath.Checked = AppConfig.ShowFilePath;
             chkOpenMoreRegedit.Checked = AppConfig.OpenMoreRegedit;
+            chkOpenMoreExplorer.Checked = AppConfig.OpenMoreExplorer;
             chkHideDisabledItems.Checked = AppConfig.HideDisabledItems;
             chkHideSysStoreItems.Checked = AppConfig.HideSysStoreItems;
 

+ 22 - 20
ContextMenuManager/Controls/EnhanceMenusItem.cs

@@ -39,37 +39,39 @@ namespace ContextMenuManager.Controls
         private static void WriteAttributesValue(XmlNode valueXN, string regPath)
         {
             if(valueXN == null) return;
-            XmlNode szXN = valueXN.SelectSingleNode("REG_SZ");
-            XmlNode binaryXN = valueXN.SelectSingleNode("REG_BINARY");
-            XmlNode dwordXN = valueXN.SelectSingleNode("REG_DWORD");
-            XmlNode expand_szXN = valueXN.SelectSingleNode("REG_EXPAND_SZ");
+            if(!EnhanceMenusList.JudgeOSVersion((XmlElement)valueXN)) return;
             using(RegistryKey key = RegistryEx.GetRegistryKey(regPath, true, true))
             {
-                if(szXN != null)
-                    foreach(XmlAttribute a in szXN.Attributes)
-                        key.SetValue(a.Name, a.Value, RegistryValueKind.String);
-                if(expand_szXN != null)
-                    foreach(XmlAttribute a in expand_szXN.Attributes)
-                        key.SetValue(a.Name, a.Value, RegistryValueKind.ExpandString);
-                if(binaryXN != null)
+                foreach(XmlNode xn in valueXN.ChildNodes)
                 {
-                    foreach(XmlAttribute a in binaryXN.Attributes)
-                        key.SetValue(a.Name, EnhanceMenusList.ConvertToBinary(a.Value), RegistryValueKind.Binary);
-                }
-                if(dwordXN != null)
-                    foreach(XmlAttribute a in dwordXN.Attributes)
+                    if(!EnhanceMenusList.JudgeOSVersion((XmlElement)xn)) continue;
+                    foreach(XmlAttribute xa in xn.Attributes)
                     {
-                        int value = a.Value.StartsWith("0x", StringComparison.OrdinalIgnoreCase)
-                            ? Convert.ToInt32(a.Value, 16) : Convert.ToInt32(a.Value);
-                        key.SetValue(a.Name, value, RegistryValueKind.DWord);
+                        switch(xn.Name)
+                        {
+                            case "REG_SZ":
+                                key.SetValue(xa.Name, 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);
+                                break;
+                            case "REG_DWORD":
+                                int num = xa.Value.ToLower().StartsWith("0x") ? 16 : 10;
+                                key.SetValue(xa.Name, Convert.ToInt32(xa.Value, num), RegistryValueKind.DWord);
+                                break;
+                        }
                     }
-
+                }
             }
         }
 
         private static void WriteSubKeysValue(XmlElement keyXE, string regPath)
         {
             if(keyXE == null) return;
+            if(!EnhanceMenusList.JudgeOSVersion(keyXE)) return;
             string defaultValue = Environment.ExpandEnvironmentVariables(keyXE.GetAttribute("Default"));
             if(!defaultValue.IsNullOrWhiteSpace())
             {

+ 21 - 15
ContextMenuManager/Controls/EnhanceMenusList.cs

@@ -129,7 +129,6 @@ namespace ContextMenuManager.Controls
             {
                 if(!JudgeOSVersion(itemXE)) continue;
                 if(!FileExists(itemXE)) continue;
-                XmlElement szXE = (XmlElement)itemXE.SelectSingleNode("Value/REG_SZ");
                 string keyName = itemXE.GetAttribute("KeyName");
                 if(keyName.IsNullOrWhiteSpace()) continue;
                 EnhanceShellItem item = new EnhanceShellItem()
@@ -138,37 +137,45 @@ namespace ContextMenuManager.Controls
                     FoldGroupItem = groupItem,
                     ItemXE = itemXE
                 };
-                if(szXE != null)
+                foreach(XmlElement szXE in itemXE.SelectNodes("Value/REG_SZ"))
                 {
-                    item.Text = ResourceString.GetDirectString(szXE.GetAttribute("MUIVerb"));
+                    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;
-                    else
+                }
+                if(item.Image == null)
+                {
+                    XmlElement cmdXE = (XmlElement)itemXE.SelectSingleNode("SubKey/Command");
+                    if(cmdXE != null)
                     {
-                        XmlElement cmdXE = (XmlElement)itemXE.SelectSingleNode("SubKey/Command");
-                        if(cmdXE != null)
+                        Icon icon = null;
+                        if(cmdXE.HasAttribute("Default"))
+                        {
+                            string filePath = ObjectPath.ExtractFilePath(cmdXE.GetAttribute("Default"));
+                            icon = ResourceIcon.GetIcon(filePath);
+                        }
+                        else
                         {
-                            Icon icon = null;
-                            if(cmdXE.HasAttribute("Default"))
+                            XmlElement fileXE = (XmlElement)cmdXE.SelectSingleNode("FileName");
+                            if(fileXE != null)
                             {
-                                string filePath = ObjectPath.ExtractFilePath(cmdXE.GetAttribute("Default"));
+                                string filePath = ObjectPath.ExtractFilePath(fileXE.InnerText);
                                 icon = ResourceIcon.GetIcon(filePath);
                             }
-                            item.Image = icon?.ToBitmap();
-                            icon?.Dispose();
                         }
+                        item.Image = icon?.ToBitmap();
+                        icon?.Dispose();
                     }
                 }
                 if(item.Image == null) item.Image = AppImage.NotFound;
                 if(item.Text.IsNullOrWhiteSpace()) item.Text = keyName;
-                item.ChkVisible.Checked = item.ItemVisible;
                 string tip = itemXE.GetAttribute("Tip");
                 if(itemXE.GetElementsByTagName("CreateFile").Count > 0)
                 {
                     if(!tip.IsNullOrWhiteSpace()) tip += "\n";
                     tip += AppString.Tip.CommandFiles;
                 }
-                MyToolTip.SetToolTip(item.ChkVisible, tip);
+                ToolTipBox.SetToolTip(item.ChkVisible, tip);
                 this.AddItem(item);
             }
         }
@@ -190,8 +197,7 @@ namespace ContextMenuManager.Controls
                 };
                 if(item.Text.IsNullOrWhiteSpace()) item.Text = GuidInfo.GetText(guid);
                 if(item.DefaultKeyName.IsNullOrWhiteSpace()) item.DefaultKeyName = guid.ToString("B");
-                item.ChkVisible.Checked = item.ItemVisible;
-                MyToolTip.SetToolTip(item.ChkVisible, itemXE.GetAttribute("Tip"));
+                ToolTipBox.SetToolTip(item.ChkVisible, itemXE.GetAttribute("Tip"));
                 this.AddItem(item);
             }
         }

+ 4 - 4
ContextMenuManager/Controls/ExplorerRestarter.cs

@@ -13,11 +13,11 @@ namespace ContextMenuManager.Controls
             this.Dock = DockStyle.Bottom;
             this.Image = AppImage.Explorer;
             this.Text = AppString.Other.RestartExplorer;
-            MyToolTip.SetToolTip(BtnRestart, AppString.Tip.RestartExplorer);
+            ToolTipBox.SetToolTip(BtnRestart, AppString.Tip.RestartExplorer);
             this.AddCtr(BtnRestart);
             this.CanMoveForm();
             BtnRestart.MouseDown += (sender, e) => { ExternalProgram.RestartExplorer(); this.Visible = false; };
-            ShowHandler += (sender, e) => this.Visible = true;
+            ShowHandler += () => this.Visible = true;
         }
 
         protected override void OnVisibleChanged(EventArgs e)
@@ -28,8 +28,8 @@ namespace ContextMenuManager.Controls
 
         private readonly PictureButton BtnRestart = new PictureButton(AppImage.RestartExplorer);
 
-        private static event EventHandler ShowHandler;
+        private static Action ShowHandler { get; set; }
 
-        public new static void Show() { ShowHandler?.Invoke(null, null); }
+        public static new void Show() { ShowHandler?.Invoke(); }
     }
 }

+ 1 - 1
ContextMenuManager/Controls/GuidBlockedItem.cs

@@ -92,7 +92,7 @@ namespace ContextMenuManager.Controls
             TsiDetails.DropDownItems.AddRange(new ToolStripItem[] { TsiSearch,
                 new ToolStripSeparator(), TsiFileProperties, TsiFileLocation, TsiRegLocation});
 
-            MyToolTip.SetToolTip(BtnDelete, AppString.Menu.Delete);
+            ToolTipBox.SetToolTip(BtnDelete, AppString.Menu.Delete);
             TsiDelete.Click += (sender, e) =>
             {
                 if(MessageBoxEx.Show(AppString.Message.ConfirmDelete, MessageBoxButtons.YesNo) == DialogResult.Yes) DeleteMe();

+ 1 - 1
ContextMenuManager/Controls/GuidBlockedList.cs

@@ -42,7 +42,7 @@ namespace ContextMenuManager.Controls
         {
             NewItem newItem = new NewItem(AppString.Other.AddGuidBlockedItem);
             this.AddItem(newItem);
-            newItem.AddNewItem += (sender, e) =>
+            newItem.AddNewItem += () =>
             {
                 using(InputDialog dlg = new InputDialog { Title = AppString.Dialog.InputGuid })
                 {

+ 0 - 1
ContextMenuManager/Controls/IEItem.cs

@@ -28,7 +28,6 @@ namespace ContextMenuManager.Controls
                 regPath = value;
                 this.Text = this.ItemText;
                 this.Image = this.ItemImage;
-                ChkVisible.Checked = this.ItemVisible;
             }
         }
         public string ValueName => null;

+ 1 - 1
ContextMenuManager/Controls/IEList.cs

@@ -50,7 +50,7 @@ namespace ContextMenuManager.Controls
         {
             NewItem newItem = new NewItem();
             this.AddItem(newItem);
-            newItem.AddNewItem += (sender, e) =>
+            newItem.AddNewItem += () =>
             {
                 using(NewIEDialog dlg = new NewIEDialog())
                 {

+ 1 - 1
ContextMenuManager/Controls/Interfaces/IBtnOpenPathItem.cs

@@ -22,7 +22,7 @@ namespace ContextMenuManager.Controls.Interfaces
                 {
                     case PathType.File:
                     case PathType.Directory:
-                        ExternalProgram.JumpExplorer(item.TargetPath);
+                        ExternalProgram.JumpExplorer(item.TargetPath, AppConfig.OpenMoreExplorer);
                         break;
                     case PathType.Registry:
                         ExternalProgram.JumpRegEdit(item.TargetPath, null, AppConfig.OpenMoreRegedit);

+ 2 - 9
ContextMenuManager/Controls/Interfaces/IChkVisibleItem.cs

@@ -1,5 +1,4 @@
 using BluePointLilac.Controls;
-using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls.Interfaces
 {
@@ -15,14 +14,8 @@ namespace ContextMenuManager.Controls.Interfaces
         {
             MyListItem listItem = (MyListItem)item;
             listItem.AddCtr(this);
-            this.MouseDown += (sender, e) =>
-            {
-                if(e.Button == MouseButtons.Left)
-                {
-                    item.ItemVisible = !this.Checked;
-                    this.Checked = item.ItemVisible;
-                }
-            };
+            this.CheckChanged += () => item.ItemVisible = this.Checked;
+            listItem.HandleCreated += (sender, e) => this.Checked = item.ItemVisible;
             listItem.ParentChanged += (sender, e) =>
             {
                 if(listItem.IsDisposed) return;

+ 6 - 6
ContextMenuManager/Controls/Interfaces/IFoldGroupItem.cs

@@ -67,11 +67,11 @@ namespace ContextMenuManager.Controls.Interfaces
             {
                 if(BtnFold.IsFold == value) return;
                 BtnFold.IsFold = value;
-                IsFoldChanegd?.Invoke(null, null);
+                //IsFoldChanegd?.Invoke();
             }
         }
 
-        public event EventHandler IsFoldChanegd;
+        //public Action IsFoldChanegd;
         public string TargetPath { get; set; }
         public PathType PathType { get; set; }
         public ObjectPathButton BtnOpenPath { get; set; }
@@ -104,16 +104,16 @@ namespace ContextMenuManager.Controls.Interfaces
                     tip = AppString.Menu.RegistryLocation;
                     break;
             }
-            MyToolTip.SetToolTip(BtnOpenPath, tip);
-            this.ImageDoubleClick += (sender, e) => this.OnDoubleClick(null);
-            this.TextDoubleClick += (sender, e) => this.OnDoubleClick(null);
+            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(var ctr in this.Parent.Controls)
+            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++;

+ 8 - 0
ContextMenuManager/Controls/Interfaces/IProtectOpenItem.cs

@@ -0,0 +1,8 @@
+namespace ContextMenuManager.Controls.Interfaces
+{
+    interface IProtectOpenItem
+    {
+        bool ItemVisible { get; set; }
+        bool TryProtectOpenItem();
+    }
+}

+ 1 - 1
ContextMenuManager/Controls/Interfaces/ITsiDeleteItem.cs

@@ -32,7 +32,7 @@ namespace ContextMenuManager.Controls.Interfaces
                     string time = DateTime.Now.ToString("HH.mm.ss");
                     string filePath = $@"{AppConfig.BackupDir}\{date}\{regItem.Text} - {time}.reg";
                     Directory.CreateDirectory(Path.GetDirectoryName(filePath));
-                    RegistryEx.Export(regItem.RegPath, filePath);
+                    ExternalProgram.ExportRegistry(regItem.RegPath, filePath);
                 }
                 else if(MessageBoxEx.Show(AppString.Message.ConfirmDeletePermanently,
                      MessageBoxButtons.YesNo) != DialogResult.Yes) return;

+ 2 - 4
ContextMenuManager/Controls/Interfaces/ITsiFilePathItem.cs

@@ -18,11 +18,9 @@ namespace ContextMenuManager.Controls.Interfaces
         {
             item.ContextMenuStrip.Opening += (sender, e) =>
             {
-                string path = item.ItemFilePath;
-                this.Visible = path != null && (Directory.Exists(path)
-                    || File.Exists(path) || path.StartsWith("shell:AppsFolder"));
+                this.Visible = item.ItemFilePath != null;
             };
-            this.Click += (sender, e) => ExternalProgram.JumpExplorer(item.ItemFilePath);
+            this.Click += (sender, e) => ExternalProgram.JumpExplorer(item.ItemFilePath, AppConfig.OpenMoreExplorer);
         }
     }
 

+ 11 - 4
ContextMenuManager/Controls/Interfaces/ITsiGuidItem.cs

@@ -30,8 +30,8 @@ namespace ContextMenuManager.Controls.Interfaces
             TsiBlockGuid.Click += (sender, e) => BlockGuid();
             TsiAddGuidDic.Click += (sender, e) => AddGuidDic();
             MyListItem listItem = (MyListItem)item;
-            listItem.ImageDoubleClick += (sender, e) => AddGuidDic();
-            listItem.TextDoubleClick += (sender, e) => AddGuidDic();
+            listItem.ImageDoubleClick += () => AddGuidDic();
+            listItem.TextDoubleClick += () => AddGuidDic();
             listItem.ContextMenuStrip.Opening += (sender, e) =>
             {
                 TsiBlockGuid.Checked = false;
@@ -70,6 +70,11 @@ namespace ContextMenuManager.Controls.Interfaces
                 }
                 else
                 {
+                    if(Item.Guid.Equals(ShellExItem.LnkOpenGuid) && AppConfig.ProtectOpenItem)
+                    {
+                        if(MessageBoxEx.Show(AppString.Message.PromptIsOpenItem,
+                            MessageBoxButtons.YesNo) != DialogResult.Yes) return;
+                    }
                     Microsoft.Win32.Registry.SetValue(path, Item.Guid.ToString("B"), string.Empty);
                 }
             }
@@ -272,7 +277,7 @@ namespace ContextMenuManager.Controls.Interfaces
                     lblIcon.Top = btnBrowse.Top + (btnBrowse.Height - lblIcon.Height) / 2;
                     btnDelete.Top = btnOk.Top = btnCancel.Top = btnBrowse.Bottom + a;
                     this.ClientSize = new Size(btnCancel.Right + a, btnCancel.Bottom + a);
-                    MyToolTip.SetToolTip(btnDelete, AppString.Tip.DeleteGuidDic);
+                    ToolTipBox.SetToolTip(btnDelete, AppString.Tip.DeleteGuidDic);
                     btnBrowse.Click += (sender, e) => SelectIcon();
                     btnDelete.Click += (sender, e) => this.IsDelete = true;
                 }
@@ -284,9 +289,11 @@ 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;
-                        picIcon.Image = ResourceIcon.GetIcon(ItemIconPath, ItemIconIndex).ToBitmap();
                     }
                 }
             }

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

@@ -26,18 +26,20 @@ namespace ContextMenuManager.Controls.Interfaces
                     dlg.IconPath = item.IconPath;
                     dlg.IconIndex = item.IconIndex;
                     if(dlg.ShowDialog() != DialogResult.OK) return;
-                    item.IconPath = dlg.IconPath;
-                    item.IconIndex = dlg.IconIndex;
-                    item.IconLocation = $"{dlg.IconPath},{dlg.IconIndex}";
                     using(Icon icon = ResourceIcon.GetIcon(dlg.IconPath, dlg.IconIndex))
                     {
-                        item.Image = icon.ToBitmap();
+                        Image image = icon?.ToBitmap();
+                        if(image == null) return;
+                        item.Image = image;
+                        item.IconPath = dlg.IconPath;
+                        item.IconIndex = dlg.IconIndex;
+                        item.IconLocation = $"{dlg.IconPath},{dlg.IconIndex}";
                     }
                 }
             };
             MyListItem listItem = (MyListItem)item;
             listItem.Disposed += (sender, e) => item.ItemIcon?.Dispose();
-            listItem.ImageDoubleClick += (sender, e) =>
+            listItem.ImageDoubleClick += () =>
             {
                 if(listItem.FindForm() is ShellStoreDialog.ShellStoreForm) return;
                 if(this.Enabled) this.OnClick(null);

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

@@ -37,7 +37,7 @@ namespace ContextMenuManager.Controls.Interfaces
                     dlg.Filter = $"{AppString.Dialog.RegistryFile}|*.reg";
                     if(dlg.ShowDialog() == DialogResult.OK)
                     {
-                        RegistryEx.Export(item.RegPath, dlg.FileName);
+                        ExternalProgram.ExportRegistry(item.RegPath, dlg.FileName);
                     }
                     if(Directory.GetFileSystemEntries(dirPath).Length == 0)
                     {

+ 1 - 1
ContextMenuManager/Controls/Interfaces/ITsiShortcutCommandItem.cs

@@ -64,7 +64,7 @@ namespace ContextMenuManager.Controls.Interfaces
                 }
             }
 
-            sealed class CommandForm : ResizbleForm
+            sealed class CommandForm : ResizeLimitedForm
             {
                 public CommandForm()
                 {

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

@@ -21,7 +21,7 @@ namespace ContextMenuManager.Controls.Interfaces
                 if(name != null) item.ItemText = name;
             };
             MyListItem listItem = (MyListItem)item;
-            listItem.TextDoubleClick += (sender, e) =>
+            listItem.TextDoubleClick += () =>
             {
                 if(listItem is IFoldGroupItem) return;
                 if(listItem.FindForm() is ShellStoreDialog.ShellStoreForm) return;

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

@@ -16,7 +16,7 @@ namespace ContextMenuManager.Controls.Interfaces
             this.Click += (sender, e) =>
             {
                 string url = AppConfig.EngineUrl.Replace("%s", item.SearchText);
-                ExternalProgram.OpenUrl(url);
+                ExternalProgram.OpenWebUrl(url);
             };
         }
     }

+ 6 - 5
ContextMenuManager/Controls/NewItem.cs

@@ -1,4 +1,5 @@
 using BluePointLilac.Controls;
+using BluePointLilac.Methods;
 using System;
 
 namespace ContextMenuManager.Controls
@@ -12,13 +13,13 @@ namespace ContextMenuManager.Controls
             this.Text = text;
             this.Image = AppImage.NewItem;
             this.AddCtr(BtnAddNewItem);
-            MyToolTip.SetToolTip(BtnAddNewItem, text);
-            BtnAddNewItem.MouseDown += (sender, e) => AddNewItem?.Invoke(null, null);
-            this.ImageDoubleClick += (sender, e) => AddNewItem?.Invoke(null, null);
-            this.TextDoubleClick += (sender, e) => AddNewItem?.Invoke(null, null);
+            ToolTipBox.SetToolTip(BtnAddNewItem, text);
+            BtnAddNewItem.MouseDown += (sender, e) => AddNewItem?.Invoke();
+            this.ImageDoubleClick += () => AddNewItem?.Invoke();
+            this.TextDoubleClick += () => AddNewItem?.Invoke();
 
         }
-        public event EventHandler AddNewItem;
+        public Action AddNewItem { get; set; }
         readonly PictureButton BtnAddNewItem = new PictureButton(AppImage.AddNewItem);
     }
 }

+ 2 - 2
ContextMenuManager/Controls/NewItemForm.cs

@@ -6,7 +6,7 @@ using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls
 {
-    class NewItemForm : ResizbleForm
+    class NewItemForm : ResizeLimitedForm
     {
         public NewItemForm()
         {
@@ -86,7 +86,7 @@ namespace ContextMenuManager.Controls
             btnCancel.Left = btnBrowse.Left = this.ClientSize.Width - btnCancel.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(250.DpiZoom() + b, btnOk.Bottom + a);
+            this.ClientSize = new Size(320.DpiZoom() + b, btnOk.Bottom + a);
             this.MinimumSize = this.Size;
             this.Resize += (sender, e) =>
             {

+ 0 - 1
ContextMenuManager/Controls/OpenWithItem.cs

@@ -30,7 +30,6 @@ namespace ContextMenuManager.Controls
                 this.ItemFilePath = ObjectPath.ExtractFilePath(ItemCommand);
                 this.Text = this.ItemText;
                 this.Image = this.ItemIcon.ToBitmap();
-                ChkVisible.Checked = this.ItemVisible;
             }
         }
         public string ValueName => null;

+ 2 - 2
ContextMenuManager/Controls/OpenWithList.cs

@@ -40,7 +40,7 @@ namespace ContextMenuManager.Controls
 
                         string keyName = names.Find(name =>
                         {
-                            using(var cmdKey = shellKey.OpenSubKey(name))
+                            using(RegistryKey cmdKey = shellKey.OpenSubKey(name))
                                 return cmdKey.GetValue("NeverDefault") == null;
                         });
                         if(keyName == null) continue;
@@ -60,7 +60,7 @@ namespace ContextMenuManager.Controls
         {
             NewItem newItem = new NewItem();
             this.InsertItem(newItem, 0);
-            newItem.AddNewItem += (sender, e) =>
+            newItem.AddNewItem += () =>
             {
                 using(NewOpenWithDialog dlg = new NewOpenWithDialog())
                 {

+ 8 - 8
ContextMenuManager/Controls/RuleItem.cs

@@ -72,7 +72,7 @@ namespace ContextMenuManager.Controls
         private VisibleRegRuleItem(ItemInfo info) : base(info)
         {
             ChkVisible = new VisibleCheckBox(this);
-            MyToolTip.SetToolTip(ChkVisible, info.Tip);
+            ToolTipBox.SetToolTip(ChkVisible, info.Tip);
             TsiRegLocation = new RegLocationMenuItem(this);
             this.ContextMenuStrip.Items.AddRange(new ToolStripItem[] { new ToolStripSeparator(), TsiRegLocation });
         }
@@ -93,7 +93,7 @@ namespace ContextMenuManager.Controls
             set
             {
                 _Rules = value;
-                ChkVisible.Checked = ItemVisible;
+                //ChkVisible.Checked = ItemVisible;
             }
         }
 
@@ -261,7 +261,7 @@ namespace ContextMenuManager.Controls
         public NumberRegRuleItem(RegRule rule, ItemInfo info) : base(info)
         {
             this.AddCtr(NudValue);
-            MyToolTip.SetToolTip(NudValue, info.Tip);
+            ToolTipBox.SetToolTip(NudValue, info.Tip);
             TsiRegLocation = new RegLocationMenuItem(this);
             this.ContextMenuStrip.Items.AddRange(new ToolStripItem[] { new ToolStripSeparator(), TsiRegLocation });
             this.Rule = rule;
@@ -327,7 +327,7 @@ namespace ContextMenuManager.Controls
         public StringRegRuleItem(RegRule rule, ItemInfo info) : base(info)
         {
             this.AddCtr(LblValue);
-            MyToolTip.SetToolTip(LblValue, info.Tip);
+            ToolTipBox.SetToolTip(LblValue, info.Tip);
             TsiRegLocation = new RegLocationMenuItem(this);
             this.ContextMenuStrip.Items.AddRange(new ToolStripItem[] { new ToolStripSeparator(), TsiRegLocation });
             this.Rule = rule;
@@ -371,8 +371,8 @@ namespace ContextMenuManager.Controls
         {
             this.Rule = rule;
             this.IniWriter = new IniWriter(rule.IniPath);
-            ChkVisible = new VisibleCheckBox(this) { Checked = ItemVisible };
-            MyToolTip.SetToolTip(ChkVisible, info.Tip);
+            ChkVisible = new VisibleCheckBox(this);// { Checked = ItemVisible };
+            ToolTipBox.SetToolTip(ChkVisible, info.Tip);
         }
 
         public IniRule Rule { get; set; }
@@ -402,7 +402,7 @@ namespace ContextMenuManager.Controls
             this.AddCtr(NudValue);
             this.Rule = rule;
             this.IniWriter = new IniWriter(rule.IniPath);
-            MyToolTip.SetToolTip(NudValue, info.Tip);
+            ToolTipBox.SetToolTip(NudValue, info.Tip);
             NudValue.Maximum = rule.MaxValue;
             NudValue.Minimum = rule.MinValue;
             NudValue.ValueChanged += (sender, e) =>
@@ -473,7 +473,7 @@ namespace ContextMenuManager.Controls
             this.Rule = rule;
             this.IniWriter = new IniWriter(rule.IniPath);
             this.AddCtr(LblValue);
-            MyToolTip.SetToolTip(LblValue, info.Tip);
+            ToolTipBox.SetToolTip(LblValue, info.Tip);
             LblValue.Text = ItemValue;
             LblValue.MouseDown += (sender, e) =>
             {

+ 1 - 2
ContextMenuManager/Controls/SendToItem.cs

@@ -27,7 +27,6 @@ namespace ContextMenuManager.Controls
                 if(IsShortcut) this.ShellLink = new ShellLink(value);
                 this.Text = this.ItemText;
                 this.Image = this.ItemIcon.ToBitmap();
-                ChkVisible.Checked = this.ItemVisible;
             }
         }
 
@@ -219,7 +218,7 @@ namespace ContextMenuManager.Controls
         {
             File.Delete(this.FilePath);
             DesktopIni.DeleteLocalizedFileNames(FilePath);
-            //this.Shortcut.Dispose();
+            this.ShellLink.Dispose();
             this.Dispose();
         }
     }

+ 3 - 3
ContextMenuManager/Controls/SendToList.cs

@@ -28,7 +28,7 @@ namespace ContextMenuManager.Controls
         {
             NewItem newItem = new NewItem();
             this.InsertItem(newItem, 0);
-            newItem.AddNewItem += (sender, e) =>
+            newItem.AddNewItem += () =>
             {
                 using(NewLnkFileDialog dlg = new NewLnkFileDialog())
                 {
@@ -57,8 +57,8 @@ namespace ContextMenuManager.Controls
                 Image = ResourceIcon.GetFolderIcon(SendToPath).ToBitmap()
             };
             PictureButton btnPath = new PictureButton(AppImage.Open);
-            MyToolTip.SetToolTip(btnPath, AppString.Menu.FileLocation);
-            btnPath.MouseDown += (sender, e) => ExternalProgram.JumpExplorer(SendToPath);
+            ToolTipBox.SetToolTip(btnPath, AppString.Menu.FileLocation);
+            btnPath.MouseDown += (sender, e) => ExternalProgram.OpenDirectory(SendToPath);
             item.AddCtr(btnPath);
             this.InsertItem(item, 1);
         }

+ 7 - 10
ContextMenuManager/Controls/ShellExItem.cs

@@ -9,7 +9,7 @@ using System.Windows.Forms;
 namespace ContextMenuManager.Controls
 {
     sealed class ShellExItem : MyListItem, IChkVisibleItem, IBtnShowMenuItem, IFoldSubItem, ITsiGuidItem,
-        ITsiWebSearchItem, ITsiFilePathItem, ITsiRegPathItem, ITsiRegDeleteItem, ITsiRegExportItem
+        ITsiWebSearchItem, ITsiFilePathItem, ITsiRegPathItem, ITsiRegDeleteItem, ITsiRegExportItem, IProtectOpenItem
     {
         public static Dictionary<string, Guid> GetPathAndGuids(string shellExPath, bool isDragDrop = false)
         {
@@ -41,7 +41,7 @@ namespace ContextMenuManager.Controls
 
         public static readonly string[] DdhParts = { "DragDropHandlers", "-DragDropHandlers" };
         public static readonly string[] CmhParts = { "ContextMenuHandlers", "-ContextMenuHandlers" };
-        private const string LnkOpenGuid = "00021401-0000-0000-c000-000000000046";
+        public static readonly Guid LnkOpenGuid = new Guid("00021401-0000-0000-c000-000000000046");
 
         public ShellExItem(Guid guid, string regPath)
         {
@@ -59,7 +59,6 @@ namespace ContextMenuManager.Controls
                 regPath = value;
                 this.Text = this.ItemText;
                 this.Image = GuidInfo.GetImage(Guid);
-                ChkVisible.Checked = this.ItemVisible;
             }
         }
 
@@ -74,7 +73,6 @@ namespace ContextMenuManager.Controls
         private string ParentKeyName => RegistryEx.GetKeyName(ParentPath);
         private string DefaultValue => Registry.GetValue(RegPath, "", null)?.ToString();
         public string ItemText => GuidInfo.GetText(Guid) ?? (KeyName.Equals(Guid.ToString("B"), StringComparison.OrdinalIgnoreCase) ? DefaultValue : KeyName);
-        private bool IsOpenLnkItem => Guid.ToString() == LnkOpenGuid;
         public bool IsDragDropItem => ParentKeyName.EndsWith(DdhParts[0], StringComparison.OrdinalIgnoreCase);
 
         private string BackupPath
@@ -95,7 +93,6 @@ namespace ContextMenuManager.Controls
             }
             set
             {
-                if(!value && TryProtectOpenItem()) return;
                 try
                 {
                     RegistryEx.MoveTo(RegPath, BackupPath);
@@ -140,14 +137,14 @@ namespace ContextMenuManager.Controls
             TsiDetails.DropDownItems.AddRange(new ToolStripItem[] { TsiSearch, new ToolStripSeparator(),
                 TsiFileProperties, TsiFileLocation, TsiRegLocation, TsiRegExport});
 
-            ContextMenuStrip.Opening += (sender, e) => TsiDeleteMe.Enabled = !(IsOpenLnkItem && AppConfig.ProtectOpenItem);
+            ContextMenuStrip.Opening += (sender, e) => TsiDeleteMe.Enabled = !(Guid.Equals(LnkOpenGuid) && AppConfig.ProtectOpenItem);
+            ChkVisible.PreCheckChanging += TryProtectOpenItem;
         }
 
-        private bool TryProtectOpenItem()
+        public bool TryProtectOpenItem()
         {
-            if(!IsOpenLnkItem) return false;
-            if(!AppConfig.ProtectOpenItem) return false;
-            return MessageBoxEx.Show(AppString.Message.PromptIsOpenItem, MessageBoxButtons.YesNo) != DialogResult.Yes;
+            if(!ChkVisible.Checked || !Guid.Equals(LnkOpenGuid) || !AppConfig.ProtectOpenItem) return true;
+            return MessageBoxEx.Show(AppString.Message.PromptIsOpenItem, MessageBoxButtons.YesNo) == DialogResult.Yes;
         }
 
         public void DeleteMe()

+ 2 - 2
ContextMenuManager/Controls/ShellExecuteDialog.cs

@@ -50,7 +50,7 @@ namespace ContextMenuManager.Controls
                 this.StartPosition = FormStartPosition.CenterParent;
                 this.ShowIcon = ShowInTaskbar = MaximizeBox = MinimizeBox = false;
                 this.HelpButton = true;
-                this.HelpButtonClicked += (sender, e) => ExternalProgram.OpenUrl(ApiInfoUrl);
+                this.HelpButtonClicked += (sender, e) => ExternalProgram.OpenWebUrl(ApiInfoUrl);
                 this.InitializeComponents();
             }
             public string Verb { get; set; }
@@ -131,7 +131,7 @@ namespace ContextMenuManager.Controls
         {
             this.Text = "ShellExecute";
             this.AutoSize = true;
-            this.Font = new Font(SystemFonts.DialogFont.FontFamily, 8F / 1F.DpiZoom());
+            this.Font = new Font(SystemFonts.DialogFont.FontFamily, 8F).DpiZoom();
         }
 
         public string Verb { get; set; }

+ 13 - 11
ContextMenuManager/Controls/ShellItem.cs

@@ -10,7 +10,7 @@ using System.Windows.Forms;
 
 namespace ContextMenuManager.Controls
 {
-    class ShellItem : MyListItem, IChkVisibleItem, IBtnShowMenuItem, ITsiTextItem, ITsiCommandItem,
+    class ShellItem : MyListItem, IChkVisibleItem, IBtnShowMenuItem, ITsiTextItem, ITsiCommandItem, IProtectOpenItem,
         ITsiIconItem, ITsiWebSearchItem, ITsiFilePathItem, ITsiRegPathItem, ITsiRegDeleteItem, ITsiRegExportItem
     {
         /// <summary>Shell公共引用子菜单注册表项路径</summary>
@@ -46,7 +46,6 @@ namespace ContextMenuManager.Controls
                 this.Text = this.ItemText;
                 this.Image = this.ItemIcon.ToBitmap();
                 if(!HasIcon) this.Image = Image.ToTransparent();
-                ChkVisible.Checked = this.ItemVisible;
                 BtnSubItems.Visible = IsMultiItem;
             }
         }
@@ -79,7 +78,7 @@ namespace ContextMenuManager.Controls
             {
                 if(value)
                 {
-                    if(TryProtectOpenItem()) return;
+                    if(!TryProtectOpenItem()) return;
                     Registry.SetValue(RegPath, "OnlyInBrowserWindow", "");
                 }
                 else RegistryEx.DeleteValue(RegPath, "OnlyInBrowserWindow");
@@ -93,7 +92,7 @@ namespace ContextMenuManager.Controls
             {
                 if(value)
                 {
-                    if(TryProtectOpenItem()) return;
+                    if(!TryProtectOpenItem()) return;
                     Registry.SetValue(RegPath, "Extended", "");
                 }
                 else RegistryEx.DeleteValue(RegPath, "Extended");
@@ -105,6 +104,7 @@ namespace ContextMenuManager.Controls
             get => Registry.GetValue(RegPath, "NoWorkingDirectory", null) != null;
             set
             {
+                if(!TryProtectOpenItem()) return;
                 if(value) Registry.SetValue(RegPath, "NoWorkingDirectory", "");
                 else RegistryEx.DeleteValue(RegPath, "NoWorkingDirectory");
             }
@@ -115,6 +115,7 @@ namespace ContextMenuManager.Controls
             get => Registry.GetValue(RegPath, "NeverDefault", null) != null;
             set
             {
+                if(!TryProtectOpenItem()) return;
                 if(value) Registry.SetValue(RegPath, "NeverDefault", "");
                 else RegistryEx.DeleteValue(RegPath, "NeverDefault");
             }
@@ -125,6 +126,7 @@ namespace ContextMenuManager.Controls
             get => Registry.GetValue(RegPath, "ShowAsDisabledIfHidden", null) != null;
             set
             {
+                if(!TryProtectOpenItem()) return;
                 if(value) Registry.SetValue(RegPath, "ShowAsDisabledIfHidden", "");
                 else RegistryEx.DeleteValue(RegPath, "ShowAsDisabledIfHidden");
                 if(value && !ItemVisible) ItemVisible = false;
@@ -203,7 +205,6 @@ namespace ContextMenuManager.Controls
                     }
                     else
                     {
-                        if(TryProtectOpenItem()) return;
                         if(WindowsOsVersion.IsAfterOrEqualWin10_1703)
                         {
                             Registry.SetValue(RegPath, "HideBasedOnVelocityId", 0x639bc8);
@@ -277,7 +278,7 @@ namespace ContextMenuManager.Controls
             }
             set
             {
-                if(TryProtectOpenItem()) return;
+                if(!TryProtectOpenItem()) return;
                 Registry.SetValue(CommandPath, "", value);
                 if(!this.HasIcon) this.Image = this.ItemIcon.ToBitmap().ToTransparent();
             }
@@ -411,10 +412,11 @@ namespace ContextMenuManager.Controls
             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));
+            ChkVisible.PreCheckChanging += () => !ChkVisible.Checked || TryProtectOpenItem();
             ContextMenuStrip.Opening += (sender, e) => RefreshMenuItem();
             BtnSubItems.MouseDown += (sender, e) => ShowSubItems();
             TsiShieldIcon.Click += (sender, e) => UseShieldIcon();
-            MyToolTip.SetToolTip(BtnSubItems, AppString.Tip.EditSubItems);
+            ToolTipBox.SetToolTip(BtnSubItems, AppString.Tip.EditSubItems);
             this.AddCtr(BtnSubItems);
         }
 
@@ -515,11 +517,11 @@ namespace ContextMenuManager.Controls
             }
         }
 
-        private bool TryProtectOpenItem()
+        public bool TryProtectOpenItem()
         {
-            if(!IsOpenItem) return false;
-            if(!AppConfig.ProtectOpenItem) return false;
-            return MessageBoxEx.Show(AppString.Message.PromptIsOpenItem, MessageBoxButtons.YesNo) != DialogResult.Yes;
+            if(!IsOpenItem) return true;
+            if(!AppConfig.ProtectOpenItem) return true;
+            return MessageBoxEx.Show(AppString.Message.PromptIsOpenItem, MessageBoxButtons.YesNo) == DialogResult.Yes;
         }
 
         public virtual void DeleteMe()

+ 8 - 8
ContextMenuManager/Controls/ShellList.cs

@@ -384,11 +384,11 @@ namespace ContextMenuManager.Controls
             string shellPath = GetShellPath(scenePath);
             NewItem newItem = new NewItem { Visible = scenePath != null };
             PictureButton btnAddExisting = new PictureButton(AppImage.AddExisting);
-            MyToolTip.SetToolTip(btnAddExisting, AppString.Tip.AddFromPublic);
+            ToolTipBox.SetToolTip(btnAddExisting, AppString.Tip.AddFromPublic);
             btnAddExisting.Visible = Scene != Scenes.DragDrop && !string.Equals(shellPath, ShellItem.CommandStorePath, StringComparison.OrdinalIgnoreCase);
             newItem.AddCtr(btnAddExisting);
             this.AddItem(newItem);
-            newItem.AddNewItem += (sender, e) =>
+            newItem.AddNewItem += () =>
             {
                 bool isShell;
                 if(Scene == Scenes.CommandStore) isShell = true;
@@ -525,7 +525,7 @@ namespace ContextMenuManager.Controls
 
         private void LoadStoreItems()
         {
-            using(var shellKey = RegistryEx.GetRegistryKey(ShellItem.CommandStorePath))
+            using(RegistryKey shellKey = RegistryEx.GetRegistryKey(ShellItem.CommandStorePath))
             {
                 bool flag = AppConfig.HideSysStoreItems;
                 foreach(string itemName in shellKey.GetSubKeyNames())
@@ -642,8 +642,8 @@ namespace ContextMenuManager.Controls
                 this.SetTextAndTip();
                 this.SetImage();
                 BtnSelect.MouseDown += (sender, e) => ShowSelectDialog();
-                this.ImageDoubleClick += (sender, e) => ShowSelectDialog();
-                this.TextDoubleClick += (sender, e) => ShowSelectDialog();
+                this.ImageDoubleClick += () => ShowSelectDialog();
+                this.TextDoubleClick += () => ShowSelectDialog();
             }
 
             readonly PictureButton BtnSelect = new PictureButton(AppImage.Select);
@@ -691,7 +691,7 @@ namespace ContextMenuManager.Controls
                             + " " + GetPerceivedTypeName(CurrentExtensionPerceivedType);
                         break;
                 }
-                MyToolTip.SetToolTip(BtnSelect, tip);
+                ToolTipBox.SetToolTip(BtnSelect, tip);
                 this.Text = text;
             }
 
@@ -933,8 +933,8 @@ namespace ContextMenuManager.Controls
                     ((MainForm)this.FindForm()).SwitchTab(index1, index2);
                 };
                 btnJump.MouseDown += (sender, e) => SwitchTab();
-                this.ImageDoubleClick += (sender, e) => SwitchTab();
-                this.TextDoubleClick += (sender, e) => SwitchTab();
+                this.ImageDoubleClick += () => SwitchTab();
+                this.TextDoubleClick += () => SwitchTab();
             }
 
             readonly PictureButton btnJump = new PictureButton(AppImage.Jump);

+ 0 - 1
ContextMenuManager/Controls/ShellNewItem.cs

@@ -43,7 +43,6 @@ namespace ContextMenuManager.Controls
                 regPath = value;
                 this.Text = this.ItemText;
                 this.Image = this.ItemIcon.ToBitmap();
-                ChkVisible.Checked = this.ItemVisible;
             }
         }
 

+ 2 - 2
ContextMenuManager/Controls/ShellNewList.cs

@@ -134,7 +134,7 @@ namespace ContextMenuManager.Controls
         {
             NewItem newItem = new NewItem();
             this.AddItem(newItem);
-            newItem.AddNewItem += (sender, e) =>
+            newItem.AddNewItem += () =>
             {
                 using(FileExtensionDialog dlg = new FileExtensionDialog())
                 {
@@ -196,7 +196,7 @@ namespace ContextMenuManager.Controls
                 this.Text = AppString.Other.LockNewMenu;
                 BtnShowMenu = new MenuButton(this);
                 ChkVisible = new VisibleCheckBox(this) { Checked = IsLocked };
-                MyToolTip.SetToolTip(ChkVisible, AppString.Tip.LockNewMenu);
+                ToolTipBox.SetToolTip(ChkVisible, AppString.Tip.LockNewMenu);
                 TsiSearch = new WebSearchMenuItem(this);
                 TsiRegLocation = new RegLocationMenuItem(this);
                 this.ContextMenuStrip.Items.AddRange(new ToolStripItem[]

+ 52 - 9
ContextMenuManager/Controls/ShellStoreDialog.cs

@@ -34,18 +34,26 @@ namespace ContextMenuManager.Controls
 
             public ShellStoreForm(string shellPath, Func<string, bool> filter, bool isReference)
             {
-                this.ShellPath = shellPath;
                 this.Filter = filter;
+                this.ShellPath = shellPath;
                 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.Text = isReference ? AppString.Dialog.CheckReference : AppString.Dialog.CheckCopy;
                 btnOk.Click += (sender, e) => GetSelectedItems();
+                chkSelectAll.Click += (sender, e) =>
+                {
+                    bool flag = chkSelectAll.Checked;
+                    foreach(StoreShellItem item in list.Controls)
+                    {
+                        item.IsSelected = flag;
+                    }
+                };
                 list.Owner = listBox;
                 InitializeComponents();
                 LoadItems(isReference);
@@ -71,16 +79,24 @@ namespace ContextMenuManager.Controls
                 Text = AppString.Dialog.Cancel,
                 AutoSize = true
             };
+            readonly CheckBox chkSelectAll = new CheckBox
+            {
+                Anchor = AnchorStyles.Bottom | AnchorStyles.Left,
+                Text = AppString.Dialog.SelectAll,
+                Cursor = Cursors.Hand,
+                AutoSize = true
+            };
 
             private void InitializeComponents()
             {
-                this.Controls.AddRange(new Control[] { listBox, pnlBorder, btnOk, btnCancel });
+                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);
-                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;
+                chkSelectAll.Left = a;
                 this.OnResize(null);
             }
 
@@ -101,7 +117,20 @@ namespace ContextMenuManager.Controls
                     {
                         if(Filter != null && !Filter(itemName)) continue;
                         string regPath = $@"{ShellPath}\{itemName}";
-                        list.AddItem(new StoreShellItem(regPath, isReference));
+                        StoreShellItem item = new StoreShellItem(regPath, isReference);
+                        item.SelectedChanged += () =>
+                        {
+                            foreach(StoreShellItem shellItem in list.Controls)
+                            {
+                                if(!shellItem.IsSelected)
+                                {
+                                    chkSelectAll.Checked = false;
+                                    return;
+                                }
+                            }
+                            chkSelectAll.Checked = true;
+                        };
+                        list.AddItem(item);
                     }
                 }
             }
@@ -111,7 +140,7 @@ namespace ContextMenuManager.Controls
                 List<string> names = new List<string>();
                 foreach(StoreShellItem item in list.Controls)
                     if(item.IsSelected) names.Add(item.KeyName);
-                SelectedKeyNames = names.ToArray();
+                this.SelectedKeyNames = names.ToArray();
             }
         }
     }
@@ -123,17 +152,31 @@ namespace ContextMenuManager.Controls
             this.IsPublic = isPublic;
             if(isSelect)
             {
-                this.AddCtr(chkSelected, 40.DpiZoom());
                 this.ContextMenuStrip = null;
+                this.AddCtr(chkSelected);
                 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);
         }
 
         public bool IsPublic { get; set; }
-        public bool IsSelected => chkSelected.Checked;
+        public bool IsSelected
+        {
+            get => chkSelected.Checked;
+            set => chkSelected.Checked = value;
+        }
+
+        readonly CheckBox chkSelected = new CheckBox
+        {
+            Cursor = Cursors.Hand,
+            AutoSize = true
+        };
 
-        readonly CheckBox chkSelected = new CheckBox { AutoSize = true };
+        public Action SelectedChanged { get; set; }
 
         public override void DeleteMe()
         {

+ 22 - 18
ContextMenuManager/Controls/ShellSubMenuDialog.cs

@@ -89,15 +89,19 @@ namespace ContextMenuManager.Controls
                     ((PrivateMultiItemsList)LstSubItems).LoadItems(ParentPath);
                     this.Text += $"({AppString.Dialog.Private})";
                 }
-                LstSubItems.HoveredItemChanged += (sender, a) =>
+                LstSubItems.HoveredItemChanged += () =>
                 {
                     if(!AppConfig.ShowFilePath) return;
                     MyListItem item = LstSubItems.HoveredItem;
-                    if(item is ITsiFilePathItem pathItem)
+                    if(item is ITsiFilePathItem pathItem1)
                     {
-                        string path = pathItem.ItemFilePath;
+                        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;
                 };
             }
@@ -166,9 +170,9 @@ namespace ContextMenuManager.Controls
                 public PulicMultiItemsList(MyListBox owner) : base(owner)
                 {
                     this.AddItem(subNewItem);
-                    subNewItem.AddNewItem += (sender, e) => AddNewItem();
-                    subNewItem.AddExisting += (sender, e) => AddReference();
-                    subNewItem.AddSeparator += (sender, e) => AddSeparator();
+                    subNewItem.AddNewItem += () => AddNewItem();
+                    subNewItem.AddExisting += () => AddReference();
+                    subNewItem.AddSeparator += () => AddSeparator();
                 }
 
                 /// <param name="parentPath">子菜单的父菜单的注册表路径</param>
@@ -327,8 +331,8 @@ namespace ContextMenuManager.Controls
                         BtnMoveUp = new MoveButton(this, true);
                         BtnMoveUp.MouseDown += (sender, e) => Owner.MoveItem(this, true);
                         BtnMoveDown.MouseDown += (sender, e) => Owner.MoveItem(this, false);
-                        MyToolTip.SetToolTip(this, AppString.Tip.InvalidItem);
-                        MyToolTip.SetToolTip(BtnDelete, AppString.Menu.Delete);
+                        ToolTipBox.SetToolTip(this, AppString.Tip.InvalidItem);
+                        ToolTipBox.SetToolTip(BtnDelete, AppString.Menu.Delete);
                     }
 
                     public DeleteButton BtnDelete { get; set; }
@@ -349,9 +353,9 @@ namespace ContextMenuManager.Controls
                 public PrivateMultiItemsList(MyListBox owner) : base(owner)
                 {
                     this.AddItem(subNewItem);
-                    subNewItem.AddNewItem += (sender, e) => AddNewItem();
-                    subNewItem.AddSeparator += (sender, e) => AddSeparator();
-                    subNewItem.AddExisting += (sender, e) => AddFromParentMenu();
+                    subNewItem.AddNewItem += () => AddNewItem();
+                    subNewItem.AddSeparator += () => AddSeparator();
+                    subNewItem.AddExisting += () => AddFromParentMenu();
                 }
 
                 readonly SubNewItem subNewItem = new SubNewItem(false);
@@ -555,7 +559,7 @@ namespace ContextMenuManager.Controls
                     BtnDelete = new DeleteButton(this);
                     BtnMoveDown = new MoveButton(this, false);
                     BtnMoveUp = new MoveButton(this, true);
-                    MyToolTip.SetToolTip(BtnDelete, AppString.Menu.Delete);
+                    ToolTipBox.SetToolTip(BtnDelete, AppString.Menu.Delete);
                 }
 
                 public DeleteButton BtnDelete { get; set; }
@@ -598,17 +602,17 @@ namespace ContextMenuManager.Controls
                 public SubNewItem(bool isPublic)
                 {
                     this.AddCtrs(new[] { btnAddExisting, btnAddSeparator });
-                    MyToolTip.SetToolTip(btnAddExisting, isPublic ? AppString.Tip.AddReference : AppString.Tip.AddFromParentMenu);
-                    MyToolTip.SetToolTip(btnAddSeparator, AppString.Tip.AddSeparator);
-                    btnAddExisting.MouseDown += (sender, e) => AddExisting?.Invoke(null, null);
-                    btnAddSeparator.MouseDown += (sender, e) => AddSeparator?.Invoke(null, null);
+                    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);
 
-                public event EventHandler AddExisting;
-                public event EventHandler AddSeparator;
+                public Action AddExisting { get; set; }
+                public Action AddSeparator { get; set; }
             }
         }
     }

+ 1 - 1
ContextMenuManager/Controls/UwpModeItem.cs

@@ -19,7 +19,7 @@ namespace ContextMenuManager.Controls
             this.Guid = guid;
             this.UwpName = uwpName;
             this.InitializeComponents();
-            ChkVisible.Checked = ItemVisible;
+            //ChkVisible.Checked = ItemVisible;
             this.Visible = GetPackageName(uwpName) != null;
             this.Image = GuidInfo.GetImage(guid);
             this.Text = this.ItemText;

+ 0 - 1
ContextMenuManager/Controls/WinXGroupItem.cs

@@ -21,7 +21,6 @@ namespace ContextMenuManager.Controls
                 base.TargetPath = value;
                 this.Text = Path.GetFileNameWithoutExtension(value);
                 this.Image = ResourceIcon.GetFolderIcon(value).ToBitmap();
-                ChkVisible.Checked = this.ItemVisible;
             }
         }
 

+ 0 - 1
ContextMenuManager/Controls/WinXItem.cs

@@ -27,7 +27,6 @@ namespace ContextMenuManager.Controls
                 this.ShellLink = new ShellLink(value);
                 this.Text = this.ItemText;
                 this.Image = this.ItemIcon.ToBitmap();
-                ChkVisible.Checked = this.ItemVisible;
             }
         }
 

+ 2 - 2
ContextMenuManager/Controls/WinXList.cs

@@ -63,10 +63,10 @@ namespace ContextMenuManager.Controls
             NewItem newItem = new NewItem();
             this.AddItem(newItem);
             PictureButton btnCreateDir = new PictureButton(AppImage.NewFolder);
-            MyToolTip.SetToolTip(btnCreateDir, AppString.Tip.CreateGroup);
+            ToolTipBox.SetToolTip(btnCreateDir, AppString.Tip.CreateGroup);
             newItem.AddCtr(btnCreateDir);
             btnCreateDir.MouseDown += (sender, e) => CreateNewGroup();
-            newItem.AddNewItem += (sender, e) =>
+            newItem.AddNewItem += () =>
             {
                 using(NewLnkFileDialog dlg1 = new NewLnkFileDialog())
                 {

+ 9 - 7
ContextMenuManager/MainForm.cs

@@ -23,15 +23,15 @@ namespace ContextMenuManager
                 = shellNewList.Owner = sendToList.Owner = openWithList.Owner
                 = winXList.Owner = guidBlockedList.Owner = enhanceMenusList.Owner
                 = thirdRuleList.Owner = iEList.Owner = MainBody;
-            ToolBar.SelectedButtonChanged += (sender, e) => SwitchTab(ToolBar.SelectedIndex);
-            SideBar.HoverIndexChanged += (sender, e) => ShowItemInfo();
-            SideBar.SelectIndexChanged += (sender, e) => SwitchItem();
+            ToolBar.SelectedButtonChanged += () => SwitchTab(ToolBar.SelectedIndex);
+            SideBar.HoverIndexChanged += () => ShowItemInfo();
+            SideBar.SelectIndexChanged += () => SwitchItem();
             ToolBarButtons[3].MouseDown += (sender, e) => SwitchItem();
             ToolBar.AddButtons(ToolBarButtons);
             ToolBar.SelectedIndex = 0;
             if(AppConfig.ShowFilePath) ShowFilePath();
             var droper = new ElevatedFileDroper(this);
-            droper.DragDrop += (sender, e) =>
+            droper.DragDrop += () =>
             {
                 ShellList.CurrentFileObjectPath = droper.DropFilePaths[0];
                 SwitchTab(1, 9);
@@ -134,7 +134,7 @@ namespace ContextMenuManager
             AppString.SideBar.CustomRegPath,
             null,
             AppString.SideBar.GuidBlocked,
-            AppString.SideBar.IEMenu
+            AppString.SideBar.IEMenu,
         };
         static readonly string[] OtherRuleItemInfos = {
             AppString.StatusBar.EnhanceMenu,
@@ -145,7 +145,7 @@ namespace ContextMenuManager
             AppString.StatusBar.CustomRegPath,
             null,
             AppString.StatusBar.GuidBlocked,
-            AppString.StatusBar.IEMenu
+            AppString.StatusBar.IEMenu,
         };
 
         static readonly string[] AboutItems = {
@@ -244,7 +244,7 @@ namespace ContextMenuManager
         {
             foreach(MyList list in new MyList[] { shellList, shellNewList, sendToList, openWithList, winXList, guidBlockedList, iEList })
             {
-                list.HoveredItemChanged += (sender, e) =>
+                list.HoveredItemChanged += () =>
                 {
                     MyListItem item = list.HoveredItem;
                     if(item is ITsiFilePathItem pathItem)
@@ -327,6 +327,8 @@ namespace ContextMenuManager
                     guidBlockedList.LoadItems(); guidBlockedList.Visible = true; break;
                 case 8:
                     iEList.LoadItems(); iEList.Visible = true; break;
+                case 9:
+                    break;
             }
         }
 

+ 47 - 21
ContextMenuManager/Updater.cs

@@ -64,9 +64,10 @@ namespace ContextMenuManager
             {
                 if(isManual)
                 {
-                    MessageBoxEx.Show(AppString.Message.WebDataReadFailed);
+                    if(MessageBoxEx.Show(AppString.Message.WebDataReadFailed + "\r\n"
+                        + AppString.Message.OpenWebUrl, MessageBoxButtons.OKCancel) != DialogResult.OK) return;
                     url = AppConfig.RequestUseGithub ? GithubLatest : GiteeReleases;
-                    ExternalProgram.OpenUrl(url);
+                    ExternalProgram.OpenWebUrl(url);
                 }
                 return;
             }
@@ -77,7 +78,8 @@ namespace ContextMenuManager
             //appVer = new Version(0, 0, 0, 0);//测试用
             if(appVer >= webVer)
             {
-                if(isManual) MessageBoxEx.Show(AppString.Message.VersionIsLatest);
+                if(isManual) MessageBoxEx.Show(AppString.Message.VersionIsLatest,
+                    MessageBoxButtons.OK, MessageBoxIcon.Information);
             }
             else
             {
@@ -97,7 +99,7 @@ namespace ContextMenuManager
                             using(DownloadDialog dlg = new DownloadDialog())
                             {
                                 dlg.Url = urlXE?.InnerText;
-                                dlg.FilePath = Path.GetTempFileName();
+                                dlg.FilePath = $@"{AppConfig.AppDataDir}\{webVer}.exe";
                                 if(dlg.ShowDialog() == DialogResult.OK)
                                 {
                                     MessageBoxEx.Show(AppString.Message.UpdateSucceeded, MessageBoxButtons.OK, MessageBoxIcon.Information);
@@ -114,7 +116,10 @@ namespace ContextMenuManager
         /// <param name="isManual">是否为手动点击更新</param>
         private static void UpdateText(bool isManual)
         {
-            string error = null;
+            string error1 = null;
+            string error2 = null;
+            bool hasError1 = false;
+            bool hasError2 = false;
             var func = new Func<string, string, bool>(WebStringToFile);
             string dirUrl = AppConfig.RequestUseGithub ? GithubTexts : GiteeTexts;
             string[] filePaths = new[]
@@ -124,30 +129,42 @@ namespace ContextMenuManager
             };
             foreach(string filePath in filePaths)
             {
-                bool flag = func.EndInvoke(func.BeginInvoke(filePath, dirUrl, null, null));
-                if(!flag) error += Path.GetFileName(filePath) + ", ";
+                string fileUrl = $"{dirUrl}/{Path.GetFileName(filePath)}";
+                bool flag = func.EndInvoke(func.BeginInvoke(filePath, fileUrl, null, null));
+                if(!flag)
+                {
+                    hasError1 = true;
+                    error1 += "\r\n ● " + Path.GetFileName(filePath);
+                }
             }
+            if(hasError1) error1 = "\r\n\r\nDictionaries:" + error1;
+
             dirUrl = AppConfig.RequestUseGithub ? GithubLangsRawDir : GiteeLangsRawDir;
             filePaths = Directory.GetFiles(AppConfig.LangsDir, "*.ini");
             foreach(string filePath in filePaths)
             {
-                bool flag = func.EndInvoke(func.BeginInvoke(filePath, dirUrl, null, null));
-                if(!flag) error += Path.GetFileName(filePath) + ", ";
+                string fileUrl = $"{dirUrl}/{Path.GetFileName(filePath)}";
+                bool flag = func.EndInvoke(func.BeginInvoke(filePath, fileUrl, null, null));
+                if(!flag)
+                {
+                    hasError2 = true;
+                    error2 += "\r\n ● " + Path.GetFileName(filePath);
+                }
             }
-            if(isManual && error != null)
+            if(hasError2) error2 = "\r\n\r\nLanguages:" + error2;
+
+            if(isManual)
             {
-                error = error.Substring(0, error.LastIndexOf(", "));
-                MessageBoxEx.Show(error + " : " + AppString.Message.WebDataReadFailed);
+                if(hasError1 || hasError2) MessageBoxEx.Show(AppString.Message.WebDataReadFailed + error1 + error2);
+                else MessageBoxEx.Show(AppString.Message.DicUpdateSucceeded, MessageBoxButtons.OK, MessageBoxIcon.Information);
             }
         }
 
         /// <summary>将网络文本写入本地文件</summary>
         /// <param name="filePath">本地文件路径</param>
-        /// <param name="dirUrl">网络文件Raw链接的目录</param>
-        private static bool WebStringToFile(string filePath, string dirUrl)
+        /// <param name="dirUrl">网络文件Raw路径</param>
+        private static bool WebStringToFile(string filePath, string fileUrl)
         {
-            string fileName = Path.GetFileName(filePath);
-            string fileUrl = $"{dirUrl}/{fileName}";
             string contents = GetWebString(fileUrl);
             bool flag = contents != null;
             if(flag) File.WriteAllText(filePath, contents, Encoding.Unicode);
@@ -184,9 +201,17 @@ namespace ContextMenuManager
                     string fileName = $"{dlg.Selected}.ini";
                     string filePath = $@"{AppConfig.LangsDir}\{fileName}";
                     string dirUrl = AppConfig.RequestUseGithub ? GithubLangsRawDir : GiteeLangsRawDir;
-                    bool flag = WebStringToFile(filePath, dirUrl);
-                    if(!flag) MessageBoxEx.Show(fileName + ": " + AppString.Message.WebDataReadFailed);
-                    return true;
+                    string fileUrl = $"{dirUrl}/{fileName}";
+                    bool flag = WebStringToFile(filePath, fileUrl);
+                    if(!flag)
+                    {
+                        if(MessageBoxEx.Show(AppString.Message.WebDataReadFailed + "\r\n ● " + fileName + "\r\n"
+                            + AppString.Message.OpenWebUrl, MessageBoxButtons.YesNo) == DialogResult.Yes)
+                        {
+                            ExternalProgram.OpenWebUrl(fileUrl);
+                        }
+                    }
+                    return flag;
                 }
             }
             return false;
@@ -200,9 +225,10 @@ namespace ContextMenuManager
             //contents = File.ReadAllText(@"..\..\..\Donate.md");//用于求和更新Donate.md文件
             if(contents == null)
             {
-                MessageBoxEx.Show(AppString.Message.WebDataReadFailed);
+                if(MessageBoxEx.Show(AppString.Message.WebDataReadFailed + "\r\n"
+                    + AppString.Message.OpenWebUrl, MessageBoxButtons.OKCancel) != DialogResult.OK) return;
                 url = AppConfig.RequestUseGithub ? GithubDonate : GiteeDonate;
-                ExternalProgram.OpenUrl(url);
+                ExternalProgram.OpenWebUrl(url);
             }
             else
             {