diff --git a/SafeExamBrowser.Contracts/Configuration/ISettings.cs b/SafeExamBrowser.Contracts/Configuration/ISettings.cs index 9eefa75a..70ed699f 100644 --- a/SafeExamBrowser.Contracts/Configuration/ISettings.cs +++ b/SafeExamBrowser.Contracts/Configuration/ISettings.cs @@ -10,7 +10,9 @@ namespace SafeExamBrowser.Contracts.Configuration { public interface ISettings { + string CopyrightInfo { get; } string LogFolderPath { get; } string LogHeader { get; } + string ProgramVersion { get; } } } diff --git a/SafeExamBrowser.Contracts/Configuration/IStartupController.cs b/SafeExamBrowser.Contracts/Configuration/IStartupController.cs index fc700b16..f04ae701 100644 --- a/SafeExamBrowser.Contracts/Configuration/IStartupController.cs +++ b/SafeExamBrowser.Contracts/Configuration/IStartupController.cs @@ -6,12 +6,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System; - namespace SafeExamBrowser.Contracts.Configuration { public interface IStartupController { - void InitializeApplication(Action terminationCallback); + bool TryInitializeApplication(); } } diff --git a/SafeExamBrowser.Contracts/Logging/ILogMessage.cs b/SafeExamBrowser.Contracts/Logging/ILogMessage.cs index d2a7e5e8..5fc62eba 100644 --- a/SafeExamBrowser.Contracts/Logging/ILogMessage.cs +++ b/SafeExamBrowser.Contracts/Logging/ILogMessage.cs @@ -15,6 +15,6 @@ namespace SafeExamBrowser.Contracts.Logging DateTime DateTime { get; } LogLevel Severity { get; } string Message { get; } - int ThreadId { get; } + IThreadInfo ThreadInfo { get; } } } diff --git a/SafeExamBrowser.Contracts/Logging/IThreadInfo.cs b/SafeExamBrowser.Contracts/Logging/IThreadInfo.cs new file mode 100644 index 00000000..1dc23ff3 --- /dev/null +++ b/SafeExamBrowser.Contracts/Logging/IThreadInfo.cs @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System; + +namespace SafeExamBrowser.Contracts.Logging +{ + public interface IThreadInfo : ICloneable + { + int Id { get; } + string Name { get; } + bool HasName { get; } + } +} diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj index c044e09c..e45dd046 100644 --- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj +++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj @@ -50,6 +50,7 @@ + diff --git a/SafeExamBrowser.Contracts/UserInterface/ISplashScreen.cs b/SafeExamBrowser.Contracts/UserInterface/ISplashScreen.cs index 9e9a5205..67396d7e 100644 --- a/SafeExamBrowser.Contracts/UserInterface/ISplashScreen.cs +++ b/SafeExamBrowser.Contracts/UserInterface/ISplashScreen.cs @@ -12,7 +12,9 @@ namespace SafeExamBrowser.Contracts.UserInterface { public interface ISplashScreen : ILogObserver { - void Show(); void Close(); + void SetMaxProgress(int max); + void Show(); + void UpdateProgress(); } } diff --git a/SafeExamBrowser.Contracts/UserInterface/ITaskbar.cs b/SafeExamBrowser.Contracts/UserInterface/ITaskbar.cs index 9458bf7a..abbaf869 100644 --- a/SafeExamBrowser.Contracts/UserInterface/ITaskbar.cs +++ b/SafeExamBrowser.Contracts/UserInterface/ITaskbar.cs @@ -12,5 +12,6 @@ namespace SafeExamBrowser.Contracts.UserInterface { void SetPosition(int x, int y); void SetSize(int widht, int height); + void Show(); } } diff --git a/SafeExamBrowser.Core/Configuration/Settings.cs b/SafeExamBrowser.Core/Configuration/Settings.cs index 111f08da..b55e8a76 100644 --- a/SafeExamBrowser.Core/Configuration/Settings.cs +++ b/SafeExamBrowser.Core/Configuration/Settings.cs @@ -15,6 +15,17 @@ namespace SafeExamBrowser.Core.Configuration { public class Settings : ISettings { + public string CopyrightInfo + { + get + { + var executable = Assembly.GetEntryAssembly(); + var copyright = executable.GetCustomAttribute().Copyright; + + return copyright; + } + } + public string LogFolderPath { get @@ -27,21 +38,27 @@ namespace SafeExamBrowser.Core.Configuration { get { - var executable = Assembly.GetEntryAssembly(); var newline = Environment.NewLine; - var version = executable.GetCustomAttribute().InformationalVersion; + var executable = Assembly.GetEntryAssembly(); var title = executable.GetCustomAttribute().Title; - var copyright = executable.GetCustomAttribute().Copyright; - var titleLine = $"/* {title}, Version {version}{newline}"; - var copyrightLine = $"/* {copyright}{newline}"; + var titleLine = $"/* {title}, Version {ProgramVersion}{newline}"; + var copyrightLine = $"/* {CopyrightInfo}{newline}"; var emptyLine = $"/* {newline}"; - var license1 = $"/* The source code of this application is subject to the terms of the Mozilla Public{newline}"; - var license2 = $"/* License, v. 2.0. If a copy of the MPL was not distributed with this software, You{newline}"; - var license3 = $"/* can obtain one at http://mozilla.org/MPL/2.0/.{newline}"; - var github = $"/* For more information or to issue bug reports, see https://github.com/SafeExamBrowser.{newline}"; + var githubLine = $"/* Please visit https://github.com/SafeExamBrowser for more information."; - return $"{titleLine}{copyrightLine}{emptyLine}{license1}{license2}{license3}{emptyLine}{github}"; + return $"{titleLine}{copyrightLine}{emptyLine}{githubLine}"; + } + } + + public string ProgramVersion + { + get + { + var executable = Assembly.GetEntryAssembly(); + var version = executable.GetCustomAttribute().InformationalVersion; + + return version; } } } diff --git a/SafeExamBrowser.Core/Configuration/ShutdownController.cs b/SafeExamBrowser.Core/Configuration/ShutdownController.cs index c46bb32e..643fba22 100644 --- a/SafeExamBrowser.Core/Configuration/ShutdownController.cs +++ b/SafeExamBrowser.Core/Configuration/ShutdownController.cs @@ -33,6 +33,8 @@ namespace SafeExamBrowser.Core.Configuration { // TODO: // - Gather TODOs! + + logger.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}"); } catch (Exception e) { diff --git a/SafeExamBrowser.Core/Configuration/StartupController.cs b/SafeExamBrowser.Core/Configuration/StartupController.cs index 5d579f88..3faf63b9 100644 --- a/SafeExamBrowser.Core/Configuration/StartupController.cs +++ b/SafeExamBrowser.Core/Configuration/StartupController.cs @@ -19,31 +19,40 @@ namespace SafeExamBrowser.Core.Configuration { private ILogger logger; private IMessageBox messageBox; + private ISettings settings; private ISplashScreen splashScreen; + private ITaskbar taskbar; private IText text; - public StartupController(ILogger logger, IMessageBox messageBox, ISplashScreen splashScreen, IText text) + public StartupController(ILogger logger, IMessageBox messageBox, ISettings settings, ISplashScreen splashScreen, ITaskbar taskbar, IText text) { this.logger = logger; this.messageBox = messageBox; + this.settings = settings; this.splashScreen = splashScreen; + this.taskbar = taskbar; this.text = text; } - public void InitializeApplication(Action terminationCallback) + public bool TryInitializeApplication() { try { - logger.Info("Rendering splash screen."); + logger.Log(settings.LogHeader); + logger.Log($"{Environment.NewLine}# Application started at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}{Environment.NewLine}"); + logger.Info("Initiating startup procedure."); + logger.Subscribe(splashScreen); - splashScreen.Show(); + + splashScreen.SetMaxProgress(4); + splashScreen.UpdateProgress(); // TODO (depending on specification): // - WCF service connection, termination if not available // TODO: // - Parse command line arguments - // - Detecting operating system and logging information + // - Detecting operating system and log that information // - Logging of all running processes // - Setting of wallpaper // - Initialization of taskbar @@ -54,21 +63,28 @@ namespace SafeExamBrowser.Core.Configuration Thread.Sleep(3000); + splashScreen.UpdateProgress(); logger.Info("Baapa-dee boopa-dee!"); Thread.Sleep(3000); + splashScreen.UpdateProgress(); logger.Info("Closing splash screen."); - logger.Unsubscribe(splashScreen); - splashScreen.Close(); + Thread.Sleep(3000); + + splashScreen.UpdateProgress(); + logger.Unsubscribe(splashScreen); logger.Info("Application successfully initialized!"); + + return true; } catch (Exception e) { logger.Error($"Failed to initialize application!", e); messageBox.Show(text.Get(Key.MessageBox_StartupError), text.Get(Key.MessageBox_StartupErrorTitle), icon: MessageBoxIcon.Error); - terminationCallback?.Invoke(); + + return false; } } } diff --git a/SafeExamBrowser.Core/I18n/Text.xml b/SafeExamBrowser.Core/I18n/Text.xml index f25c4eb0..bd495c9e 100644 --- a/SafeExamBrowser.Core/I18n/Text.xml +++ b/SafeExamBrowser.Core/I18n/Text.xml @@ -2,8 +2,6 @@ An unexpected error occurred during the shutdown procedure! Please consult the application log for more information... Shutdown Error - You can only run one instance of SEB at a time. - Startup Not Allowed An unexpected error occurred during the startup procedure! Please consult the application log for more information... Startup Error \ No newline at end of file diff --git a/SafeExamBrowser.Core/Logging/LogFileWriter.cs b/SafeExamBrowser.Core/Logging/LogFileWriter.cs index 0ac5dc7a..a5e78d6b 100644 --- a/SafeExamBrowser.Core/Logging/LogFileWriter.cs +++ b/SafeExamBrowser.Core/Logging/LogFileWriter.cs @@ -53,8 +53,9 @@ namespace SafeExamBrowser.Core.Logging { var date = message.DateTime.ToString("yyyy-MM-dd HH:mm:ss.fff"); var severity = message.Severity.ToString().ToUpper(); + var threadInfo = $"{message.ThreadInfo.Id}{(message.ThreadInfo.HasName ? ": " + message.ThreadInfo.Name : string.Empty)}"; - Write($"{date} [{message.ThreadId}] - {severity}: {message.Message}"); + Write($"{date} [{threadInfo}] - {severity}: {message.Message}"); } private void Write(string content) diff --git a/SafeExamBrowser.Core/Logging/LogMessage.cs b/SafeExamBrowser.Core/Logging/LogMessage.cs index e4301f8a..5f35ad37 100644 --- a/SafeExamBrowser.Core/Logging/LogMessage.cs +++ b/SafeExamBrowser.Core/Logging/LogMessage.cs @@ -11,24 +11,29 @@ using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Core.Entities { - public class LogMessage : ILogMessage + class LogMessage : ILogMessage { public DateTime DateTime { get; private set; } public LogLevel Severity { get; private set; } public string Message { get; private set; } - public int ThreadId { get; private set; } + public IThreadInfo ThreadInfo { get; private set; } - public LogMessage(DateTime dateTime, LogLevel severity, int threadId, string message) + public LogMessage(DateTime dateTime, LogLevel severity, string message, IThreadInfo threadInfo) { + if (threadInfo == null) + { + throw new ArgumentNullException(nameof(threadInfo)); + } + DateTime = dateTime; Severity = severity; Message = message; - ThreadId = threadId; + ThreadInfo = threadInfo; } public object Clone() { - return new LogMessage(DateTime, Severity, ThreadId, Message); + return new LogMessage(DateTime, Severity, Message, ThreadInfo.Clone() as IThreadInfo); } } } diff --git a/SafeExamBrowser.Core/Logging/Logger.cs b/SafeExamBrowser.Core/Logging/Logger.cs index edae921e..5660c700 100644 --- a/SafeExamBrowser.Core/Logging/Logger.cs +++ b/SafeExamBrowser.Core/Logging/Logger.cs @@ -106,8 +106,10 @@ namespace SafeExamBrowser.Core.Logging private void Add(LogLevel severity, string message) { var threadId = Thread.CurrentThread.ManagedThreadId; + var threadName = Thread.CurrentThread.Name; + var threadInfo = new ThreadInfo(threadId, threadName); - Add(new LogMessage(DateTime.Now, severity, threadId, message)); + Add(new LogMessage(DateTime.Now, severity, message, threadInfo)); } private void Add(ILogContent content) diff --git a/SafeExamBrowser.Core/Logging/ThreadInfo.cs b/SafeExamBrowser.Core/Logging/ThreadInfo.cs new file mode 100644 index 00000000..d7b7a666 --- /dev/null +++ b/SafeExamBrowser.Core/Logging/ThreadInfo.cs @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System; +using SafeExamBrowser.Contracts.Logging; + +namespace SafeExamBrowser.Core.Logging +{ + class ThreadInfo : IThreadInfo + { + public int Id { get; private set; } + public string Name { get; private set; } + + public bool HasName + { + get { return !String.IsNullOrWhiteSpace(Name); } + } + + public ThreadInfo(int id, string name = null) + { + Id = id; + Name = name; + } + + public object Clone() + { + return new ThreadInfo(Id, Name); + } + } +} diff --git a/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj b/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj index c7e4f48a..f05e7753 100644 --- a/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj +++ b/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj @@ -49,6 +49,7 @@ + diff --git a/SafeExamBrowser.UserInterface/Images/SplashScreen.png b/SafeExamBrowser.UserInterface/Images/SplashScreen.png new file mode 100644 index 00000000..c56dd2b0 Binary files /dev/null and b/SafeExamBrowser.UserInterface/Images/SplashScreen.png differ diff --git a/SafeExamBrowser.UserInterface/SafeExamBrowser.UserInterface.csproj b/SafeExamBrowser.UserInterface/SafeExamBrowser.UserInterface.csproj index acb4423c..f5f9645c 100644 --- a/SafeExamBrowser.UserInterface/SafeExamBrowser.UserInterface.csproj +++ b/SafeExamBrowser.UserInterface/SafeExamBrowser.UserInterface.csproj @@ -66,6 +66,7 @@ Taskbar.xaml + ResXFileCodeGenerator @@ -92,5 +93,8 @@ SafeExamBrowser.Contracts + + + \ No newline at end of file diff --git a/SafeExamBrowser.UserInterface/SplashScreen.xaml b/SafeExamBrowser.UserInterface/SplashScreen.xaml index 6f04d7f1..f8727931 100644 --- a/SafeExamBrowser.UserInterface/SplashScreen.xaml +++ b/SafeExamBrowser.UserInterface/SplashScreen.xaml @@ -3,23 +3,27 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:local="clr-namespace:SafeExamBrowser.UserInterface" mc:Ignorable="d" - Title="SplashScreen" Height="200" Width="350" WindowStyle="None" AllowsTransparency="True" Topmost="True" - WindowStartupLocation="CenterScreen" Cursor="Wait"> + Title="SplashScreen" Height="200" Width="350" WindowStyle="None" AllowsTransparency="True" WindowStartupLocation="CenterScreen" Cursor="Wait"> - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/SafeExamBrowser.UserInterface/SplashScreen.xaml.cs b/SafeExamBrowser.UserInterface/SplashScreen.xaml.cs index 9cbd9209..583bb8b7 100644 --- a/SafeExamBrowser.UserInterface/SplashScreen.xaml.cs +++ b/SafeExamBrowser.UserInterface/SplashScreen.xaml.cs @@ -7,21 +7,47 @@ */ using System.Windows; +using System.Windows.Documents; +using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.UserInterface; +using SafeExamBrowser.UserInterface.ViewModels; namespace SafeExamBrowser.UserInterface { public partial class SplashScreen : Window, ISplashScreen { - public SplashScreen() + private SplashScreenViewModel model = new SplashScreenViewModel(); + + public SplashScreen(ISettings settings) { InitializeComponent(); + + StatusTextBlock.DataContext = model; + ProgressBar.DataContext = model; + + InfoTextBlock.Inlines.Add(new Run($"Version {settings.ProgramVersion}") { FontStyle = FontStyles.Italic }); + InfoTextBlock.Inlines.Add(new LineBreak()); + InfoTextBlock.Inlines.Add(new LineBreak()); + InfoTextBlock.Inlines.Add(new Run(settings.CopyrightInfo) { FontSize = 10 }); } public void Notify(ILogContent content) { - // TODO + if (content is ILogMessage) + { + model.Status = (content as ILogMessage).Message; + } + } + + public void SetMaxProgress(int max) + { + model.MaxProgress = max; + } + + public void UpdateProgress() + { + model.CurrentProgress += 1; } } } diff --git a/SafeExamBrowser.UserInterface/Taskbar.xaml b/SafeExamBrowser.UserInterface/Taskbar.xaml index df082d53..46fa7371 100644 --- a/SafeExamBrowser.UserInterface/Taskbar.xaml +++ b/SafeExamBrowser.UserInterface/Taskbar.xaml @@ -5,11 +5,16 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:SafeExamBrowser.UserInterface" mc:Ignorable="d" - Title="Taskbar" Height="40" Width="300" WindowStyle="None" AllowsTransparency="True" Topmost="True"> + Title="Taskbar" Height="40" Width="750" WindowStyle="None" AllowsTransparency="True" Topmost="True"> - + + + + + + diff --git a/SafeExamBrowser.UserInterface/ViewModels/SplashScreenViewModel.cs b/SafeExamBrowser.UserInterface/ViewModels/SplashScreenViewModel.cs new file mode 100644 index 00000000..e3d858c2 --- /dev/null +++ b/SafeExamBrowser.UserInterface/ViewModels/SplashScreenViewModel.cs @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System.ComponentModel; + +namespace SafeExamBrowser.UserInterface.ViewModels +{ + class SplashScreenViewModel : INotifyPropertyChanged + { + private int currentProgress; + private int maxProgress; + private string status; + + public event PropertyChangedEventHandler PropertyChanged; + + public int CurrentProgress + { + get + { + return currentProgress; + } + set + { + currentProgress = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentProgress))); + } + } + + public int MaxProgress + { + get + { + return maxProgress; + } + set + { + maxProgress = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MaxProgress))); + } + } + + public string Status + { + get + { + return status; + } + set + { + status = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Status))); + } + } + } +} diff --git a/SafeExamBrowser/App.cs b/SafeExamBrowser/App.cs index 64d61499..4eb077df 100644 --- a/SafeExamBrowser/App.cs +++ b/SafeExamBrowser/App.cs @@ -9,7 +9,6 @@ using System; using System.Threading; using System.Windows; -using SafeExamBrowser.Contracts.I18n; namespace SafeExamBrowser { @@ -17,6 +16,8 @@ namespace SafeExamBrowser { private static readonly Mutex mutex = new Mutex(true, "safe_exam_browser_single_instance_mutex"); + private CompositionRoot instances; + [STAThread] public static void Main() { @@ -32,36 +33,59 @@ namespace SafeExamBrowser private static void StartApplication() { - var root = new CompositionRoot(); - - root.BuildObjectGraph(); - - root.Logger.Log(root.Settings.LogHeader); - root.Logger.Log($"# Application started at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}{Environment.NewLine}"); - - if (NoInstanceRunning(root)) + if (NoInstanceRunning()) { - var app = new App(); - - root.Logger.Info("No instance is running, initiating startup procedure."); - - app.Startup += (o, args) => root.StartupController.InitializeApplication(app.Shutdown); - app.Exit += (o, args) => root.ShutdownController.FinalizeApplication(); - - app.Run(root.Taskbar); + new App().Run(); } else { - root.Logger.Info("Could not start because of an already running instance."); - root.MessageBox.Show(root.Text.Get(Key.MessageBox_SingleInstance), root.Text.Get(Key.MessageBox_SingleInstanceTitle)); + MessageBox.Show("You can only run one instance of SEB at a time.", "Startup Not Allowed"); } - - root.Logger.Log($"# Application terminating normally at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}"); } - private static bool NoInstanceRunning(CompositionRoot root) + private static bool NoInstanceRunning() { return mutex.WaitOne(TimeSpan.Zero, true); } + + protected override void OnStartup(StartupEventArgs e) + { + base.OnStartup(e); + + var initializationThread = new Thread(Initialize); + + instances = new CompositionRoot(); + instances.BuildObjectGraph(); + instances.SplashScreen.Show(); + + MainWindow = instances.SplashScreen; + + initializationThread.SetApartmentState(ApartmentState.STA); + initializationThread.Name = "Initialization Thread"; + initializationThread.Start(); + } + + protected override void OnExit(ExitEventArgs e) + { + instances.ShutdownController.FinalizeApplication(); + + base.OnExit(e); + } + + private void Initialize() + { + var success = instances.StartupController.TryInitializeApplication(); + + if (success) + { + instances.Taskbar.Dispatcher.Invoke(() => + { + MainWindow = instances.Taskbar; + MainWindow.Show(); + }); + } + + //instances.SplashScreen.Dispatcher.Invoke(instances.SplashScreen.Close); + } } } diff --git a/SafeExamBrowser/CompositionRoot.cs b/SafeExamBrowser/CompositionRoot.cs index edf88c98..d5ed86fb 100644 --- a/SafeExamBrowser/CompositionRoot.cs +++ b/SafeExamBrowser/CompositionRoot.cs @@ -6,7 +6,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System.Windows; using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; @@ -24,24 +23,24 @@ namespace SafeExamBrowser public IMessageBox MessageBox { get; private set; } public ISettings Settings { get; private set; } public IShutdownController ShutdownController { get; set; } - public ISplashScreen SplashScreen { get; private set; } public IStartupController StartupController { get; private set; } public IText Text { get; private set; } - public Window Taskbar { get; private set; } + public SplashScreen SplashScreen { get; private set; } + public Taskbar Taskbar { get; private set; } public void BuildObjectGraph() { MessageBox = new WpfMessageBox(); Settings = new Settings(); - SplashScreen = new UserInterface.SplashScreen(); Taskbar = new Taskbar(); - Text = new Text(new XmlTextResource()); Logger = new Logger(); Logger.Subscribe(new LogFileWriter(Settings)); + Text = new Text(new XmlTextResource()); + SplashScreen = new SplashScreen(Settings); ShutdownController = new ShutdownController(Logger, MessageBox, Text); - StartupController = new StartupController(Logger, MessageBox, SplashScreen, Text); + StartupController = new StartupController(Logger, MessageBox, Settings, SplashScreen, Taskbar, Text); } } }