Found solution to multi-threading issue at application startup and created draft of startup procedure.

This commit is contained in:
Damian Büchel 2017-07-13 08:51:00 +02:00
parent 8adb72bb0f
commit d86bd79252
4 changed files with 181 additions and 80 deletions

View file

@ -7,6 +7,8 @@
*/ */
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading; using System.Threading;
using SafeExamBrowser.Contracts.Behaviour; using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.Configuration;
@ -27,6 +29,23 @@ namespace SafeExamBrowser.Core.Behaviour
private IText text; private IText text;
private IUiElementFactory uiFactory; private IUiElementFactory uiFactory;
private IEnumerable<Action> StartupOperations
{
get
{
yield return InitializeApplicationLog;
yield return HandleCommandLineArguments;
yield return DetectOperatingSystem;
yield return EstablishWcfServiceConnection;
yield return DeactivateWindowsFeatures;
yield return InitializeProcessMonitoring;
yield return InitializeWorkArea;
yield return InitializeTaskbar;
yield return InitializeBrowser;
yield return FinishInitialization;
}
}
public StartupController(IApplicationInfo browserInfo, ILogger logger, IMessageBox messageBox, ISettings settings, ISplashScreen splashScreen, ITaskbar taskbar, IText text, IUiElementFactory uiFactory) public StartupController(IApplicationInfo browserInfo, ILogger logger, IMessageBox messageBox, ISettings settings, ISplashScreen splashScreen, ITaskbar taskbar, IText text, IUiElementFactory uiFactory)
{ {
this.browserInfo = browserInfo; this.browserInfo = browserInfo;
@ -43,47 +62,15 @@ namespace SafeExamBrowser.Core.Behaviour
{ {
try try
{ {
logger.Log(settings.LogHeader); foreach (var operation in StartupOperations)
logger.Log($"{Environment.NewLine}# Application started at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}{Environment.NewLine}"); {
logger.Info("Initiating startup procedure."); operation();
logger.Subscribe(splashScreen);
splashScreen.SetMaxProgress(3);
logger.Info("Initializing browser.");
var browserButton = uiFactory.CreateButton(browserInfo);
taskbar.AddButton(browserButton);
splashScreen.UpdateProgress(); splashScreen.UpdateProgress();
// TODO (depending on specification): // TODO: Remove!
// - WCF service connection, termination if not available Thread.Sleep(250);
}
// TODO:
// - Parse command line arguments
// - Detecting operating system and log that information
// - Logging of all running processes
// - Setting of wallpaper
// - Initialization of taskbar
// - Killing explorer.exe
// - Minimizing all open windows
// - Emptying clipboard
// - Activation of process monitoring
Thread.Sleep(1000);
splashScreen.UpdateProgress();
logger.Info("Baapa-dee boopa-dee!");
Thread.Sleep(1000);
splashScreen.UpdateProgress();
logger.Info("Closing splash screen.");
Thread.Sleep(1000);
logger.Unsubscribe(splashScreen);
logger.Info("Application successfully initialized!");
return true; return true;
} }
@ -95,5 +82,88 @@ namespace SafeExamBrowser.Core.Behaviour
return false; return false;
} }
} }
private void InitializeApplicationLog()
{
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.SetMaxProgress(StartupOperations.Count());
}
private void HandleCommandLineArguments()
{
logger.Info("Parsing command line arguments.");
// TODO
}
private void DetectOperatingSystem()
{
logger.Info("Detecting operating system.");
// TODO
}
private void EstablishWcfServiceConnection()
{
logger.Info("Establishing connection to WCF service.");
// TODO
}
private void DeactivateWindowsFeatures()
{
logger.Info("Deactivating Windows Update.");
// TODO
logger.Info("Disabling lock screen options.");
// TODO
}
private void InitializeProcessMonitoring()
{
logger.Info("Initializing process monitoring.");
// TODO
}
private void InitializeWorkArea()
{
logger.Info("Initializing work area.");
// TODO
// - Killing explorer.exe
// - Minimizing all open windows
// - Emptying clipboard
}
private void InitializeTaskbar()
{
logger.Info("Initializing taskbar.");
// TODO
}
private void InitializeBrowser()
{
logger.Info("Initializing browser.");
var browserButton = uiFactory.CreateButton(browserInfo);
// TODO
taskbar.AddButton(browserButton);
}
private void FinishInitialization()
{
logger.Info("Application successfully initialized!");
logger.Unsubscribe(splashScreen);
}
} }
} }

View file

@ -22,14 +22,7 @@ namespace SafeExamBrowser.UserInterface
public SplashScreen(ISettings settings) public SplashScreen(ISettings settings)
{ {
InitializeComponent(); InitializeComponent();
InitializeSplashScreen(settings);
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) public void Notify(ILogContent content)
@ -49,5 +42,19 @@ namespace SafeExamBrowser.UserInterface
{ {
model.CurrentProgress += amount; model.CurrentProgress += amount;
} }
private void InitializeSplashScreen(ISettings settings)
{
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 });
StatusTextBlock.DataContext = model;
ProgressBar.DataContext = model;
// To prevent the progress bar going from max to min value at startup...
model.MaxProgress = 1;
}
} }
} }

View file

@ -15,7 +15,7 @@ namespace SafeExamBrowser
public class App : Application public class App : Application
{ {
private static readonly Mutex mutex = new Mutex(true, "safe_exam_browser_single_instance_mutex"); private static readonly Mutex mutex = new Mutex(true, "safe_exam_browser_single_instance_mutex");
private CompositionRoot instances; private CompositionRoot instances = new CompositionRoot();
[STAThread] [STAThread]
public static void Main() public static void Main()
@ -51,17 +51,8 @@ namespace SafeExamBrowser
{ {
base.OnStartup(e); base.OnStartup(e);
var initializationThread = new Thread(Initialize); ShowSplashScreen();
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) protected override void OnExit(ExitEventArgs e)
@ -73,22 +64,43 @@ namespace SafeExamBrowser
private void Initialize() private void Initialize()
{ {
instances.BuildObjectGraph();
var success = instances.StartupController.TryInitializeApplication(); var success = instances.StartupController.TryInitializeApplication();
if (success) if (success)
{
Dispatcher.Invoke(() =>
{ {
MainWindow = instances.Taskbar; MainWindow = instances.Taskbar;
MainWindow.Show(); MainWindow.Show();
});
} }
else else
{ {
Dispatcher.Invoke(Shutdown); Shutdown();
} }
Dispatcher.Invoke(instances.SplashScreen.Close); instances.SplashScreen?.Dispatcher.InvokeAsync(instances.SplashScreen.Close);
}
private void ShowSplashScreen()
{
var splashReadyEvent = new AutoResetEvent(false);
var splashScreenThread = new Thread(() =>
{
instances.SplashScreen = new UserInterface.SplashScreen(instances.Settings);
instances.SplashScreen.Closed += (o, args) => instances.SplashScreen.Dispatcher.InvokeShutdown();
instances.SplashScreen.Show();
splashReadyEvent.Set();
System.Windows.Threading.Dispatcher.Run();
});
splashScreenThread.SetApartmentState(ApartmentState.STA);
splashScreenThread.Name = "Splash Screen Thread";
splashScreenThread.IsBackground = true;
splashScreenThread.Start();
splashReadyEvent.WaitOne();
} }
} }
} }

View file

@ -8,6 +8,10 @@
using SafeExamBrowser.Browser; using SafeExamBrowser.Browser;
using SafeExamBrowser.Contracts.Behaviour; using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
using SafeExamBrowser.Core.Behaviour; using SafeExamBrowser.Core.Behaviour;
using SafeExamBrowser.Core.Configuration; using SafeExamBrowser.Core.Configuration;
using SafeExamBrowser.Core.I18n; using SafeExamBrowser.Core.I18n;
@ -18,27 +22,35 @@ namespace SafeExamBrowser
{ {
internal class CompositionRoot internal class CompositionRoot
{ {
public IShutdownController ShutdownController { get; set; } private IApplicationInfo browserInfo;
public IStartupController StartupController { get; private set; } private IMessageBox messageBox;
private ILogger logger;
private IUiElementFactory uiFactory;
private IText text;
public SplashScreen SplashScreen { get; private set; } public ISettings Settings { get; private set; }
public IShutdownController ShutdownController { get; private set; }
public IStartupController StartupController { get; private set; }
public SplashScreen SplashScreen { get; set; }
public Taskbar Taskbar { get; private set; } public Taskbar Taskbar { get; private set; }
public CompositionRoot()
{
browserInfo = new BrowserApplicationInfo();
messageBox = new WpfMessageBox();
logger = new Logger();
Settings = new Settings();
Taskbar = new Taskbar();
uiFactory = new UiElementFactory();
}
public void BuildObjectGraph() public void BuildObjectGraph()
{ {
var browserInfo = new BrowserApplicationInfo(); logger.Subscribe(new LogFileWriter(Settings));
var messageBox = new WpfMessageBox();
var settings = new Settings();
var logger = new Logger();
var text = new Text(new XmlTextResource());
var uiFactory = new UiElementFactory();
logger.Subscribe(new LogFileWriter(settings)); text = new Text(new XmlTextResource());
Taskbar = new Taskbar();
SplashScreen = new SplashScreen(settings);
ShutdownController = new ShutdownController(logger, messageBox, text); ShutdownController = new ShutdownController(logger, messageBox, text);
StartupController = new StartupController(browserInfo, logger, messageBox, settings, SplashScreen, Taskbar, text, uiFactory); StartupController = new StartupController(browserInfo, logger, messageBox, Settings, SplashScreen, Taskbar, text, uiFactory);
} }
} }
} }