diff --git a/SafeExamBrowser.Configuration/Settings.cs b/SafeExamBrowser.Configuration/Settings.cs
index 1fde9f4e..1df2934d 100644
--- a/SafeExamBrowser.Configuration/Settings.cs
+++ b/SafeExamBrowser.Configuration/Settings.cs
@@ -16,16 +16,16 @@ namespace SafeExamBrowser.Configuration
public class Settings : ISettings
{
private const string AppDataFolder = "SafeExamBrowser";
- private static readonly string LogFileDate = DateTime.Now.ToString("yyyy-MM-dd HH\\hmm\\mss\\s");
+ private static readonly string LogFileDate = DateTime.Now.ToString("yyyy-MM-dd\\_HH\\hmm\\mss\\s");
public string ApplicationLogFile
{
- get { return Path.Combine(LogFolderPath, $"{LogFileDate} Application.txt"); }
+ get { return Path.Combine(LogFolderPath, $"{LogFileDate}_Application.txt"); }
}
public string BrowserLogFile
{
- get { return Path.Combine(LogFolderPath, $"{LogFileDate} Browser.txt"); }
+ get { return Path.Combine(LogFolderPath, $"{LogFileDate}_Browser.txt"); }
}
public string BrowserCachePath
diff --git a/SafeExamBrowser.Contracts/Monitoring/IProcessMonitor.cs b/SafeExamBrowser.Contracts/Monitoring/IProcessMonitor.cs
index 710acc68..ad269baf 100644
--- a/SafeExamBrowser.Contracts/Monitoring/IProcessMonitor.cs
+++ b/SafeExamBrowser.Contracts/Monitoring/IProcessMonitor.cs
@@ -20,17 +20,16 @@ namespace SafeExamBrowser.Contracts.Monitoring
///
event ExplorerStartedHandler ExplorerStarted;
+ ///
+ /// Performs a check whether the process associated to the given window is allowed.
+ ///
+ bool BelongsToAllowedProcess(IntPtr window);
+
///
/// Terminates the Windows explorer shell, i.e. the taskbar.
///
void CloseExplorerShell();
- ///
- /// Performs a check whether the process associated to the given window is allowed,
- /// i.e. whether the specified window should be hidden.
- ///
- void OnWindowChanged(IntPtr window, out bool hide);
-
///
/// Starts a new instance of the Windows explorer shell.
///
diff --git a/SafeExamBrowser.Contracts/Monitoring/IWindowMonitor.cs b/SafeExamBrowser.Contracts/Monitoring/IWindowMonitor.cs
index 8f79d0f1..58480537 100644
--- a/SafeExamBrowser.Contracts/Monitoring/IWindowMonitor.cs
+++ b/SafeExamBrowser.Contracts/Monitoring/IWindowMonitor.cs
@@ -10,7 +10,7 @@ using System;
namespace SafeExamBrowser.Contracts.Monitoring
{
- public delegate void WindowChangedHandler(IntPtr window, out bool hide);
+ public delegate void WindowChangedHandler(IntPtr window);
public interface IWindowMonitor
{
@@ -19,6 +19,16 @@ namespace SafeExamBrowser.Contracts.Monitoring
///
event WindowChangedHandler WindowChanged;
+ ///
+ /// Forcefully closes the specified window.
+ ///
+ void Close(IntPtr window);
+
+ ///
+ /// Hides the specified window. Returns true if the window was successfully hidden, otherwise false.
+ ///
+ bool Hide(IntPtr window);
+
///
/// Hides all currently opened windows.
///
diff --git a/SafeExamBrowser.Contracts/WindowsApi/INativeMethods.cs b/SafeExamBrowser.Contracts/WindowsApi/INativeMethods.cs
index 926b1828..baeb550d 100644
--- a/SafeExamBrowser.Contracts/WindowsApi/INativeMethods.cs
+++ b/SafeExamBrowser.Contracts/WindowsApi/INativeMethods.cs
@@ -54,9 +54,9 @@ namespace SafeExamBrowser.Contracts.WindowsApi
RECT GetWorkingArea();
///
- /// Hides the given window.
+ /// Hides the given window. Returns true if successful, otherwise false.
///
- void HideWindow(IntPtr window);
+ bool HideWindow(IntPtr window);
///
/// Minimizes all open windows.
@@ -88,6 +88,11 @@ namespace SafeExamBrowser.Contracts.WindowsApi
///
void RestoreWindow(IntPtr window);
+ ///
+ /// Sends a close message to the given window.
+ ///
+ void SendCloseMessageTo(IntPtr window);
+
///
/// Sets the working area of the primary screen according to the given dimensions.
///
diff --git a/SafeExamBrowser.Core/Behaviour/EventController.cs b/SafeExamBrowser.Core/Behaviour/EventController.cs
index dadcf1d3..b76e30dd 100644
--- a/SafeExamBrowser.Core/Behaviour/EventController.cs
+++ b/SafeExamBrowser.Core/Behaviour/EventController.cs
@@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
+using System;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Logging;
@@ -39,13 +40,13 @@ namespace SafeExamBrowser.Core.Behaviour
public void Start()
{
processMonitor.ExplorerStarted += ProcessMonitor_ExplorerStarted;
- windowMonitor.WindowChanged += processMonitor.OnWindowChanged;
+ windowMonitor.WindowChanged += WindowMonitor_WindowChanged;
}
public void Stop()
{
processMonitor.ExplorerStarted -= ProcessMonitor_ExplorerStarted;
- windowMonitor.WindowChanged -= processMonitor.OnWindowChanged;
+ windowMonitor.WindowChanged -= WindowMonitor_WindowChanged;
}
private void ProcessMonitor_ExplorerStarted()
@@ -56,7 +57,22 @@ namespace SafeExamBrowser.Core.Behaviour
workingArea.InitializeFor(taskbar);
logger.Info("Reinitializing taskbar bounds...");
taskbar.InitializeBounds();
- logger.Info("Desktop successfully restored!");
+ logger.Info("Desktop successfully restored.");
+ }
+
+ private void WindowMonitor_WindowChanged(IntPtr window)
+ {
+ var allowed = processMonitor.BelongsToAllowedProcess(window);
+
+ if (!allowed)
+ {
+ var success = windowMonitor.Hide(window);
+
+ if (!success)
+ {
+ windowMonitor.Close(window);
+ }
+ }
}
}
}
diff --git a/SafeExamBrowser.Monitoring/Processes/ProcessMonitor.cs b/SafeExamBrowser.Monitoring/Processes/ProcessMonitor.cs
index a415e894..4e28c3dc 100644
--- a/SafeExamBrowser.Monitoring/Processes/ProcessMonitor.cs
+++ b/SafeExamBrowser.Monitoring/Processes/ProcessMonitor.cs
@@ -32,6 +32,26 @@ namespace SafeExamBrowser.Monitoring.Processes
this.nativeMethods = nativeMethods;
}
+ public bool BelongsToAllowedProcess(IntPtr window)
+ {
+ var processId = nativeMethods.GetProcessIdFor(window);
+ var process = Process.GetProcessById(Convert.ToInt32(processId));
+
+ if (process != null)
+ {
+ var allowed = process.ProcessName == "SafeExamBrowser";
+
+ if (!allowed)
+ {
+ logger.Warn($"Window with handle = {window} belongs to not allowed process '{process.ProcessName}'!");
+ }
+
+ return allowed;
+ }
+
+ return true;
+ }
+
public void CloseExplorerShell()
{
var processId = nativeMethods.GetShellProcessId();
@@ -58,21 +78,6 @@ namespace SafeExamBrowser.Monitoring.Processes
}
}
- public void OnWindowChanged(IntPtr window, out bool hide)
- {
- var processId = nativeMethods.GetProcessIdFor(window);
- var process = Process.GetProcessById(Convert.ToInt32(processId));
-
- if (process != null)
- {
- hide = process.ProcessName != "SafeExamBrowser";
- }
- else
- {
- hide = true;
- }
- }
-
public void StartExplorerShell()
{
var process = new Process();
diff --git a/SafeExamBrowser.Monitoring/Windows/WindowMonitor.cs b/SafeExamBrowser.Monitoring/Windows/WindowMonitor.cs
index adc2df70..7edac1c2 100644
--- a/SafeExamBrowser.Monitoring/Windows/WindowMonitor.cs
+++ b/SafeExamBrowser.Monitoring/Windows/WindowMonitor.cs
@@ -30,6 +30,31 @@ namespace SafeExamBrowser.Monitoring.Windows
this.nativeMethods = nativeMethods;
}
+ public void Close(IntPtr window)
+ {
+ var title = nativeMethods.GetWindowTitle(window);
+
+ nativeMethods.SendCloseMessageTo(window);
+ logger.Info($"Sent close message to window '{title}' with handle = {window}.");
+ }
+
+ public bool Hide(IntPtr window)
+ {
+ var title = nativeMethods.GetWindowTitle(window);
+ var success = nativeMethods.HideWindow(window);
+
+ if (success)
+ {
+ logger.Info($"Hid window '{title}' with handle = {window}.");
+ }
+ else
+ {
+ logger.Warn($"Failed to hide window '{title}' with handle = {window}!");
+ }
+
+ return success;
+ }
+
public void HideAllWindows()
{
logger.Info("Saving windows to be minimized...");
@@ -90,18 +115,7 @@ namespace SafeExamBrowser.Monitoring.Windows
private void OnWindowChanged(IntPtr window)
{
- if (WindowChanged != null)
- {
- WindowChanged.Invoke(window, out bool hide);
-
- if (hide)
- {
- var title = nativeMethods.GetWindowTitle(window);
-
- nativeMethods.HideWindow(window);
- logger.Info($"Hid window '{title}' with handle = {window}.");
- }
- }
+ WindowChanged?.Invoke(window);
}
private struct Window
diff --git a/SafeExamBrowser.WindowsApi/Constants/Constant.cs b/SafeExamBrowser.WindowsApi/Constants/Constant.cs
index 9451edba..32760a7b 100644
--- a/SafeExamBrowser.WindowsApi/Constants/Constant.cs
+++ b/SafeExamBrowser.WindowsApi/Constants/Constant.cs
@@ -48,5 +48,13 @@ namespace SafeExamBrowser.WindowsApi.Constants
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms647591(v=vs.85).aspx.
///
internal const int WM_COMMAND = 0x111;
+
+ ///
+ /// A window receives this message when the user chooses a command from the Window menu (formerly known as the system or control
+ /// menu) or when the user chooses the maximize button, minimize button, restore button, or close button.
+ ///
+ /// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms646360(v=vs.85).aspx.
+ ///
+ internal const int WM_SYSCOMMAND = 0x112;
}
}
diff --git a/SafeExamBrowser.WindowsApi/Constants/SystemCommand.cs b/SafeExamBrowser.WindowsApi/Constants/SystemCommand.cs
new file mode 100644
index 00000000..2ce64ab9
--- /dev/null
+++ b/SafeExamBrowser.WindowsApi/Constants/SystemCommand.cs
@@ -0,0 +1,21 @@
+/*
+ * 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 https://msdn.microsoft.com/en-us/library/windows/desktop/ms646360(v=vs.85).aspx.
+ ///
+ internal enum SystemCommand
+ {
+ ///
+ /// Closes the window.
+ ///
+ CLOSE = 0xF060
+ }
+}
diff --git a/SafeExamBrowser.WindowsApi/NativeMethods.cs b/SafeExamBrowser.WindowsApi/NativeMethods.cs
index 7244d2d7..7e88feb2 100644
--- a/SafeExamBrowser.WindowsApi/NativeMethods.cs
+++ b/SafeExamBrowser.WindowsApi/NativeMethods.cs
@@ -1,10 +1,10 @@
/*
-* 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/.
-*/
+ * 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;
using System.Collections.Concurrent;
@@ -92,9 +92,9 @@ namespace SafeExamBrowser.WindowsApi
return workingArea;
}
- public void HideWindow(IntPtr window)
+ public bool HideWindow(IntPtr window)
{
- User32.ShowWindow(window, (int)ShowWindowCommand.Hide);
+ return User32.ShowWindow(window, (int) ShowWindowCommand.Hide);
}
public void MinimizeAllOpenWindows()
@@ -157,6 +157,11 @@ namespace SafeExamBrowser.WindowsApi
User32.ShowWindow(window, (int)ShowWindowCommand.Restore);
}
+ public void SendCloseMessageTo(IntPtr window)
+ {
+ User32.SendMessage(window, Constant.WM_SYSCOMMAND, (IntPtr) SystemCommand.CLOSE, IntPtr.Zero);
+ }
+
public void SetWorkingArea(RECT bounds)
{
var success = User32.SystemParametersInfo(SPI.SETWORKAREA, 0, ref bounds, SPIF.UPDATEANDCHANGE);
diff --git a/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj b/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj
index 2d9401db..a1c46fd1 100644
--- a/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj
+++ b/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj
@@ -60,6 +60,7 @@
+