From 14abfccc2e2cdd7ffb2386ac43a7604fef042cf8 Mon Sep 17 00:00:00 2001 From: dbuechel Date: Tue, 19 Mar 2019 12:26:03 +0100 Subject: [PATCH] SEBWIN-226: Changed termination mechanism of explorer shell to accommodate bug (?) in Windows and fixed setting of working area parameters. --- .../ConfigurationData/DataMapper.Security.cs | 2 +- .../Operations/KioskModeOperation.cs | 4 +- SafeExamBrowser.WindowsApi/ExplorerShell.cs | 59 +++++++++++++++---- SafeExamBrowser.WindowsApi/NativeMethods.cs | 2 +- 4 files changed, 52 insertions(+), 15 deletions(-) diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.Security.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.Security.cs index 141de63c..0ad00558 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.Security.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.Security.cs @@ -16,7 +16,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData private void MapKioskMode(IDictionary rawData, Settings settings) { var hasCreateNewDesktop = rawData.TryGetValue(Keys.Security.KioskModeCreateNewDesktop, out var createNewDesktop); - var hasDisableExplorerShell = rawData.TryGetValue(Keys.Security.KioskModeCreateNewDesktop, out var disableExplorerShell); + var hasDisableExplorerShell = rawData.TryGetValue(Keys.Security.KioskModeDisableExplorerShell, out var disableExplorerShell); if (hasDisableExplorerShell && disableExplorerShell as bool? == true) { diff --git a/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs b/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs index e48b0f1c..36938d51 100644 --- a/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs +++ b/SafeExamBrowser.Runtime/Operations/KioskModeOperation.cs @@ -62,6 +62,8 @@ namespace SafeExamBrowser.Runtime.Operations logger.Info($"Initializing kiosk mode '{Context.Next.Settings.KioskMode}'..."); StatusChanged?.Invoke(TextKey.OperationStatus_InitializeKioskMode); + ActiveMode = Context.Next.Settings.KioskMode; + switch (Context.Next.Settings.KioskMode) { case KioskMode.CreateNewDesktop: @@ -72,8 +74,6 @@ namespace SafeExamBrowser.Runtime.Operations break; } - ActiveMode = Context.Next.Settings.KioskMode; - return OperationResult.Success; } diff --git a/SafeExamBrowser.WindowsApi/ExplorerShell.cs b/SafeExamBrowser.WindowsApi/ExplorerShell.cs index 5b5af83e..8d5603ac 100644 --- a/SafeExamBrowser.WindowsApi/ExplorerShell.cs +++ b/SafeExamBrowser.WindowsApi/ExplorerShell.cs @@ -99,12 +99,14 @@ namespace SafeExamBrowser.WindowsApi var process = new System.Diagnostics.Process(); var explorerPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "explorer.exe"); - logger.Info("Restarting explorer shell..."); + logger.Debug("Starting explorer shell process..."); process.StartInfo.CreateNoWindow = true; process.StartInfo.FileName = explorerPath; process.Start(); + logger.Debug("Waiting for explorer shell to initialize..."); + while (nativeMethods.GetShellWindowHandle() == IntPtr.Zero) { Thread.Sleep(20); @@ -119,13 +121,13 @@ namespace SafeExamBrowser.WindowsApi { var processId = nativeMethods.GetShellProcessId(); var explorerProcesses = System.Diagnostics.Process.GetProcessesByName("explorer"); - var shellProcess = explorerProcesses.FirstOrDefault(p => p.Id == processId); + var process = explorerProcesses.FirstOrDefault(p => p.Id == processId); - if (shellProcess != null) + if (process != null) { - logger.Debug($"Found explorer shell processes with PID = {processId} and {shellProcess.Threads.Count} threads."); + logger.Debug($"Found explorer shell processes with PID = {processId} and {process.Threads.Count} threads."); - foreach (ProcessThread thread in shellProcess.Threads) + foreach (ProcessThread thread in process.Threads) { var success = nativeMethods.SuspendThread(thread.Id); @@ -140,6 +142,7 @@ namespace SafeExamBrowser.WindowsApi } logger.Info($"Successfully suspended explorer shell process with PID = {processId}."); + process.Close(); } else { @@ -149,28 +152,62 @@ namespace SafeExamBrowser.WindowsApi public void Terminate() { + const int THREE_SECONDS = 3000; var processId = nativeMethods.GetShellProcessId(); var explorerProcesses = System.Diagnostics.Process.GetProcessesByName("explorer"); - var shellProcess = explorerProcesses.FirstOrDefault(p => p.Id == processId); + var process = explorerProcesses.FirstOrDefault(p => p.Id == processId); - if (shellProcess != null) + if (process != null) { logger.Debug($"Found explorer shell processes with PID = {processId}. Sending close message..."); - nativeMethods.PostCloseMessageToShell(); + logger.Debug("Waiting for explorer shell to terminate..."); - while (!shellProcess.HasExited) + while (nativeMethods.GetShellWindowHandle() != IntPtr.Zero) { - shellProcess.Refresh(); Thread.Sleep(20); } - logger.Info($"Successfully terminated explorer shell process with PID = {processId}."); + process.WaitForExit(THREE_SECONDS); + process.Refresh(); + + if (!process.HasExited) + { + KillExplorerShell(process.Id); + } + + process.Refresh(); + + if (process.HasExited) + { + logger.Info($"Successfully terminated explorer shell process with PID = {processId}."); + } + else + { + logger.Error($"Failed to completely terminate explorer shell process with PID = {processId}."); + } + + process.Close(); } else { logger.Info("The explorer shell seems to already be terminated."); } } + + private void KillExplorerShell(int processId) + { + var process = new System.Diagnostics.Process(); + var taskkillPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "taskkill.exe"); + + logger.Warn("Failed to gracefully terminate, attempting forceful termination..."); + + process.StartInfo.Arguments = $"/F /PID {processId}"; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.FileName = taskkillPath; + process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; + process.Start(); + process.WaitForExit(); + } } } diff --git a/SafeExamBrowser.WindowsApi/NativeMethods.cs b/SafeExamBrowser.WindowsApi/NativeMethods.cs index dff30251..5b65da41 100644 --- a/SafeExamBrowser.WindowsApi/NativeMethods.cs +++ b/SafeExamBrowser.WindowsApi/NativeMethods.cs @@ -370,7 +370,7 @@ namespace SafeExamBrowser.WindowsApi public void SetWorkingArea(IBounds bounds) { var workingArea = new RECT { Left = bounds.Left, Top = bounds.Top, Right = bounds.Right, Bottom = bounds.Bottom }; - var success = User32.SystemParametersInfo(SPI.SETWORKAREA, 0, ref workingArea, SPIF.NONE); + var success = User32.SystemParametersInfo(SPI.SETWORKAREA, 0, ref workingArea, SPIF.UPDATEINIFILE); if (!success) {