From 9ab04ecc77b592037754ab7392d6ea16df09fac8 Mon Sep 17 00:00:00 2001 From: dbuechel Date: Wed, 26 Jul 2017 14:36:20 +0200 Subject: [PATCH] Implemented basic monitoring of Windows explorer and added event controller module. --- .../Behaviour/IEventController.cs | 23 ++++++++ SafeExamBrowser.Contracts/I18n/Key.cs | 3 ++ SafeExamBrowser.Contracts/Logging/LogLevel.cs | 2 +- .../Monitoring/IProcessMonitor.cs | 10 +++- .../SafeExamBrowser.Contracts.csproj | 1 + .../UserInterface/ITaskbar.cs | 5 ++ .../Logging/LoggerTests.cs | 4 +- .../Behaviour/EventController.cs | 53 +++++++++++++++++++ ...zationOperation.cs => BrowserOperation.cs} | 8 +-- .../Operations/EventControllerOperation.cs | 45 ++++++++++++++++ ...peration.cs => ProcessMonitorOperation.cs} | 4 +- ...zationOperation.cs => TaskbarOperation.cs} | 4 +- ...Operation.cs => WindowMonitorOperation.cs} | 4 +- .../Behaviour/ShutdownController.cs | 18 ++++--- .../Behaviour/StartupController.cs | 17 +++--- SafeExamBrowser.Core/I18n/Text.xml | 39 +++++++------- SafeExamBrowser.Core/Logging/Logger.cs | 2 +- .../SafeExamBrowser.Core.csproj | 10 ++-- .../Processes/ProcessMonitor.cs | 31 ++++++++++- .../SafeExamBrowser.Monitoring.csproj | 1 + SafeExamBrowser.UserInterface/Taskbar.xaml.cs | 46 +++++++++------- SafeExamBrowser/CompositionRoot.cs | 11 ++-- 22 files changed, 259 insertions(+), 82 deletions(-) create mode 100644 SafeExamBrowser.Contracts/Behaviour/IEventController.cs create mode 100644 SafeExamBrowser.Core/Behaviour/EventController.cs rename SafeExamBrowser.Core/Behaviour/Operations/{BrowserInitializationOperation.cs => BrowserOperation.cs} (88%) create mode 100644 SafeExamBrowser.Core/Behaviour/Operations/EventControllerOperation.cs rename SafeExamBrowser.Core/Behaviour/Operations/{ProcessMonitoringOperation.cs => ProcessMonitorOperation.cs} (91%) rename SafeExamBrowser.Core/Behaviour/Operations/{TaskbarInitializationOperation.cs => TaskbarOperation.cs} (86%) rename SafeExamBrowser.Core/Behaviour/Operations/{WindowMonitoringOperation.cs => WindowMonitorOperation.cs} (90%) diff --git a/SafeExamBrowser.Contracts/Behaviour/IEventController.cs b/SafeExamBrowser.Contracts/Behaviour/IEventController.cs new file mode 100644 index 00000000..6b518de1 --- /dev/null +++ b/SafeExamBrowser.Contracts/Behaviour/IEventController.cs @@ -0,0 +1,23 @@ +/* + * 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/. + */ + +namespace SafeExamBrowser.Contracts.Behaviour +{ + public interface IEventController + { + /// + /// Wires up the event handling, i.e. subscribes to all relevant application events. + /// + void Start(); + + /// + /// Removes all event subscriptions. + /// + void Stop(); + } +} diff --git a/SafeExamBrowser.Contracts/I18n/Key.cs b/SafeExamBrowser.Contracts/I18n/Key.cs index af6dbb2f..70475318 100644 --- a/SafeExamBrowser.Contracts/I18n/Key.cs +++ b/SafeExamBrowser.Contracts/I18n/Key.cs @@ -27,9 +27,12 @@ namespace SafeExamBrowser.Contracts.I18n SplashScreen_InitializeWorkingArea, SplashScreen_RestoreWorkingArea, SplashScreen_ShutdownProcedure, + SplashScreen_StartEventHandling, SplashScreen_StartupProcedure, + SplashScreen_StopEventHandling, SplashScreen_StopProcessMonitoring, SplashScreen_StopWindowMonitoring, + SplashScreen_TerminateBrowser, SplashScreen_WaitExplorerStartup, SplashScreen_WaitExplorerTermination, Version diff --git a/SafeExamBrowser.Contracts/Logging/LogLevel.cs b/SafeExamBrowser.Contracts/Logging/LogLevel.cs index 4eb47a55..69a897b2 100644 --- a/SafeExamBrowser.Contracts/Logging/LogLevel.cs +++ b/SafeExamBrowser.Contracts/Logging/LogLevel.cs @@ -14,7 +14,7 @@ namespace SafeExamBrowser.Contracts.Logging public enum LogLevel { Info = 1, - Warn = 2, + Warning = 2, Error = 3 } } diff --git a/SafeExamBrowser.Contracts/Monitoring/IProcessMonitor.cs b/SafeExamBrowser.Contracts/Monitoring/IProcessMonitor.cs index 7b12ba0c..94157ca8 100644 --- a/SafeExamBrowser.Contracts/Monitoring/IProcessMonitor.cs +++ b/SafeExamBrowser.Contracts/Monitoring/IProcessMonitor.cs @@ -8,8 +8,16 @@ namespace SafeExamBrowser.Contracts.Monitoring { + public delegate void ExplorerStartedHandler(); + public interface IProcessMonitor { + /// + /// Event fired when the process monitor observes that a new instance of + /// the Windows explorer has been started. + /// + event ExplorerStartedHandler ExplorerStarted; + /// /// Starts a new instance of the Windows explorer shell. /// @@ -17,7 +25,7 @@ namespace SafeExamBrowser.Contracts.Monitoring /// /// Starts monitoring the Windows explorer, i.e. any newly created instances of - /// explorer.exe will automatically be terminated. + /// explorer.exe will trigger the ExplorerStarted event. /// void StartMonitoringExplorer(); diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj index c5d07b3d..ddd82773 100644 --- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj +++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj @@ -59,6 +59,7 @@ + diff --git a/SafeExamBrowser.Contracts/UserInterface/ITaskbar.cs b/SafeExamBrowser.Contracts/UserInterface/ITaskbar.cs index 0a91efaa..d463331e 100644 --- a/SafeExamBrowser.Contracts/UserInterface/ITaskbar.cs +++ b/SafeExamBrowser.Contracts/UserInterface/ITaskbar.cs @@ -25,5 +25,10 @@ namespace SafeExamBrowser.Contracts.UserInterface /// Returns the absolute height of the taskbar (i.e. in physical pixels). /// int GetAbsoluteHeight(); + + /// + /// Moves the taskbar to the bottom of and resizes it according to the current working area. + /// + void InitializeBounds(); } } diff --git a/SafeExamBrowser.Core.UnitTests/Logging/LoggerTests.cs b/SafeExamBrowser.Core.UnitTests/Logging/LoggerTests.cs index 94acaf1c..23f08876 100644 --- a/SafeExamBrowser.Core.UnitTests/Logging/LoggerTests.cs +++ b/SafeExamBrowser.Core.UnitTests/Logging/LoggerTests.cs @@ -38,7 +38,7 @@ namespace SafeExamBrowser.Core.UnitTests.Logging Assert.IsTrue((log[0] as ILogMessage).Severity == LogLevel.Info); Assert.IsTrue(warn.Equals((log[1] as ILogMessage).Message)); - Assert.IsTrue((log[1] as ILogMessage).Severity == LogLevel.Warn); + Assert.IsTrue((log[1] as ILogMessage).Severity == LogLevel.Warning); Assert.IsTrue(error.Equals((log[2] as ILogMessage).Message)); Assert.IsTrue((log[2] as ILogMessage).Severity == LogLevel.Error); @@ -122,7 +122,7 @@ namespace SafeExamBrowser.Core.UnitTests.Logging Assert.IsTrue((messages[0] as ILogMessage).Severity == LogLevel.Info); Assert.IsTrue(message.Equals((messages[0] as ILogMessage).Message)); - Assert.IsTrue((messages[1] as ILogMessage).Severity == LogLevel.Warn); + Assert.IsTrue((messages[1] as ILogMessage).Severity == LogLevel.Warning); Assert.IsTrue(message.Equals((messages[1] as ILogMessage).Message)); } diff --git a/SafeExamBrowser.Core/Behaviour/EventController.cs b/SafeExamBrowser.Core/Behaviour/EventController.cs new file mode 100644 index 00000000..3004b473 --- /dev/null +++ b/SafeExamBrowser.Core/Behaviour/EventController.cs @@ -0,0 +1,53 @@ +/* + * 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 SafeExamBrowser.Contracts.Behaviour; +using SafeExamBrowser.Contracts.Configuration; +using SafeExamBrowser.Contracts.Logging; +using SafeExamBrowser.Contracts.Monitoring; +using SafeExamBrowser.Contracts.UserInterface; + +namespace SafeExamBrowser.Core.Behaviour +{ + public class EventController : IEventController + { + private IProcessMonitor processMonitor; + private ITaskbar taskbar; + private IWorkingArea workingArea; + private ILogger logger; + + public EventController(ILogger logger, IProcessMonitor processMonitor, ITaskbar taskbar, IWorkingArea workingArea) + { + this.logger = logger; + this.processMonitor = processMonitor; + this.taskbar = taskbar; + this.workingArea = workingArea; + } + + public void Start() + { + processMonitor.ExplorerStarted += ProcessMonitor_ExplorerStarted; + } + + public void Stop() + { + processMonitor.ExplorerStarted -= ProcessMonitor_ExplorerStarted; + } + + private void ProcessMonitor_ExplorerStarted() + { + logger.Info("Trying to shut down explorer..."); + processMonitor.CloseExplorerShell(); + logger.Info("Reinitializing working area..."); + workingArea.InitializeFor(taskbar); + logger.Info("Reinitializing taskbar bounds..."); + taskbar.InitializeBounds(); + logger.Info("Desktop successfully restored!"); + } + } +} diff --git a/SafeExamBrowser.Core/Behaviour/Operations/BrowserInitializationOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/BrowserOperation.cs similarity index 88% rename from SafeExamBrowser.Core/Behaviour/Operations/BrowserInitializationOperation.cs rename to SafeExamBrowser.Core/Behaviour/Operations/BrowserOperation.cs index 93bbbfc9..0b159e30 100644 --- a/SafeExamBrowser.Core/Behaviour/Operations/BrowserInitializationOperation.cs +++ b/SafeExamBrowser.Core/Behaviour/Operations/BrowserOperation.cs @@ -14,7 +14,7 @@ using SafeExamBrowser.Contracts.UserInterface; namespace SafeExamBrowser.Core.Behaviour.Operations { - public class BrowserInitializationOperation : IOperation + public class BrowserOperation : IOperation { private IApplicationController browserController; private IApplicationInfo browserInfo; @@ -24,7 +24,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations public ISplashScreen SplashScreen { private get; set; } - public BrowserInitializationOperation( + public BrowserOperation( IApplicationController browserController, IApplicationInfo browserInfo, ILogger logger, @@ -49,14 +49,14 @@ namespace SafeExamBrowser.Core.Behaviour.Operations browserController.RegisterApplicationButton(browserButton); taskbar.AddButton(browserButton); - logger.Info("Browser successfully initialized."); } public void Revert() { logger.Info("Terminating browser..."); + SplashScreen.UpdateText(Key.SplashScreen_TerminateBrowser); + browserController.Terminate(); - logger.Info("Browser successfully terminated."); } } } diff --git a/SafeExamBrowser.Core/Behaviour/Operations/EventControllerOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/EventControllerOperation.cs new file mode 100644 index 00000000..c859d9b3 --- /dev/null +++ b/SafeExamBrowser.Core/Behaviour/Operations/EventControllerOperation.cs @@ -0,0 +1,45 @@ +/* + * 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 SafeExamBrowser.Contracts.Behaviour; +using SafeExamBrowser.Contracts.I18n; +using SafeExamBrowser.Contracts.Logging; +using SafeExamBrowser.Contracts.UserInterface; + +namespace SafeExamBrowser.Core.Behaviour.Operations +{ + public class EventControllerOperation : IOperation + { + private ILogger logger; + private IEventController controller; + + public ISplashScreen SplashScreen { private get; set; } + + public EventControllerOperation(IEventController controller, ILogger logger) + { + this.controller = controller; + this.logger = logger; + } + + public void Perform() + { + logger.Info("Starting event handling..."); + SplashScreen.UpdateText(Key.SplashScreen_StartEventHandling); + + controller.Start(); + } + + public void Revert() + { + logger.Info("Stopping event handling..."); + SplashScreen.UpdateText(Key.SplashScreen_StopEventHandling); + + controller.Stop(); + } + } +} diff --git a/SafeExamBrowser.Core/Behaviour/Operations/ProcessMonitoringOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/ProcessMonitorOperation.cs similarity index 91% rename from SafeExamBrowser.Core/Behaviour/Operations/ProcessMonitoringOperation.cs rename to SafeExamBrowser.Core/Behaviour/Operations/ProcessMonitorOperation.cs index c60dc53e..7214df81 100644 --- a/SafeExamBrowser.Core/Behaviour/Operations/ProcessMonitoringOperation.cs +++ b/SafeExamBrowser.Core/Behaviour/Operations/ProcessMonitorOperation.cs @@ -14,14 +14,14 @@ using SafeExamBrowser.Contracts.UserInterface; namespace SafeExamBrowser.Core.Behaviour.Operations { - public class ProcessMonitoringOperation : IOperation + public class ProcessMonitorOperation : IOperation { private ILogger logger; private IProcessMonitor processMonitor; public ISplashScreen SplashScreen { private get; set; } - public ProcessMonitoringOperation(ILogger logger, IProcessMonitor processMonitor) + public ProcessMonitorOperation(ILogger logger, IProcessMonitor processMonitor) { this.logger = logger; this.processMonitor = processMonitor; diff --git a/SafeExamBrowser.Core/Behaviour/Operations/TaskbarInitializationOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/TaskbarOperation.cs similarity index 86% rename from SafeExamBrowser.Core/Behaviour/Operations/TaskbarInitializationOperation.cs rename to SafeExamBrowser.Core/Behaviour/Operations/TaskbarOperation.cs index 758b7910..0308d8de 100644 --- a/SafeExamBrowser.Core/Behaviour/Operations/TaskbarInitializationOperation.cs +++ b/SafeExamBrowser.Core/Behaviour/Operations/TaskbarOperation.cs @@ -14,7 +14,7 @@ using SafeExamBrowser.Contracts.UserInterface; namespace SafeExamBrowser.Core.Behaviour.Operations { - public class TaskbarInitializationOperation : IOperation + public class TaskbarOperation : IOperation { private ILogger logger; private ITaskbar taskbar; @@ -23,7 +23,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations public ISplashScreen SplashScreen { private get; set; } - public TaskbarInitializationOperation(ILogger logger, INotificationInfo aboutInfo, ITaskbar taskbar, IUiElementFactory uiFactory) + public TaskbarOperation(ILogger logger, INotificationInfo aboutInfo, ITaskbar taskbar, IUiElementFactory uiFactory) { this.logger = logger; this.aboutInfo = aboutInfo; diff --git a/SafeExamBrowser.Core/Behaviour/Operations/WindowMonitoringOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/WindowMonitorOperation.cs similarity index 90% rename from SafeExamBrowser.Core/Behaviour/Operations/WindowMonitoringOperation.cs rename to SafeExamBrowser.Core/Behaviour/Operations/WindowMonitorOperation.cs index 7b88f62e..a33ffd5e 100644 --- a/SafeExamBrowser.Core/Behaviour/Operations/WindowMonitoringOperation.cs +++ b/SafeExamBrowser.Core/Behaviour/Operations/WindowMonitorOperation.cs @@ -14,14 +14,14 @@ using SafeExamBrowser.Contracts.UserInterface; namespace SafeExamBrowser.Core.Behaviour.Operations { - public class WindowMonitoringOperation : IOperation + public class WindowMonitorOperation : IOperation { private ILogger logger; private IWindowMonitor windowMonitor; public ISplashScreen SplashScreen { private get; set; } - public WindowMonitoringOperation(ILogger logger, IWindowMonitor windowMonitor) + public WindowMonitorOperation(ILogger logger, IWindowMonitor windowMonitor) { this.logger = logger; this.windowMonitor = windowMonitor; diff --git a/SafeExamBrowser.Core/Behaviour/ShutdownController.cs b/SafeExamBrowser.Core/Behaviour/ShutdownController.cs index 9f459911..1cd53da7 100644 --- a/SafeExamBrowser.Core/Behaviour/ShutdownController.cs +++ b/SafeExamBrowser.Core/Behaviour/ShutdownController.cs @@ -37,18 +37,18 @@ namespace SafeExamBrowser.Core.Behaviour { try { - InitializeSplashScreen(); - RevertOperations(operations); - FinishFinalization(); + Initialize(); + Revert(operations); + Finish(); } catch (Exception e) { LogAndShowException(e); - FinishFinalization(false); + Finish(false); } } - private void RevertOperations(Queue operations) + private void Revert(Queue operations) { foreach (var operation in operations) { @@ -60,13 +60,15 @@ namespace SafeExamBrowser.Core.Behaviour } } - private void InitializeSplashScreen() + private void Initialize() { + logger.Log(string.Empty); + logger.Info("--- Initiating shutdown procedure ---"); + splashScreen = uiFactory.CreateSplashScreen(settings, text); splashScreen.SetIndeterminate(); splashScreen.UpdateText(Key.SplashScreen_ShutdownProcedure); splashScreen.InvokeShow(); - logger.Info("--- Initiating shutdown procedure ---"); } private void LogAndShowException(Exception e) @@ -75,7 +77,7 @@ namespace SafeExamBrowser.Core.Behaviour uiFactory.Show(text.Get(Key.MessageBox_ShutdownError), text.Get(Key.MessageBox_ShutdownErrorTitle), icon: MessageBoxIcon.Error); } - private void FinishFinalization(bool success = true) + private void Finish(bool success = true) { if (success) { diff --git a/SafeExamBrowser.Core/Behaviour/StartupController.cs b/SafeExamBrowser.Core/Behaviour/StartupController.cs index 494caac4..b648d69a 100644 --- a/SafeExamBrowser.Core/Behaviour/StartupController.cs +++ b/SafeExamBrowser.Core/Behaviour/StartupController.cs @@ -40,12 +40,9 @@ namespace SafeExamBrowser.Core.Behaviour { try { - InitializeApplicationLog(); - InitializeSplashScreen(operations.Count); - + Initialize(operations.Count); Perform(operations); - - FinishInitialization(); + Finish(); return true; } @@ -53,7 +50,7 @@ namespace SafeExamBrowser.Core.Behaviour { LogAndShowException(e); RevertOperations(); - FinishInitialization(false); + Finish(false); return false; } @@ -89,7 +86,7 @@ namespace SafeExamBrowser.Core.Behaviour } } - private void InitializeApplicationLog() + private void Initialize(int operationCount) { var titleLine = $"/* {settings.ProgramTitle}, Version {settings.ProgramVersion}{Environment.NewLine}"; var copyrightLine = $"/* {settings.ProgramCopyright}{Environment.NewLine}"; @@ -99,10 +96,7 @@ namespace SafeExamBrowser.Core.Behaviour logger.Log($"{titleLine}{copyrightLine}{emptyLine}{githubLine}"); logger.Log($"{Environment.NewLine}# Application started at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}{Environment.NewLine}"); logger.Info("--- Initiating startup procedure ---"); - } - private void InitializeSplashScreen(int operationCount) - { splashScreen = uiFactory.CreateSplashScreen(settings, text); splashScreen.SetMaxProgress(operationCount); splashScreen.UpdateText(Key.SplashScreen_StartupProcedure); @@ -116,11 +110,12 @@ namespace SafeExamBrowser.Core.Behaviour logger.Info("Reverting operations..."); } - private void FinishInitialization(bool success = true) + private void Finish(bool success = true) { if (success) { logger.Info("--- Application successfully initialized! ---"); + logger.Log(string.Empty); splashScreen?.InvokeClose(); } else diff --git a/SafeExamBrowser.Core/I18n/Text.xml b/SafeExamBrowser.Core/I18n/Text.xml index 95c13c55..39de7e61 100644 --- a/SafeExamBrowser.Core/I18n/Text.xml +++ b/SafeExamBrowser.Core/I18n/Text.xml @@ -1,21 +1,24 @@  - An unexpected error occurred during the shutdown procedure! Please consult the application log for more information... - Shutdown Error - An unexpected error occurred during the startup procedure! Please consult the application log for more information... - Startup Error - About Safe Exam Browser - Initializing browser - Initializing process monitoring - Initializing taskbar - Initializing window monitoring - Initializing working area - Restoring working area - Initiating shutdown procedure - Initiating startup procedure - Stopping process monitoring - Stopping window monitoring - Waiting for Windows explorer to start up - Waiting for Windows explorer to shut down - Version + An unexpected error occurred during the shutdown procedure! Please consult the application log for more information... + Shutdown Error + An unexpected error occurred during the startup procedure! Please consult the application log for more information... + Startup Error + About Safe Exam Browser + Initializing browser + Initializing process monitoring + Initializing taskbar + Initializing window monitoring + Initializing working area + Restoring working area + Initiating shutdown procedure + Starting event handling + Initiating startup procedure + Stopping event handling + Stopping process monitoring + Stopping window monitoring + Terminating browser + Waiting for Windows explorer to start up + Waiting for Windows explorer to shut down + Version \ No newline at end of file diff --git a/SafeExamBrowser.Core/Logging/Logger.cs b/SafeExamBrowser.Core/Logging/Logger.cs index 5660c700..7e65fa76 100644 --- a/SafeExamBrowser.Core/Logging/Logger.cs +++ b/SafeExamBrowser.Core/Logging/Logger.cs @@ -29,7 +29,7 @@ namespace SafeExamBrowser.Core.Logging public void Warn(string message) { - Add(LogLevel.Warn, message); + Add(LogLevel.Warning, message); } public void Error(string message) diff --git a/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj b/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj index f7c6be2d..7aa9f8fc 100644 --- a/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj +++ b/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj @@ -58,10 +58,12 @@ - - - - + + + + + + diff --git a/SafeExamBrowser.Monitoring/Processes/ProcessMonitor.cs b/SafeExamBrowser.Monitoring/Processes/ProcessMonitor.cs index dc7cde93..ca924e80 100644 --- a/SafeExamBrowser.Monitoring/Processes/ProcessMonitor.cs +++ b/SafeExamBrowser.Monitoring/Processes/ProcessMonitor.cs @@ -10,6 +10,7 @@ using System; using System.Diagnostics; using System.IO; using System.Linq; +using System.Management; using System.Threading; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Monitoring; @@ -20,6 +21,9 @@ namespace SafeExamBrowser.Monitoring.Processes public class ProcessMonitor : IProcessMonitor { private ILogger logger; + private ManagementEventWatcher explorerWatcher; + + public event ExplorerStartedHandler ExplorerStarted; public ProcessMonitor(ILogger logger) { @@ -49,12 +53,14 @@ namespace SafeExamBrowser.Monitoring.Processes public void StartMonitoringExplorer() { - // TODO + explorerWatcher = new ManagementEventWatcher(@"\\.\root\CIMV2", GetQueryFor("explorer.exe")); + explorerWatcher.EventArrived += new EventArrivedEventHandler(ExplorerWatcher_EventArrived); + explorerWatcher.Start(); } public void StopMonitoringExplorer() { - // TODO + explorerWatcher?.Stop(); } public void CloseExplorerShell() @@ -81,5 +87,26 @@ namespace SafeExamBrowser.Monitoring.Processes logger.Info("The explorer shell seems to already be terminated. Skipping this step..."); } } + + private void ExplorerWatcher_EventArrived(object sender, EventArrivedEventArgs e) + { + var eventName = e.NewEvent.ClassPath.ClassName; + + if (eventName == "__InstanceCreationEvent") + { + logger.Warn("A new instance of Windows explorer has been started!"); + ExplorerStarted?.Invoke(); + } + } + + private string GetQueryFor(string processName) + { + return $@" + SELECT * + FROM __InstanceOperationEvent + WITHIN 2 + WHERE TargetInstance ISA 'Win32_Process' + AND TargetInstance.Name = '{processName}'"; + } } } diff --git a/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj b/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj index de380c5f..7c7308ff 100644 --- a/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj +++ b/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj @@ -50,6 +50,7 @@ + diff --git a/SafeExamBrowser.UserInterface/Taskbar.xaml.cs b/SafeExamBrowser.UserInterface/Taskbar.xaml.cs index 3ece46dd..6a6af27f 100644 --- a/SafeExamBrowser.UserInterface/Taskbar.xaml.cs +++ b/SafeExamBrowser.UserInterface/Taskbar.xaml.cs @@ -20,14 +20,7 @@ namespace SafeExamBrowser.UserInterface { InitializeComponent(); - Loaded += Taskbar_Loaded; - } - - private void Taskbar_Loaded(object sender, RoutedEventArgs e) - { - Width = SystemParameters.WorkArea.Right; - Left = SystemParameters.WorkArea.Right - Width; - Top = SystemParameters.WorkArea.Bottom; + Loaded += (o, args) => InitializeBounds(); } public void AddButton(ITaskbarButton button) @@ -52,22 +45,35 @@ namespace SafeExamBrowser.UserInterface // to get the real height of the taskbar (in absolute, device-specific pixels). // Source: https://stackoverflow.com/questions/3286175/how-do-i-convert-a-wpf-size-to-physical-pixels - Matrix transformToDevice; - var source = PresentationSource.FromVisual(this); + return Dispatcher.Invoke(() => + { + Matrix transformToDevice; + var source = PresentationSource.FromVisual(this); - if (source != null) - { - transformToDevice = source.CompositionTarget.TransformToDevice; - } - else - { - using (var newSource = new HwndSource(new HwndSourceParameters())) + if (source != null) { - transformToDevice = newSource.CompositionTarget.TransformToDevice; + transformToDevice = source.CompositionTarget.TransformToDevice; + } + else + { + using (var newSource = new HwndSource(new HwndSourceParameters())) + { + transformToDevice = newSource.CompositionTarget.TransformToDevice; + } } - } - return (int) transformToDevice.Transform((Vector) new Size(Width, Height)).Y; + return (int)transformToDevice.Transform((Vector)new Size(Width, Height)).Y; + }); + } + + public void InitializeBounds() + { + Dispatcher.Invoke(() => + { + Width = SystemParameters.WorkArea.Right; + Left = SystemParameters.WorkArea.Right - Width; + Top = SystemParameters.WorkArea.Bottom; + }); } private void ApplicationScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e) diff --git a/SafeExamBrowser/CompositionRoot.cs b/SafeExamBrowser/CompositionRoot.cs index 584db56b..d9c61164 100644 --- a/SafeExamBrowser/CompositionRoot.cs +++ b/SafeExamBrowser/CompositionRoot.cs @@ -29,6 +29,7 @@ namespace SafeExamBrowser { private IApplicationController browserController; private IApplicationInfo browserInfo; + private IEventController eventController; private ILogger logger; private INotificationInfo aboutInfo; private IProcessMonitor processMonitor; @@ -61,15 +62,17 @@ namespace SafeExamBrowser processMonitor = new ProcessMonitor(new ModuleLogger(logger, typeof(ProcessMonitor))); windowMonitor = new WindowMonitor(new ModuleLogger(logger, typeof(WindowMonitor))); workingArea = new WorkingArea(new ModuleLogger(logger, typeof(WorkingArea))); + eventController = new EventController(new ModuleLogger(logger, typeof(EventController)), processMonitor, Taskbar, workingArea); ShutdownController = new ShutdownController(logger, settings, text, uiFactory); StartupController = new StartupController(logger, settings, text, uiFactory); StartupOperations = new Queue(); - StartupOperations.Enqueue(new WindowMonitoringOperation(logger, windowMonitor)); - StartupOperations.Enqueue(new ProcessMonitoringOperation(logger, processMonitor)); + StartupOperations.Enqueue(new WindowMonitorOperation(logger, windowMonitor)); + StartupOperations.Enqueue(new ProcessMonitorOperation(logger, processMonitor)); StartupOperations.Enqueue(new WorkingAreaOperation(logger, Taskbar, workingArea)); - StartupOperations.Enqueue(new TaskbarInitializationOperation(logger, aboutInfo, Taskbar, uiFactory)); - StartupOperations.Enqueue(new BrowserInitializationOperation(browserController, browserInfo, logger, Taskbar, uiFactory)); + StartupOperations.Enqueue(new TaskbarOperation(logger, aboutInfo, Taskbar, uiFactory)); + StartupOperations.Enqueue(new BrowserOperation(browserController, browserInfo, logger, Taskbar, uiFactory)); + StartupOperations.Enqueue(new EventControllerOperation(eventController, logger)); } } }