1+ using Microsoft . Extensions . Logging ;
2+ using System . IO . Pipes ;
3+
14namespace FileSyncAppWin
25{
36 internal static class Program
47 {
8+
9+ private static Mutex mutex = new Mutex ( true , "PraewemaFileSyncAppWin" ) ;
10+ private static volatile bool autoRestart = true ;
11+ private static ILogger logger ;
12+ private static Form mainForm ;
13+ private const string PipeName = "PraewemaFileSyncAppWinPipe" ;
14+
515 /// <summary>
616 /// The main entry point for the application.
717 /// </summary>
818 [ STAThread ]
9- static void Main ( )
19+ static void Main ( string [ ] args )
1020 {
11- // To customize application configuration such as set high DPI settings or default font,
12- // see https://aka.ms/applicationconfiguration.
13- ApplicationConfiguration . Initialize ( ) ;
14- Application . Run ( new MainForm ( ) ) ;
21+ FileSyncApp . Program . ConfigureLogger ( ) ;
22+ logger = FileSyncApp . Program . LoggerFactory . CreateLogger ( "FileSyncAppWin" ) ;
23+ if ( args . Contains ( "noautorestart" ) )
24+ {
25+ logger ? . LogInformation ( "startup argument noautorestart given, settings autoRestart to false" ) ;
26+ autoRestart = false ;
27+ }
28+ if ( args . Contains ( "restart" ) )
29+ {
30+ logger ? . LogInformation ( "startup argument restart given, sending exit signal to running instance" ) ;
31+ SendExitSignalToFirstInstance ( ) ;
32+ }
33+ logger ? . LogInformation ( "try to get mutex" ) ;
34+ // Try to acquire the mutex
35+ if ( ! mutex . WaitOne ( TimeSpan . FromSeconds ( 15 ) ) )
36+ {
37+ // Mutex was not acquired, meaning another instance is running
38+
39+ Console . WriteLine ( "FileSyncAppWin another instance is running, exiting." ) ;
40+ logger ? . LogInformation ( "FileSyncAppWin another instance is running, exiting." ) ;
41+ return ; // Exit the second instance
42+ }
43+
44+ try
45+ {
46+ var pipeServer = new NamedPipeServerStream ( PipeName , PipeDirection . InOut ) ;
47+ // Start listening for incoming connections
48+ pipeServer . BeginWaitForConnection ( PipeConnectedCallback , pipeServer ) ;
49+
50+ logger ? . LogInformation ( "FileSyncAppWin Main program starting..." ) ;
51+ Application . ThreadException += Application_ThreadException ;
52+ Application . SetUnhandledExceptionMode ( UnhandledExceptionMode . CatchException ) ;
53+ AppDomain . CurrentDomain . UnhandledException += CurrentDomain_UnhandledException ;
54+ ApplicationConfiguration . Initialize ( ) ;
55+ mainForm = new MainForm ( ) ;
56+ Application . Run ( mainForm ) ;
57+ }
58+ catch ( Exception exception )
59+ {
60+ logger ? . LogError ( exception , "FileSyncAppWin exception in main logic" ) ;
61+ }
62+ finally
63+ {
64+ logger ? . LogInformation ( "FileSyncAppWin releasing mutex" ) ;
65+ mutex . ReleaseMutex ( ) ;
66+ }
67+
68+ }
69+
70+ private static void CurrentDomain_UnhandledException ( object sender , UnhandledExceptionEventArgs e )
71+ {
72+ try
73+ {
74+ logger ? . LogCritical ( ( Exception ) e . ExceptionObject , "CurrentDomain_UnhandledException isTerminating {A}" , e . IsTerminating ) ;
75+ }
76+ catch ( Exception castException )
77+ {
78+ logger ? . LogCritical ( castException , "CurrentDomain_UnhandledException, Exception object {@A}" , e . ExceptionObject ) ;
79+ }
80+ //if (e.IsTerminating)
81+ {
82+ RestartApplication ( ) ;
83+ }
84+
85+ }
86+
87+ private static void Application_ThreadException ( object sender , ThreadExceptionEventArgs e )
88+ {
89+ logger ? . LogCritical ( e . Exception , "Application_ThreadException" ) ;
90+ RestartApplication ( ) ;
91+ }
92+
93+ private static void PipeConnectedCallback ( IAsyncResult result )
94+ {
95+ var pipeServer = ( NamedPipeServerStream ) result . AsyncState ;
96+
97+ try
98+ {
99+ // End waiting for the connection
100+ pipeServer . EndWaitForConnection ( result ) ;
101+
102+ // Read the message from the pipe
103+ using ( var reader = new StreamReader ( pipeServer ) )
104+ {
105+ string message = reader . ReadLine ( ) ;
106+ if ( message == "Exit" )
107+ {
108+ logger ? . LogInformation ( "Received exit signal from second instance. Exiting gracefully." ) ;
109+ mainForm . Close ( ) ;
110+ //Environment.Exit(0); // Gracefully exit the application
111+ }
112+ }
113+
114+ // Close the pipe
115+ pipeServer . Close ( ) ;
116+ }
117+ catch ( Exception ex )
118+ {
119+ logger ? . LogError ( ex , "Error handling named pipe connection." ) ;
120+ }
121+ }
122+
123+ private static void SendExitSignalToFirstInstance ( )
124+ {
125+ try
126+ {
127+ using ( var pipeClient = new NamedPipeClientStream ( "." , PipeName , PipeDirection . Out ) )
128+ {
129+ pipeClient . Connect ( 500 ) ; // Connect with a timeout
130+
131+ // Send an exit signal
132+ using ( var writer = new StreamWriter ( pipeClient ) )
133+ {
134+ writer . WriteLine ( "Exit" ) ;
135+ }
136+ }
137+ }
138+ catch ( Exception ex )
139+ {
140+ logger ? . LogError ( ex , "Error sending exit signal to first instance." ) ;
141+ }
142+ }
143+
144+
145+ private static void RestartApplication ( )
146+ {
147+ if ( autoRestart )
148+ {
149+ // Get the path of the current application
150+ string assemblyPath = System . Diagnostics . Process . GetCurrentProcess ( ) . MainModule . FileName ;
151+ // Restart the application using the path
152+ logger ? . LogInformation ( "RestartApplication, starting new process {A}" , assemblyPath ) ;
153+ System . Diagnostics . Process . Start ( assemblyPath ) ;
154+
155+ // Exit the current instance of the application
156+ Environment . Exit ( 0 ) ;
157+ }
158+ else
159+ {
160+ logger ? . LogInformation ( "RestartApplication, skip starting new process -> autoRestart=false" ) ;
161+ }
15162 }
16163 }
17164}
0 commit comments