2023-05-02 02:24:33 +12:00
|
|
|
|
// <copyright file="SingleAppInstance.cs" company="PlaceholderCompany">
|
|
|
|
|
// Copyright (c) PlaceholderCompany. All rights reserved.
|
|
|
|
|
// </copyright>
|
|
|
|
|
|
|
|
|
|
namespace SystemTrayMenu.Utilities
|
|
|
|
|
{
|
|
|
|
|
using System;
|
|
|
|
|
using System.Diagnostics;
|
2022-10-23 11:02:31 +13:00
|
|
|
|
using System.Linq;
|
2023-06-04 06:18:10 +12:00
|
|
|
|
using SystemTrayMenu.Business;
|
2023-05-02 02:24:33 +12:00
|
|
|
|
|
|
|
|
|
internal static class SingleAppInstance
|
|
|
|
|
{
|
2023-06-04 06:18:10 +12:00
|
|
|
|
private const string IpcServiceName = nameof(SingleAppInstance);
|
|
|
|
|
private const string IpcWakeupCmd = "wakeup";
|
|
|
|
|
private const string IpcWakeupResponseOK = "OK";
|
|
|
|
|
private static IpcPipe? ipcPipe;
|
|
|
|
|
|
|
|
|
|
internal static event Action? Wakeup;
|
|
|
|
|
|
2023-05-02 02:24:33 +12:00
|
|
|
|
internal static bool Initialize()
|
|
|
|
|
{
|
|
|
|
|
bool success = true;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2023-06-04 06:18:10 +12:00
|
|
|
|
foreach (Process p in
|
|
|
|
|
Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).
|
2023-05-02 02:24:33 +12:00
|
|
|
|
Where(s => s.Id != Environment.ProcessId))
|
|
|
|
|
{
|
2023-06-04 06:18:10 +12:00
|
|
|
|
try
|
2022-10-23 11:02:31 +13:00
|
|
|
|
{
|
2023-06-04 06:18:10 +12:00
|
|
|
|
if (Properties.Settings.Default.SendHotkeyInsteadKillOtherInstances)
|
2023-05-02 02:24:33 +12:00
|
|
|
|
{
|
2023-06-04 06:18:10 +12:00
|
|
|
|
// Instead of using hotkeys we use IPC via pipes
|
|
|
|
|
string pipeName = IpcServiceName + "-" + p.Id.ToString();
|
|
|
|
|
ipcPipe = new(1, pipeName);
|
|
|
|
|
string response = ipcPipe.SendToServer(IpcWakeupCmd) ?? string.Empty;
|
|
|
|
|
if (!string.Equals(response, IpcWakeupResponseOK))
|
2023-05-02 02:24:33 +12:00
|
|
|
|
{
|
2023-06-04 06:18:10 +12:00
|
|
|
|
throw new Exception("Error at IPC pipe \"" + pipeName + "\": \"" + response + "\"");
|
2023-05-02 02:24:33 +12:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-04 06:18:10 +12:00
|
|
|
|
ipcPipe.Dispose();
|
|
|
|
|
ipcPipe = null;
|
|
|
|
|
success = false; // This is "success" but it means we cannot start this instance -> false
|
2023-05-02 02:24:33 +12:00
|
|
|
|
}
|
2023-06-04 06:18:10 +12:00
|
|
|
|
else
|
2023-05-02 02:24:33 +12:00
|
|
|
|
{
|
|
|
|
|
if (!p.CloseMainWindow())
|
|
|
|
|
{
|
|
|
|
|
p.Kill();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.WaitForExit();
|
|
|
|
|
p.Close();
|
|
|
|
|
}
|
2023-06-04 06:18:10 +12:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Log.Error("Run as single instance failed", ex);
|
|
|
|
|
success = false;
|
2023-05-02 02:24:33 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Log.Error("Run as single instance failed", ex);
|
2023-06-04 06:18:10 +12:00
|
|
|
|
success = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (success)
|
|
|
|
|
{
|
|
|
|
|
// We are the only process running, so we are responsible for the IPC server
|
|
|
|
|
ipcPipe = new(1, IpcServiceName + "-" + Environment.ProcessId.ToString());
|
|
|
|
|
ipcPipe.StartServer((request) =>
|
|
|
|
|
{
|
|
|
|
|
if (string.Equals(request, IpcWakeupCmd))
|
|
|
|
|
{
|
|
|
|
|
Wakeup?.Invoke();
|
|
|
|
|
return IpcWakeupResponseOK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return string.Empty;
|
|
|
|
|
});
|
2023-05-02 02:24:33 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return success;
|
|
|
|
|
}
|
2023-06-04 06:18:10 +12:00
|
|
|
|
|
|
|
|
|
internal static void Unload()
|
|
|
|
|
{
|
|
|
|
|
ipcPipe?.Dispose();
|
|
|
|
|
}
|
2023-05-02 02:24:33 +12:00
|
|
|
|
}
|
|
|
|
|
}
|