From 8c32d3bc4a7fd9fbd7704b4a6b69c9bd2166ce37 Mon Sep 17 00:00:00 2001 From: dbuechel Date: Thu, 27 Jul 2017 13:57:12 +0200 Subject: [PATCH] Improved window handling and replaced whitespaces in log file names with underscores. --- SafeExamBrowser.Configuration/Settings.cs | 6 +-- .../Monitoring/IProcessMonitor.cs | 11 +++--- .../Monitoring/IWindowMonitor.cs | 12 +++++- .../WindowsApi/INativeMethods.cs | 9 ++++- .../Behaviour/EventController.cs | 22 +++++++++-- .../Processes/ProcessMonitor.cs | 35 +++++++++-------- .../Windows/WindowMonitor.cs | 38 +++++++++++++------ .../Constants/Constant.cs | 8 ++++ .../Constants/SystemCommand.cs | 21 ++++++++++ SafeExamBrowser.WindowsApi/NativeMethods.cs | 21 ++++++---- .../SafeExamBrowser.WindowsApi.csproj | 1 + 11 files changed, 134 insertions(+), 50 deletions(-) create mode 100644 SafeExamBrowser.WindowsApi/Constants/SystemCommand.cs 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 @@ +