@@ -19,13 +19,14 @@ namespace NETworkManager;
1919 * Class: App
2020 * 1) Get command line args
2121 * 2) Detect current configuration
22- * 3) Get assembly info
23- * 4) Load settings
24- * 5) Load localization / language
22+ * 3) Get assembly info
23+ * 4) Load system-wide policies
24+ * 5) Load settings
25+ * 6) Load localization / language
2526 *
2627 * Class: MainWindow
27- * 6 ) Load appearance
28- * 7 ) Load profiles
28+ * 7 ) Load appearance
29+ * 8 ) Load profiles
2930 */
3031
3132public partial class App
@@ -81,14 +82,14 @@ by BornToBeRoot
8182 Log . Info ( $ "NETworkManager process with Pid { CommandLineManager . Current . RestartPid } has been exited.") ;
8283 }
8384
85+ // Load system-wide policies
86+ PolicyManager . Load ( ) ;
87+
8488 // Load (or initialize) settings
8589 try
8690 {
8791 Log . Info ( "Application settings are being loaded..." ) ;
8892
89- // Load system-wide policies first (from app directory)
90- PolicyManager . Load ( ) ;
91-
9293 if ( CommandLineManager . Current . ResetSettings )
9394 SettingsManager . Initialize ( ) ;
9495 else
@@ -131,7 +132,7 @@ by BornToBeRoot
131132 Log . Info (
132133 $ "Application localization culture has been set to { localizationManager . Current . Code } (Settings value is \" { SettingsManager . Current . Localization_CultureCode } \" ).") ;
133134
134- // Show (localized) help window
135+ // Show help window
135136 if ( CommandLineManager . Current . Help )
136137 {
137138 Log . Info ( "Set StartupUri to CommandLineWindow.xaml..." ) ;
@@ -152,70 +153,72 @@ by BornToBeRoot
152153 if ( mutexIsAcquired )
153154 _mutex . ReleaseMutex ( ) ;
154155
155- if ( mutexIsAcquired || SettingsManager . Current . Window_MultipleInstances )
156+ // If another instance is running, bring it to the foreground
157+ if ( ! mutexIsAcquired && ! SettingsManager . Current . Window_MultipleInstances )
156158 {
157- // Setup background job
158- if ( SettingsManager . Current . General_BackgroundJobInterval != 0 )
159- {
160- Log . Info (
161- $ "Setup background job with interval { SettingsManager . Current . General_BackgroundJobInterval } minute(s)...") ;
162-
163- _dispatcherTimer = new DispatcherTimer
164- {
165- Interval = TimeSpan . FromMinutes ( SettingsManager . Current . General_BackgroundJobInterval )
166- } ;
167- _dispatcherTimer . Tick += DispatcherTimer_Tick ;
168- _dispatcherTimer . Start ( ) ;
169- }
170- else
171- {
172- Log . Info ( "Background job is disabled." ) ;
173- }
174-
175- // Setup ThreadPool for the application
176- ThreadPool . GetMaxThreads ( out var workerThreadsMax , out var completionPortThreadsMax ) ;
177- ThreadPool . GetMinThreads ( out var workerThreadsMin , out var completionPortThreadsMin ) ;
159+ // Bring the already running application into the foreground
160+ Log . Info (
161+ "Another NETworkManager process is already running. Trying to bring the window to the foreground..." ) ;
162+ SingleInstance . PostMessage ( SingleInstance . HWND_BROADCAST , SingleInstance . WM_SHOWME , IntPtr . Zero ,
163+ IntPtr . Zero ) ;
178164
179- var workerThreadsMinNew = workerThreadsMin + SettingsManager . Current . General_ThreadPoolAdditionalMinThreads ;
180- var completionPortThreadsMinNew = completionPortThreadsMin +
181- SettingsManager . Current . General_ThreadPoolAdditionalMinThreads ;
165+ // Close the application
166+ _singleInstanceClose = true ;
167+ Shutdown ( ) ;
182168
183- if ( workerThreadsMinNew > workerThreadsMax )
184- workerThreadsMinNew = workerThreadsMax ;
169+ return ;
170+ }
185171
186- if ( completionPortThreadsMinNew > completionPortThreadsMax )
187- completionPortThreadsMinNew = completionPortThreadsMax ;
188172
189- if ( ThreadPool . SetMinThreads ( workerThreadsMinNew , completionPortThreadsMinNew ) )
190- Log . Info (
191- $ "ThreadPool min threads set to: workerThreads: { workerThreadsMinNew } , completionPortThreads: { completionPortThreadsMinNew } ") ;
192- else
193- Log . Warn (
194- $ "ThreadPool min threads could not be set to workerThreads: { workerThreadsMinNew } , completionPortThreads: { completionPortThreadsMinNew } ") ;
173+ // Setup background job
174+ if ( SettingsManager . Current . General_BackgroundJobInterval != 0 )
175+ {
176+ Log . Info (
177+ $ "Setup background job with interval { SettingsManager . Current . General_BackgroundJobInterval } minute(s)...") ;
195178
196- // Show splash screen
197- if ( SettingsManager . Current . SplashScreen_Enabled )
179+ _dispatcherTimer = new DispatcherTimer
198180 {
199- Log . Info ( "Show SplashScreen while application is loading..." ) ;
200- new SplashScreen ( @"SplashScreen.png" ) . Show ( true , true ) ;
201- }
202-
203- // Show main window
204- Log . Info ( "Set StartupUri to MainWindow.xaml..." ) ;
205- StartupUri = new Uri ( "MainWindow.xaml" , UriKind . Relative ) ;
181+ Interval = TimeSpan . FromMinutes ( SettingsManager . Current . General_BackgroundJobInterval )
182+ } ;
183+ _dispatcherTimer . Tick += DispatcherTimer_Tick ;
184+ _dispatcherTimer . Start ( ) ;
206185 }
207186 else
208187 {
209- // Bring the already running application into the foreground
188+ Log . Info ( "Background job is disabled." ) ;
189+ }
190+
191+ // Setup ThreadPool for the application
192+ ThreadPool . GetMaxThreads ( out var workerThreadsMax , out var completionPortThreadsMax ) ;
193+ ThreadPool . GetMinThreads ( out var workerThreadsMin , out var completionPortThreadsMin ) ;
194+
195+ var workerThreadsMinNew = workerThreadsMin + SettingsManager . Current . General_ThreadPoolAdditionalMinThreads ;
196+ var completionPortThreadsMinNew = completionPortThreadsMin +
197+ SettingsManager . Current . General_ThreadPoolAdditionalMinThreads ;
198+
199+ if ( workerThreadsMinNew > workerThreadsMax )
200+ workerThreadsMinNew = workerThreadsMax ;
201+
202+ if ( completionPortThreadsMinNew > completionPortThreadsMax )
203+ completionPortThreadsMinNew = completionPortThreadsMax ;
204+
205+ if ( ThreadPool . SetMinThreads ( workerThreadsMinNew , completionPortThreadsMinNew ) )
210206 Log . Info (
211- "Another NETworkManager process is already running. Trying to bring the window to the foreground..." ) ;
212- SingleInstance . PostMessage ( SingleInstance . HWND_BROADCAST , SingleInstance . WM_SHOWME , IntPtr . Zero ,
213- IntPtr . Zero ) ;
207+ $ "ThreadPool min threads set to: workerThreads: { workerThreadsMinNew } , completionPortThreads: { completionPortThreadsMinNew } ") ;
208+ else
209+ Log . Warn (
210+ $ "ThreadPool min threads could not be set to workerThreads: { workerThreadsMinNew } , completionPortThreads: { completionPortThreadsMinNew } ") ;
214211
215- // Close the application
216- _singleInstanceClose = true ;
217- Shutdown ( ) ;
212+ // Show splash screen
213+ if ( SettingsManager . Current . SplashScreen_Enabled )
214+ {
215+ Log . Info ( "Show SplashScreen while application is loading..." ) ;
216+ new SplashScreen ( @"SplashScreen.png" ) . Show ( true , true ) ;
218217 }
218+
219+ // Show main window
220+ Log . Info ( "Set StartupUri to MainWindow.xaml..." ) ;
221+ StartupUri = new Uri ( "MainWindow.xaml" , UriKind . Relative ) ;
219222 }
220223
221224 /// <summary>
@@ -239,13 +242,26 @@ private void HandleCorruptedSettingsFile()
239242 ConfigurationManager . Current . ShowSettingsResetNoteOnStartup = true ;
240243 }
241244
245+ /// <summary>
246+ /// Handles the tick event of the dispatcher timer to trigger a background job and save data.
247+ /// </summary>
248+ /// <param name="sender">The source of the event, typically the dispatcher timer instance.</param>
249+ /// <param name="e">The event data associated with the timer tick.</param>
242250 private void DispatcherTimer_Tick ( object sender , EventArgs e )
243251 {
244252 Log . Info ( "Run background job..." ) ;
245253
246254 Save ( ) ;
247255 }
248256
257+ /// <summary>
258+ /// Handles the session ending event by canceling the session termination and initiating application shutdown.
259+ /// </summary>
260+ /// <remarks>This method overrides the default session ending behavior to prevent the session from ending
261+ /// automatically. Instead, it cancels the session termination and shuts down the application gracefully. Use this
262+ /// override to implement custom shutdown logic when the user logs off or shuts down the system.</remarks>
263+ /// <param name="e">The event data for the session ending event. Provides information about the session ending request and allows
264+ /// cancellation of the event.</param>
249265 protected override void OnSessionEnding ( SessionEndingCancelEventArgs e )
250266 {
251267 base . OnSessionEnding ( e ) ;
@@ -255,6 +271,15 @@ protected override void OnSessionEnding(SessionEndingCancelEventArgs e)
255271 Shutdown ( ) ;
256272 }
257273
274+ /// <summary>
275+ /// Handles the application exit event to perform cleanup operations such as stopping background tasks and saving
276+ /// settings.
277+ /// </summary>
278+ /// <remarks>This method is intended to be called when the application is shutting down. It ensures that
279+ /// any running background jobs are stopped and application settings are saved, unless the application is closed due
280+ /// to a single instance or help command scenario.</remarks>
281+ /// <param name="sender">The source of the event, typically the application instance.</param>
282+ /// <param name="e">The event data associated with the application exit event.</param>
258283 private void Application_Exit ( object sender , ExitEventArgs e )
259284 {
260285 Log . Info ( "Exiting NETworkManager..." ) ;
@@ -272,6 +297,12 @@ private void Application_Exit(object sender, ExitEventArgs e)
272297 Log . Info ( "Bye!" ) ;
273298 }
274299
300+ /// <summary>
301+ /// Saves application settings and profile data if changes have been detected.
302+ /// </summary>
303+ /// <remarks>This method saves settings only if they have been modified. Profile data is saved if a
304+ /// profile file is loaded, its data is available, and changes have been made. If no profile file is loaded or the
305+ /// file is encrypted and not unlocked, profile data will not be saved and a warning is logged.</remarks>
275306 private void Save ( )
276307 {
277308 // Save settings if they have changed
0 commit comments