using MediaBrowser.Common.IO; using MediaBrowser.Common.Kernel; using MediaBrowser.Common.Logging; using MediaBrowser.Common.Updates; using MediaBrowser.Model.Logging; using Microsoft.Win32; using System; using System.Collections.Generic; using System.ComponentModel; using System.Deployment.Application; using System.Net.Cache; using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; namespace MediaBrowser.Common.UI { /// /// Serves as a base Application class for both the UI and Server apps. /// public abstract class BaseApplication : Application, INotifyPropertyChanged { /// /// The single instance mutex /// private Mutex SingleInstanceMutex; /// /// Gets the name of the publisher. /// /// The name of the publisher. protected abstract string PublisherName { get; } /// /// Gets the name of the suite. /// /// The name of the suite. protected abstract string SuiteName { get; } /// /// Gets the name of the product. /// /// The name of the product. protected abstract string ProductName { get; } /// /// Gets the name of the uninstaller file. /// /// The name of the uninstaller file. protected abstract string UninstallerFileName { get; } /// /// Gets or sets a value indicating whether [last run at startup value]. /// /// null if [last run at startup value] contains no value, true if [last run at startup value]; otherwise, false. private bool? LastRunAtStartupValue { get; set; } /// /// Gets or sets the kernel. /// /// The kernel. protected IKernel Kernel { get; set; } /// /// Instantiates the kernel. /// /// IKernel. protected abstract IKernel InstantiateKernel(); /// /// Instantiates the main window. /// /// Window. protected abstract Window InstantiateMainWindow(); /// /// Occurs when [property changed]. /// public event PropertyChangedEventHandler PropertyChanged; /// /// Gets or sets the logger. /// /// The logger. protected ILogger Logger { get; set; } /// /// Instantiates the iso manager. /// /// The kernel. /// IIsoManager. protected abstract IIsoManager InstantiateIsoManager(IKernel kernel); /// /// Initializes a new instance of the class. /// protected BaseApplication() { Logger = LogManager.GetLogger("App"); } /// /// Called when [property changed]. /// /// The info. public void OnPropertyChanged(String info) { if (PropertyChanged != null) { try { PropertyChanged(this, new PropertyChangedEventArgs(info)); } catch (Exception ex) { Logger.ErrorException("Error in event handler", ex); } } } /// /// Raises the event. /// /// A that contains the event data. protected override void OnStartup(StartupEventArgs e) { bool createdNew; SingleInstanceMutex = new Mutex(true, @"Local\" + GetType().Assembly.GetName().Name, out createdNew); if (!createdNew) { SingleInstanceMutex = null; Shutdown(); return; } AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; LoadKernel(); SystemEvents.SessionEnding += SystemEvents_SessionEnding; } /// /// Handles the UnhandledException event of the CurrentDomain control. /// /// The source of the event. /// The instance containing the event data. void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { var exception = (Exception) e.ExceptionObject; Logger.ErrorException("UnhandledException", exception); MessageBox.Show("Unhandled exception: " + exception.Message); } /// /// Handles the SessionEnding event of the SystemEvents control. /// /// The source of the event. /// The instance containing the event data. void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e) { // Try to shut down gracefully Shutdown(); } /// /// Loads the kernel. /// protected virtual async void LoadKernel() { Kernel = InstantiateKernel(); try { InstantiateMainWindow().Show(); var now = DateTime.UtcNow; await Kernel.Init(InstantiateIsoManager(Kernel)); var done = (DateTime.UtcNow - now); Logger.Info("Kernel.Init completed in {0}{1} minutes and {2} seconds.", done.Hours > 0 ? done.Hours + " Hours " : "", done.Minutes, done.Seconds); await OnKernelLoaded(); } catch (Exception ex) { Logger.ErrorException("Error launching application", ex); MessageBox.Show("There was an error launching Media Browser: " + ex.Message); // Shutdown the app with an error code Shutdown(1); } } /// /// Called when [kernel loaded]. /// /// Task. protected virtual Task OnKernelLoaded() { return Task.Run(() => { Kernel.ApplicationRestartRequested += Kernel_ApplicationRestartRequested; Kernel.ConfigurationUpdated += Kernel_ConfigurationUpdated; ConfigureClickOnceStartup(); }); } /// /// Handles the ConfigurationUpdated event of the Kernel control. /// /// The source of the event. /// The instance containing the event data. void Kernel_ConfigurationUpdated(object sender, EventArgs e) { if (!LastRunAtStartupValue.HasValue || LastRunAtStartupValue.Value != Kernel.Configuration.RunAtStartup) { ConfigureClickOnceStartup(); } } /// /// Configures the click once startup. /// private void ConfigureClickOnceStartup() { if (!ApplicationDeployment.IsNetworkDeployed) { return; } try { var clickOnceHelper = new ClickOnceHelper(PublisherName, ProductName, SuiteName); if (Kernel.Configuration.RunAtStartup) { clickOnceHelper.UpdateUninstallParameters(UninstallerFileName); clickOnceHelper.AddShortcutToStartup(); } else { clickOnceHelper.RemoveShortcutFromStartup(); } LastRunAtStartupValue = Kernel.Configuration.RunAtStartup; } catch (Exception ex) { Logger.ErrorException("Error configuring ClickOnce", ex); } } /// /// Handles the ApplicationRestartRequested event of the Kernel control. /// /// The source of the event. /// The instance containing the event data. void Kernel_ApplicationRestartRequested(object sender, EventArgs e) { Restart(); } /// /// Restarts this instance. /// public void Restart() { Dispatcher.Invoke(ReleaseMutex); Kernel.Dispose(); System.Windows.Forms.Application.Restart(); Dispatcher.Invoke(Shutdown); } /// /// Releases the mutex. /// private void ReleaseMutex() { if (SingleInstanceMutex == null) { return; } SingleInstanceMutex.ReleaseMutex(); SingleInstanceMutex.Close(); SingleInstanceMutex.Dispose(); SingleInstanceMutex = null; } /// /// Raises the event. /// /// An that contains the event data. protected override void OnExit(ExitEventArgs e) { ReleaseMutex(); base.OnExit(e); Kernel.Dispose(); } /// /// Signals the external command line args. /// /// The args. /// true if XXXX, false otherwise public bool SignalExternalCommandLineArgs(IList args) { OnSecondInstanceLaunched(args); return true; } /// /// Called when [second instance launched]. /// /// The args. protected virtual void OnSecondInstanceLaunched(IList args) { if (MainWindow.WindowState == WindowState.Minimized) { MainWindow.WindowState = WindowState.Maximized; } } /// /// Gets the image. /// /// The URI. /// Image. /// uri public Image GetImage(string uri) { if (string.IsNullOrEmpty(uri)) { throw new ArgumentNullException("uri"); } return GetImage(new Uri(uri)); } /// /// Gets the image. /// /// The URI. /// Image. /// uri public Image GetImage(Uri uri) { if (uri == null) { throw new ArgumentNullException("uri"); } return new Image { Source = GetBitmapImage(uri) }; } /// /// Gets the bitmap image. /// /// The URI. /// BitmapImage. /// uri public BitmapImage GetBitmapImage(string uri) { if (string.IsNullOrEmpty(uri)) { throw new ArgumentNullException("uri"); } return GetBitmapImage(new Uri(uri)); } /// /// Gets the bitmap image. /// /// The URI. /// BitmapImage. /// uri public BitmapImage GetBitmapImage(Uri uri) { if (uri == null) { throw new ArgumentNullException("uri"); } var bitmap = new BitmapImage { CreateOptions = BitmapCreateOptions.DelayCreation, CacheOption = BitmapCacheOption.OnDemand, UriCachePolicy = new RequestCachePolicy(RequestCacheLevel.CacheIfAvailable) }; bitmap.BeginInit(); bitmap.UriSource = uri; bitmap.EndInit(); RenderOptions.SetBitmapScalingMode(bitmap, BitmapScalingMode.Fant); return bitmap; } /// /// Runs the application. /// /// The type of the T application type. /// The unique key. public static void RunApplication(string uniqueKey) where TApplicationType : BaseApplication, IApplication, new() { var application = new TApplicationType(); application.InitializeComponent(); application.Run(); } } /// /// Interface IApplication /// public interface IApplication { /// /// Initializes the component. /// void InitializeComponent(); } }