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 getCurrrent = 0;
var createNew = 0; var createNew = 0;
var activate = 0; var activate = 0;
var hide = 0;
var setStartup = 0; var setStartup = 0;
var suspend = 0; var terminate = 0;
nextSettings.Security.KioskMode = KioskMode.CreateNewDesktop; nextSettings.Security.KioskMode = KioskMode.CreateNewDesktop;
desktopFactory.Setup(f => f.GetCurrent()).Callback(() => getCurrrent = ++order).Returns(originalDesktop.Object); 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); 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); newDesktop.Setup(d => d.Activate()).Callback(() => activate = ++order);
processFactory.SetupSet(f => f.StartupDesktop = It.IsAny<IDesktop>()).Callback(() => setStartup = ++order); processFactory.SetupSet(f => f.StartupDesktop = It.IsAny<IDesktop>()).Callback(() => setStartup = ++order);
explorerShell.Setup(s => s.Suspend()).Callback(() => suspend = ++order);
var result = sut.Perform(); var result = sut.Perform();
desktopFactory.Verify(f => f.GetCurrent(), Times.Once); desktopFactory.Verify(f => f.GetCurrent(), Times.Once);
desktopFactory.Verify(f => f.CreateNew(It.IsAny<string>()), 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); newDesktop.Verify(d => d.Activate(), Times.Once);
processFactory.VerifySet(f => f.StartupDesktop = newDesktop.Object, 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(OperationResult.Success, result);
Assert.AreEqual(1, getCurrrent); Assert.AreEqual(1, hide);
Assert.AreEqual(2, createNew); Assert.AreEqual(2, terminate);
Assert.AreEqual(3, activate); Assert.AreEqual(3, getCurrrent);
Assert.AreEqual(4, setStartup); Assert.AreEqual(4, createNew);
Assert.AreEqual(5, suspend); Assert.AreEqual(5, activate);
Assert.AreEqual(6, setStartup);
} }
[TestMethod] [TestMethod]
@ -111,62 +115,236 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
} }
[TestMethod] [TestMethod]
public void Repeat_MustCorrectlySwitchToNewKioskMode() public void Repeat_MustCorrectlySwitchFromCreateNewDesktopToDisableExplorerShell()
{ {
var newDesktop = new Mock<IDesktop>(); var newDesktop = new Mock<IDesktop>();
var originalDesktop = 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.GetCurrent()).Returns(originalDesktop.Object);
desktopFactory.Setup(f => f.CreateNew(It.IsAny<string>())).Returns(newDesktop.Object); desktopFactory.Setup(f => f.CreateNew(It.IsAny<string>())).Returns(newDesktop.Object);
nextSettings.Security.KioskMode = KioskMode.CreateNewDesktop; 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(OperationResult.Success, result);
Assert.AreEqual(1, activate);
Assert.AreEqual(2, startup);
Assert.AreEqual(3, close);
}
explorerShell.Verify(s => s.Terminate(), Times.Never); [TestMethod]
explorerShell.Verify(s => s.Start(), Times.Never); public void Repeat_MustCorrectlySwitchFromCreateNewDesktopToNone()
explorerShell.Verify(s => s.Resume(), Times.Never); {
explorerShell.Verify(s => s.Suspend(), Times.Once); var newDesktop = new Mock<IDesktop>();
explorerShell.Verify(s => s.HideAllWindows(), Times.Never); var originalDesktop = new Mock<IDesktop>();
explorerShell.Verify(s => s.RestoreAllWindows(), Times.Never); var order = 0;
newDesktop.Verify(d => d.Activate(), Times.Once); var activate = 0;
newDesktop.Verify(d => d.Close(), Times.Never); var close = 0;
originalDesktop.Verify(d => d.Activate(), Times.Never); 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; nextSettings.Security.KioskMode = KioskMode.DisableExplorerShell;
result = sut.Repeat(); sut.Perform();
Assert.AreEqual(OperationResult.Success, result); desktopFactory.Reset();
desktopFactory.Setup(f => f.GetCurrent()).Returns(originalDesktop.Object).Callback(() => current = ++order);
explorerShell.Verify(s => s.Terminate(), Times.Once); desktopFactory.Setup(f => f.CreateNew(It.IsAny<string>())).Returns(newDesktop.Object);
explorerShell.Verify(s => s.Start(), Times.Never); explorerShell.Reset();
explorerShell.Verify(s => s.Resume(), Times.Once); newDesktop.Reset();
explorerShell.Verify(s => s.Suspend(), Times.Once); newDesktop.Setup(d => d.Activate()).Callback(() => activate = ++order);
explorerShell.Verify(s => s.HideAllWindows(), Times.Once); originalDesktop.Reset();
explorerShell.Verify(s => s.RestoreAllWindows(), Times.Never); processFactory.Reset();
newDesktop.Verify(d => d.Activate(), Times.Once); processFactory.SetupSet(f => f.StartupDesktop = It.Is<IDesktop>(d => d == newDesktop.Object)).Callback(() => startup = ++order);
newDesktop.Verify(d => d.Close(), Times.Once);
originalDesktop.Verify(d => d.Activate(), Times.Once);
currentSettings.Security.KioskMode = nextSettings.Security.KioskMode;
nextSettings.Security.KioskMode = KioskMode.CreateNewDesktop; 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(OperationResult.Success, result);
Assert.AreEqual(1, current);
Assert.AreEqual(2, activate);
Assert.AreEqual(3, startup);
}
explorerShell.Verify(s => s.Terminate(), Times.Once); [TestMethod]
explorerShell.Verify(s => s.Start(), Times.Once); public void Repeat_MustCorrectlySwitchFromDisableExplorerShellToNone()
explorerShell.Verify(s => s.Resume(), Times.Once); {
explorerShell.Verify(s => s.Suspend(), Times.Exactly(2)); var order = 0;
explorerShell.Verify(s => s.HideAllWindows(), Times.Once); 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); explorerShell.Verify(s => s.RestoreAllWindows(), Times.Once);
newDesktop.Verify(d => d.Activate(), Times.Exactly(2)); explorerShell.Verify(s => s.Start(), Times.Once);
newDesktop.Verify(d => d.Close(), Times.Once); processFactory.VerifySet(f => f.StartupDesktop = It.IsAny<IDesktop>(), Times.Never);
originalDesktop.Verify(d => d.Activate(), Times.Once);
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] [TestMethod]
@ -196,8 +374,10 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
newDesktop.Verify(d => d.Activate(), Times.Once); newDesktop.Verify(d => d.Activate(), Times.Once);
newDesktop.Verify(d => d.Close(), Times.Never); newDesktop.Verify(d => d.Close(), Times.Never);
processFactory.VerifySet(f => f.StartupDesktop = newDesktop.Object, Times.Once); processFactory.VerifySet(f => f.StartupDesktop = newDesktop.Object, 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.Terminate(), Times.Once);
explorerShell.Verify(s => s.HideAllWindows(), Times.Once);
explorerShell.Verify(s => s.RestoreAllWindows(), Times.Never);
} }
[TestMethod] [TestMethod]
@ -230,36 +410,48 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
var originalDesktop = new Mock<IDesktop>(); var originalDesktop = new Mock<IDesktop>();
var order = 0; var order = 0;
var activate = 0; var activate = 0;
var restore = 0;
var setStartup = 0; var setStartup = 0;
var close = 0; var close = 0;
var resume = 0; var start = 0;
currentSettings.Security.KioskMode = KioskMode.CreateNewDesktop; currentSettings.Security.KioskMode = KioskMode.CreateNewDesktop;
nextSettings.Security.KioskMode = KioskMode.CreateNewDesktop; nextSettings.Security.KioskMode = KioskMode.CreateNewDesktop;
desktopFactory.Setup(f => f.GetCurrent()).Returns(originalDesktop.Object); desktopFactory.Setup(f => f.GetCurrent()).Returns(originalDesktop.Object);
desktopFactory.Setup(f => f.CreateNew(It.IsAny<string>())).Returns(newDesktop.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(); 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(); var revertResult = sut.Revert();
desktopFactory.VerifyNoOtherCalls();
originalDesktop.Verify(d => d.Activate(), Times.Once); originalDesktop.Verify(d => d.Activate(), Times.Once);
processFactory.VerifySet(f => f.StartupDesktop = originalDesktop.Object, Times.Once); processFactory.VerifySet(f => f.StartupDesktop = originalDesktop.Object, Times.Once);
newDesktop.Verify(d => d.Close(), Times.Once); newDesktop.Verify(d => d.Close(), Times.Once);
explorerShell.Verify(s => s.Resume(), Times.Once); explorerShell.Verify(s => s.Start(), Times.Once);
explorerShell.Verify(s => s.Start(), Times.Never); explorerShell.Verify(s => s.Terminate(), Times.Never);
explorerShell.Verify(s => s.RestoreAllWindows(), 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, performResult);
Assert.AreEqual(OperationResult.Success, revertResult); Assert.AreEqual(OperationResult.Success, revertResult);
Assert.AreEqual(1, activate); Assert.AreEqual(1, activate);
Assert.AreEqual(2, setStartup); Assert.AreEqual(2, setStartup);
Assert.AreEqual(3, close); Assert.AreEqual(3, close);
Assert.AreEqual(4, resume); Assert.AreEqual(4, start);
Assert.AreEqual(5, restore);
} }
[TestMethod] [TestMethod]
@ -289,6 +481,9 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
Assert.AreEqual(OperationResult.Success, sut.Perform()); 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.Repeat());
Assert.AreEqual(OperationResult.Success, sut.Revert()); Assert.AreEqual(OperationResult.Success, sut.Revert());
desktopFactory.VerifyNoOtherCalls(); desktopFactory.VerifyNoOtherCalls();

View file

@ -51,6 +51,7 @@ namespace SafeExamBrowser.Runtime.Operations
switch (Context.Next.Settings.Security.KioskMode) switch (Context.Next.Settings.Security.KioskMode)
{ {
case KioskMode.CreateNewDesktop: case KioskMode.CreateNewDesktop:
TerminateExplorerShell();
CreateNewDesktop(); CreateNewDesktop();
break; break;
case KioskMode.DisableExplorerShell: case KioskMode.DisableExplorerShell:
@ -64,7 +65,6 @@ namespace SafeExamBrowser.Runtime.Operations
public override OperationResult Repeat() public override OperationResult Repeat()
{ {
var newMode = Context.Next.Settings.Security.KioskMode; var newMode = Context.Next.Settings.Security.KioskMode;
var result = OperationResult.Success;
if (activeMode == newMode) if (activeMode == newMode)
{ {
@ -72,15 +72,33 @@ namespace SafeExamBrowser.Runtime.Operations
} }
else 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() public override OperationResult Revert()
@ -92,6 +110,7 @@ namespace SafeExamBrowser.Runtime.Operations
{ {
case KioskMode.CreateNewDesktop: case KioskMode.CreateNewDesktop:
CloseNewDesktop(); CloseNewDesktop();
RestartExplorerShell();
break; break;
case KioskMode.DisableExplorerShell: case KioskMode.DisableExplorerShell:
RestartExplorerShell(); RestartExplorerShell();
@ -112,8 +131,6 @@ namespace SafeExamBrowser.Runtime.Operations
newDesktop.Activate(); newDesktop.Activate();
processFactory.StartupDesktop = newDesktop; processFactory.StartupDesktop = newDesktop;
logger.Info("Successfully activated new desktop."); logger.Info("Successfully activated new desktop.");
explorerShell.Suspend();
} }
private void CloseNewDesktop() private void CloseNewDesktop()
@ -138,8 +155,6 @@ namespace SafeExamBrowser.Runtime.Operations
{ {
logger.Warn($"No new desktop found to close!"); logger.Warn($"No new desktop found to close!");
} }
explorerShell.Resume();
} }
private void TerminateExplorerShell() private void TerminateExplorerShell()

View file

@ -89,11 +89,12 @@ namespace SafeExamBrowser.SystemComponents
{ {
var process = new Process(); 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.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.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.Start();
process.WaitForExit(5000); process.WaitForExit(5000);

View file

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

View file

@ -23,14 +23,12 @@ namespace SafeExamBrowser.WindowsApi
private ILogger logger; private ILogger logger;
private INativeMethods nativeMethods; private INativeMethods nativeMethods;
private IList<Window> minimizedWindows = new List<Window>(); private IList<Window> minimizedWindows = new List<Window>();
private IList<ProcessThread> suspendedThreads;
public ExplorerShell(ILogger logger, INativeMethods nativeMethods) public ExplorerShell(ILogger logger, INativeMethods nativeMethods)
{ {
this.logger = logger; this.logger = logger;
this.nativeMethods = nativeMethods; this.nativeMethods = nativeMethods;
this.minimizedWindows = new List<Window>(); this.minimizedWindows = new List<Window>();
this.suspendedThreads = new List<ProcessThread>();
} }
public void HideAllWindows() public void HideAllWindows()
@ -68,32 +66,6 @@ namespace SafeExamBrowser.WindowsApi
logger.Info("Minimized windows successfully restored."); 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() public void Start()
{ {
var process = new System.Diagnostics.Process(); var process = new System.Diagnostics.Process();
@ -103,6 +75,8 @@ namespace SafeExamBrowser.WindowsApi
process.StartInfo.CreateNoWindow = true; process.StartInfo.CreateNoWindow = true;
process.StartInfo.FileName = explorerPath; process.StartInfo.FileName = explorerPath;
process.StartInfo.UseShellExecute = false;
process.StartInfo.WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
process.Start(); process.Start();
logger.Debug("Waiting for explorer shell to initialize..."); logger.Debug("Waiting for explorer shell to initialize...");
@ -117,39 +91,6 @@ namespace SafeExamBrowser.WindowsApi
process.Close(); 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() public void Terminate()
{ {
const int THREE_SECONDS = 3000; const int THREE_SECONDS = 3000;
@ -205,7 +146,9 @@ namespace SafeExamBrowser.WindowsApi
process.StartInfo.Arguments = $"/F /PID {processId}"; process.StartInfo.Arguments = $"/F /PID {processId}";
process.StartInfo.CreateNoWindow = true; process.StartInfo.CreateNoWindow = true;
process.StartInfo.FileName = taskkillPath; process.StartInfo.FileName = taskkillPath;
process.StartInfo.UseShellExecute = false;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
process.Start(); process.Start();
process.WaitForExit(); process.WaitForExit();
} }

View file

@ -168,12 +168,15 @@ namespace SafeExamBrowser.WindowsApi
private System.Diagnostics.Process StartNormal(string path, params string[] args) private System.Diagnostics.Process StartNormal(string path, params string[] args)
{ {
return System.Diagnostics.Process.Start(new ProcessStartInfo var process = new System.Diagnostics.Process();
{
Arguments = string.Join(" ", args), process.StartInfo.Arguments = string.Join(" ", args);
FileName = path, process.StartInfo.FileName = path;
UseShellExecute = false 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) private System.Diagnostics.Process StartOnDesktop(string path, params string[] args)