private static void Main() { Application.SetHighDpiMode(HighDpiMode.SystemAware); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); using var serviceProvider = new ServiceCollection() .AddLogging(builder => builder.SetMinimumLevel(LogLevel.Trace).AddNLog("NLog.config.xml")) .AddSingleton <AppState>() .AddSingleton <ChangeLogger>() // Application context .AddSingleton <TrayApplicationContext>() .AddSingleton <NotifyIconManager>() // Menu .AddSingleton <TrayContextMenuStrip>() .AddSingleton(provider => new TrayHandlerCollection( provider.GetServices <IMenuHandler>().OrderBy(m => m.GetSortOrder()).ToArray() )) .AddSingleton <IMenuHandler, ExitMenuHandler>() .AddSingleton <IMenuHandler, ConfigureMenuHandler>() .AddSingleton <IMenuHandler, MachineControlMenuHandler>() .AddSingleton <IMenuHandler, KeepAwakeMenuHandler>() .AddSingleton <KeepAwakeTask>() .AddSingleton <IMenuHandler, MassControlMenuHandler>() // Virtual machines .AddSingleton <IMachineController, VirtualBoxInterface>() .AddSingleton <IMachineLocator, VirtualBoxInterface>() .AddSingleton(p => new VirtualBoxProxyFactory(p.GetService <ILogger <VirtualBoxProxyFactory> >(), p)) .AddTransient <VirtualMachine.VirtualBoxSdk.Proxy.Version60.VirtualBoxProxy>() .AddTransient <VirtualMachine.VirtualBoxSdk.Proxy.Version61.VirtualBoxProxy>() .AddSingleton <MachineStateUpdater>() .AddSingleton <MassController>() // Configuration .AddSingleton <IConfigurationFileLocator, UserProfileFileLocator>() .AddSingleton <IConfigurationReader, XmlConfigurationReader>() .AddSingleton <IConfigurationWriter, XmlConfigurationWriter>() .AddSingleton <ConfigurationFactory>() .AddSingleton <ConfigurationUpdater>() // Shutdown monitor .AddSingleton <MonitorForm>() .AddSingleton <ShutdownLocker>() .AddSingleton(_ => { var currentFile = Process.GetCurrentProcess().MainModule?.FileName; if (string.IsNullOrWhiteSpace(currentFile)) { throw new InvalidOperationException("Unable to retrieve current process name"); } var command = $"\"{currentFile}\" --auto-start"; return(new StartupManager("VBoxHeadlessAutoStart", command)); }) .AddSingleton <InstanceLocker>() .BuildServiceProvider(); var locker = serviceProvider.GetService <InstanceLocker>(); if (!locker.StartLock()) { MonitorForm.BroadcastConfigureMessage(); return; } var logger = serviceProvider.GetService <ILogger <TrayApplicationContext> >(); logger.LogTrace($"TrayApp {Process.GetCurrentProcess().Id} started"); var appState = serviceProvider.GetService <AppState>(); appState.OnConfigurationChange += (object sender, ConfigurationChangeEventArgs e) => // Update the log level from the configuration LogLevelConfigurationManager.SetLogLevel(e.NewConfiguration.LogLevel); // Load the change logger so it attaches its event listeners to the app state _ = serviceProvider.GetService <ChangeLogger>(); try { // Load the configuration and machines into the store appState.UpdateConfiguration(); appState.UpdateMachines(); } catch (InvalidInstallException e) { if (!IsAutoStarting()) { MessageBox.Show( $"Could not continue, {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error ); } return; } if (IsAutoStarting()) { var massController = serviceProvider.GetService <MassController>(); Task.Run(() => massController.StartAll((_, c) => c?.AutoStart == true)); } // Show the shutdown monitor form so it can listen for shutdown events and block them if needed serviceProvider.GetService <MonitorForm>().Show(); // Run the application Application.Run(serviceProvider.GetService <TrayApplicationContext>()); locker.StopLock(); logger.LogTrace($"TrayApp {Process.GetCurrentProcess().Id} finished"); NLog.LogManager.Flush(); NLog.LogManager.Shutdown(); }