SEBWIN-313: Started implementing blacklist monitoring.
This commit is contained in:
parent
8d0d1832a9
commit
d3d98c7df7
10 changed files with 136 additions and 102 deletions
|
@ -94,7 +94,7 @@ namespace SafeExamBrowser.Client
|
||||||
taskbar = BuildTaskbar();
|
taskbar = BuildTaskbar();
|
||||||
terminationActivator = new TerminationActivator(ModuleLogger(nameof(TerminationActivator)));
|
terminationActivator = new TerminationActivator(ModuleLogger(nameof(TerminationActivator)));
|
||||||
|
|
||||||
var applicationMonitor = new ApplicationMonitor(ModuleLogger(nameof(ApplicationMonitor)), nativeMethods, new ProcessFactory(ModuleLogger(nameof(ProcessFactory))));
|
var applicationMonitor = new ApplicationMonitor(FIVE_SECONDS, ModuleLogger(nameof(ApplicationMonitor)), nativeMethods, new ProcessFactory(ModuleLogger(nameof(ProcessFactory))));
|
||||||
var displayMonitor = new DisplayMonitor(ModuleLogger(nameof(DisplayMonitor)), nativeMethods, systemInfo);
|
var displayMonitor = new DisplayMonitor(ModuleLogger(nameof(DisplayMonitor)), nativeMethods, systemInfo);
|
||||||
var explorerShell = new ExplorerShell(ModuleLogger(nameof(ExplorerShell)), nativeMethods);
|
var explorerShell = new ExplorerShell(ModuleLogger(nameof(ExplorerShell)), nativeMethods);
|
||||||
var hashAlgorithm = new HashAlgorithm();
|
var hashAlgorithm = new HashAlgorithm();
|
||||||
|
|
|
@ -14,7 +14,6 @@ using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||||
using SafeExamBrowser.I18n.Contracts;
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
using SafeExamBrowser.Monitoring.Contracts.Applications;
|
using SafeExamBrowser.Monitoring.Contracts.Applications;
|
||||||
using SafeExamBrowser.Settings;
|
|
||||||
using SafeExamBrowser.Settings.Applications;
|
using SafeExamBrowser.Settings.Applications;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Client.Operations
|
namespace SafeExamBrowser.Client.Operations
|
||||||
|
@ -110,18 +109,18 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
|
|
||||||
private void StartMonitor()
|
private void StartMonitor()
|
||||||
{
|
{
|
||||||
if (Context.Settings.KioskMode != KioskMode.None)
|
//TODO: if (Context.Settings.KioskMode != KioskMode.None)
|
||||||
{
|
//{
|
||||||
applicationMonitor.Start();
|
applicationMonitor.Start();
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StopMonitor()
|
private void StopMonitor()
|
||||||
{
|
{
|
||||||
if (Context.Settings.KioskMode != KioskMode.None)
|
//TODO: if (Context.Settings.KioskMode != KioskMode.None)
|
||||||
{
|
//{
|
||||||
applicationMonitor.Stop();
|
applicationMonitor.Stop();
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
private OperationResult TryTerminate(IEnumerable<RunningApplication> runningApplications)
|
private OperationResult TryTerminate(IEnumerable<RunningApplication> runningApplications)
|
||||||
|
|
|
@ -9,8 +9,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Management;
|
using System.Timers;
|
||||||
using System.Threading;
|
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
using SafeExamBrowser.Monitoring.Contracts.Applications;
|
using SafeExamBrowser.Monitoring.Contracts.Applications;
|
||||||
using SafeExamBrowser.Monitoring.Contracts.Applications.Events;
|
using SafeExamBrowser.Monitoring.Contracts.Applications.Events;
|
||||||
|
@ -24,21 +23,24 @@ namespace SafeExamBrowser.Monitoring.Applications
|
||||||
private IntPtr activeWindow;
|
private IntPtr activeWindow;
|
||||||
private IList<BlacklistApplication> blacklist;
|
private IList<BlacklistApplication> blacklist;
|
||||||
private Guid? captureHookId;
|
private Guid? captureHookId;
|
||||||
private ManagementEventWatcher explorerWatcher;
|
|
||||||
private Guid? foregroundHookId;
|
private Guid? foregroundHookId;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
private INativeMethods nativeMethods;
|
private INativeMethods nativeMethods;
|
||||||
|
private IList<IProcess> processes;
|
||||||
private IProcessFactory processFactory;
|
private IProcessFactory processFactory;
|
||||||
|
private Timer timer;
|
||||||
private IList<WhitelistApplication> whitelist;
|
private IList<WhitelistApplication> whitelist;
|
||||||
|
|
||||||
public event ExplorerStartedEventHandler ExplorerStarted;
|
public event ExplorerStartedEventHandler ExplorerStarted;
|
||||||
|
|
||||||
public ApplicationMonitor(ILogger logger, INativeMethods nativeMethods, IProcessFactory processFactory)
|
public ApplicationMonitor(int interval_ms, ILogger logger, INativeMethods nativeMethods, IProcessFactory processFactory)
|
||||||
{
|
{
|
||||||
this.blacklist = new List<BlacklistApplication>();
|
this.blacklist = new List<BlacklistApplication>();
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.nativeMethods = nativeMethods;
|
this.nativeMethods = nativeMethods;
|
||||||
|
this.processes = new List<IProcess>();
|
||||||
this.processFactory = processFactory;
|
this.processFactory = processFactory;
|
||||||
|
this.timer = new Timer(interval_ms);
|
||||||
this.whitelist = new List<WhitelistApplication>();
|
this.whitelist = new List<WhitelistApplication>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,17 +61,19 @@ namespace SafeExamBrowser.Monitoring.Applications
|
||||||
logger.Debug($"Initialized blacklist with {blacklist.Count} applications{(blacklist.Any() ? $": {string.Join(", ", blacklist.Select(a => a.ExecutableName))}" : ".")}");
|
logger.Debug($"Initialized blacklist with {blacklist.Count} applications{(blacklist.Any() ? $": {string.Join(", ", blacklist.Select(a => a.ExecutableName))}" : ".")}");
|
||||||
logger.Debug($"Initialized whitelist with {whitelist.Count} applications{(whitelist.Any() ? $": {string.Join(", ", whitelist.Select(a => a.ExecutableName))}" : ".")}");
|
logger.Debug($"Initialized whitelist with {whitelist.Count} applications{(whitelist.Any() ? $": {string.Join(", ", whitelist.Select(a => a.ExecutableName))}" : ".")}");
|
||||||
|
|
||||||
foreach (var process in processFactory.GetAllRunning())
|
processes = processFactory.GetAllRunning();
|
||||||
|
|
||||||
|
foreach (var process in processes)
|
||||||
{
|
{
|
||||||
foreach (var application in blacklist)
|
foreach (var application in blacklist)
|
||||||
{
|
{
|
||||||
var isMatch = BelongsToApplication(process, application);
|
var isBlacklisted = BelongsToApplication(process, application);
|
||||||
|
|
||||||
if (isMatch && !application.AutoTerminate)
|
if (isBlacklisted && !application.AutoTerminate)
|
||||||
{
|
{
|
||||||
AddForTermination(application.ExecutableName, process, result);
|
AddForTermination(application.ExecutableName, process, result);
|
||||||
}
|
}
|
||||||
else if (isMatch && application.AutoTerminate && !TryTerminate(process))
|
else if (isBlacklisted && application.AutoTerminate && !TryTerminate(process))
|
||||||
{
|
{
|
||||||
AddFailed(application.ExecutableName, process, result);
|
AddFailed(application.ExecutableName, process, result);
|
||||||
}
|
}
|
||||||
|
@ -86,13 +90,10 @@ namespace SafeExamBrowser.Monitoring.Applications
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
// TODO: Start monitoring blacklist...
|
timer.AutoReset = false;
|
||||||
|
timer.Elapsed += Timer_Elapsed;
|
||||||
// TODO: Remove WMI event and use timer mechanism!
|
timer.Start();
|
||||||
explorerWatcher = new ManagementEventWatcher(@"\\.\root\CIMV2", GetQueryFor("explorer.exe"));
|
logger.Info("Started monitoring applications.");
|
||||||
explorerWatcher.EventArrived += new EventArrivedEventHandler(ExplorerWatcher_EventArrived);
|
|
||||||
explorerWatcher.Start();
|
|
||||||
logger.Info("Started monitoring process 'explorer.exe'.");
|
|
||||||
|
|
||||||
captureHookId = nativeMethods.RegisterSystemCaptureStartEvent(SystemEvent_WindowChanged);
|
captureHookId = nativeMethods.RegisterSystemCaptureStartEvent(SystemEvent_WindowChanged);
|
||||||
logger.Info($"Registered system capture start event with ID = {captureHookId}.");
|
logger.Info($"Registered system capture start event with ID = {captureHookId}.");
|
||||||
|
@ -103,8 +104,9 @@ namespace SafeExamBrowser.Monitoring.Applications
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
explorerWatcher?.Stop();
|
timer.Stop();
|
||||||
logger.Info("Stopped monitoring 'explorer.exe'.");
|
timer.Elapsed -= Timer_Elapsed;
|
||||||
|
logger.Info("Stopped monitoring applications.");
|
||||||
|
|
||||||
if (captureHookId.HasValue)
|
if (captureHookId.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -142,7 +144,7 @@ namespace SafeExamBrowser.Monitoring.Applications
|
||||||
}
|
}
|
||||||
|
|
||||||
application.Processes.Add(process);
|
application.Processes.Add(process);
|
||||||
logger.Error($"Process '{process.Name}' belongs to application '{application.Name}' and could not be terminated automatically!");
|
logger.Error($"Process {process} belongs to application '{application.Name}' and could not be terminated automatically!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddForTermination(string name, IProcess process, InitializationResult result)
|
private void AddForTermination(string name, IProcess process, InitializationResult result)
|
||||||
|
@ -156,7 +158,7 @@ namespace SafeExamBrowser.Monitoring.Applications
|
||||||
}
|
}
|
||||||
|
|
||||||
application.Processes.Add(process);
|
application.Processes.Add(process);
|
||||||
logger.Debug($"Process '{process.Name}' belongs to application '{application.Name}' and needs to be terminated.");
|
logger.Debug($"Process {process} belongs to application '{application.Name}' and needs to be terminated.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool BelongsToApplication(IProcess process, BlacklistApplication application)
|
private bool BelongsToApplication(IProcess process, BlacklistApplication application)
|
||||||
|
@ -231,63 +233,73 @@ namespace SafeExamBrowser.Monitoring.Applications
|
||||||
private bool TryTerminate(IProcess process)
|
private bool TryTerminate(IProcess process)
|
||||||
{
|
{
|
||||||
const int MAX_ATTEMPTS = 5;
|
const int MAX_ATTEMPTS = 5;
|
||||||
const int TIMEOUT = 100;
|
const int TIMEOUT = 500;
|
||||||
|
|
||||||
try
|
for (var attempt = 0; attempt < MAX_ATTEMPTS; attempt++)
|
||||||
|
{
|
||||||
|
if (process.TryClose(TIMEOUT))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!process.HasTerminated)
|
||||||
{
|
{
|
||||||
for (var attempt = 0; attempt < MAX_ATTEMPTS; attempt++)
|
for (var attempt = 0; attempt < MAX_ATTEMPTS; attempt++)
|
||||||
{
|
{
|
||||||
if (process.TryClose())
|
if (process.TryKill(TIMEOUT))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Thread.Sleep(TIMEOUT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!process.HasTerminated)
|
|
||||||
{
|
|
||||||
for (var attempt = 0; attempt < MAX_ATTEMPTS; attempt++)
|
|
||||||
{
|
|
||||||
if (process.TryKill())
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Thread.Sleep(TIMEOUT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.HasTerminated)
|
|
||||||
{
|
|
||||||
logger.Info($"Successfully terminated process '{process.Name}'.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.Warn($"Failed to terminate process '{process.Name}'!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
|
if (process.HasTerminated)
|
||||||
{
|
{
|
||||||
logger.Error($"An error occurred while attempting to terminate process '{process.Name}'!", e);
|
logger.Info($"Successfully terminated process {process}.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Warn($"Failed to terminate process {process}!");
|
||||||
}
|
}
|
||||||
|
|
||||||
return process.HasTerminated;
|
return process.HasTerminated;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExplorerWatcher_EventArrived(object sender, EventArrivedEventArgs e)
|
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
var eventName = e.NewEvent.ClassPath.ClassName;
|
var running = processFactory.GetAllRunning();
|
||||||
|
var started = running.Where(r => processes.All(p => p.Id != r.Id)).ToList();
|
||||||
|
var terminated = processes.Where(p => running.All(r => r.Id != p.Id)).ToList();
|
||||||
|
|
||||||
if (eventName == "__InstanceCreationEvent")
|
foreach (var process in started)
|
||||||
{
|
{
|
||||||
logger.Warn("A new instance of Windows explorer has been started!");
|
logger.Debug($"Process {process} has been started.");
|
||||||
ExplorerStarted?.Invoke();
|
processes.Add(process);
|
||||||
|
|
||||||
|
foreach (var application in blacklist)
|
||||||
|
{
|
||||||
|
if (BelongsToApplication(process, application))
|
||||||
|
{
|
||||||
|
logger.Warn($"Process {process} belongs to blacklisted application '{application.ExecutableName}'! Attempting termination...");
|
||||||
|
|
||||||
|
var success = TryTerminate(process);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
// TODO: Invoke event -> Show lock screen!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var process in terminated)
|
||||||
|
{
|
||||||
|
logger.Debug($"Process {process} has been terminated.");
|
||||||
|
processes.Remove(process);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SystemEvent_WindowChanged(IntPtr window)
|
private void SystemEvent_WindowChanged(IntPtr window)
|
||||||
|
@ -299,15 +311,5 @@ namespace SafeExamBrowser.Monitoring.Applications
|
||||||
Check(window);
|
Check(window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetQueryFor(string processName)
|
|
||||||
{
|
|
||||||
return $@"
|
|
||||||
SELECT *
|
|
||||||
FROM __InstanceOperationEvent
|
|
||||||
WITHIN 2
|
|
||||||
WHERE TargetInstance ISA 'Win32_Process'
|
|
||||||
AND TargetInstance.Name = '{processName}'";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,6 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
<Reference Include="System.Management" />
|
|
||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<Reference Include="WindowsBase" />
|
<Reference Include="WindowsBase" />
|
||||||
|
|
|
@ -172,7 +172,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
||||||
|
|
||||||
proxy.Verify(p => p.InitiateShutdown(), Times.Once);
|
proxy.Verify(p => p.InitiateShutdown(), Times.Once);
|
||||||
proxy.Verify(p => p.Disconnect(), Times.Once);
|
proxy.Verify(p => p.Disconnect(), Times.Once);
|
||||||
process.Verify(p => p.TryKill(), Times.Never);
|
process.Verify(p => p.TryKill(default(int)), Times.Never);
|
||||||
|
|
||||||
Assert.IsNull(sessionContext.ClientProcess);
|
Assert.IsNull(sessionContext.ClientProcess);
|
||||||
Assert.IsNull(sessionContext.ClientProxy);
|
Assert.IsNull(sessionContext.ClientProxy);
|
||||||
|
@ -181,12 +181,12 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Revert_MustKillClientIfStoppingFailed()
|
public void Revert_MustKillClientIfStoppingFailed()
|
||||||
{
|
{
|
||||||
process.Setup(p => p.TryKill()).Callback(() => process.SetupGet(p => p.HasTerminated).Returns(true));
|
process.Setup(p => p.TryKill(default(int))).Callback(() => process.SetupGet(p => p.HasTerminated).Returns(true));
|
||||||
|
|
||||||
PerformNormally();
|
PerformNormally();
|
||||||
sut.Revert();
|
sut.Revert();
|
||||||
|
|
||||||
process.Verify(p => p.TryKill(), Times.AtLeastOnce);
|
process.Verify(p => p.TryKill(default(int)), Times.AtLeastOnce);
|
||||||
|
|
||||||
Assert.IsNull(sessionContext.ClientProcess);
|
Assert.IsNull(sessionContext.ClientProcess);
|
||||||
Assert.IsNull(sessionContext.ClientProxy);
|
Assert.IsNull(sessionContext.ClientProxy);
|
||||||
|
@ -198,7 +198,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
||||||
PerformNormally();
|
PerformNormally();
|
||||||
sut.Revert();
|
sut.Revert();
|
||||||
|
|
||||||
process.Verify(p => p.TryKill(), Times.Exactly(5));
|
process.Verify(p => p.TryKill(default(int)), Times.Exactly(5));
|
||||||
|
|
||||||
Assert.IsNotNull(sessionContext.ClientProcess);
|
Assert.IsNotNull(sessionContext.ClientProcess);
|
||||||
Assert.IsNotNull(sessionContext.ClientProxy);
|
Assert.IsNotNull(sessionContext.ClientProxy);
|
||||||
|
@ -213,7 +213,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
||||||
|
|
||||||
proxy.Verify(p => p.InitiateShutdown(), Times.Never);
|
proxy.Verify(p => p.InitiateShutdown(), Times.Never);
|
||||||
proxy.Verify(p => p.Disconnect(), Times.Never);
|
proxy.Verify(p => p.Disconnect(), Times.Never);
|
||||||
process.Verify(p => p.TryKill(), Times.Never);
|
process.Verify(p => p.TryKill(default(int)), Times.Never);
|
||||||
|
|
||||||
Assert.IsNull(sessionContext.ClientProcess);
|
Assert.IsNull(sessionContext.ClientProcess);
|
||||||
Assert.IsNull(sessionContext.ClientProxy);
|
Assert.IsNull(sessionContext.ClientProxy);
|
||||||
|
|
|
@ -81,7 +81,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
|
||||||
|
|
||||||
proxy.Verify(p => p.InitiateShutdown(), Times.Once);
|
proxy.Verify(p => p.InitiateShutdown(), Times.Once);
|
||||||
proxy.Verify(p => p.Disconnect(), Times.Once);
|
proxy.Verify(p => p.Disconnect(), Times.Once);
|
||||||
process.Verify(p => p.TryKill(), Times.Never);
|
process.Verify(p => p.TryKill(default(int)), Times.Never);
|
||||||
|
|
||||||
Assert.IsNull(sessionContext.ClientProcess);
|
Assert.IsNull(sessionContext.ClientProcess);
|
||||||
Assert.IsNull(sessionContext.ClientProxy);
|
Assert.IsNull(sessionContext.ClientProxy);
|
||||||
|
|
|
@ -41,13 +41,16 @@ namespace SafeExamBrowser.WindowsApi.Contracts
|
||||||
event ProcessTerminatedEventHandler Terminated;
|
event ProcessTerminatedEventHandler Terminated;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to gracefully terminate the process by closing its main window. This will only work for interactive processes which have a main window.
|
/// Attempts to gracefully terminate the process by closing its main window. This will only work for interactive processes which have a main
|
||||||
|
/// window. Optionally waits the specified amount of time for the process to terminate. Returns <c>true</c> if the process has terminated,
|
||||||
|
/// otherwise <c>false</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool TryClose();
|
bool TryClose(int timeout_ms = 0);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to immediately kill the process.
|
/// Attempts to immediately kill the process. Optionally waits the specified amount of time for the process to terminate. Returns <c>true</c>
|
||||||
|
/// if the process has terminated, otherwise <c>false</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool TryKill();
|
bool TryKill(int timeout_ms = 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace SafeExamBrowser.WindowsApi.Contracts
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves all currently running processes.
|
/// Retrieves all currently running processes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IEnumerable<IProcess> GetAllRunning();
|
IList<IProcess> GetAllRunning();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Starts a new process with the given command-line arguments.
|
/// Starts a new process with the given command-line arguments.
|
||||||
|
|
|
@ -62,18 +62,25 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
this.originalNameInitialized = true;
|
this.originalNameInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryClose()
|
public bool TryClose(int timeout_ms = 0)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
logger.Debug("Attempting to close process...");
|
||||||
process.Refresh();
|
process.Refresh();
|
||||||
|
|
||||||
if (!process.HasExited)
|
var success = process.CloseMainWindow();
|
||||||
|
|
||||||
|
if (success)
|
||||||
{
|
{
|
||||||
process.CloseMainWindow();
|
logger.Debug("Successfully sent close message to main window.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Warn("Failed to send close message to main window!");
|
||||||
}
|
}
|
||||||
|
|
||||||
return process.HasExited;
|
return success && WaitForTermination(timeout_ms);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -83,18 +90,16 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryKill()
|
public bool TryKill(int timeout_ms = 0)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
logger.Debug("Attempting to kill process...");
|
||||||
|
|
||||||
process.Refresh();
|
process.Refresh();
|
||||||
|
process.Kill();
|
||||||
|
|
||||||
if (!process.HasExited)
|
return WaitForTermination(timeout_ms);
|
||||||
{
|
|
||||||
process.Kill();
|
|
||||||
}
|
|
||||||
|
|
||||||
return process.HasExited;
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -104,6 +109,11 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"'{Name}' ({Id})";
|
||||||
|
}
|
||||||
|
|
||||||
private bool IsTerminated()
|
private bool IsTerminated()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -127,6 +137,7 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
eventInitialized = true;
|
eventInitialized = true;
|
||||||
process.Exited += Process_Exited;
|
process.Exited += Process_Exited;
|
||||||
process.EnableRaisingEvents = true;
|
process.EnableRaisingEvents = true;
|
||||||
|
logger.Debug("Initialized termination event.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,9 +176,26 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
return originalName;
|
return originalName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool WaitForTermination(int timeout_ms)
|
||||||
|
{
|
||||||
|
var terminated = process.WaitForExit(timeout_ms);
|
||||||
|
|
||||||
|
if (terminated)
|
||||||
|
{
|
||||||
|
logger.Debug($"Process has terminated within {timeout_ms}ms.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Warn($"Process failed to terminate within {timeout_ms}ms!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return terminated;
|
||||||
|
}
|
||||||
|
|
||||||
private void Process_Exited(object sender, EventArgs e)
|
private void Process_Exited(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
TerminatedEvent?.Invoke(process.ExitCode);
|
TerminatedEvent?.Invoke(process.ExitCode);
|
||||||
|
logger.Debug("Process has terminated.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,17 +32,20 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IProcess> GetAllRunning()
|
public IList<IProcess> GetAllRunning()
|
||||||
{
|
{
|
||||||
var processes = System.Diagnostics.Process.GetProcesses();
|
var processes = new List<IProcess>();
|
||||||
|
var running = System.Diagnostics.Process.GetProcesses();
|
||||||
var originalNames = LoadOriginalNames();
|
var originalNames = LoadOriginalNames();
|
||||||
|
|
||||||
foreach (var process in processes)
|
foreach (var process in running)
|
||||||
{
|
{
|
||||||
var originalName = originalNames.FirstOrDefault(n => n.processId == process.Id).originalName;
|
var originalName = originalNames.FirstOrDefault(n => n.processId == process.Id).originalName;
|
||||||
|
|
||||||
yield return new Process(process, originalName, LoggerFor(process));
|
processes.Add(new Process(process, originalName, LoggerFor(process)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return processes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IProcess StartNew(string path, params string[] args)
|
public IProcess StartNew(string path, params string[] args)
|
||||||
|
|
Loading…
Reference in a new issue