From b4f468a2b4bae94197d21c3db0bb7920daeb536b Mon Sep 17 00:00:00 2001 From: dbuechel Date: Tue, 30 Oct 2018 11:24:28 +0100 Subject: [PATCH] SEBWIN-221: Moved hide & restore windows mechanism for Disable Explorer Shell to IExplorerShell and made reconfiguration dialogs modal to respective browser window. --- .../BrowserApplicationInstance.cs | 9 +++- .../Handlers/DownloadHandler.cs | 1 + .../Operations/WindowMonitorOperationTests.cs | 4 -- SafeExamBrowser.Client/ClientController.cs | 8 ++-- .../Browser/DownloadEventArgs.cs | 9 +++- .../Monitoring/IWindowMonitor.cs | 10 ----- .../WindowsApi/IExplorerShell.cs | 10 +++++ .../SafeExamBrowser.Monitoring.csproj | 1 - .../Windows/WindowMonitor.cs | 36 --------------- .../Operations/KioskModeOperationTests.cs | 28 ++++++++++-- .../KioskModeTerminationOperationTests.cs | 44 +++++++++++++++++++ .../Operations/KioskModeOperation.cs | 7 ++- SafeExamBrowser.Runtime/RuntimeController.cs | 3 -- SafeExamBrowser.WindowsApi/ExplorerShell.cs | 37 ++++++++++++++++ .../SafeExamBrowser.WindowsApi.csproj | 1 + .../Types}/Window.cs | 2 +- 16 files changed, 142 insertions(+), 68 deletions(-) rename {SafeExamBrowser.Monitoring/Windows => SafeExamBrowser.WindowsApi/Types}/Window.cs (90%) diff --git a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs index 279578c3..a694efd1 100644 --- a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs +++ b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs @@ -63,7 +63,7 @@ namespace SafeExamBrowser.Browser var downloadLogger = logger.CloneFor($"{nameof(DownloadHandler)} {Id}"); var downloadHandler = new DownloadHandler(appConfig, settings, downloadLogger); - downloadHandler.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args); + downloadHandler.ConfigurationDownloadRequested += DownloadHandler_ConfigurationDownloadRequested; control = new BrowserControl(appConfig, settings, controlLogger, text); control.AddressChanged += Control_AddressChanged; @@ -101,6 +101,13 @@ namespace SafeExamBrowser.Browser NameChanged?.Invoke(title); } + private void DownloadHandler_ConfigurationDownloadRequested(string fileName, DownloadEventArgs args) + { + args.BrowserWindow = window; + + ConfigurationDownloadRequested?.Invoke(fileName, args); + } + private void Window_AddressChanged(string address) { logger.Debug($"The user requested to navigate to '{address}'."); diff --git a/SafeExamBrowser.Browser/Handlers/DownloadHandler.cs b/SafeExamBrowser.Browser/Handlers/DownloadHandler.cs index 38ee5709..cb1dbb3d 100644 --- a/SafeExamBrowser.Browser/Handlers/DownloadHandler.cs +++ b/SafeExamBrowser.Browser/Handlers/DownloadHandler.cs @@ -82,6 +82,7 @@ namespace SafeExamBrowser.Browser.Handlers { var args = new DownloadEventArgs(); + logger.Debug($"Detected download request for configuration file '{downloadItem.Url}'."); ConfigurationDownloadRequested?.Invoke(downloadItem.SuggestedFileName, args); logger.Debug($"Download of configuration file '{downloadItem.Url}' was {(args.AllowDownload ? "granted" : "denied")}."); diff --git a/SafeExamBrowser.Client.UnitTests/Operations/WindowMonitorOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/WindowMonitorOperationTests.cs index b4e6c7d7..5ee2beff 100644 --- a/SafeExamBrowser.Client.UnitTests/Operations/WindowMonitorOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Operations/WindowMonitorOperationTests.cs @@ -35,7 +35,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations sut.Perform(); - windowMonitorMock.Verify(w => w.HideAllWindows(), Times.Never); windowMonitorMock.Verify(w => w.StartMonitoringWindows(), Times.Once); } @@ -47,7 +46,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations sut.Revert(); windowMonitorMock.Verify(w => w.StopMonitoringWindows(), Times.Once); - windowMonitorMock.Verify(w => w.RestoreHiddenWindows(), Times.Never); } [TestMethod] @@ -57,7 +55,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations sut.Perform(); - windowMonitorMock.Verify(w => w.HideAllWindows(), Times.Never); windowMonitorMock.Verify(w => w.StartMonitoringWindows(), Times.Once); } @@ -69,7 +66,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations sut.Revert(); windowMonitorMock.Verify(w => w.StopMonitoringWindows(), Times.Once); - windowMonitorMock.Verify(w => w.RestoreHiddenWindows(), Times.Never); } [TestMethod] diff --git a/SafeExamBrowser.Client/ClientController.cs b/SafeExamBrowser.Client/ClientController.cs index c288dd93..8564025f 100644 --- a/SafeExamBrowser.Client/ClientController.cs +++ b/SafeExamBrowser.Client/ClientController.cs @@ -206,9 +206,11 @@ namespace SafeExamBrowser.Client { if (Settings.ConfigurationMode == ConfigurationMode.ConfigureClient) { - logger.Info($"Detected download request for configuration file '{fileName}'."); + logger.Debug($"Received download request for configuration file '{fileName}'. Asking user to confirm the reconfiguration..."); - var result = messageBox.Show(TextKey.MessageBox_ReconfigurationQuestion, TextKey.MessageBox_ReconfigurationQuestionTitle, MessageBoxAction.YesNo, MessageBoxIcon.Question); + var message = TextKey.MessageBox_ReconfigurationQuestion; + var title = TextKey.MessageBox_ReconfigurationQuestionTitle; + var result = messageBox.Show(message, title, MessageBoxAction.YesNo, MessageBoxIcon.Question, args.BrowserWindow); var reconfigure = result == MessageBoxResult.Yes; logger.Info($"The user chose to {(reconfigure ? "start" : "abort")} the reconfiguration."); @@ -223,7 +225,7 @@ namespace SafeExamBrowser.Client else { logger.Info($"Denied download request for configuration file '{fileName}' due to '{Settings.ConfigurationMode}' mode."); - messageBox.Show(TextKey.MessageBox_ReconfigurationDenied, TextKey.MessageBox_ReconfigurationDeniedTitle); + messageBox.Show(TextKey.MessageBox_ReconfigurationDenied, TextKey.MessageBox_ReconfigurationDeniedTitle, parent: args.BrowserWindow); } } diff --git a/SafeExamBrowser.Contracts/Browser/DownloadEventArgs.cs b/SafeExamBrowser.Contracts/Browser/DownloadEventArgs.cs index 09c45e18..20e85dea 100644 --- a/SafeExamBrowser.Contracts/Browser/DownloadEventArgs.cs +++ b/SafeExamBrowser.Contracts/Browser/DownloadEventArgs.cs @@ -6,10 +6,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using SafeExamBrowser.Contracts.UserInterface.Browser; + namespace SafeExamBrowser.Contracts.Browser { /// - /// The event arguments used for all download events fired by the . + /// The event arguments used for all download events. /// public class DownloadEventArgs { @@ -18,6 +20,11 @@ namespace SafeExamBrowser.Contracts.Browser /// public bool AllowDownload { get; set; } + /// + /// The browser window from which the download request originated. + /// + public IBrowserWindow BrowserWindow { get; set; } + /// /// Callback executed once a download has been finished. /// diff --git a/SafeExamBrowser.Contracts/Monitoring/IWindowMonitor.cs b/SafeExamBrowser.Contracts/Monitoring/IWindowMonitor.cs index 774dc178..70c2d57f 100644 --- a/SafeExamBrowser.Contracts/Monitoring/IWindowMonitor.cs +++ b/SafeExamBrowser.Contracts/Monitoring/IWindowMonitor.cs @@ -31,16 +31,6 @@ namespace SafeExamBrowser.Contracts.Monitoring /// bool Hide(IntPtr window); - /// - /// Hides all currently opened windows. - /// - void HideAllWindows(); - - /// - /// Restores all windows which were hidden during the startup procedure. - /// - void RestoreHiddenWindows(); - /// /// Starts monitoring application windows by subscribing to specific system events. /// If a window is shown which is not supposed to do so, it will be automatically hidden. diff --git a/SafeExamBrowser.Contracts/WindowsApi/IExplorerShell.cs b/SafeExamBrowser.Contracts/WindowsApi/IExplorerShell.cs index e46d7b6a..d9f77aae 100644 --- a/SafeExamBrowser.Contracts/WindowsApi/IExplorerShell.cs +++ b/SafeExamBrowser.Contracts/WindowsApi/IExplorerShell.cs @@ -13,6 +13,16 @@ namespace SafeExamBrowser.Contracts.WindowsApi /// public interface IExplorerShell { + /// + /// Hides all currently opened windows. The explorer shell needs to be running in order to execute this operation! + /// + void HideAllWindows(); + + /// + /// Restores all previously hidden windows. The explorer shell needs to be running in order to execute this operation! + /// + void RestoreAllWindows(); + /// /// Resumes the explorer shell process, if it was previously suspended. /// diff --git a/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj b/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj index a3adfb66..8cdf993b 100644 --- a/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj +++ b/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj @@ -61,7 +61,6 @@ - diff --git a/SafeExamBrowser.Monitoring/Windows/WindowMonitor.cs b/SafeExamBrowser.Monitoring/Windows/WindowMonitor.cs index cca5ebcc..afab82bc 100644 --- a/SafeExamBrowser.Monitoring/Windows/WindowMonitor.cs +++ b/SafeExamBrowser.Monitoring/Windows/WindowMonitor.cs @@ -7,7 +7,6 @@ */ using System; -using System.Collections.Generic; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Monitoring; using SafeExamBrowser.Contracts.Monitoring.Events; @@ -21,7 +20,6 @@ namespace SafeExamBrowser.Monitoring.Windows private Guid? captureHookId; private Guid? foregroundHookId; private ILogger logger; - private IList minimizedWindows = new List(); private INativeMethods nativeMethods; public event WindowChangedEventHandler WindowChanged; @@ -57,40 +55,6 @@ namespace SafeExamBrowser.Monitoring.Windows return success; } - public void HideAllWindows() - { - logger.Info("Searching for windows to be minimized..."); - - foreach (var handle in nativeMethods.GetOpenWindows()) - { - var window = new Window - { - Handle = handle, - Title = nativeMethods.GetWindowTitle(handle) - }; - - minimizedWindows.Add(window); - logger.Info($"Found window '{window.Title}' with handle = {window.Handle}."); - } - - logger.Info("Minimizing all open windows..."); - nativeMethods.MinimizeAllOpenWindows(); - logger.Info("Open windows successfully minimized."); - } - - public void RestoreHiddenWindows() - { - logger.Info("Restoring all minimized windows..."); - - foreach (var window in minimizedWindows) - { - nativeMethods.RestoreWindow(window.Handle); - logger.Info($"Restored window '{window.Title}' with handle = {window.Handle}."); - } - - logger.Info("Minimized windows successfully restored."); - } - public void StartMonitoringWindows() { captureHookId = nativeMethods.RegisterSystemCaptureStartEvent(OnWindowChanged); diff --git a/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeOperationTests.cs index 6e140fd5..0592e149 100644 --- a/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeOperationTests.cs +++ b/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeOperationTests.cs @@ -80,6 +80,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations newDesktop.Verify(d => d.Activate(), Times.Once); processFactory.VerifySet(f => f.StartupDesktop = newDesktop.Object, Times.Once); explorerShell.Verify(s => s.Suspend(), Times.Once); + explorerShell.Verify(s => s.Terminate(), Times.Never); + explorerShell.Verify(s => s.HideAllWindows(), Times.Never); Assert.AreSame(sessionContext.NewDesktop, newDesktop.Object); Assert.AreSame(sessionContext.OriginalDesktop, originalDesktop.Object); @@ -93,10 +95,15 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations [TestMethod] public void MustCorrectlyInitializeDisableExplorerShell() { + var order = 0; + nextSettings.KioskMode = KioskMode.DisableExplorerShell; + explorerShell.Setup(s => s.HideAllWindows()).Callback(() => Assert.AreEqual(1, ++order)); + explorerShell.Setup(s => s.Terminate()).Callback(() => Assert.AreEqual(2, ++order)); sut.Perform(); + explorerShell.Verify(s => s.HideAllWindows(), Times.Once); explorerShell.Verify(s => s.Terminate(), Times.Once); } @@ -128,6 +135,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations processFactory.VerifySet(f => f.StartupDesktop = originalDesktop.Object, Times.Once); newDesktop.Verify(d => d.Close(), Times.Once); explorerShell.Verify(s => s.Resume(), Times.Once); + explorerShell.Verify(s => s.Start(), Times.Never); + explorerShell.Verify(s => s.RestoreAllWindows(), Times.Never); Assert.AreEqual(OperationResult.Success, performResult); Assert.AreEqual(OperationResult.Success, revertResult); @@ -140,13 +149,18 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations [TestMethod] public void MustCorrectlyRevertDisableExplorerShell() { + var order = 0; + currentSettings.KioskMode = KioskMode.DisableExplorerShell; nextSettings.KioskMode = KioskMode.DisableExplorerShell; + explorerShell.Setup(s => s.Start()).Callback(() => Assert.AreEqual(1, ++order)); + explorerShell.Setup(s => s.RestoreAllWindows()).Callback(() => Assert.AreEqual(2, ++order)); var performResult = sut.Perform(); var revertResult = sut.Revert(); explorerShell.Verify(s => s.Start(), Times.Once); + explorerShell.Verify(s => s.RestoreAllWindows(), Times.Once); Assert.AreEqual(OperationResult.Success, performResult); Assert.AreEqual(OperationResult.Success, revertResult); @@ -171,6 +185,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations explorerShell.Verify(s => s.Start(), Times.Never); explorerShell.Verify(s => s.Resume(), Times.Never); explorerShell.Verify(s => s.Suspend(), Times.Once); + explorerShell.Verify(s => s.HideAllWindows(), Times.Never); + explorerShell.Verify(s => s.RestoreAllWindows(), Times.Never); newDesktop.Verify(d => d.Activate(), Times.Once); newDesktop.Verify(d => d.Close(), Times.Never); originalDesktop.Verify(d => d.Activate(), Times.Never); @@ -181,10 +197,12 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations Assert.AreEqual(OperationResult.Success, result); - explorerShell.Verify(s => s.Resume(), Times.Never); explorerShell.Verify(s => s.Terminate(), Times.Once); - explorerShell.Verify(s => s.Suspend(), Times.Once); explorerShell.Verify(s => s.Start(), Times.Never); + explorerShell.Verify(s => s.Resume(), Times.Never); + explorerShell.Verify(s => s.Suspend(), Times.Once); + explorerShell.Verify(s => s.HideAllWindows(), Times.Once); + explorerShell.Verify(s => s.RestoreAllWindows(), Times.Never); newDesktop.Verify(d => d.Activate(), Times.Once); newDesktop.Verify(d => d.Close(), Times.Never); originalDesktop.Verify(d => d.Activate(), Times.Never); @@ -196,10 +214,12 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations Assert.AreEqual(OperationResult.Success, result); - explorerShell.Verify(s => s.Resume(), Times.Never); explorerShell.Verify(s => s.Terminate(), Times.Once); - explorerShell.Verify(s => s.Suspend(), Times.Exactly(2)); explorerShell.Verify(s => s.Start(), Times.Never); + explorerShell.Verify(s => s.Resume(), Times.Never); + explorerShell.Verify(s => s.Suspend(), Times.Exactly(2)); + explorerShell.Verify(s => s.HideAllWindows(), Times.Once); + explorerShell.Verify(s => s.RestoreAllWindows(), Times.Never); newDesktop.Verify(d => d.Activate(), Times.Exactly(2)); newDesktop.Verify(d => d.Close(), Times.Never); originalDesktop.Verify(d => d.Activate(), Times.Never); diff --git a/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeTerminationOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeTerminationOperationTests.cs index 9fb83993..56eab478 100644 --- a/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeTerminationOperationTests.cs +++ b/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeTerminationOperationTests.cs @@ -88,6 +88,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations explorerShell.Verify(s => s.Start(), Times.Once); explorerShell.Verify(s => s.Suspend(), Times.Never); explorerShell.Verify(s => s.Terminate(), Times.Never); + explorerShell.Verify(s => s.HideAllWindows(), Times.Never); + explorerShell.Verify(s => s.RestoreAllWindows(), Times.Once); newDesktop.Verify(d => d.Activate(), Times.Never); newDesktop.Verify(d => d.Close(), Times.Never); originalDesktop.Verify(d => d.Activate(), Times.Never); @@ -103,6 +105,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations explorerShell.Verify(s => s.Start(), Times.Once); explorerShell.Verify(s => s.Suspend(), Times.Never); explorerShell.Verify(s => s.Terminate(), Times.Never); + explorerShell.Verify(s => s.HideAllWindows(), Times.Never); + explorerShell.Verify(s => s.RestoreAllWindows(), Times.Once); newDesktop.Verify(d => d.Activate(), Times.Never); newDesktop.Verify(d => d.Close(), Times.Once); originalDesktop.Verify(d => d.Activate(), Times.Once); @@ -118,6 +122,8 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations explorerShell.Verify(s => s.Start(), Times.Exactly(2)); explorerShell.Verify(s => s.Suspend(), Times.Never); explorerShell.Verify(s => s.Terminate(), Times.Never); + explorerShell.Verify(s => s.HideAllWindows(), Times.Never); + explorerShell.Verify(s => s.RestoreAllWindows(), Times.Exactly(2)); newDesktop.Verify(d => d.Activate(), Times.Never); newDesktop.Verify(d => d.Close(), Times.Once); originalDesktop.Verify(d => d.Activate(), Times.Once); @@ -126,7 +132,45 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations [TestMethod] public void MustNotTerminateKioskModeIfSameInNextSesssion() { + var newDesktop = new Mock(); + var originalDesktop = new Mock(); + var result = default(OperationResult); + sessionContext.NewDesktop = newDesktop.Object; + sessionContext.OriginalDesktop = originalDesktop.Object; + sessionContext.ActiveMode = KioskMode.DisableExplorerShell; + nextSettings.KioskMode = KioskMode.DisableExplorerShell; + + result = sut.Repeat(); + + Assert.AreEqual(OperationResult.Success, result); + + explorerShell.Verify(s => s.Resume(), Times.Never); + explorerShell.Verify(s => s.Start(), Times.Never); + explorerShell.Verify(s => s.Suspend(), Times.Never); + explorerShell.Verify(s => s.Terminate(), Times.Never); + explorerShell.Verify(s => s.HideAllWindows(), Times.Never); + explorerShell.Verify(s => s.RestoreAllWindows(), Times.Never); + newDesktop.Verify(d => d.Activate(), Times.Never); + newDesktop.Verify(d => d.Close(), Times.Never); + originalDesktop.Verify(d => d.Activate(), Times.Never); + + sessionContext.ActiveMode = KioskMode.CreateNewDesktop; + nextSettings.KioskMode = KioskMode.CreateNewDesktop; + + result = sut.Repeat(); + + Assert.AreEqual(OperationResult.Success, result); + + explorerShell.Verify(s => s.Resume(), Times.Never); + explorerShell.Verify(s => s.Start(), Times.Never); + explorerShell.Verify(s => s.Suspend(), Times.Never); + explorerShell.Verify(s => s.Terminate(), Times.Never); + explorerShell.Verify(s => s.HideAllWindows(), Times.Never); + explorerShell.Verify(s => s.RestoreAllWindows(), Times.Never); + newDesktop.Verify(d => d.Activate(), Times.Never); + newDesktop.Verify(d => d.Close(), Times.Never); + originalDesktop.Verify(d => d.Activate(), Times.Never); } [TestMethod] diff --git a/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs b/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs index b80f3995..ff6c04a2 100644 --- a/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs +++ b/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs @@ -158,17 +158,16 @@ namespace SafeExamBrowser.Runtime.Operations { StatusChanged?.Invoke(TextKey.OperationStatus_WaitExplorerTermination); - // TODO: Hiding all windows must be done here, as the explorer shell is needed to do so! - + explorerShell.HideAllWindows(); explorerShell.Terminate(); } private void RestartExplorerShell() { StatusChanged?.Invoke(TextKey.OperationStatus_WaitExplorerStartup); - explorerShell.Start(); - // TODO: Restore all hidden windows! + explorerShell.Start(); + explorerShell.RestoreAllWindows(); } } } diff --git a/SafeExamBrowser.Runtime/RuntimeController.cs b/SafeExamBrowser.Runtime/RuntimeController.cs index 0a441c72..5a362008 100644 --- a/SafeExamBrowser.Runtime/RuntimeController.cs +++ b/SafeExamBrowser.Runtime/RuntimeController.cs @@ -448,9 +448,6 @@ namespace SafeExamBrowser.Runtime runtimeWindow?.UpdateStatus(status, true); } - /// - /// TODO: Move to utility in core library and use in client controller! - /// private void MapProgress(IProgressIndicator progressIndicator, ProgressChangedEventArgs args) { if (args.CurrentValue.HasValue) diff --git a/SafeExamBrowser.WindowsApi/ExplorerShell.cs b/SafeExamBrowser.WindowsApi/ExplorerShell.cs index 9cad87ad..f7b7996a 100644 --- a/SafeExamBrowser.WindowsApi/ExplorerShell.cs +++ b/SafeExamBrowser.WindowsApi/ExplorerShell.cs @@ -14,6 +14,7 @@ using System.Linq; using System.Threading; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.WindowsApi; +using SafeExamBrowser.WindowsApi.Types; namespace SafeExamBrowser.WindowsApi { @@ -21,15 +22,51 @@ namespace SafeExamBrowser.WindowsApi { private ILogger logger; private INativeMethods nativeMethods; + private IList minimizedWindows = new List(); private IList suspendedThreads; public ExplorerShell(ILogger logger, INativeMethods nativeMethods) { this.logger = logger; this.nativeMethods = nativeMethods; + this.minimizedWindows = new List(); this.suspendedThreads = new List(); } + public void HideAllWindows() + { + logger.Info("Searching for windows to be minimized..."); + + foreach (var handle in nativeMethods.GetOpenWindows()) + { + var window = new Window + { + Handle = handle, + Title = nativeMethods.GetWindowTitle(handle) + }; + + minimizedWindows.Add(window); + logger.Info($"Found window '{window.Title}' with handle = {window.Handle}."); + } + + logger.Info("Minimizing all open windows..."); + nativeMethods.MinimizeAllOpenWindows(); + logger.Info("Open windows successfully minimized."); + } + + public void RestoreAllWindows() + { + logger.Info("Restoring all minimized windows..."); + + foreach (var window in minimizedWindows) + { + nativeMethods.RestoreWindow(window.Handle); + logger.Info($"Restored window '{window.Title}' with handle = {window.Handle}."); + } + + logger.Info("Minimized windows successfully restored."); + } + public void Resume() { const int MAX_ATTEMPTS = 3; diff --git a/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj b/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj index 8b927bfb..b9df673a 100644 --- a/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj +++ b/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj @@ -83,6 +83,7 @@ + diff --git a/SafeExamBrowser.Monitoring/Windows/Window.cs b/SafeExamBrowser.WindowsApi/Types/Window.cs similarity index 90% rename from SafeExamBrowser.Monitoring/Windows/Window.cs rename to SafeExamBrowser.WindowsApi/Types/Window.cs index 1b881686..3c009be0 100644 --- a/SafeExamBrowser.Monitoring/Windows/Window.cs +++ b/SafeExamBrowser.WindowsApi/Types/Window.cs @@ -8,7 +8,7 @@ using System; -namespace SafeExamBrowser.Monitoring.Windows +namespace SafeExamBrowser.WindowsApi.Types { internal struct Window {