@@ -27,11 +27,26 @@ namespace Flow.Launcher
27
27
{
28
28
public partial class App : IDisposable , ISingleInstanceApp
29
29
{
30
+ #region Public Properties
31
+
30
32
public static IPublicAPI API { get ; private set ; }
31
- private const string Unique = "Flow.Launcher_Unique_Application_Mutex" ;
33
+
34
+ #endregion
35
+
36
+ #region Private Fields
37
+
32
38
private static bool _disposed ;
39
+ private MainWindow _mainWindow ;
40
+ private readonly MainViewModel _mainVM ;
33
41
private readonly Settings _settings ;
34
42
43
+ // To prevent two disposals running at the same time.
44
+ private static readonly object _disposingLock = new ( ) ;
45
+
46
+ #endregion
47
+
48
+ #region Constructor
49
+
35
50
public App ( )
36
51
{
37
52
// Initialize settings
@@ -79,34 +94,44 @@ public App()
79
94
{
80
95
API = Ioc . Default . GetRequiredService < IPublicAPI > ( ) ;
81
96
_settings . Initialize ( ) ;
97
+ _mainVM = Ioc . Default . GetRequiredService < MainViewModel > ( ) ;
82
98
}
83
99
catch ( Exception e )
84
100
{
85
101
ShowErrorMsgBoxAndFailFast ( "Cannot initialize api and settings, please open new issue in Flow.Launcher" , e ) ;
86
102
return ;
87
103
}
88
- }
89
104
90
- private static void ShowErrorMsgBoxAndFailFast ( string message , Exception e )
91
- {
92
- // Firstly show users the message
93
- MessageBox . Show ( e . ToString ( ) , message , MessageBoxButton . OK , MessageBoxImage . Error ) ;
105
+ // Local function
106
+ static void ShowErrorMsgBoxAndFailFast ( string message , Exception e )
107
+ {
108
+ // Firstly show users the message
109
+ MessageBox . Show ( e . ToString ( ) , message , MessageBoxButton . OK , MessageBoxImage . Error ) ;
94
110
95
- // Flow cannot construct its App instance, so ensure Flow crashes w/ the exception info.
96
- Environment . FailFast ( message , e ) ;
111
+ // Flow cannot construct its App instance, so ensure Flow crashes w/ the exception info.
112
+ Environment . FailFast ( message , e ) ;
113
+ }
97
114
}
98
115
116
+ #endregion
117
+
118
+ #region Main
119
+
99
120
[ STAThread ]
100
121
public static void Main ( )
101
122
{
102
- if ( SingleInstance < App > . InitializeAsFirstInstance ( Unique ) )
123
+ if ( SingleInstance < App > . InitializeAsFirstInstance ( ) )
103
124
{
104
125
using var application = new App ( ) ;
105
126
application . InitializeComponent ( ) ;
106
127
application . Run ( ) ;
107
128
}
108
129
}
109
130
131
+ #endregion
132
+
133
+ #region App Events
134
+
110
135
#pragma warning disable VSTHRD100 // Avoid async void methods
111
136
112
137
private async void OnStartup ( object sender , StartupEventArgs e )
@@ -142,11 +167,11 @@ await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () =>
142
167
143
168
await imageLoadertask ;
144
169
145
- var window = new MainWindow ( ) ;
170
+ _mainWindow = new MainWindow ( ) ;
146
171
147
172
Log . Info ( $ "|App.OnStartup|Dependencies Info:{ ErrorReporting . DependenciesInfo ( ) } ") ;
148
173
149
- Current . MainWindow = window ;
174
+ Current . MainWindow = _mainWindow ;
150
175
Current . MainWindow . Title = Constant . FlowLauncher ;
151
176
152
177
HotKeyMapper . Initialize ( ) ;
@@ -163,8 +188,7 @@ await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () =>
163
188
AutoUpdates ( ) ;
164
189
165
190
API . SaveAppAllSettings ( ) ;
166
- Log . Info (
167
- "|App.OnStartup|End Flow Launcher startup ---------------------------------------------------- " ) ;
191
+ Log . Info ( "|App.OnStartup|End Flow Launcher startup ----------------------------------------------------" ) ;
168
192
} ) ;
169
193
}
170
194
@@ -197,7 +221,6 @@ private void AutoStartup()
197
221
}
198
222
}
199
223
200
- //[Conditional("RELEASE")]
201
224
private void AutoUpdates ( )
202
225
{
203
226
_ = Task . Run ( async ( ) =>
@@ -215,11 +238,29 @@ private void AutoUpdates()
215
238
} ) ;
216
239
}
217
240
241
+ #endregion
242
+
243
+ #region Register Events
244
+
218
245
private void RegisterExitEvents ( )
219
246
{
220
- AppDomain . CurrentDomain . ProcessExit += ( s , e ) => Dispose ( ) ;
221
- Current . Exit += ( s , e ) => Dispose ( ) ;
222
- Current . SessionEnding += ( s , e ) => Dispose ( ) ;
247
+ AppDomain . CurrentDomain . ProcessExit += ( s , e ) =>
248
+ {
249
+ Log . Info ( "|App.RegisterExitEvents|Process Exit" ) ;
250
+ Dispose ( ) ;
251
+ } ;
252
+
253
+ Current . Exit += ( s , e ) =>
254
+ {
255
+ Log . Info ( "|App.RegisterExitEvents|Application Exit" ) ;
256
+ Dispose ( ) ;
257
+ } ;
258
+
259
+ Current . SessionEnding += ( s , e ) =>
260
+ {
261
+ Log . Info ( "|App.RegisterExitEvents|Session Ending" ) ;
262
+ Dispose ( ) ;
263
+ } ;
223
264
}
224
265
225
266
/// <summary>
@@ -240,20 +281,60 @@ private static void RegisterAppDomainExceptions()
240
281
AppDomain . CurrentDomain . UnhandledException += ErrorReporting . UnhandledExceptionHandle ;
241
282
}
242
283
243
- public void Dispose ( )
284
+ #endregion
285
+
286
+ #region IDisposable
287
+
288
+ protected virtual void Dispose ( bool disposing )
244
289
{
245
- // if sessionending is called, exit proverbially be called when log off / shutdown
246
- // but if sessionending is not called, exit won't be called when log off / shutdown
247
- if ( ! _disposed )
290
+ // Prevent two disposes at the same time.
291
+ lock ( _disposingLock )
248
292
{
249
- API . SaveAppAllSettings ( ) ;
293
+ if ( ! disposing )
294
+ {
295
+ return ;
296
+ }
297
+
298
+ if ( _disposed )
299
+ {
300
+ return ;
301
+ }
302
+
250
303
_disposed = true ;
251
304
}
305
+
306
+ Stopwatch . Normal ( "|App.Dispose|Dispose cost" , ( ) =>
307
+ {
308
+ Log . Info ( "|App.Dispose|Begin Flow Launcher dispose ----------------------------------------------------" ) ;
309
+
310
+ if ( disposing )
311
+ {
312
+ // Dispose needs to be called on the main Windows thread,
313
+ // since some resources owned by the thread need to be disposed.
314
+ _mainWindow ? . Dispatcher . Invoke ( _mainWindow . Dispose ) ;
315
+ _mainVM ? . Dispose ( ) ;
316
+ }
317
+
318
+ Log . Info ( "|App.Dispose|End Flow Launcher dispose ----------------------------------------------------" ) ;
319
+ } ) ;
252
320
}
253
321
322
+ public void Dispose ( )
323
+ {
324
+ // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
325
+ Dispose ( disposing : true ) ;
326
+ GC . SuppressFinalize ( this ) ;
327
+ }
328
+
329
+ #endregion
330
+
331
+ #region ISingleInstanceApp
332
+
254
333
public void OnSecondAppStarted ( )
255
334
{
256
335
Ioc . Default . GetRequiredService < MainViewModel > ( ) . Show ( ) ;
257
336
}
337
+
338
+ #endregion
258
339
}
259
340
}
0 commit comments