seb-win-refactoring/SafeExamBrowser.WindowsApi/Process.cs
2021-02-03 00:45:33 +01:00

152 lines
3.1 KiB
C#

/*
* Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.WindowsApi.Contracts;
using SafeExamBrowser.WindowsApi.Contracts.Events;
namespace SafeExamBrowser.WindowsApi
{
internal class Process : IProcess
{
private bool eventInitialized;
private ILogger logger;
private System.Diagnostics.Process process;
public bool HasTerminated
{
get { return IsTerminated(); }
}
public int Id
{
get { return process.Id; }
}
public string Name { get; }
public string OriginalName { get; }
private event ProcessTerminatedEventHandler TerminatedEvent;
public event ProcessTerminatedEventHandler Terminated
{
add { TerminatedEvent += value; InitializeEvent(); }
remove { TerminatedEvent -= value; }
}
internal Process(System.Diagnostics.Process process, string name, string originalName, ILogger logger)
{
this.logger = logger;
this.process = process;
this.Name = name;
this.OriginalName = originalName;
}
public bool TryClose(int timeout_ms = 0)
{
try
{
logger.Debug("Attempting to close process...");
process.Refresh();
var success = process.CloseMainWindow();
if (success)
{
logger.Debug("Successfully sent close message to main window.");
}
else
{
logger.Warn("Failed to send close message to main window!");
}
return success && WaitForTermination(timeout_ms);
}
catch (Exception e)
{
logger.Error("Failed to close main window!", e);
}
return false;
}
public bool TryKill(int timeout_ms = 0)
{
try
{
logger.Debug("Attempting to kill process...");
process.Refresh();
process.Kill();
return WaitForTermination(timeout_ms);
}
catch (Exception e)
{
logger.Error("Failed to kill process!", e);
}
return false;
}
public override string ToString()
{
return $"'{Name}' ({Id})";
}
private bool IsTerminated()
{
try
{
process.Refresh();
return process.HasExited;
}
catch (Exception e)
{
logger.Error("Failed to check whether process is terminated!", e);
}
return false;
}
private void InitializeEvent()
{
if (!eventInitialized)
{
eventInitialized = true;
process.Exited += Process_Exited;
process.EnableRaisingEvents = true;
logger.Debug("Initialized termination event.");
}
}
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)
{
TerminatedEvent?.Invoke(process.ExitCode);
logger.Debug("Process has terminated.");
}
}
}