11using System ;
22using System . IO ;
33using System . Runtime . Versioning ;
4+ using System . Threading ;
45
56using Avalonia ;
67using Avalonia . ReactiveUI ;
1314namespace TwitchStreamingTools ;
1415
1516internal 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.
0 commit comments