diff --git a/Netch/Controllers/MainController.cs b/Netch/Controllers/MainController.cs index 783194b9..b049f24c 100644 --- a/Netch/Controllers/MainController.cs +++ b/Netch/Controllers/MainController.cs @@ -32,7 +32,7 @@ namespace Netch.Controllers { using var releaser = await Lock.EnterAsync(); - Log.Information("Start MainController: {Server} {Mode}", $"{server.Type}", $"[{(int)mode.Type}]{mode.Remark}"); + Log.Information("Start MainController: {Server} {Mode}", $"{server.Type}", $"[{(int)mode.Type}]{mode.i18NRemark}"); if (await DnsUtils.LookupAsync(server.Hostname) == null) throw new MessageException(i18N.Translate("Lookup Server hostname failed")); diff --git a/Netch/Forms/LogForm.cs b/Netch/Forms/LogForm.cs index 7726c82e..77c67253 100644 --- a/Netch/Forms/LogForm.cs +++ b/Netch/Forms/LogForm.cs @@ -66,13 +66,20 @@ namespace Netch.Forms _parent.LocationChanged += Parent_Move; _parent.SizeChanged += Parent_Move; _parent.Activated += Parent_Activated; + _parent.VisibleChanged += Parent_VisibleChanged; + } + + private void Parent_VisibleChanged(object? sender, EventArgs e) + { + Visible = _parent.Visible; } protected override void OnClosing(CancelEventArgs? e) { - _parent.Activated -= Parent_Activated; _parent.LocationChanged -= Parent_Move; _parent.SizeChanged -= Parent_Move; + _parent.Activated -= Parent_Activated; + _parent.VisibleChanged -= Parent_VisibleChanged; base.OnClosing(e!); } } diff --git a/Netch/Forms/MainForm.cs b/Netch/Forms/MainForm.cs index dc89a4d9..69c3eb55 100644 --- a/Netch/Forms/MainForm.cs +++ b/Netch/Forms/MainForm.cs @@ -884,83 +884,54 @@ namespace Netch.Forms } } - private void ActiveProfile(Profile profile) - { - ProfileNameText.Text = profile.ProfileName; - - var server = ServerComboBox.Items.Cast().FirstOrDefault(s => s.Remark.Equals(profile.ServerRemark)); - var mode = ModeComboBox.Items.Cast().FirstOrDefault(m => m.Remark.Equals(profile.ModeRemark)); - - if (server == null) - throw new Exception("Server not found."); - - if (mode == null) - throw new Exception("Mode not found."); - - ServerComboBox.SelectedItem = server; - ModeComboBox.SelectedItem = mode; - } - - private Profile CreateProfileAtIndex(int index) - { - var server = (Server)ServerComboBox.SelectedItem; - var mode = (Mode)ModeComboBox.SelectedItem; - var name = ProfileNameText.Text; - - Profile? profile; - if ((profile = Global.Settings.Profiles.SingleOrDefault(p => p.Index == index)) != null) - Global.Settings.Profiles.Remove(profile); - - profile = new Profile(server, mode, name, index); - Global.Settings.Profiles.Add(profile); - return profile; - } - private async void ProfileButton_Click([NotNull] object? sender, EventArgs? e) { if (sender == null) - throw new ArgumentNullException(nameof(sender)); + throw new InvalidOperationException(); - var profileButton = (Button)sender; - var profile = (Profile?)profileButton.Tag; - var index = ProfileTable.Controls.IndexOf(profileButton); + var button = (Button)sender; + var profile = (Profile?)button.Tag; + var index = ProfileTable.Controls.IndexOf(button); switch (ModifierKeys) { case Keys.Control: - if (ServerComboBox.SelectedIndex == -1) + // Save Profile + if (ServerComboBox.SelectedItem is not Server server) { MessageBoxX.Show(i18N.Translate("Please select a server first")); return; } - if (ModeComboBox.SelectedIndex == -1) + if (ModeComboBox.SelectedItem is not Mode mode) { MessageBoxX.Show(i18N.Translate("Please select a mode first")); return; } - if (ProfileNameText.Text == "") - { - MessageBoxX.Show(i18N.Translate("Please enter a profile name first")); - ProfileNameText.Focus(); - return; - } + var name = ProfileNameText.Text; + + Global.Settings.Profiles.RemoveAll(p => p.Index == index); + profile = new Profile(server, mode, name, index); + Global.Settings.Profiles.Add(profile); + button.Tag = profile; + button.Text = profile.ProfileName; - profileButton.Tag = profile = CreateProfileAtIndex(index); - profileButton.Text = profile.ProfileName; ProfileNameText.Clear(); return; case Keys.Shift: + // Delete Profile if (profile == null) return; Global.Settings.Profiles.Remove(profile); - profileButton.Tag = null; - profileButton.Text = i18N.Translate("None"); + button.Tag = null; + button.Text = i18N.Translate("None"); return; } + // Activate Profile + if (profile == null) { MessageBoxX.Show(i18N.Translate("No saved profile here. Save a profile first by Ctrl+Click on the button")); @@ -969,23 +940,29 @@ namespace Netch.Forms try { - ActiveProfile(profile); + ProfileNameText.Text = profile.ProfileName; + + var server = ServerComboBox.Items.Cast().FirstOrDefault(s => s.Remark.Equals(profile.ServerRemark)); + var mode = ModeComboBox.Items.Cast().FirstOrDefault(m => m.Remark.Any(s => s.Value.Equals(profile.ModeRemark))); + + if (server == null) + throw new MessageException("Server not found."); + + if (mode == null) + throw new MessageException("Mode not found."); + + // set active server and mode + ServerComboBox.SelectedItem = server; + ModeComboBox.SelectedItem = mode; } - catch (Exception exception) + catch (MessageException exception) { MessageBoxX.Show(exception.Message, LogLevel.ERROR); return; } - // start the profile - ControlButton_Click(null, null); - if (State == State.Stopping || State == State.Stopped) - { - while (State != State.Stopped) - await Task.Delay(250); - - ControlButton_Click(null, null); - } + await StopAsync(); + ControlButton.PerformClick(); } #endregion @@ -1259,7 +1236,7 @@ namespace Netch.Forms private bool _resumeFlag; - private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e) + private async void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e) { switch (e.Mode) { @@ -1268,7 +1245,7 @@ namespace Netch.Forms { _resumeFlag = true; Log.Information("OS Suspend, Stop"); - ControlButton_Click(null, null); + await StopAsync(); } break; @@ -1277,7 +1254,7 @@ namespace Netch.Forms { _resumeFlag = false; Log.Information("OS Resume, Restart"); - ControlButton_Click(null, null); + ControlButton.PerformClick(); } break; @@ -1307,7 +1284,7 @@ namespace Netch.Forms { MessageBoxX.Show(i18N.Translate("Please press Stop button first")); - NotifyIcon_MouseDoubleClick(null, null); + ShowMainFormToolStripButton.PerformClick(); return; } @@ -1417,26 +1394,9 @@ namespace Netch.Forms #region NotifyIcon - public void ShowMainFormToolStripButton_Click(object sender, EventArgs e) + private void ShowMainFormToolStripButton_Click(object sender, EventArgs e) { - if (InvokeRequired) - { - Invoke(new Action(() => ShowMainFormToolStripButton_Click(sender, e))); - return; - } - - var forms = Application.OpenForms.Cast
().ToList(); - var anyWindowOpened = forms.Any(f => f is not (MainForm or LogForm)); - - forms.ForEach(f => - { - if (anyWindowOpened && f is MainForm or LogForm) - return; - - f.Show(); - f.WindowState = FormWindowState.Normal; - f.Activate(); - }); + Utils.Utils.ActivateVisibleWindows(); } /// diff --git a/Netch/Program.cs b/Netch/Program.cs index 97d5d49c..19cdf8db 100644 --- a/Netch/Program.cs +++ b/Netch/Program.cs @@ -27,24 +27,29 @@ namespace Netch { public static class Program { - public static readonly SingleInstanceService SingleInstance = new($"Global\\{nameof(Program)}"); + public static readonly SingleInstanceService SingleInstance = new($"Global\\{nameof(Netch)}"); internal static HWND ConsoleHwnd { get; private set; } - /// - /// 应用程序的主入口点 - /// +#pragma warning disable VSTHRD002 + // VSTHRD002: Avoid problematic synchronous waits + // Main never re-called, so we can ignore this + [STAThread] public static void Main(string[] args) { + // handle arguments if (args.Contains(Constants.Parameter.ForceUpdate)) Flags.AlwaysShowNewVersionFound = true; - // 设置当前目录 + // set working directory Directory.SetCurrentDirectory(Global.NetchDir); + + // append .\bin to PATH var binPath = Path.Combine(Global.NetchDir, "bin"); Environment.SetEnvironmentVariable("PATH", $"{Environment.GetEnvironmentVariable("PATH")};{binPath}"); + // check if .\bin directory exists if (!Directory.Exists("bin") || !Directory.EnumerateFileSystemEntries("bin").Any()) { i18N.Load("System"); @@ -52,19 +57,19 @@ namespace Netch Environment.Exit(2); } + // clean up old files Updater.CleanOld(Global.NetchDir); - // 预创建目录 + // pre-create directories var directories = new[] { "mode\\Custom", "data", "i18n", "logging" }; foreach (var item in directories) if (!Directory.Exists(item)) Directory.CreateDirectory(item); - // 加载配置 -#pragma warning disable VSTHRD002 + // load configuration Configuration.LoadAsync().Wait(); -#pragma warning restore VSTHRD002 + // check if the program is already running if (!SingleInstance.IsFirstInstance) { SingleInstance.PassArgumentsToFirstInstance(args.Append(Constants.Parameter.Show)); @@ -74,7 +79,7 @@ namespace Netch SingleInstance.ArgumentsReceived.Subscribe(SingleInstance_ArgumentsReceived); - // 清理上一次的日志文件,防止淤积占用磁盘空间 + // clean up old logs if (Directory.Exists("logging")) { var directory = new DirectoryInfo("logging"); @@ -90,14 +95,15 @@ namespace Netch CreateLogger(); - // 加载语言 + // load i18n i18N.Load(Global.Settings.Language); + // log environment information Task.Run(LogEnvironment).Forget(); CheckClr(); CheckOS(); - // 绑定错误捕获 + // handle exceptions Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); Application.ThreadException += Application_OnException; Application.ApplicationExit += Application_OnExit; @@ -108,6 +114,8 @@ namespace Netch Application.Run(Global.MainForm); } +#pragma warning restore VSTHRD002 + private static void LogEnvironment() { Log.Information("Netch Version: {Version}", $"{UpdateChecker.Owner}/{UpdateChecker.Repo}@{UpdateChecker.Version}"); @@ -167,6 +175,7 @@ namespace Netch ConsoleHwnd = PInvoke.GetConsoleWindow(); #if RELEASE + // hide console window PInvoke.ShowWindow(ConsoleHwnd, SHOW_WINDOW_CMD.SW_HIDE); #endif } @@ -202,7 +211,7 @@ namespace Netch { if (args.Contains(Constants.Parameter.Show)) { - Global.MainForm.ShowMainFormToolStripButton_Click(null!, null!); + Utils.Utils.ActivateVisibleWindows(); } } } diff --git a/Netch/Utils/Utils.cs b/Netch/Utils/Utils.cs index 64a149dd..1f74ffa4 100644 --- a/Netch/Utils/Utils.cs +++ b/Netch/Utils/Utils.cs @@ -255,5 +255,17 @@ namespace Netch.Utils var endIndex = str.IndexOf(':'); return endIndex == -1 ? str : str[..endIndex]; } + + public static void ActivateVisibleWindows() + { + foreach (var f in Application.OpenForms.Cast()) + { + if (!f.Visible) + continue; + + f.WindowState = FormWindowState.Normal; + f.Activate(); + } + } } } \ No newline at end of file