Found solution to multi-threading issue at application startup and created draft of startup procedure.
This commit is contained in:
parent
8adb72bb0f
commit
d86bd79252
4 changed files with 181 additions and 80 deletions
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue