ProcessExtensions
This commit is contained in:
parent
decc2cecc4
commit
253b1010cf
@ -1,21 +0,0 @@
|
|||||||
namespace DTLib.Extensions;
|
|
||||||
|
|
||||||
public static class IfMethod
|
|
||||||
{
|
|
||||||
public static T If<T>(this T input, bool condition, Func<T, T> if_true, Func<T, T> if_false) =>
|
|
||||||
condition ? if_true(input) : if_false(input);
|
|
||||||
|
|
||||||
public static void If<T>(this T input, bool condition, Action<T> if_true, Action<T> if_false)
|
|
||||||
{
|
|
||||||
if (condition) if_true(input);
|
|
||||||
else if_false(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T If<T>(this T input, bool condition, Func<T, T> if_true) =>
|
|
||||||
condition ? if_true(input) : input;
|
|
||||||
|
|
||||||
public static void If<T>(this T input, bool condition, Action<T> if_true)
|
|
||||||
{
|
|
||||||
if (condition) if_true(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
11
DTLib/Extensions/ProcessExtensions/IProcessSuspenderImpl.cs
Normal file
11
DTLib/Extensions/ProcessExtensions/IProcessSuspenderImpl.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace DTLib.Extensions;
|
||||||
|
|
||||||
|
internal interface IProcessSuspenderImpl
|
||||||
|
{
|
||||||
|
void Suspend(Process p);
|
||||||
|
void Suspend(int pid);
|
||||||
|
void Resume(Process p);
|
||||||
|
void Resume(int pid);
|
||||||
|
}
|
||||||
38
DTLib/Extensions/ProcessExtensions/ProcessExtensions.cs
Normal file
38
DTLib/Extensions/ProcessExtensions/ProcessExtensions.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
// ReSharper disable UnusedMember.Local
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace DTLib.Extensions;
|
||||||
|
|
||||||
|
public static class ProcessExtensions
|
||||||
|
{
|
||||||
|
private static IProcessSuspenderImpl processSuspender;
|
||||||
|
|
||||||
|
|
||||||
|
static ProcessExtensions()
|
||||||
|
{
|
||||||
|
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
|
||||||
|
processSuspender = new ProcessSuspenderImplWindows();
|
||||||
|
else
|
||||||
|
processSuspender = new ProcessSuspenderImplUnix();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Suspend(this Process p) => processSuspender.Suspend(p);
|
||||||
|
|
||||||
|
public static void Suspend(int pid)
|
||||||
|
{
|
||||||
|
if (pid <= 0)
|
||||||
|
throw new Exception($"invalid pid: {pid}");
|
||||||
|
processSuspender.Suspend(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Resume(this Process p) => processSuspender.Resume(p);
|
||||||
|
|
||||||
|
public static void Resume(int pid)
|
||||||
|
{
|
||||||
|
if (pid <= 0)
|
||||||
|
throw new Exception($"invalid pid: {pid}");
|
||||||
|
processSuspender.Resume(pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace DTLib.Extensions;
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/41041730/net-core-app-how-to-send-sigterm-to-child-processes
|
||||||
|
internal class ProcessSuspenderImplUnix : IProcessSuspenderImpl
|
||||||
|
{
|
||||||
|
[SuppressMessage("ReSharper", "UnusedMember.Local")]
|
||||||
|
enum Signum
|
||||||
|
{
|
||||||
|
/// Hangup (POSIX).
|
||||||
|
SIGHUP = 1,
|
||||||
|
/// Interrupt (ANSI).
|
||||||
|
SIGINT = 2,
|
||||||
|
/// Quit (POSIX).
|
||||||
|
SIGQUIT = 3,
|
||||||
|
/// Illegal instruction (ANSI).
|
||||||
|
SIGILL = 4,
|
||||||
|
/// Trace trap (POSIX).
|
||||||
|
SIGTRAP = 5,
|
||||||
|
/// Abort (ANSI).
|
||||||
|
SIGABRT = 6,
|
||||||
|
/// IOT trap (4.2 BSD).
|
||||||
|
SIGIOT = 6,
|
||||||
|
/// BUS error (4.2 BSD).
|
||||||
|
SIGBUS = 7,
|
||||||
|
/// Floating-point exception (ANSI).
|
||||||
|
SIGFPE = 8,
|
||||||
|
/// Kill, unblockable (POSIX).
|
||||||
|
SIGKILL = 9,
|
||||||
|
/// User-defined signal 1 (POSIX).
|
||||||
|
SIGUSR1 = 10,
|
||||||
|
/// Segmentation violation (ANSI).
|
||||||
|
SIGSEGV = 11,
|
||||||
|
/// User-defined signal 2 (POSIX).
|
||||||
|
SIGUSR2 = 12,
|
||||||
|
/// Broken pipe (POSIX).
|
||||||
|
SIGPIPE = 13,
|
||||||
|
/// Alarm clock (POSIX).
|
||||||
|
SIGALRM = 14,
|
||||||
|
/// Termination (ANSI).
|
||||||
|
SIGTERM = 15,
|
||||||
|
/// Stack fault.
|
||||||
|
SIGSTKFLT = 16,
|
||||||
|
/// Same as SIGCHLD (System V).
|
||||||
|
SIGCLD = SIGCHLD,
|
||||||
|
/// Child status has changed (POSIX).
|
||||||
|
SIGCHLD = 17,
|
||||||
|
/// Continue (POSIX).
|
||||||
|
SIGCONT = 18,
|
||||||
|
/// Stop, unblockable (POSIX).
|
||||||
|
SIGSTOP = 19,
|
||||||
|
/// Keyboard stop (POSIX).
|
||||||
|
SIGTSTP = 20,
|
||||||
|
/// Background read from tty (POSIX).
|
||||||
|
SIGTTIN = 21,
|
||||||
|
/// Background write to tty (POSIX).
|
||||||
|
SIGTTOU = 22,
|
||||||
|
/// Urgent condition on socket (4.2 BSD).
|
||||||
|
SIGURG = 23,
|
||||||
|
/// CPU limit exceeded (4.2 BSD).
|
||||||
|
SIGXCPU = 24,
|
||||||
|
/// File size limit exceeded (4.2 BSD).
|
||||||
|
SIGXFSZ = 25,
|
||||||
|
/// Virtual alarm clock (4.2 BSD).
|
||||||
|
SIGVTALRM = 26,
|
||||||
|
/// Profiling alarm clock (4.2 BSD).
|
||||||
|
SIGPROF = 27,
|
||||||
|
/// Window size change (4.3 BSD, Sun).
|
||||||
|
SIGWINCH = 28,
|
||||||
|
/// Pollable event occurred (System V).
|
||||||
|
SIGPOLL = SIGIO,
|
||||||
|
/// I/O now possible (4.2 BSD).
|
||||||
|
SIGIO = 29,
|
||||||
|
/// Power failure restart (System V).
|
||||||
|
SIGPWR = 30,
|
||||||
|
/// Bad system call.
|
||||||
|
SIGSYS = 31,
|
||||||
|
SIGUNUSED = 31
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport ("libc", SetLastError=true, EntryPoint="kill")]
|
||||||
|
private static extern int sys_kill (int pid, int sig);
|
||||||
|
|
||||||
|
public void Suspend(Process p) => Suspend(p.Id);
|
||||||
|
public void Suspend(int pid) => sys_kill(pid, (int)Signum.SIGSTOP);
|
||||||
|
|
||||||
|
public void Resume(Process p) => Resume(p.Id);
|
||||||
|
public void Resume(int pid) => sys_kill(pid, (int)Signum.SIGCONT);
|
||||||
|
}
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace DTLib.Extensions;
|
||||||
|
|
||||||
|
// https://github.com/SarathR/ProcessUtil
|
||||||
|
internal class ProcessSuspenderImplWindows : IProcessSuspenderImpl
|
||||||
|
{
|
||||||
|
[SuppressMessage("ReSharper", "UnusedMember.Local")]
|
||||||
|
enum ThreadAccess
|
||||||
|
{
|
||||||
|
TERMINATE = 0x0001,
|
||||||
|
SUSPEND_RESUME = 0x0002,
|
||||||
|
GET_CONTEXT = 0x0008,
|
||||||
|
SET_CONTEXT = 0x0010,
|
||||||
|
SET_INFORMATION = 0x0020,
|
||||||
|
QUERY_INFORMATION = 0x0040,
|
||||||
|
SET_THREAD_TOKEN = 0x0080,
|
||||||
|
IMPERSONATE = 0x0100,
|
||||||
|
DIRECT_IMPERSONATION = 0x0200
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
static extern uint SuspendThread(IntPtr hThread);
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
static extern int ResumeThread(IntPtr hThread);
|
||||||
|
|
||||||
|
|
||||||
|
public void Suspend(Process process)
|
||||||
|
{
|
||||||
|
foreach (ProcessThread thread in process.Threads)
|
||||||
|
{
|
||||||
|
var pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)thread.Id);
|
||||||
|
if (pOpenThread == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
int errCode=Marshal.GetLastWin32Error();
|
||||||
|
throw new Exception($"unmanaged function exited with error: {errCode}");
|
||||||
|
}
|
||||||
|
SuspendThread(pOpenThread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Suspend(int pid) => Suspend(Process.GetProcessById(pid));
|
||||||
|
|
||||||
|
public void Resume(Process process)
|
||||||
|
{
|
||||||
|
foreach (ProcessThread thread in process.Threads)
|
||||||
|
{
|
||||||
|
var pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)thread.Id);
|
||||||
|
if (pOpenThread == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
int errCode=Marshal.GetLastWin32Error();
|
||||||
|
throw new Exception($"unmanaged function exited with error: {errCode}");
|
||||||
|
}
|
||||||
|
ResumeThread(pOpenThread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resume(int pid) => Resume(Process.GetProcessById(pid));
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@ using System.IO;
|
|||||||
|
|
||||||
namespace DTLib.Extensions;
|
namespace DTLib.Extensions;
|
||||||
|
|
||||||
public static class OtherStuff
|
public static class StreamExtensions
|
||||||
{
|
{
|
||||||
public static void Write(this Stream stream, byte[] buff)
|
public static void Write(this Stream stream, byte[] buff)
|
||||||
=> stream.Write(buff, 0, buff.Length);
|
=> stream.Write(buff, 0, buff.Length);
|
||||||
Loading…
Reference in New Issue
Block a user