public static IEnumerable <Share> GetShares() { ILocalSharesManagement sharesManagement = ServiceRegistration.Get <ILocalSharesManagement>(); return(sharesManagement.Shares.Values); }
public override void UpdateShare(RelocationMode relocationMode) { ILocalSharesManagement sharesManagement = ServiceRegistration.Get <ILocalSharesManagement>(); sharesManagement.UpdateShare(_origShare.ShareId, ChoosenResourcePath, ShareName, GetMediaCategoriesCleanedUp(), relocationMode); }
public override void ReImportShare() { ILocalSharesManagement sharesManagement = ServiceRegistration.Get <ILocalSharesManagement>(); sharesManagement.ReImportShare(_origShare.ShareId); }
protected override bool ShareNameExists(string shareName) { ILocalSharesManagement sharesManagement = ServiceRegistration.Get <ILocalSharesManagement>(); return(sharesManagement.Shares.Values.Any(share => (_origShare == null || share.ShareId != _origShare.ShareId) && share.Name == shareName)); }
protected override bool SharePathExists(ResourcePath sharePath) { ILocalSharesManagement sharesManagement = ServiceRegistration.Get <ILocalSharesManagement>(); return(sharesManagement.Shares.Values.Any(share => (_origShare == null || share.ShareId != _origShare.ShareId) && share.BaseResourcePath == sharePath)); }
void OnMessageReceived(AsynchronousMessageQueue queue, SystemMessage message) { if (message.ChannelName == SharesMessaging.CHANNEL) { IContentDirectory cd = ContentDirectory; SharesMessaging.MessageType messageType = (SharesMessaging.MessageType)message.MessageType; IImporterWorker importerWorker = ServiceRegistration.Get <IImporterWorker>(); Share share; switch (messageType) { case SharesMessaging.MessageType.ShareAdded: share = (Share)message.MessageData[SharesMessaging.SHARE]; if (cd != null) { cd.RegisterShareAsync(share); } importerWorker.ScheduleImport(share.BaseResourcePath, share.MediaCategories, true); break; case SharesMessaging.MessageType.ShareRemoved: share = (Share)message.MessageData[SharesMessaging.SHARE]; importerWorker.CancelJobsForPath(share.BaseResourcePath); if (cd != null) { cd.RemoveShareAsync(share.ShareId); } break; case SharesMessaging.MessageType.ShareChanged: RelocationMode relocationMode = (RelocationMode)message.MessageData[SharesMessaging.RELOCATION_MODE]; share = (Share)message.MessageData[SharesMessaging.SHARE]; importerWorker.CancelJobsForPath(share.BaseResourcePath); if (cd == null) { ISettingsManager settingsManager = ServiceRegistration.Get <ISettingsManager>(); ServerConnectionSettings settings = settingsManager.Load <ServerConnectionSettings>(); RelocationMode oldMode; if (settings.CachedSharesUpdates.TryGetValue(share.ShareId, out oldMode) && oldMode == RelocationMode.ClearAndReImport) { // ClearAndReimport is stronger than Relocate, use ClearAndReImport relocationMode = oldMode; } settings.CachedSharesUpdates[share.ShareId] = relocationMode; settingsManager.Save(settings); } else { cd.UpdateShareAsync(share.ShareId, share.BaseResourcePath, share.Name, share.UseShareWatcher, share.MediaCategories, relocationMode); switch (relocationMode) { case RelocationMode.ClearAndReImport: importerWorker.ScheduleImport(share.BaseResourcePath, share.MediaCategories, true); break; case RelocationMode.Relocate: importerWorker.ScheduleRefresh(share.BaseResourcePath, share.MediaCategories, true); break; } } break; case SharesMessaging.MessageType.ReImportShare: share = (Share)message.MessageData[SharesMessaging.SHARE]; importerWorker.ScheduleRefresh(share.BaseResourcePath, share.MediaCategories, true); break; } } else if (message.ChannelName == ImporterWorkerMessaging.CHANNEL) { IContentDirectory cd = ContentDirectory; ImporterWorkerMessaging.MessageType messageType = (ImporterWorkerMessaging.MessageType)message.MessageType; switch (messageType) { case ImporterWorkerMessaging.MessageType.ImportStarted: case ImporterWorkerMessaging.MessageType.ImportCompleted: if (cd == null) { break; } ResourcePath path = (ResourcePath)message.MessageData[ImporterWorkerMessaging.RESOURCE_PATH]; ILocalSharesManagement lsm = ServiceRegistration.Get <ILocalSharesManagement>(); ICollection <Share> shares = lsm.Shares.Values; Share share = shares.BestContainingPath(path); if (share == null) { break; } if (messageType == ImporterWorkerMessaging.MessageType.ImportStarted) { cd.ClientStartedShareImportAsync(share.ShareId); } else { cd.ClientCompletedShareImportAsync(share.ShareId); } break; } } else if (message.ChannelName == ServerStateMessaging.CHANNEL) { //Check if Tv Server state has changed and update if necessary ServerStateMessaging.MessageType messageType = (ServerStateMessaging.MessageType)message.MessageType; if (messageType == ServerStateMessaging.MessageType.StatesChanged) { var states = message.MessageData[ServerStateMessaging.STATES] as IDictionary <Guid, object>; if (states != null && states.ContainsKey(ShareImportServerState.STATE_ID)) { ShareImportServerState importState = states[ShareImportServerState.STATE_ID] as ShareImportServerState; if (importState != null) { List <ShareImportState> shareStates = new List <ShareImportState>(importState.Shares); lock (_syncObj) { UpdateCurrentlyImportingShares(shareStates.Where(s => s.IsImporting).Select(s => s.ShareId).ToList()); UpdateCurrentlyImportingSharesProgresses(shareStates.Where(s => s.IsImporting).ToDictionary(s => s.ShareId, s => s.Progress)); } } } else if (states != null && states.ContainsKey(DatabaseUpgradeServerState.STATE_ID)) { DatabaseUpgradeServerState upgradeState = states[DatabaseUpgradeServerState.STATE_ID] as DatabaseUpgradeServerState; if (upgradeState != null && !upgradeState.IsUpgrading && upgradeState.Progress == 100) { ServerConnectionMessaging.SendServerConnectionStateChangedMessage(ServerConnectionMessaging.MessageType.HomeServerDisconnected); ServerConnectionMessaging.SendServerConnectionStateChangedMessage(ServerConnectionMessaging.MessageType.HomeServerConnected); } } } } }
void OnMessageReceived(AsynchronousMessageQueue queue, SystemMessage message) { if (message.ChannelName == SharesMessaging.CHANNEL) { IContentDirectory cd = ContentDirectory; SharesMessaging.MessageType messageType = (SharesMessaging.MessageType)message.MessageType; IImporterWorker importerWorker = ServiceRegistration.Get <IImporterWorker>(); Share share; switch (messageType) { case SharesMessaging.MessageType.ShareAdded: share = (Share)message.MessageData[SharesMessaging.SHARE]; if (cd != null) { cd.RegisterShare(share); } importerWorker.ScheduleImport(share.BaseResourcePath, share.MediaCategories, true); break; case SharesMessaging.MessageType.ShareRemoved: share = (Share)message.MessageData[SharesMessaging.SHARE]; importerWorker.CancelJobsForPath(share.BaseResourcePath); if (cd != null) { cd.RemoveShare(share.ShareId); } break; case SharesMessaging.MessageType.ShareChanged: RelocationMode relocationMode = (RelocationMode)message.MessageData[SharesMessaging.RELOCATION_MODE]; share = (Share)message.MessageData[SharesMessaging.SHARE]; importerWorker.CancelJobsForPath(share.BaseResourcePath); if (cd == null) { ISettingsManager settingsManager = ServiceRegistration.Get <ISettingsManager>(); ServerConnectionSettings settings = settingsManager.Load <ServerConnectionSettings>(); RelocationMode oldMode; if (settings.CachedSharesUpdates.TryGetValue(share.ShareId, out oldMode) && oldMode == RelocationMode.ClearAndReImport) { // ClearAndReimport is stronger than Relocate, use ClearAndReImport relocationMode = oldMode; } settings.CachedSharesUpdates[share.ShareId] = relocationMode; settingsManager.Save(settings); } else { cd.UpdateShare(share.ShareId, share.BaseResourcePath, share.Name, share.MediaCategories, relocationMode); switch (relocationMode) { case RelocationMode.ClearAndReImport: importerWorker.ScheduleImport(share.BaseResourcePath, share.MediaCategories, true); break; case RelocationMode.Relocate: importerWorker.ScheduleRefresh(share.BaseResourcePath, share.MediaCategories, true); break; } } break; case SharesMessaging.MessageType.ReImportShare: share = (Share)message.MessageData[SharesMessaging.SHARE]; importerWorker.ScheduleRefresh(share.BaseResourcePath, share.MediaCategories, true); break; } } else if (message.ChannelName == ImporterWorkerMessaging.CHANNEL) { IContentDirectory cd = ContentDirectory; ImporterWorkerMessaging.MessageType messageType = (ImporterWorkerMessaging.MessageType)message.MessageType; switch (messageType) { case ImporterWorkerMessaging.MessageType.ImportStarted: case ImporterWorkerMessaging.MessageType.ImportCompleted: if (cd == null) { break; } ResourcePath path = (ResourcePath)message.MessageData[ImporterWorkerMessaging.RESOURCE_PATH]; ILocalSharesManagement lsm = ServiceRegistration.Get <ILocalSharesManagement>(); ICollection <Share> shares = lsm.Shares.Values; Share share = shares.BestContainingPath(path); if (share == null) { break; } if (messageType == ImporterWorkerMessaging.MessageType.ImportStarted) { cd.ClientStartedShareImport(share.ShareId); } else { cd.ClientCompletedShareImport(share.ShareId); } break; } } }
/// <summary> /// The main entry point for the MP2 client application. /// </summary> private static void Main(params string[] args) { Thread.CurrentThread.Name = "Main"; // Parse command line options var mpOptions = new CommandLineOptions(); var parser = new CommandLine.Parser(with => with.HelpWriter = Console.Out); parser.ParseArgumentsStrict(args, mpOptions, () => Environment.Exit(1)); // Check if another instance is already running if (SingleInstanceHelper.IsAlreadyRunning(MUTEX_ID, out _mutex)) { _mutex = null; // Set focus on previously running app SingleInstanceHelper.SwitchToCurrentInstance(SingleInstanceHelper.SHOW_MP2_CLIENT_MESSAGE); // Stop current instance Console.Out.WriteLine("Application already running."); Environment.Exit(2); } #if !DEBUG string logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), @"Team MediaPortal\MP2-Client\Log"); #endif Application.ThreadException += LauncherExceptionHandling.Application_ThreadException; AppDomain.CurrentDomain.UnhandledException += LauncherExceptionHandling.CurrentDomain_UnhandledException; TaskScheduler.UnobservedTaskException += LauncherExceptionHandling.TaskScheduler_UnobservedTaskException; SystemStateService systemStateService = new SystemStateService(); ServiceRegistration.Set <ISystemStateService>(systemStateService); systemStateService.SwitchSystemState(SystemState.Initializing, false); try { #if !DEBUG SplashScreen splashScreen = null; #endif ILogger logger = null; try { // Check if user wants to override the default Application Data location. ApplicationCore.RegisterVitalCoreServices(true, mpOptions.DataDirectory); #if !DEBUG splashScreen = CreateSplashScreen(); splashScreen.ShowSplashScreen(); #endif ApplicationCore.RegisterCoreServices(); logger = ServiceRegistration.Get <ILogger>(); #if !DEBUG IPathManager pathManager = ServiceRegistration.Get <IPathManager>(); logPath = pathManager.GetPath("<LOG>"); #endif UiExtension.RegisterUiServices(); } catch (Exception e) { if (logger != null) { logger.Critical("Error starting application", e); } systemStateService.SwitchSystemState(SystemState.ShuttingDown, true); ServiceRegistration.IsShuttingDown = true; UiExtension.DisposeUiServices(); ApplicationCore.DisposeCoreServices(); throw; } // Start the core logger.Debug("ApplicationLauncher: Starting application"); try { IPluginManager pluginManager = ServiceRegistration.Get <IPluginManager>(); pluginManager.Initialize(); pluginManager.Startup(false); ApplicationCore.StartCoreServices(); ISkinEngine skinEngine = ServiceRegistration.Get <ISkinEngine>(); IWorkflowManager workflowManager = ServiceRegistration.Get <IWorkflowManager>(); IMediaAccessor mediaAccessor = ServiceRegistration.Get <IMediaAccessor>(); ILocalSharesManagement localSharesManagement = ServiceRegistration.Get <ILocalSharesManagement>(); // We have to handle some dependencies here in the start order: // 1) After all plugins are loaded, the SkinEngine can initialize (=load all skin resources) // 2) After the skin resources are loaded, the workflow manager can initialize (=load its states and actions) // 3) Before the main window is shown, the splash screen should be hidden // 4) After the workflow states and actions are loaded, the main window can be shown // 5) After the skinengine triggers the first workflow state/startup screen, the default shortcuts can be registered mediaAccessor.Initialize(); // Independent from other services localSharesManagement.Initialize(); // After media accessor was initialized skinEngine.Initialize(); // 1) workflowManager.Initialize(); // 2) #if !DEBUG splashScreen.CloseSplashScreen(); // 3) #endif skinEngine.Startup(); // 4) UiExtension.Startup(); // 5) ApplicationCore.RegisterDefaultMediaItemAspectTypes().Wait(); // To be done after UI services are running _ipcServer = new IpcServer("Client"); _ipcServer.CustomShutdownCallback = () => { ServiceRegistration.Get <IScreenControl>().Shutdown(); return(true); }; try { _ipcServer.Open(); } catch (Exception ipcEx) { logger.Error(ipcEx); } systemStateService.SwitchSystemState(SystemState.Running, true); if (mpOptions.AutoStart) { StartFocusKeeper(); } Application.Run(); systemStateService.SwitchSystemState(SystemState.ShuttingDown, true); ServiceRegistration.IsShuttingDown = true; // Block ServiceRegistration from trying to load new services in shutdown phase // 1) Stop UI extensions (Releases all active players, must be done before shutting down SE) // 2) Shutdown SkinEngine (Closes all screens, uninstalls background manager, stops render thread) // 3) Shutdown WorkflowManager (Disposes all models) // 4) Shutdown ImporterWorker // 5) Shutdown PluginManager (Shuts down all plugins) // 6) Remove all services UiExtension.StopUiServices(); skinEngine.Shutdown(); workflowManager.Shutdown(); ServiceRegistration.Get <IImporterWorker>().Shutdown(); pluginManager.Shutdown(); mediaAccessor.Shutdown(); localSharesManagement.Shutdown(); ApplicationCore.StopCoreServices(); } catch (Exception e) { logger.Critical("Error executing application", e); systemStateService.SwitchSystemState(SystemState.ShuttingDown, true); ServiceRegistration.IsShuttingDown = true; } finally { if (_ipcServer != null) { _ipcServer.Close(); } UiExtension.DisposeUiServices(); ApplicationCore.DisposeCoreServices(); systemStateService.SwitchSystemState(SystemState.Ending, false); } } catch (Exception ex) { #if DEBUG ConsoleLogger log = new ConsoleLogger(LogLevel.All, false); log.Error(ex); #else UiCrashLogger crash = new UiCrashLogger(logPath); crash.CreateLog(ex); #endif systemStateService.SwitchSystemState(SystemState.Ending, false); // Release mutex for single instance if (_mutex != null) { _mutex.ReleaseMutex(); } Application.Exit(); } }
public override void AddShare() { ILocalSharesManagement sharesManagement = ServiceRegistration.Get <ILocalSharesManagement>(); sharesManagement.RegisterShare(ChoosenResourcePath, ShareName, MediaCategories); }
protected internal async Task UpdateShareLists_NoLock(bool create) { lock (_syncObj) { if (_updatingProperties) { return; } _updatingProperties = true; if (create) { _serverSharesList = new ItemsList(); _localSharesList = new ItemsList(); } } try { ILocalSharesManagement sharesManagement = ServiceRegistration.Get <ILocalSharesManagement>(); var shares = sharesManagement.Shares.Values; _localSharesList.Clear(); foreach (Share share in shares) { ListItem item = new ListItem(); item.SetLabel(Consts.KEY_NAME, share.Name); item.AdditionalProperties[Consts.KEY_SHARE] = share; if (UserProxy != null) { item.Selected = UserProxy.SelectedShares.Contains(share.ShareId); } lock (_syncObj) _localSharesList.Add(item); } IServerConnectionManager scm = ServiceRegistration.Get <IServerConnectionManager>(); if (scm == null || scm.ContentDirectory == null) { return; } // add users to expose them shares = await scm.ContentDirectory.GetSharesAsync(scm.HomeServerSystemId, SharesFilter.All); _serverSharesList.Clear(); foreach (Share share in shares) { ListItem item = new ListItem(); item.SetLabel(Consts.KEY_NAME, share.Name); item.AdditionalProperties[Consts.KEY_SHARE] = share; if (UserProxy != null) { item.Selected = UserProxy.SelectedShares.Contains(share.ShareId); } lock (_syncObj) _serverSharesList.Add(item); } SystemName homeServerSystem = scm.LastHomeServerSystem; IsLocalHomeServer = homeServerSystem != null && homeServerSystem.IsLocalSystem(); IsHomeServerConnected = homeServerSystem != null; ShowLocalShares = !IsLocalHomeServer || _localSharesList.Count > 0; AnyShareAvailable = _serverSharesList.Count > 0 || _localSharesList.Count > 0; } catch (NotConnectedException) { throw; } catch (Exception e) { ServiceRegistration.Get <ILogger>().Error("Problems updating shares", e); } finally { lock (_syncObj) _updatingProperties = false; } }
public override async Task <AsyncResult <ContentDirectoryMessaging.MediaItemChangeType> > ProcessAsync(MediaItem mediaItem) { // If the MediaItem was loaded from ML if (IsManagedByMediaLibrary(mediaItem)) { IContentDirectory cd = ServiceRegistration.Get <IServerConnectionManager>().ContentDirectory; if (cd == null) { return(new AsyncResult <ContentDirectoryMessaging.MediaItemChangeType>(false, ContentDirectoryMessaging.MediaItemChangeType.None)); } SubtitleMatchModel misub = ServiceRegistration.Get <IWorkflowManager>().GetModel(SubtitleMatchModel.MODEL_ID_SUBMATCH) as SubtitleMatchModel; await misub.OpenSelectEditionDialogAsync(mediaItem).ConfigureAwait(false); IEnumerable <MediaItemAspect> aspects = await misub.OpenSelectMatchDialogAsync(mediaItem).ConfigureAwait(false); if (aspects != null) { SubtitleInfo subtitle = new SubtitleInfo(); subtitle.FromMetadata(MediaItemAspect.GetAspects(aspects)); //Check if it is from a local share bool isLocalMediaItem = false; ILocalSharesManagement sharesManagement = ServiceRegistration.Get <ILocalSharesManagement>(); var localShares = sharesManagement.Shares.Values; foreach (var media in subtitle.MediaFiles) { if (localShares.Any(s => s.BaseResourcePath.IsSameOrParentOf(media.NativeResourcePath))) { isLocalMediaItem = true; break; } } //Import directly if it is a local media item if (isLocalMediaItem) { ServiceRegistration.Get <ILogger>().Debug("Downloading subtitle with local extractors"); IMediaAccessor mediaAccessor = ServiceRegistration.Get <IMediaAccessor>(); foreach (IMetadataExtractor extractor in mediaAccessor.LocalMetadataExtractors.Values) { if (!extractor.Metadata.ExtractedAspectTypes.ContainsKey(SubtitleAspect.ASPECT_ID)) { continue; } await extractor.DownloadMetadataAsync(mediaItem.MediaItemId, MediaItemAspect.GetAspects(aspects)).ConfigureAwait(false); } foreach (var media in subtitle.MediaFiles) { var share = localShares.FirstOrDefault(s => s.BaseResourcePath.IsSameOrParentOf(media.NativeResourcePath)); if (share != null) { sharesManagement.ReImportShare(share.ShareId); break; } } return(new AsyncResult <ContentDirectoryMessaging.MediaItemChangeType>(true, ContentDirectoryMessaging.MediaItemChangeType.Updated)); } else //If not get the server to import { ServiceRegistration.Get <ILogger>().Debug("Downloading subtitle with server extractors"); await cd.DownloadMetadataAsync(mediaItem.MediaItemId, aspects); //After refresh is completed on server a change message will be fired return(new AsyncResult <ContentDirectoryMessaging.MediaItemChangeType>(true, ContentDirectoryMessaging.MediaItemChangeType.None)); } } } return(new AsyncResult <ContentDirectoryMessaging.MediaItemChangeType>(false, ContentDirectoryMessaging.MediaItemChangeType.None)); }
/// <summary> /// The main entry point for the MP 2 client application. /// </summary> private static void Main(params string[] args) { Thread.CurrentThread.Name = "Main"; #if !DEBUG SplashScreen splashScreen = CreateSplashScreen(); splashScreen.ShowSplashScreen(); #endif // Parse Command Line options CommandLineOptions mpArgs = new CommandLineOptions(); ICommandLineParser parser = new CommandLineParser(new CommandLineParserSettings(Console.Error)); if (!parser.ParseArguments(args, mpArgs, Console.Out)) { Environment.Exit(1); } #if !DEBUG string logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), @"Team MediaPortal\MP2-Client\Log"); #endif SystemStateService systemStateService = new SystemStateService(); ServiceRegistration.Set <ISystemStateService>(systemStateService); systemStateService.SwitchSystemState(SystemState.Initializing, false); try { ILogger logger = null; try { // Check if user wants to override the default Application Data location. ApplicationCore.RegisterCoreServices(mpArgs.DataDirectory); logger = ServiceRegistration.Get <ILogger>(); #if !DEBUG IPathManager pathManager = ServiceRegistration.Get <IPathManager>(); logPath = pathManager.GetPath("<LOG>"); #endif UiExtension.RegisterUiServices(); } catch (Exception e) { if (logger != null) { logger.Critical("Error starting application", e); } systemStateService.SwitchSystemState(SystemState.ShuttingDown, true); ServiceRegistration.IsShuttingDown = true; UiExtension.DisposeUiServices(); ApplicationCore.DisposeCoreServices(); throw; } // Start the core logger.Debug("ApplicationLauncher: Starting application"); try { IPluginManager pluginManager = ServiceRegistration.Get <IPluginManager>(); pluginManager.Initialize(); pluginManager.Startup(false); ApplicationCore.StartCoreServices(); ISkinEngine skinEngine = ServiceRegistration.Get <ISkinEngine>(); IWorkflowManager workflowManager = ServiceRegistration.Get <IWorkflowManager>(); IMediaAccessor mediaAccessor = ServiceRegistration.Get <IMediaAccessor>(); ILocalSharesManagement localSharesManagement = ServiceRegistration.Get <ILocalSharesManagement>(); // We have to handle some dependencies here in the start order: // 1) After all plugins are loaded, the SkinEngine can initialize (=load all skin resources) // 2) After the skin resources are loaded, the workflow manager can initialize (=load its states and actions) // 3) Before the main window is shown, the splash screen should be hidden // 4) After the workflow states and actions are loaded, the main window can be shown // 5) After the skinengine triggers the first workflow state/startup screen, the default shortcuts can be registered mediaAccessor.Initialize(); // Independent from other services localSharesManagement.Initialize(); // After media accessor was initialized skinEngine.Initialize(); // 1) workflowManager.Initialize(); // 2) #if !DEBUG splashScreen.CloseSplashScreen(); // 3) #endif skinEngine.Startup(); // 4) UiExtension.Startup(); // 5) ApplicationCore.RegisterDefaultMediaItemAspectTypes(); // To be done after UI services are running systemStateService.SwitchSystemState(SystemState.Running, true); Application.Run(); systemStateService.SwitchSystemState(SystemState.ShuttingDown, true); ServiceRegistration.IsShuttingDown = true; // Block ServiceRegistration from trying to load new services in shutdown phase // 1) Stop UI extensions (Releases all active players, must be done before shutting down SE) // 2) Shutdown SkinEngine (Closes all screens, uninstalls background manager, stops render thread) // 3) Shutdown WorkflowManager (Disposes all models) // 4) Shutdown PluginManager (Shuts down all plugins) // 5) Remove all services UiExtension.StopUiServices(); skinEngine.Shutdown(); workflowManager.Shutdown(); pluginManager.Shutdown(); mediaAccessor.Shutdown(); localSharesManagement.Shutdown(); ApplicationCore.StopCoreServices(); } catch (Exception e) { logger.Critical("Error executing application", e); systemStateService.SwitchSystemState(SystemState.ShuttingDown, true); ServiceRegistration.IsShuttingDown = true; } finally { UiExtension.DisposeUiServices(); ApplicationCore.DisposeCoreServices(); systemStateService.SwitchSystemState(SystemState.Ending, false); } } catch (Exception ex) { #if DEBUG ConsoleLogger log = new ConsoleLogger(LogLevel.All, false); log.Error(ex); #else UiCrashLogger crash = new UiCrashLogger(logPath); crash.CreateLog(ex); #endif systemStateService.SwitchSystemState(SystemState.Ending, false); Application.Exit(); } }