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.

This commit is contained in:
Damian Büchel 2020-02-28 18:59:46 +01:00
parent ba4d4cec81
commit 5f01973b57
6 changed files with 293 additions and 146 deletions

View file

@ -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<string>())).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<IDesktop>()).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<string>()), 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<IDesktop>();
var originalDesktop = new Mock<IDesktop>();
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<string>())).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<IDesktop>(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<IDesktop>(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<IDesktop>();
var originalDesktop = new Mock<IDesktop>();
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<string>())).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<IDesktop>(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<IDesktop>(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<IDesktop>();
var originalDesktop = new Mock<IDesktop>();
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<string>())).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<IDesktop>(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<string>()), Times.Once);
explorerShell.VerifyNoOtherCalls();
newDesktop.Verify(d => d.Activate(), Times.Once);
originalDesktop.VerifyNoOtherCalls();
processFactory.VerifySet(f => f.StartupDesktop = It.Is<IDesktop>(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<IDesktop>(), Times.Never);
Assert.AreEqual(OperationResult.Success, result);
Assert.AreEqual(1, start);
Assert.AreEqual(2, restore);
}
[TestMethod]
public void Repeat_MustCorrectlySwitchFromNoneToCreateNewDesktop()
{
var newDesktop = new Mock<IDesktop>();
var originalDesktop = new Mock<IDesktop>();
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<string>())).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<IDesktop>(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<string>()), 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<IDesktop>(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<IDesktop>(), 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<IDesktop>();
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<string>())).Returns(newDesktop.Object);
originalDesktop.Setup(d => d.Activate()).Callback(() => activate = ++order);
processFactory.SetupSet(f => f.StartupDesktop = It.Is<IDesktop>(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<IDesktop>(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();

View file

@ -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()

View file

@ -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);

View file

@ -23,21 +23,11 @@ namespace SafeExamBrowser.WindowsApi.Contracts
/// </summary>
void RestoreAllWindows();
/// <summary>
/// Resumes the explorer shell process, if it was previously suspended.
/// </summary>
void Resume();
/// <summary>
/// Starts the Windows explorer shell, if it isn't already running.
/// </summary>
void Start();
/// <summary>
/// Suspends the explorer shell process, if it is running.
/// </summary>
void Suspend();
/// <summary>
/// Gracefully terminates the Windows explorer shell, if it is running.
/// </summary>

View file

@ -23,14 +23,12 @@ namespace SafeExamBrowser.WindowsApi
private ILogger logger;
private INativeMethods nativeMethods;
private IList<Window> minimizedWindows = new List<Window>();
private IList<ProcessThread> suspendedThreads;
public ExplorerShell(ILogger logger, INativeMethods nativeMethods)
{
this.logger = logger;
this.nativeMethods = nativeMethods;
this.minimizedWindows = new List<Window>();
this.suspendedThreads = new List<ProcessThread>();
}
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();
}

View file

@ -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)