Skip to content

Commit d4828e1

Browse files
Merge pull request #110 from nullinside-development-group/stuff
feat: single instance of application
2 parents 70a2d0a + 40aa11d commit d4828e1

File tree

2 files changed

+34
-9
lines changed

2 files changed

+34
-9
lines changed

src/TwitchStreamingTools/Program.cs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.IO;
33
using System.Runtime.Versioning;
4+
using System.Threading;
45

56
using Avalonia;
67
using Avalonia.ReactiveUI;
@@ -13,14 +14,24 @@
1314
namespace TwitchStreamingTools;
1415

1516
internal sealed class Program {
17+
// Initialization code. Don't use any Avalonia, third-party APIs or any
18+
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
19+
// yet and stuff might break.
20+
21+
/// <summary>
22+
/// The name used to ensure only a single instance of the application is running.
23+
/// </summary>
24+
private const string MutexName = "TwitchStreamingTools_SingleInstance";
25+
1626
/// <summary>
1727
/// The logger.
1828
/// </summary>
1929
private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
2030

21-
// Initialization code. Don't use any Avalonia, third-party APIs or any
22-
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
23-
// yet and stuff might break.
31+
/// <summary>
32+
/// Used to prevent multiple instances of the application from running.
33+
/// </summary>
34+
private static Mutex? _mutex;
2435

2536
/// <summary>
2637
/// Main entrypoint of the application.
@@ -31,7 +42,7 @@ public static void Main(string[] args) {
3142
#if DEBUG
3243
XmlConfigurator.Configure(new FileInfo("log4net.debug.config"));
3344
#else
34-
XmlConfigurator.Configure(new FileInfo("log4net.config"));
45+
XmlConfigurator.Configure(new FileInfo("log4net.config"));
3546
#endif
3647

3748
Log.Info("Started application");
@@ -40,11 +51,24 @@ public static void Main(string[] args) {
4051
Log.Fatal("Unhandled exception", exceptArgs.ExceptionObject as Exception);
4152
};
4253

43-
BuildAvaloniaApp()
44-
.StartWithClassicDesktopLifetime(args);
45-
}
54+
// We only allow a single instance of the application to be launched at once (due to having only a single config
55+
// file)
56+
_mutex = new Mutex(true, MutexName, out bool onlyAppInstance);
57+
if (!onlyAppInstance) {
58+
Log.Info("Application instance already running. Exiting.");
59+
return;
60+
}
4661

47-
// Avalonia configuration, don't remove; also used by visual designer.
62+
try {
63+
BuildAvaloniaApp()
64+
.StartWithClassicDesktopLifetime(args);
65+
}
66+
finally {
67+
// Release the mutex when the application exits
68+
_mutex.ReleaseMutex();
69+
_mutex.Dispose();
70+
}
71+
}
4872

4973
/// <summary>
5074
/// Builds the avalonia application.
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
<wpf:ResourceDictionary xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib"
1+
<wpf:ResourceDictionary xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
2+
xmlns:s="clr-namespace:System;assembly=mscorlib"
23
xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
34
xml:space="preserve">
45
<s:String x:Key="/Default/CodeInspection/Daemon/ConfigureAwaitAnalysisMode/@EntryValue">Library</s:String></wpf:ResourceDictionary>

0 commit comments

Comments
 (0)