From ace23b954e9071dbd0e7dd9d978a66384c6a64de Mon Sep 17 00:00:00 2001 From: kislovdm Date: Mon, 27 Apr 2026 01:46:52 +0300 Subject: [PATCH] auth --- .semver.txt | 2 +- src/MonsterMonitor/MonsterMonitor.csproj | 8 ++--- src/MonsterMonitor/Program.cs | 46 +++++++++++++++++++++++- src/MonsterMonitor/UI/MainForm.cs | 27 ++++++++++++++ 4 files changed, 77 insertions(+), 6 deletions(-) diff --git a/.semver.txt b/.semver.txt index c2320f5..b112f91 100644 --- a/.semver.txt +++ b/.semver.txt @@ -1 +1 @@ -1.0.20 +1.0.21 diff --git a/src/MonsterMonitor/MonsterMonitor.csproj b/src/MonsterMonitor/MonsterMonitor.csproj index 950745e..14abc3d 100644 --- a/src/MonsterMonitor/MonsterMonitor.csproj +++ b/src/MonsterMonitor/MonsterMonitor.csproj @@ -6,10 +6,10 @@ 7.3 MonsterMonitor devenv - 1.0.20 - 1.0.20 - 1.0.20 - 1.0.20 + 1.0.21 + 1.0.21 + 1.0.21 + 1.0.21 diff --git a/src/MonsterMonitor/Program.cs b/src/MonsterMonitor/Program.cs index b126fbe..183628d 100644 --- a/src/MonsterMonitor/Program.cs +++ b/src/MonsterMonitor/Program.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Windows.Forms; using MonsterMonitor.UI; @@ -6,9 +7,21 @@ namespace MonsterMonitor { internal static class Program { + private const string SingleInstanceMutexName = @"Global\MonsterMonitor_v2_SingleInstance"; + private const string ActivateEventName = @"Global\MonsterMonitor_v2_Activate"; + [STAThread] private static void Main() { + var createdNew = false; + using (var mutex = new Mutex(true, SingleInstanceMutexName, out createdNew)) + { + if (!createdNew) + { + TrySignalExistingInstance(); + return; + } + Application.ThreadException += (sender, args) => { MessageBox.Show( @@ -29,7 +42,38 @@ namespace MonsterMonitor Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new MainForm()); + using (var activateEvent = new EventWaitHandle(false, EventResetMode.AutoReset, ActivateEventName)) + { + var form = new MainForm(); + ThreadPool.RegisterWaitForSingleObject( + activateEvent, + (state, timedOut) => + { + var mainForm = state as MainForm; + mainForm?.RestoreAndActivateFromExternalSignal(); + }, + form, + Timeout.Infinite, + false); + + Application.Run(form); + } + } + } + + private static void TrySignalExistingInstance() + { + try + { + using (var activateEvent = EventWaitHandle.OpenExisting(ActivateEventName)) + { + activateEvent.Set(); + } + } + catch + { + // Если не удалось отправить сигнал, просто завершаем второй инстанс. + } } } } diff --git a/src/MonsterMonitor/UI/MainForm.cs b/src/MonsterMonitor/UI/MainForm.cs index a88b6c3..081f158 100644 --- a/src/MonsterMonitor/UI/MainForm.cs +++ b/src/MonsterMonitor/UI/MainForm.cs @@ -135,6 +135,33 @@ namespace MonsterMonitor.UI Activate(); } + public void RestoreAndActivateFromExternalSignal() + { + if (InvokeRequired) + { + BeginInvoke(new Action(RestoreAndActivateFromExternalSignal)); + return; + } + + _log.Info("Получен сигнал активации от второго инстанса."); + + if (!Visible) + { + Show(); + } + + if (WindowState == FormWindowState.Minimized) + { + WindowState = FormWindowState.Normal; + } + + // Небольшой трюк для надежного вывода окна на передний план. + TopMost = true; + Activate(); + TopMost = false; + Focus(); + } + private void ExitApplication() { _allowClose = true;