From 5f01973b5760df4a42d2d7bfc4964855a74d0eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20B=C3=BCchel?= Date: Fri, 28 Feb 2020 18:59:46 +0100 Subject: [PATCH] SEBWIN-373: Fixed system freeze caused by kiosk mode Create New Desktop due to it freezing the Windows shell. Thus, the Windows shell will henceforth be terminated for both kiosk modes. Furthermore ensured that processes started by SEB do not retain handles to the SEB directory. --- .../Operations/KioskModeOperationTests.cs | 309 ++++++++++++++---- .../Operations/KioskModeOperation.cs | 33 +- SafeExamBrowser.SystemComponents/UserInfo.cs | 7 +- .../IExplorerShell.cs | 10 - SafeExamBrowser.WindowsApi/ExplorerShell.cs | 65 +--- SafeExamBrowser.WindowsApi/ProcessFactory.cs | 15 +- 6 files changed, 293 insertions(+), 146 deletions(-) diff --git a/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeOperationTests.cs index 91db0ff1..7740fdaf 100644 --- a/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeOperationTests.cs +++ b/SafeExamBrowser.Runtime.UnitTests/Operations/KioskModeOperationTests.cs @@ -63,34 +63,38 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations var getCurrrent = 0; var createNew = 0; var activate = 0; + var hide = 0; var setStartup = 0; - var suspend = 0; + var terminate = 0; nextSettings.Security.KioskMode = KioskMode.CreateNewDesktop; desktopFactory.Setup(f => f.GetCurrent()).Callback(() => getCurrrent = ++order).Returns(originalDesktop.Object); desktopFactory.Setup(f => f.CreateNew(It.IsAny())).Callback(() => createNew = ++order).Returns(newDesktop.Object); + explorerShell.Setup(s => s.HideAllWindows()).Callback(() => hide = ++order); + explorerShell.Setup(s => s.Terminate()).Callback(() => terminate = ++order); newDesktop.Setup(d => d.Activate()).Callback(() => activate = ++order); processFactory.SetupSet(f => f.StartupDesktop = It.IsAny()).Callback(() => setStartup = ++order); - explorerShell.Setup(s => s.Suspend()).Callback(() => suspend = ++order); var result = sut.Perform(); desktopFactory.Verify(f => f.GetCurrent(), Times.Once); desktopFactory.Verify(f => f.CreateNew(It.IsAny()), Times.Once); + explorerShell.Verify(s => s.Start(), Times.Never); + explorerShell.Verify(s => s.Terminate(), Times.Once); + explorerShell.Verify(s => s.HideAllWindows(), Times.Once); + explorerShell.Verify(s => s.RestoreAllWindows(), Times.Never); 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.AreEqual(OperationResult.Success, result); - Assert.AreEqual(1, getCurrrent); - Assert.AreEqual(2, createNew); - Assert.AreEqual(3, activate); - Assert.AreEqual(4, setStartup); - Assert.AreEqual(5, suspend); + Assert.AreEqual(1, hide); + Assert.AreEqual(2, terminate); + Assert.AreEqual(3, getCurrrent); + Assert.AreEqual(4, createNew); + Assert.AreEqual(5, activate); + Assert.AreEqual(6, setStartup); } [TestMethod] @@ -111,62 +115,236 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations } [TestMethod] - public void Repeat_MustCorrectlySwitchToNewKioskMode() + public void Repeat_MustCorrectlySwitchFromCreateNewDesktopToDisableExplorerShell() { var newDesktop = new Mock(); var originalDesktop = new Mock(); - var result = default(OperationResult); + var order = 0; + var activate = 0; + var close = 0; + var startup = 0; desktopFactory.Setup(f => f.GetCurrent()).Returns(originalDesktop.Object); desktopFactory.Setup(f => f.CreateNew(It.IsAny())).Returns(newDesktop.Object); nextSettings.Security.KioskMode = KioskMode.CreateNewDesktop; - result = sut.Perform(); + sut.Perform(); + + desktopFactory.Reset(); + explorerShell.Reset(); + newDesktop.Reset(); + newDesktop.Setup(d => d.Close()).Callback(() => close = ++order); + originalDesktop.Reset(); + originalDesktop.Setup(d => d.Activate()).Callback(() => activate = ++order); + processFactory.Reset(); + processFactory.SetupSet(f => f.StartupDesktop = It.Is(d => d == originalDesktop.Object)).Callback(() => startup = ++order); + nextSettings.Security.KioskMode = KioskMode.DisableExplorerShell; + + var result = sut.Repeat(); + + desktopFactory.VerifyNoOtherCalls(); + explorerShell.VerifyNoOtherCalls(); + newDesktop.Verify(d => d.Close(), Times.Once); + originalDesktop.Verify(d => d.Activate(), Times.Once); + processFactory.VerifySet(f => f.StartupDesktop = It.Is(d => d == originalDesktop.Object), Times.Once); Assert.AreEqual(OperationResult.Success, result); + Assert.AreEqual(1, activate); + Assert.AreEqual(2, startup); + Assert.AreEqual(3, close); + } - explorerShell.Verify(s => s.Terminate(), Times.Never); - 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); + [TestMethod] + public void Repeat_MustCorrectlySwitchFromCreateNewDesktopToNone() + { + var newDesktop = new Mock(); + var originalDesktop = new Mock(); + var order = 0; + var activate = 0; + var close = 0; + var restore = 0; + var start = 0; + var startupDesktop = 0; + + desktopFactory.Setup(f => f.GetCurrent()).Returns(originalDesktop.Object); + desktopFactory.Setup(f => f.CreateNew(It.IsAny())).Returns(newDesktop.Object); + nextSettings.Security.KioskMode = KioskMode.CreateNewDesktop; + + sut.Perform(); + + desktopFactory.Reset(); + explorerShell.Reset(); + explorerShell.Setup(s => s.RestoreAllWindows()).Callback(() => restore = ++order); + explorerShell.Setup(s => s.Start()).Callback(() => start = ++order); + newDesktop.Reset(); + newDesktop.Setup(d => d.Close()).Callback(() => close = ++order); + originalDesktop.Reset(); + originalDesktop.Setup(d => d.Activate()).Callback(() => activate = ++order); + processFactory.Reset(); + processFactory.SetupSet(f => f.StartupDesktop = It.Is(d => d == originalDesktop.Object)).Callback(() => startupDesktop = ++order); + nextSettings.Security.KioskMode = KioskMode.None; + + var result = sut.Repeat(); + + desktopFactory.VerifyNoOtherCalls(); + explorerShell.Verify(s => s.RestoreAllWindows(), Times.Once); + explorerShell.Verify(s => s.Start(), Times.Once); + newDesktop.Verify(d => d.Close(), Times.Once); + originalDesktop.Verify(d => d.Activate(), Times.Once); + processFactory.VerifySet(f => f.StartupDesktop = It.Is(d => d == originalDesktop.Object), Times.Once); + + Assert.AreEqual(OperationResult.Success, result); + Assert.AreEqual(1, activate); + Assert.AreEqual(2, startupDesktop); + Assert.AreEqual(3, close); + Assert.AreEqual(4, start); + Assert.AreEqual(5, restore); + } + + [TestMethod] + public void Repeat_MustCorrectlySwitchFromDisableExplorerShellToCreateNewDesktop() + { + var newDesktop = new Mock(); + var originalDesktop = new Mock(); + var order = 0; + var activate = 0; + var current = 0; + var startup = 0; nextSettings.Security.KioskMode = KioskMode.DisableExplorerShell; - result = sut.Repeat(); + sut.Perform(); - Assert.AreEqual(OperationResult.Success, result); - - explorerShell.Verify(s => s.Terminate(), Times.Once); - explorerShell.Verify(s => s.Start(), Times.Never); - explorerShell.Verify(s => s.Resume(), Times.Once); - 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.Once); - originalDesktop.Verify(d => d.Activate(), Times.Once); - - currentSettings.Security.KioskMode = nextSettings.Security.KioskMode; + desktopFactory.Reset(); + desktopFactory.Setup(f => f.GetCurrent()).Returns(originalDesktop.Object).Callback(() => current = ++order); + desktopFactory.Setup(f => f.CreateNew(It.IsAny())).Returns(newDesktop.Object); + explorerShell.Reset(); + newDesktop.Reset(); + newDesktop.Setup(d => d.Activate()).Callback(() => activate = ++order); + originalDesktop.Reset(); + processFactory.Reset(); + processFactory.SetupSet(f => f.StartupDesktop = It.Is(d => d == newDesktop.Object)).Callback(() => startup = ++order); nextSettings.Security.KioskMode = KioskMode.CreateNewDesktop; - result = sut.Repeat(); + var result = sut.Repeat(); + + desktopFactory.Verify(f => f.GetCurrent(), Times.Once); + desktopFactory.Verify(f => f.CreateNew(It.IsAny()), Times.Once); + explorerShell.VerifyNoOtherCalls(); + newDesktop.Verify(d => d.Activate(), Times.Once); + originalDesktop.VerifyNoOtherCalls(); + processFactory.VerifySet(f => f.StartupDesktop = It.Is(d => d == newDesktop.Object), Times.Once); Assert.AreEqual(OperationResult.Success, result); + Assert.AreEqual(1, current); + Assert.AreEqual(2, activate); + Assert.AreEqual(3, startup); + } - explorerShell.Verify(s => s.Terminate(), Times.Once); - explorerShell.Verify(s => s.Start(), Times.Once); - explorerShell.Verify(s => s.Resume(), Times.Once); - explorerShell.Verify(s => s.Suspend(), Times.Exactly(2)); - explorerShell.Verify(s => s.HideAllWindows(), Times.Once); + [TestMethod] + public void Repeat_MustCorrectlySwitchFromDisableExplorerShellToNone() + { + var order = 0; + var restore = 0; + var start = 0; + + nextSettings.Security.KioskMode = KioskMode.DisableExplorerShell; + + sut.Perform(); + + explorerShell.Reset(); + explorerShell.Setup(s => s.RestoreAllWindows()).Callback(() => restore = ++order); + explorerShell.Setup(s => s.Start()).Callback(() => start = ++order); + processFactory.Reset(); + nextSettings.Security.KioskMode = KioskMode.None; + + var result = sut.Repeat(); + + desktopFactory.VerifyNoOtherCalls(); explorerShell.Verify(s => s.RestoreAllWindows(), Times.Once); - newDesktop.Verify(d => d.Activate(), Times.Exactly(2)); - newDesktop.Verify(d => d.Close(), Times.Once); - originalDesktop.Verify(d => d.Activate(), Times.Once); + explorerShell.Verify(s => s.Start(), Times.Once); + processFactory.VerifySet(f => f.StartupDesktop = It.IsAny(), Times.Never); + + Assert.AreEqual(OperationResult.Success, result); + Assert.AreEqual(1, start); + Assert.AreEqual(2, restore); + } + + [TestMethod] + public void Repeat_MustCorrectlySwitchFromNoneToCreateNewDesktop() + { + var newDesktop = new Mock(); + var originalDesktop = new Mock(); + var order = 0; + var activate = 0; + var current = 0; + var hide = 0; + var startup = 0; + var terminate = 0; + + nextSettings.Security.KioskMode = KioskMode.None; + + sut.Perform(); + + desktopFactory.Reset(); + desktopFactory.Setup(f => f.GetCurrent()).Returns(originalDesktop.Object).Callback(() => current = ++order); + desktopFactory.Setup(f => f.CreateNew(It.IsAny())).Returns(newDesktop.Object); + explorerShell.Reset(); + explorerShell.Setup(s => s.HideAllWindows()).Callback(() => hide = ++order); + explorerShell.Setup(s => s.Terminate()).Callback(() => terminate = ++order); + newDesktop.Reset(); + newDesktop.Setup(d => d.Activate()).Callback(() => activate = ++order); + originalDesktop.Reset(); + processFactory.Reset(); + processFactory.SetupSet(f => f.StartupDesktop = It.Is(d => d == newDesktop.Object)).Callback(() => startup = ++order); + nextSettings.Security.KioskMode = KioskMode.CreateNewDesktop; + + var result = sut.Repeat(); + + desktopFactory.Verify(f => f.GetCurrent(), Times.Once); + desktopFactory.Verify(f => f.CreateNew(It.IsAny()), Times.Once); + explorerShell.Verify(s => s.HideAllWindows(), Times.Once); + explorerShell.Verify(s => s.Terminate(), Times.Once); + newDesktop.Verify(d => d.Activate(), Times.Once); + originalDesktop.VerifyNoOtherCalls(); + processFactory.VerifySet(f => f.StartupDesktop = It.Is(d => d == newDesktop.Object), Times.Once); + + Assert.AreEqual(OperationResult.Success, result); + Assert.AreEqual(1, hide); + Assert.AreEqual(2, terminate); + Assert.AreEqual(3, current); + Assert.AreEqual(4, activate); + Assert.AreEqual(5, startup); + } + + [TestMethod] + public void Repeat_MustCorrectlySwitchFromNoneToDisableExplorerShell() + { + var order = 0; + var hide = 0; + var terminate = 0; + + nextSettings.Security.KioskMode = KioskMode.None; + + sut.Perform(); + + desktopFactory.Reset(); + explorerShell.Reset(); + explorerShell.Setup(s => s.HideAllWindows()).Callback(() => hide = ++order); + explorerShell.Setup(s => s.Terminate()).Callback(() => terminate = ++order); + processFactory.Reset(); + nextSettings.Security.KioskMode = KioskMode.DisableExplorerShell; + + var result = sut.Repeat(); + + desktopFactory.VerifyNoOtherCalls(); + explorerShell.Verify(s => s.HideAllWindows(), Times.Once); + explorerShell.Verify(s => s.Terminate(), Times.Once); + processFactory.VerifySet(f => f.StartupDesktop = It.IsAny(), Times.Never); + + Assert.AreEqual(OperationResult.Success, result); + Assert.AreEqual(1, hide); + Assert.AreEqual(2, terminate); } [TestMethod] @@ -196,8 +374,10 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations newDesktop.Verify(d => d.Activate(), Times.Once); newDesktop.Verify(d => d.Close(), Times.Never); processFactory.VerifySet(f => f.StartupDesktop = newDesktop.Object, Times.Once); - explorerShell.Verify(s => s.Suspend(), Times.Once); - explorerShell.Verify(s => s.Resume(), Times.Never); + explorerShell.Verify(s => s.Start(), Times.Never); + explorerShell.Verify(s => s.Terminate(), Times.Once); + explorerShell.Verify(s => s.HideAllWindows(), Times.Once); + explorerShell.Verify(s => s.RestoreAllWindows(), Times.Never); } [TestMethod] @@ -230,36 +410,48 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations var originalDesktop = new Mock(); var order = 0; var activate = 0; + var restore = 0; var setStartup = 0; var close = 0; - var resume = 0; + var start = 0; currentSettings.Security.KioskMode = KioskMode.CreateNewDesktop; nextSettings.Security.KioskMode = KioskMode.CreateNewDesktop; - desktopFactory.Setup(f => f.GetCurrent()).Returns(originalDesktop.Object); desktopFactory.Setup(f => f.CreateNew(It.IsAny())).Returns(newDesktop.Object); - originalDesktop.Setup(d => d.Activate()).Callback(() => activate = ++order); - processFactory.SetupSet(f => f.StartupDesktop = It.Is(d => d == originalDesktop.Object)).Callback(() => setStartup = ++order); - newDesktop.Setup(d => d.Close()).Callback(() => close = ++order); - explorerShell.Setup(s => s.Resume()).Callback(() => resume = ++order); var performResult = sut.Perform(); + + Assert.AreEqual(OperationResult.Success, performResult); + + desktopFactory.Reset(); + originalDesktop.Reset(); + originalDesktop.Setup(d => d.Activate()).Callback(() => activate = ++order); + processFactory.SetupSet(f => f.StartupDesktop = It.Is(d => d == originalDesktop.Object)).Callback(() => setStartup = ++order); + newDesktop.Reset(); + newDesktop.Setup(d => d.Close()).Callback(() => close = ++order); + explorerShell.Reset(); + explorerShell.Setup(s => s.Start()).Callback(() => start = ++order); + explorerShell.Setup(s => s.RestoreAllWindows()).Callback(() => restore = ++order); + var revertResult = sut.Revert(); + desktopFactory.VerifyNoOtherCalls(); originalDesktop.Verify(d => d.Activate(), Times.Once); 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); + explorerShell.Verify(s => s.Start(), Times.Once); + explorerShell.Verify(s => s.Terminate(), Times.Never); + explorerShell.Verify(s => s.HideAllWindows(), Times.Never); + explorerShell.Verify(s => s.RestoreAllWindows(), Times.Once); Assert.AreEqual(OperationResult.Success, performResult); Assert.AreEqual(OperationResult.Success, revertResult); Assert.AreEqual(1, activate); Assert.AreEqual(2, setStartup); Assert.AreEqual(3, close); - Assert.AreEqual(4, resume); + Assert.AreEqual(4, start); + Assert.AreEqual(5, restore); } [TestMethod] @@ -289,6 +481,9 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations Assert.AreEqual(OperationResult.Success, sut.Perform()); Assert.AreEqual(OperationResult.Success, sut.Repeat()); + Assert.AreEqual(OperationResult.Success, sut.Repeat()); + Assert.AreEqual(OperationResult.Success, sut.Repeat()); + Assert.AreEqual(OperationResult.Success, sut.Repeat()); Assert.AreEqual(OperationResult.Success, sut.Revert()); desktopFactory.VerifyNoOtherCalls(); diff --git a/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs b/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs index 0a0217ed..1e1549a6 100644 --- a/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs +++ b/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs @@ -51,6 +51,7 @@ namespace SafeExamBrowser.Runtime.Operations switch (Context.Next.Settings.Security.KioskMode) { case KioskMode.CreateNewDesktop: + TerminateExplorerShell(); CreateNewDesktop(); break; case KioskMode.DisableExplorerShell: @@ -64,7 +65,6 @@ namespace SafeExamBrowser.Runtime.Operations public override OperationResult Repeat() { var newMode = Context.Next.Settings.Security.KioskMode; - var result = OperationResult.Success; if (activeMode == newMode) { @@ -72,15 +72,33 @@ namespace SafeExamBrowser.Runtime.Operations } else { - result = Revert(); + logger.Info($"Switching from kiosk mode '{activeMode}' to '{newMode}'..."); + StatusChanged?.Invoke(TextKey.OperationStatus_InitializeKioskMode); - if (result == OperationResult.Success) + switch (activeMode) { - result = Perform(); + case KioskMode.CreateNewDesktop: + CloseNewDesktop(); + break; + case KioskMode.None: + TerminateExplorerShell(); + break; + } + + activeMode = newMode; + + switch (newMode) + { + case KioskMode.CreateNewDesktop: + CreateNewDesktop(); + break; + case KioskMode.None: + RestartExplorerShell(); + break; } } - return result; + return OperationResult.Success; } public override OperationResult Revert() @@ -92,6 +110,7 @@ namespace SafeExamBrowser.Runtime.Operations { case KioskMode.CreateNewDesktop: CloseNewDesktop(); + RestartExplorerShell(); break; case KioskMode.DisableExplorerShell: RestartExplorerShell(); @@ -112,8 +131,6 @@ namespace SafeExamBrowser.Runtime.Operations newDesktop.Activate(); processFactory.StartupDesktop = newDesktop; logger.Info("Successfully activated new desktop."); - - explorerShell.Suspend(); } private void CloseNewDesktop() @@ -138,8 +155,6 @@ namespace SafeExamBrowser.Runtime.Operations { logger.Warn($"No new desktop found to close!"); } - - explorerShell.Resume(); } private void TerminateExplorerShell() diff --git a/SafeExamBrowser.SystemComponents/UserInfo.cs b/SafeExamBrowser.SystemComponents/UserInfo.cs index d32af919..196283f4 100644 --- a/SafeExamBrowser.SystemComponents/UserInfo.cs +++ b/SafeExamBrowser.SystemComponents/UserInfo.cs @@ -89,11 +89,12 @@ namespace SafeExamBrowser.SystemComponents { var process = new Process(); - process.StartInfo.FileName = "cmd.exe"; process.StartInfo.Arguments = string.Format("/c \"wmic useraccount where name='{0}' get sid\"", userName); - process.StartInfo.UseShellExecute = false; - process.StartInfo.RedirectStandardOutput = true; process.StartInfo.CreateNoWindow = true; + process.StartInfo.FileName = "cmd.exe"; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.UseShellExecute = false; + process.StartInfo.WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Windows); process.Start(); process.WaitForExit(5000); diff --git a/SafeExamBrowser.WindowsApi.Contracts/IExplorerShell.cs b/SafeExamBrowser.WindowsApi.Contracts/IExplorerShell.cs index 9de42b42..15556652 100644 --- a/SafeExamBrowser.WindowsApi.Contracts/IExplorerShell.cs +++ b/SafeExamBrowser.WindowsApi.Contracts/IExplorerShell.cs @@ -23,21 +23,11 @@ namespace SafeExamBrowser.WindowsApi.Contracts /// void RestoreAllWindows(); - /// - /// Resumes the explorer shell process, if it was previously suspended. - /// - void Resume(); - /// /// Starts the Windows explorer shell, if it isn't already running. /// void Start(); - /// - /// Suspends the explorer shell process, if it is running. - /// - void Suspend(); - /// /// Gracefully terminates the Windows explorer shell, if it is running. /// diff --git a/SafeExamBrowser.WindowsApi/ExplorerShell.cs b/SafeExamBrowser.WindowsApi/ExplorerShell.cs index b692c058..599b1083 100644 --- a/SafeExamBrowser.WindowsApi/ExplorerShell.cs +++ b/SafeExamBrowser.WindowsApi/ExplorerShell.cs @@ -23,14 +23,12 @@ 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() @@ -68,32 +66,6 @@ namespace SafeExamBrowser.WindowsApi logger.Info("Minimized windows successfully restored."); } - public void Resume() - { - const int MAX_ATTEMPTS = 3; - - logger.Debug($"Attempting to resume all {suspendedThreads.Count} previously suspended explorer shell threads..."); - - for (var attempts = 0; suspendedThreads.Any(); attempts++) - { - var thread = suspendedThreads.First(); - var success = nativeMethods.ResumeThread(thread.Id); - - if (success || attempts == MAX_ATTEMPTS) - { - attempts = 0; - suspendedThreads.Remove(thread); - - if (!success) - { - logger.Warn($"Failed to resume explorer shell thread with ID = {thread.Id} within {MAX_ATTEMPTS} attempts!"); - } - } - } - - logger.Info($"Successfully resumed explorer shell process."); - } - public void Start() { var process = new System.Diagnostics.Process(); @@ -103,6 +75,8 @@ namespace SafeExamBrowser.WindowsApi process.StartInfo.CreateNoWindow = true; process.StartInfo.FileName = explorerPath; + process.StartInfo.UseShellExecute = false; + process.StartInfo.WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Windows); process.Start(); logger.Debug("Waiting for explorer shell to initialize..."); @@ -117,39 +91,6 @@ namespace SafeExamBrowser.WindowsApi process.Close(); } - public void Suspend() - { - var processId = nativeMethods.GetShellProcessId(); - var explorerProcesses = System.Diagnostics.Process.GetProcessesByName("explorer"); - var process = explorerProcesses.FirstOrDefault(p => p.Id == processId); - - if (process != null) - { - logger.Debug($"Found explorer shell processes with PID = {processId} and {process.Threads.Count} threads."); - - foreach (ProcessThread thread in process.Threads) - { - var success = nativeMethods.SuspendThread(thread.Id); - - if (success) - { - suspendedThreads.Add(thread); - } - else - { - logger.Warn($"Failed to suspend explorer shell thread with ID = {thread.Id}!"); - } - } - - logger.Info($"Successfully suspended explorer shell process with PID = {processId}."); - process.Close(); - } - else - { - logger.Info("The explorer shell can't be suspended, as it seems to not be running."); - } - } - public void Terminate() { const int THREE_SECONDS = 3000; @@ -205,7 +146,9 @@ namespace SafeExamBrowser.WindowsApi process.StartInfo.Arguments = $"/F /PID {processId}"; process.StartInfo.CreateNoWindow = true; process.StartInfo.FileName = taskkillPath; + process.StartInfo.UseShellExecute = false; process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; + process.StartInfo.WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Windows); process.Start(); process.WaitForExit(); } diff --git a/SafeExamBrowser.WindowsApi/ProcessFactory.cs b/SafeExamBrowser.WindowsApi/ProcessFactory.cs index 11899c47..f44982f4 100644 --- a/SafeExamBrowser.WindowsApi/ProcessFactory.cs +++ b/SafeExamBrowser.WindowsApi/ProcessFactory.cs @@ -168,12 +168,15 @@ namespace SafeExamBrowser.WindowsApi private System.Diagnostics.Process StartNormal(string path, params string[] args) { - return System.Diagnostics.Process.Start(new ProcessStartInfo - { - Arguments = string.Join(" ", args), - FileName = path, - UseShellExecute = false - }); + var process = new System.Diagnostics.Process(); + + process.StartInfo.Arguments = string.Join(" ", args); + process.StartInfo.FileName = path; + process.StartInfo.UseShellExecute = false; + process.StartInfo.WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Windows); + process.Start(); + + return process; } private System.Diagnostics.Process StartOnDesktop(string path, params string[] args)