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.Collections.Generic;
using System.Linq;
using System.Threading;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Configuration;
@ -27,6 +29,23 @@ namespace SafeExamBrowser.Core.Behaviour
private IText text;
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)
{
this.browserInfo = browserInfo;
@ -43,47 +62,15 @@ namespace SafeExamBrowser.Core.Behaviour
{
try
{
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);
foreach (var operation in StartupOperations)
{
operation();
splashScreen.SetMaxProgress(3);
logger.Info("Initializing browser.");
splashScreen.UpdateProgress();
var browserButton = uiFactory.CreateButton(browserInfo);
taskbar.AddButton(browserButton);
splashScreen.UpdateProgress();
// TODO (depending on specification):
// - WCF service connection, termination if not available
// 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!");
// TODO: Remove!
Thread.Sleep(250);
}
return true;
}
@ -95,5 +82,88 @@ namespace SafeExamBrowser.Core.Behaviour
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)
{
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 });
InitializeSplashScreen(settings);
}
public void Notify(ILogContent content)
@ -49,5 +42,19 @@ namespace SafeExamBrowser.UserInterface
{
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
{
private static readonly Mutex mutex = new Mutex(true, "safe_exam_browser_single_instance_mutex");
private CompositionRoot instances;
private CompositionRoot instances = new CompositionRoot();
[STAThread]
public static void Main()
@ -51,17 +51,8 @@ namespace SafeExamBrowser
{
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();
ShowSplashScreen();
Initialize();
}
protected override void OnExit(ExitEventArgs e)
@ -73,22 +64,43 @@ namespace SafeExamBrowser
private void Initialize()
{
instances.BuildObjectGraph();
var success = instances.StartupController.TryInitializeApplication();
if (success)
{
Dispatcher.Invoke(() =>
{
MainWindow = instances.Taskbar;
MainWindow.Show();
});
MainWindow = instances.Taskbar;
MainWindow.Show();
}
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.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.Configuration;
using SafeExamBrowser.Core.I18n;
@ -18,27 +22,35 @@ namespace SafeExamBrowser
{
internal class CompositionRoot
{
public IShutdownController ShutdownController { get; set; }
public IStartupController StartupController { get; private set; }
private IApplicationInfo browserInfo;
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 CompositionRoot()
{
browserInfo = new BrowserApplicationInfo();
messageBox = new WpfMessageBox();
logger = new Logger();
Settings = new Settings();
Taskbar = new Taskbar();
uiFactory = new UiElementFactory();
}
public void BuildObjectGraph()
{
var browserInfo = new BrowserApplicationInfo();
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));
logger.Subscribe(new LogFileWriter(Settings));
Taskbar = new Taskbar();
SplashScreen = new SplashScreen(settings);
text = new Text(new XmlTextResource());
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);
}
}
}