diff --git a/SafeExamBrowser.Contracts/I18n/Key.cs b/SafeExamBrowser.Contracts/I18n/Key.cs
index e8060f11..af6dbb2f 100644
--- a/SafeExamBrowser.Contracts/I18n/Key.cs
+++ b/SafeExamBrowser.Contracts/I18n/Key.cs
@@ -23,11 +23,13 @@ namespace SafeExamBrowser.Contracts.I18n
SplashScreen_InitializeBrowser,
SplashScreen_InitializeProcessMonitoring,
SplashScreen_InitializeTaskbar,
+ SplashScreen_InitializeWindowMonitoring,
SplashScreen_InitializeWorkingArea,
SplashScreen_RestoreWorkingArea,
SplashScreen_ShutdownProcedure,
SplashScreen_StartupProcedure,
SplashScreen_StopProcessMonitoring,
+ SplashScreen_StopWindowMonitoring,
SplashScreen_WaitExplorerStartup,
SplashScreen_WaitExplorerTermination,
Version
diff --git a/SafeExamBrowser.Contracts/UserInterface/IUiElementFactory.cs b/SafeExamBrowser.Contracts/UserInterface/IUiElementFactory.cs
index 55fe0277..23e732e6 100644
--- a/SafeExamBrowser.Contracts/UserInterface/IUiElementFactory.cs
+++ b/SafeExamBrowser.Contracts/UserInterface/IUiElementFactory.cs
@@ -11,21 +11,21 @@ using SafeExamBrowser.Contracts.I18n;
namespace SafeExamBrowser.Contracts.UserInterface
{
- public interface IUiElementFactory
+ public interface IUiElementFactory : IMessageBox
{
///
/// Creates a taskbar button, initialized with the given application information.
///
ITaskbarButton CreateApplicationButton(IApplicationInfo info);
- ///
- /// Creates a new splash screen which runs on its own thread.
- ///
- ISplashScreen CreateSplashScreen(ISettings settings, IText text);
-
///
/// Creates a taskbar notification, initialized with the given notification information.
///
ITaskbarNotification CreateNotification(INotificationInfo info);
+
+ ///
+ /// Creates a new splash screen which runs on its own thread.
+ ///
+ ISplashScreen CreateSplashScreen(ISettings settings, IText text);
}
}
diff --git a/SafeExamBrowser.Core.UnitTests/Behaviour/ShutdownControllerTests.cs b/SafeExamBrowser.Core.UnitTests/Behaviour/ShutdownControllerTests.cs
index f2ad03f9..1af3cfea 100644
--- a/SafeExamBrowser.Core.UnitTests/Behaviour/ShutdownControllerTests.cs
+++ b/SafeExamBrowser.Core.UnitTests/Behaviour/ShutdownControllerTests.cs
@@ -13,7 +13,6 @@ using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
-using SafeExamBrowser.Contracts.Monitoring;
using SafeExamBrowser.Contracts.UserInterface;
using SafeExamBrowser.Core.Behaviour;
@@ -22,45 +21,24 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
[TestClass]
public class ShutdownControllerTests
{
- private Mock browserControllerMock;
- private Mock browserInfoMock;
private Mock loggerMock;
- private Mock messageBoxMock;
- private Mock aboutInfoMock;
- private Mock processMonitorMock;
private Mock settingsMock;
- private Mock taskbarMock;
private Mock textMock;
private Mock uiFactoryMock;
- private Mock workingAreaMock;
private IShutdownController sut;
[TestInitialize]
public void Initialize()
{
- browserControllerMock = new Mock();
- browserInfoMock = new Mock();
loggerMock = new Mock();
- messageBoxMock = new Mock();
- aboutInfoMock = new Mock();
- processMonitorMock = new Mock();
settingsMock = new Mock();
- taskbarMock = new Mock();
textMock = new Mock();
uiFactoryMock = new Mock();
- workingAreaMock = new Mock();
uiFactoryMock.Setup(f => f.CreateSplashScreen(settingsMock.Object, textMock.Object)).Returns(new Mock().Object);
- sut = new ShutdownController(
- loggerMock.Object,
- messageBoxMock.Object,
- processMonitorMock.Object,
- settingsMock.Object,
- textMock.Object,
- uiFactoryMock.Object,
- workingAreaMock.Object);
+ sut = new ShutdownController(loggerMock.Object, settingsMock.Object, textMock.Object, uiFactoryMock.Object);
}
[TestMethod]
diff --git a/SafeExamBrowser.Core.UnitTests/Behaviour/StartupControllerTests.cs b/SafeExamBrowser.Core.UnitTests/Behaviour/StartupControllerTests.cs
index 281a1996..389615d3 100644
--- a/SafeExamBrowser.Core.UnitTests/Behaviour/StartupControllerTests.cs
+++ b/SafeExamBrowser.Core.UnitTests/Behaviour/StartupControllerTests.cs
@@ -14,7 +14,6 @@ using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
-using SafeExamBrowser.Contracts.Monitoring;
using SafeExamBrowser.Contracts.UserInterface;
using SafeExamBrowser.Core.Behaviour;
@@ -23,49 +22,24 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
[TestClass]
public class StartupControllerTests
{
- private Mock browserControllerMock;
- private Mock browserInfoMock;
private Mock loggerMock;
- private Mock messageBoxMock;
- private Mock aboutInfoMock;
- private Mock processMonitorMock;
private Mock settingsMock;
- private Mock taskbarMock;
private Mock textMock;
private Mock uiFactoryMock;
- private Mock workingAreaMock;
private IStartupController sut;
[TestInitialize]
public void Initialize()
{
- browserControllerMock = new Mock();
- browserInfoMock = new Mock();
loggerMock = new Mock();
- messageBoxMock = new Mock();
- aboutInfoMock = new Mock();
- processMonitorMock = new Mock();
settingsMock = new Mock();
- taskbarMock = new Mock();
textMock = new Mock();
uiFactoryMock = new Mock();
- workingAreaMock = new Mock();
uiFactoryMock.Setup(f => f.CreateSplashScreen(settingsMock.Object, textMock.Object)).Returns(new Mock().Object);
- sut = new StartupController(
- browserControllerMock.Object,
- browserInfoMock.Object,
- loggerMock.Object,
- messageBoxMock.Object,
- aboutInfoMock.Object,
- processMonitorMock.Object,
- settingsMock.Object,
- taskbarMock.Object,
- textMock.Object,
- uiFactoryMock.Object,
- workingAreaMock.Object);
+ sut = new StartupController(loggerMock.Object, settingsMock.Object, textMock.Object, uiFactoryMock.Object);
}
[TestMethod]
diff --git a/SafeExamBrowser.Core/Behaviour/Operations/BrowserInitializationOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/BrowserInitializationOperation.cs
index c489ca08..0daf7abb 100644
--- a/SafeExamBrowser.Core/Behaviour/Operations/BrowserInitializationOperation.cs
+++ b/SafeExamBrowser.Core/Behaviour/Operations/BrowserInitializationOperation.cs
@@ -40,7 +40,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
public void Perform()
{
- logger.Info("--- Initializing browser ---");
+ logger.Info("Initializing browser...");
SplashScreen.UpdateText(Key.SplashScreen_InitializeBrowser);
var browserButton = uiFactory.CreateApplicationButton(browserInfo);
diff --git a/SafeExamBrowser.Core/Behaviour/Operations/ProcessMonitoringOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/ProcessMonitoringOperation.cs
index 862a947c..c60dc53e 100644
--- a/SafeExamBrowser.Core/Behaviour/Operations/ProcessMonitoringOperation.cs
+++ b/SafeExamBrowser.Core/Behaviour/Operations/ProcessMonitoringOperation.cs
@@ -29,7 +29,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
public void Perform()
{
- logger.Info("--- Initializing process monitoring ---");
+ logger.Info("Initializing process monitoring...");
SplashScreen.UpdateText(Key.SplashScreen_WaitExplorerTermination, true);
processMonitor.CloseExplorerShell();
@@ -42,7 +42,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
public void Revert()
{
- logger.Info("--- Stopping process monitoring ---");
+ logger.Info("Stopping process monitoring...");
SplashScreen.UpdateText(Key.SplashScreen_StopProcessMonitoring);
// TODO
diff --git a/SafeExamBrowser.Core/Behaviour/Operations/TaskbarInitializationOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/TaskbarInitializationOperation.cs
index 63552b82..758b7910 100644
--- a/SafeExamBrowser.Core/Behaviour/Operations/TaskbarInitializationOperation.cs
+++ b/SafeExamBrowser.Core/Behaviour/Operations/TaskbarInitializationOperation.cs
@@ -33,7 +33,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
public void Perform()
{
- logger.Info("--- Initializing taskbar ---");
+ logger.Info("Initializing taskbar...");
SplashScreen.UpdateText(Key.SplashScreen_InitializeTaskbar);
var aboutNotification = uiFactory.CreateNotification(aboutInfo);
diff --git a/SafeExamBrowser.Core/Behaviour/Operations/WindowMonitoringOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/WindowMonitoringOperation.cs
new file mode 100644
index 00000000..7b88f62e
--- /dev/null
+++ b/SafeExamBrowser.Core/Behaviour/Operations/WindowMonitoringOperation.cs
@@ -0,0 +1,48 @@
+/*
+ * 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.Monitoring;
+using SafeExamBrowser.Contracts.UserInterface;
+
+namespace SafeExamBrowser.Core.Behaviour.Operations
+{
+ public class WindowMonitoringOperation : IOperation
+ {
+ private ILogger logger;
+ private IWindowMonitor windowMonitor;
+
+ public ISplashScreen SplashScreen { private get; set; }
+
+ public WindowMonitoringOperation(ILogger logger, IWindowMonitor windowMonitor)
+ {
+ this.logger = logger;
+ this.windowMonitor = windowMonitor;
+ }
+
+ public void Perform()
+ {
+ logger.Info("Initializing window monitoring...");
+ SplashScreen.UpdateText(Key.SplashScreen_InitializeWindowMonitoring);
+
+ windowMonitor.HideAllWindows();
+ windowMonitor.StartMonitoringWindows();
+ }
+
+ public void Revert()
+ {
+ logger.Info("Stopping window monitoring...");
+ SplashScreen.UpdateText(Key.SplashScreen_StopWindowMonitoring);
+
+ windowMonitor.StopMonitoringWindows();
+ windowMonitor.RestoreHiddenWindows();
+ }
+ }
+}
diff --git a/SafeExamBrowser.Core/Behaviour/Operations/WorkingAreaOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/WorkingAreaOperation.cs
index af911eb4..bdc642a4 100644
--- a/SafeExamBrowser.Core/Behaviour/Operations/WorkingAreaOperation.cs
+++ b/SafeExamBrowser.Core/Behaviour/Operations/WorkingAreaOperation.cs
@@ -31,7 +31,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
public void Perform()
{
- logger.Info("--- Initializing working area ---");
+ logger.Info("Initializing working area...");
SplashScreen.UpdateText(Key.SplashScreen_InitializeWorkingArea);
// TODO
@@ -42,7 +42,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
public void Revert()
{
- logger.Info("--- Restoring working area ---");
+ logger.Info("Restoring working area...");
SplashScreen.UpdateText(Key.SplashScreen_RestoreWorkingArea);
// TODO
diff --git a/SafeExamBrowser.Core/Behaviour/ShutdownController.cs b/SafeExamBrowser.Core/Behaviour/ShutdownController.cs
index e238cfa0..b9e61e61 100644
--- a/SafeExamBrowser.Core/Behaviour/ShutdownController.cs
+++ b/SafeExamBrowser.Core/Behaviour/ShutdownController.cs
@@ -13,7 +13,6 @@ using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
-using SafeExamBrowser.Contracts.Monitoring;
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Core.Behaviour
@@ -21,30 +20,17 @@ namespace SafeExamBrowser.Core.Behaviour
public class ShutdownController : IShutdownController
{
private ILogger logger;
- private IMessageBox messageBox;
- private IProcessMonitor processMonitor;
private ISettings settings;
private ISplashScreen splashScreen;
private IText text;
private IUiElementFactory uiFactory;
- private IWorkingArea workingArea;
- public ShutdownController(
- ILogger logger,
- IMessageBox messageBox,
- IProcessMonitor processMonitor,
- ISettings settings,
- IText text,
- IUiElementFactory uiFactory,
- IWorkingArea workingArea)
+ public ShutdownController(ILogger logger, ISettings settings, IText text, IUiElementFactory uiFactory)
{
this.logger = logger;
- this.messageBox = messageBox;
- this.processMonitor = processMonitor;
this.settings = settings;
this.text = text;
this.uiFactory = uiFactory;
- this.workingArea = workingArea;
}
public void FinalizeApplication(Queue operations)
@@ -86,7 +72,7 @@ namespace SafeExamBrowser.Core.Behaviour
private void LogAndShowException(Exception e)
{
logger.Error($"Failed to finalize application!", e);
- messageBox.Show(text.Get(Key.MessageBox_ShutdownError), text.Get(Key.MessageBox_ShutdownErrorTitle), icon: MessageBoxIcon.Error);
+ uiFactory.Show(text.Get(Key.MessageBox_ShutdownError), text.Get(Key.MessageBox_ShutdownErrorTitle), icon: MessageBoxIcon.Error);
}
private void FinalizeApplicationLog(bool success = true)
@@ -95,10 +81,8 @@ namespace SafeExamBrowser.Core.Behaviour
{
logger.Info("--- Application successfully finalized! ---");
}
- else
- {
- logger.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
- }
+
+ logger.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
}
}
}
diff --git a/SafeExamBrowser.Core/Behaviour/StartupController.cs b/SafeExamBrowser.Core/Behaviour/StartupController.cs
index be13b0c0..5111f4cd 100644
--- a/SafeExamBrowser.Core/Behaviour/StartupController.cs
+++ b/SafeExamBrowser.Core/Behaviour/StartupController.cs
@@ -14,52 +14,26 @@ using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
-using SafeExamBrowser.Contracts.Monitoring;
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Core.Behaviour
{
public class StartupController : IStartupController
{
- private IApplicationController browserController;
- private IApplicationInfo browserInfo;
private ILogger logger;
- private IMessageBox messageBox;
- private INotificationInfo aboutInfo;
- private IProcessMonitor processMonitor;
private ISettings settings;
private ISplashScreen splashScreen;
- private ITaskbar taskbar;
private IText text;
private IUiElementFactory uiFactory;
- private IWorkingArea workingArea;
private Stack stack = new Stack();
- public StartupController(
- IApplicationController browserController,
- IApplicationInfo browserInfo,
- ILogger logger,
- IMessageBox messageBox,
- INotificationInfo aboutInfo,
- IProcessMonitor processMonitor,
- ISettings settings,
- ITaskbar taskbar,
- IText text,
- IUiElementFactory uiFactory,
- IWorkingArea workingArea)
+ public StartupController(ILogger logger, ISettings settings, IText text, IUiElementFactory uiFactory)
{
- this.browserController = browserController;
- this.browserInfo = browserInfo;
this.logger = logger;
- this.messageBox = messageBox;
- this.aboutInfo = aboutInfo;
- this.processMonitor = processMonitor;
this.settings = settings;
- this.taskbar = taskbar;
this.text = text;
this.uiFactory = uiFactory;
- this.workingArea = workingArea;
}
public bool TryInitializeApplication(Queue operations)
@@ -138,7 +112,7 @@ namespace SafeExamBrowser.Core.Behaviour
private void LogAndShowException(Exception e)
{
logger.Error($"Failed to initialize application!", e);
- messageBox.Show(text.Get(Key.MessageBox_StartupError), text.Get(Key.MessageBox_StartupErrorTitle), icon: MessageBoxIcon.Error);
+ uiFactory.Show(text.Get(Key.MessageBox_StartupError), text.Get(Key.MessageBox_StartupErrorTitle), icon: MessageBoxIcon.Error);
logger.Info("Reverting operations...");
}
diff --git a/SafeExamBrowser.Core/I18n/Text.xml b/SafeExamBrowser.Core/I18n/Text.xml
index 4046706f..95c13c55 100644
--- a/SafeExamBrowser.Core/I18n/Text.xml
+++ b/SafeExamBrowser.Core/I18n/Text.xml
@@ -8,11 +8,13 @@
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
diff --git a/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj b/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj
index ea76dd20..35af286c 100644
--- a/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj
+++ b/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj
@@ -43,6 +43,7 @@
+
diff --git a/SafeExamBrowser.Monitoring/Windows/WindowMonitor.cs b/SafeExamBrowser.Monitoring/Windows/WindowMonitor.cs
index 86240d43..ac5df2a6 100644
--- a/SafeExamBrowser.Monitoring/Windows/WindowMonitor.cs
+++ b/SafeExamBrowser.Monitoring/Windows/WindowMonitor.cs
@@ -7,6 +7,7 @@
*/
using System;
+using System.Collections.Generic;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.Monitoring;
using SafeExamBrowser.WindowsApi;
@@ -16,17 +17,29 @@ namespace SafeExamBrowser.Monitoring.Windows
public class WindowMonitor : IWindowMonitor
{
private ILogger logger;
+ private IList minimizedWindows = new List();
public WindowMonitor(ILogger logger)
{
this.logger = logger;
-
- // TODO: Make operation for window monitor OR operation for all desktop initialization?!
- // ...
}
public void HideAllWindows()
{
+ logger.Info("Saving windows to be minimized...");
+
+ foreach (var handle in User32.GetOpenWindows())
+ {
+ var window = new Window
+ {
+ Handle = handle,
+ Title = User32.GetWindowTitle(handle)
+ };
+
+ minimizedWindows.Add(window);
+ logger.Info($"Saved window '{window.Title}' with handle = {window.Handle}.");
+ }
+
logger.Info("Minimizing all open windows...");
User32.MinimizeAllOpenWindows();
logger.Info("Open windows successfully minimized.");
@@ -34,17 +47,31 @@ namespace SafeExamBrowser.Monitoring.Windows
public void RestoreHiddenWindows()
{
- throw new NotImplementedException();
+ logger.Info("Restoring all minimized windows...");
+
+ foreach (var window in minimizedWindows)
+ {
+ User32.RestoreWindow(window.Handle);
+ logger.Info($"Restored window '{window.Title}' with handle = {window.Handle}.");
+ }
+
+ logger.Info("Minimized windows successfully restored.");
}
public void StartMonitoringWindows()
{
- throw new NotImplementedException();
+ // TODO
}
public void StopMonitoringWindows()
{
- throw new NotImplementedException();
+ // TODO
+ }
+
+ private struct Window
+ {
+ internal IntPtr Handle { get; set; }
+ internal string Title { get; set; }
}
}
}
diff --git a/SafeExamBrowser.UserInterface/SafeExamBrowser.UserInterface.csproj b/SafeExamBrowser.UserInterface/SafeExamBrowser.UserInterface.csproj
index 618e18ba..db842aad 100644
--- a/SafeExamBrowser.UserInterface/SafeExamBrowser.UserInterface.csproj
+++ b/SafeExamBrowser.UserInterface/SafeExamBrowser.UserInterface.csproj
@@ -85,7 +85,6 @@
-
ResXFileCodeGenerator
Resources.Designer.cs
diff --git a/SafeExamBrowser.UserInterface/SplashScreen.xaml b/SafeExamBrowser.UserInterface/SplashScreen.xaml
index eec07ee3..38e3c041 100644
--- a/SafeExamBrowser.UserInterface/SplashScreen.xaml
+++ b/SafeExamBrowser.UserInterface/SplashScreen.xaml
@@ -4,11 +4,12 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
- Title="SplashScreen" Height="200" Width="350" WindowStyle="None" AllowsTransparency="True" WindowStartupLocation="CenterScreen" Cursor="Wait" Icon="./Images/SafeExamBrowser.ico">
+ Title="SplashScreen" Height="200" Width="350" WindowStyle="None" AllowsTransparency="True" WindowStartupLocation="CenterScreen"
+ Cursor="Wait" Icon="./Images/SafeExamBrowser.ico" ResizeMode="NoResize" Topmost="True">
-
+
diff --git a/SafeExamBrowser.UserInterface/Taskbar.xaml b/SafeExamBrowser.UserInterface/Taskbar.xaml
index 64d5696a..08ef9925 100644
--- a/SafeExamBrowser.UserInterface/Taskbar.xaml
+++ b/SafeExamBrowser.UserInterface/Taskbar.xaml
@@ -10,26 +10,28 @@
-
-
-
-
-
-
-
-
-
- 5
-
-
-
-
-
- 5
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
diff --git a/SafeExamBrowser.UserInterface/UiElementFactory.cs b/SafeExamBrowser.UserInterface/UiElementFactory.cs
index 9956843c..fc0641e1 100644
--- a/SafeExamBrowser.UserInterface/UiElementFactory.cs
+++ b/SafeExamBrowser.UserInterface/UiElementFactory.cs
@@ -7,6 +7,7 @@
*/
using System.Threading;
+using System.Windows;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.UserInterface;
@@ -21,6 +22,16 @@ namespace SafeExamBrowser.UserInterface
return new ApplicationButton(info);
}
+ public void Show(string message, string title, MessageBoxAction action = MessageBoxAction.Confirm, MessageBoxIcon icon = MessageBoxIcon.Information)
+ {
+ MessageBox.Show(message, title, ToButton(action), ToImage(icon));
+ }
+
+ public ITaskbarNotification CreateNotification(INotificationInfo info)
+ {
+ return new NotificationIcon(info);
+ }
+
public ISplashScreen CreateSplashScreen(ISettings settings, IText text)
{
SplashScreen splashScreen = null;
@@ -46,9 +57,26 @@ namespace SafeExamBrowser.UserInterface
return splashScreen;
}
- public ITaskbarNotification CreateNotification(INotificationInfo info)
+ private MessageBoxButton ToButton(MessageBoxAction action)
{
- return new NotificationIcon(info);
+ switch (action)
+ {
+ default:
+ return MessageBoxButton.OK;
+ }
+ }
+
+ private MessageBoxImage ToImage(MessageBoxIcon icon)
+ {
+ switch (icon)
+ {
+ case MessageBoxIcon.Warning:
+ return MessageBoxImage.Warning;
+ case MessageBoxIcon.Error:
+ return MessageBoxImage.Error;
+ default:
+ return MessageBoxImage.Information;
+ }
}
}
}
diff --git a/SafeExamBrowser.UserInterface/WpfMessageBox.cs b/SafeExamBrowser.UserInterface/WpfMessageBox.cs
deleted file mode 100644
index 64061903..00000000
--- a/SafeExamBrowser.UserInterface/WpfMessageBox.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.Windows;
-using SafeExamBrowser.Contracts.UserInterface;
-
-namespace SafeExamBrowser.UserInterface
-{
- public class WpfMessageBox : IMessageBox
- {
- public void Show(string message, string title, MessageBoxAction action = MessageBoxAction.Confirm, MessageBoxIcon icon = MessageBoxIcon.Information)
- {
- MessageBox.Show(message, title, ToButton(action), ToImage(icon));
- }
-
- private MessageBoxButton ToButton(MessageBoxAction action)
- {
- switch (action)
- {
- default:
- return MessageBoxButton.OK;
- }
- }
-
- private MessageBoxImage ToImage(MessageBoxIcon icon)
- {
- switch (icon)
- {
- case MessageBoxIcon.Warning:
- return MessageBoxImage.Warning;
- case MessageBoxIcon.Error:
- return MessageBoxImage.Error;
- default:
- return MessageBoxImage.Information;
- }
- }
- }
-}
diff --git a/SafeExamBrowser.WindowsApi/Constants/Constant.cs b/SafeExamBrowser.WindowsApi/Constants/Constant.cs
index 1cbb46d0..61af4425 100644
--- a/SafeExamBrowser.WindowsApi/Constants/Constant.cs
+++ b/SafeExamBrowser.WindowsApi/Constants/Constant.cs
@@ -11,6 +11,10 @@ namespace SafeExamBrowser.WindowsApi.Constants
static class Constant
{
internal const int WM_COMMAND = 0x111;
+
+ ///
+ /// Minimize all open windows.
+ ///
internal const int MIN_ALL = 419;
}
}
diff --git a/SafeExamBrowser.WindowsApi/Constants/ShowWindowCommand.cs b/SafeExamBrowser.WindowsApi/Constants/ShowWindowCommand.cs
new file mode 100644
index 00000000..7d236995
--- /dev/null
+++ b/SafeExamBrowser.WindowsApi/Constants/ShowWindowCommand.cs
@@ -0,0 +1,97 @@
+/*
+ * 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.WindowsApi.Constants
+{
+ ///
+ /// See http://www.pinvoke.net/default.aspx/Enums/ShowWindowCommand.html.
+ ///
+ internal enum ShowWindowCommand
+ {
+ ///
+ /// Hides the window and activates another window.
+ ///
+ Hide = 0,
+
+ ///
+ /// Activates and displays a window. If the window is minimized or
+ /// maximized, the system restores it to its original size and position.
+ /// An application should specify this flag when displaying the window
+ /// for the first time.
+ ///
+ Normal = 1,
+
+ ///
+ /// Activates the window and displays it as a minimized window.
+ ///
+ ShowMinimized = 2,
+
+ ///
+ /// Maximizes the specified window.
+ ///
+ Maximize = 3,
+
+ ///
+ /// Activates the window and displays it as a maximized window.
+ ///
+ ShowMaximized = 3,
+
+ ///
+ /// Displays a window in its most recent size and position. This value
+ /// is similar to , except
+ /// the window is not activated.
+ ///
+ ShowNoActivate = 4,
+
+ ///
+ /// Activates the window and displays it in its current size and position.
+ ///
+ Show = 5,
+
+ ///
+ /// Minimizes the specified window and activates the next top-level
+ /// window in the Z order.
+ ///
+ Minimize = 6,
+
+ ///
+ /// Displays the window as a minimized window. This value is similar to
+ /// , except the
+ /// window is not activated.
+ ///
+ ShowMinNoActive = 7,
+
+ ///
+ /// Displays the window in its current size and position. This value is
+ /// similar to , except the
+ /// window is not activated.
+ ///
+ ShowNA = 8,
+
+ ///
+ /// Activates and displays the window. If the window is minimized or
+ /// maximized, the system restores it to its original size and position.
+ /// An application should specify this flag when restoring a minimized window.
+ ///
+ Restore = 9,
+
+ ///
+ /// Sets the show state based on the SW_* value specified in the
+ /// STARTUPINFO structure passed to the CreateProcess function by the
+ /// program that started the application.
+ ///
+ ShowDefault = 10,
+
+ ///
+ /// Windows 2000/XP: Minimizes a window, even if the thread
+ /// that owns the window is not responding. This flag should only be
+ /// used when minimizing windows from a different thread.
+ ///
+ ForceMinimize = 11
+ }
+}
diff --git a/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj b/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj
index 074f5027..5e244155 100644
--- a/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj
+++ b/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj
@@ -41,6 +41,7 @@
+
diff --git a/SafeExamBrowser.WindowsApi/User32.cs b/SafeExamBrowser.WindowsApi/User32.cs
index 926f12d6..b5562b3a 100644
--- a/SafeExamBrowser.WindowsApi/User32.cs
+++ b/SafeExamBrowser.WindowsApi/User32.cs
@@ -7,8 +7,10 @@
*/
using System;
+using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
+using System.Text;
using SafeExamBrowser.WindowsApi.Constants;
using SafeExamBrowser.WindowsApi.Types;
@@ -19,6 +21,30 @@ namespace SafeExamBrowser.WindowsApi
///
public static class User32
{
+ ///
+ /// Retrieves a collection of handles to all currently open (i.e. visible) windows.
+ ///
+ public static IEnumerable GetOpenWindows()
+ {
+ var windows = new List();
+ var success = EnumWindows(delegate (IntPtr hWnd, IntPtr lParam)
+ {
+ if (hWnd != GetShellWindowHandle() && IsWindowVisible(hWnd) && GetWindowTextLength(hWnd) > 0)
+ {
+ windows.Add(hWnd);
+ }
+
+ return true;
+ }, IntPtr.Zero);
+
+ if (!success)
+ {
+ throw new Win32Exception(Marshal.GetLastWin32Error());
+ }
+
+ return windows;
+ }
+
///
/// Retrieves a window handle to the Windows taskbar. Returns IntPtr.Zero
/// if the taskbar could not be found (i.e. if it isn't running).
@@ -32,7 +58,6 @@ namespace SafeExamBrowser.WindowsApi
/// Retrieves the process ID of the main Windows explorer instance controlling
/// desktop and taskbar or 0, if the process isn't running.
///
- ///
public static uint GetShellProcessId()
{
var handle = GetShellWindowHandle();
@@ -41,6 +66,26 @@ namespace SafeExamBrowser.WindowsApi
return processId;
}
+ ///
+ /// Retrieves the title of the specified window, or an empty string, if the
+ /// given window does not have a title.
+ ///
+ public static string GetWindowTitle(IntPtr window)
+ {
+ var length = GetWindowTextLength(window);
+
+ if (length > 0)
+ {
+ var builder = new StringBuilder(length);
+
+ GetWindowText(window, builder, length + 1);
+
+ return builder.ToString();
+ }
+
+ return string.Empty;
+ }
+
///
/// Retrieves the currently configured working area of the primary screen.
///
@@ -91,6 +136,14 @@ namespace SafeExamBrowser.WindowsApi
}
}
+ ///
+ /// Restores the specified window to its original size and position.
+ ///
+ public static void RestoreWindow(IntPtr window)
+ {
+ ShowWindow(window, (int) ShowWindowCommand.Restore);
+ }
+
///
/// Sets the working area of the primary screen according to the given dimensions.
///
@@ -107,21 +160,40 @@ namespace SafeExamBrowser.WindowsApi
}
}
+ private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
+
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ private static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ private static extern int GetWindowTextLength(IntPtr hWnd);
+
[DllImport("user32.dll", SetLastError = true)]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
-
- [DllImport("user32.dll", EntryPoint = "SendMessage")]
- private static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
+ private static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
- static extern bool SystemParametersInfo(SPI uiAction, uint uiParam, ref RECT pvParam, SPIF fWinIni);
+ private static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
+
+ [DllImport("user32.dll", SetLastError = true, EntryPoint = "SendMessage")]
+ private static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool SystemParametersInfo(SPI uiAction, uint uiParam, ref RECT pvParam, SPIF fWinIni);
}
}
diff --git a/SafeExamBrowser/CompositionRoot.cs b/SafeExamBrowser/CompositionRoot.cs
index 0a54ae71..46300259 100644
--- a/SafeExamBrowser/CompositionRoot.cs
+++ b/SafeExamBrowser/CompositionRoot.cs
@@ -30,7 +30,6 @@ namespace SafeExamBrowser
private IApplicationController browserController;
private IApplicationInfo browserInfo;
private ILogger logger;
- private IMessageBox messageBox;
private INotificationInfo aboutInfo;
private IProcessMonitor processMonitor;
private ISettings settings;
@@ -50,7 +49,6 @@ namespace SafeExamBrowser
browserController = new BrowserApplicationController();
browserInfo = new BrowserApplicationInfo();
logger = new Logger();
- messageBox = new WpfMessageBox();
settings = new Settings();
Taskbar = new Taskbar();
textResource = new XmlTextResource();
@@ -63,10 +61,11 @@ 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)));
- ShutdownController = new ShutdownController(logger, messageBox, processMonitor, settings, text, uiFactory, workingArea);
- StartupController = new StartupController(browserController, browserInfo, logger, messageBox, aboutInfo, processMonitor, settings, Taskbar, text, uiFactory, 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 WorkingAreaOperation(logger, Taskbar, workingArea));
StartupOperations.Enqueue(new TaskbarInitializationOperation(logger, aboutInfo, Taskbar, uiFactory));