Gapotchenko.FX.Diagnostics.Process
2024.1.3
Prefix Reserved
dotnet add package Gapotchenko.FX.Diagnostics.Process --version 2024.1.3
NuGet\Install-Package Gapotchenko.FX.Diagnostics.Process -Version 2024.1.3
<PackageReference Include="Gapotchenko.FX.Diagnostics.Process" Version="2024.1.3" />
paket add Gapotchenko.FX.Diagnostics.Process --version 2024.1.3
#r "nuget: Gapotchenko.FX.Diagnostics.Process, 2024.1.3"
// Install Gapotchenko.FX.Diagnostics.Process as a Cake Addin #addin nuget:?package=Gapotchenko.FX.Diagnostics.Process&version=2024.1.3 // Install Gapotchenko.FX.Diagnostics.Process as a Cake Tool #tool nuget:?package=Gapotchenko.FX.Diagnostics.Process&version=2024.1.3
Overview
The module provides extended functionality for process manipulation.
Process Extensions
GetParent()
GetParent()
is an extension method provided by Gapotchenko.FX.Diagnostics.Process
module
for System.Diagnostics.Process
class.
What it does is returns the parent process. Or null
when parent process is absent or no longer running.
EnumerateParents()
Enumerates a chain of parent processes beginning with the closest parent.
ReadEnvironmentVariables()
Reads environment variables of a process.
The functionality is achieved by reading the process environment block (PEB) at the operating system level.
For example, this is how a PATH environment variable can be retrieved from all running instances of Microsoft Visual Studio:
using Gapotchenko.FX.Diagnostics;
using System;
using System.Diagnostics;
class Program
{
static void Main()
{
var processes = Process.GetProcessesByName("devenv");
if (processes.Length == 0)
Console.WriteLine("Process with a given name not found. Please modify the code and specify the existing process name.");
foreach (var process in processes)
{
Console.WriteLine();
Console.WriteLine("Process with ID {0} has the following value of PATH environment variable:", process.Id);
var env = process.ReadEnvironmentVariables();
string path = env["PATH"];
Console.WriteLine(path);
}
}
}
ReadArguments()
The method retrieves a set of command-line arguments specified at the process start. The functionality is achieved by reading the process environment block at the operating system level.
using Gapotchenko.FX.Diagnostics;
using System;
using System.Diagnostics;
class Program
{
static void Main()
{
var processes = Process.GetProcessesByName("devenv");
if (processes.Length == 0)
Console.WriteLine("Process with a given name not found. Please modify the code and specify the existing process name.");
foreach (var process in processes)
{
Console.WriteLine(
"Process with ID {0} was started with the following command line: {1}",
process.Id,
process.ReadArguments());
}
}
}
ReadArgumentList()
The method retrieves a sequence of command-line arguments specified at the process start.
It is similar to aforementioned ReadArguments()
method but returns a sequence of command-line arguments instead of a single command line string.
This fundamental difference may be essential in multi-platform scenarios. For instance, Windows OS natively represents the command line of a process as a single string, while Unix operating systems natively represent the command line as a strongly-typed array of command-line arguments.
Whichever method is used the results are similar, but every method provides a higher degree of detalization for a particular operating system.
End()
Allows to end a process according to a specified mode of operation.
The End()
method is interesting and a bit intricate.
The stock Process
class already provides a similar Kill()
method
which performs an immediate forceful termination of a process without giving it a chance to exit gracefully.
Depending on a kind of process being terminated, Kill()
is not always suitable.
For example, it may have devastating consequences if someone kills a Microsoft Visual Studio process without giving it a graceful shutdown.
Lost files, potentially corrupted extensions and so on.
Meet the End()
method provided by Gapotchenko.FX.Diagnostics.Process
module.
It allows to end a process according to a specified mode of operation.
The default mode of operation is ProcessEndMode.Complete
that follows a sequence presented below:
- Graceful techniques are tried first:
1.1.End()
method tries to close a main window of the process
1.2. If that fails, it tries to send Ctrl+C (SIGTERM) signal to the process - Forceful techniques:
2.1. If graceful techniques fail,End()
method tries to exit the process (suitable for the current process only)
2.2. If that fails, it kills the process (SIGKILL)
The method returns a ProcessEndMode
value on completion indicating how the process was actually ended.
Let's take a look on example that tries to end all running instances of Notepad:
using Gapotchenko.FX.Diagnostics;
foreach (var process in Process.GetProcessesByName("notepad"))
{
var result = process.End();
Console.WriteLine(result);
}
Once there is a running Notepad app, the sample produces the following output:
Close
signifying that a Notepad process was gracefully ended by closing its main window.
Now let's repeat the experiment by launching a Notepad app again and opening its "File Save" dialog via menu (File → Save As...). This time, let's keep the "File Save" dialog open, and launch the example code once again.
This time the result will be different:
Kill
The Notepad process was unable to shutdown gracefully and thus was forcefully killed. Graceful shutdown was not possible because the process had an active modal dialog.
<details> <summary>More examples</summary>
Let's modify sample a bit:
foreach (var process in Process.GetProcessesByName("notepad"))
{
var result = process.End();
Console.WriteLine("PID {0}", process.Id);
Console.WriteLine("Graceful: {0}", (result & ProcessEndMode.Graceful) != 0);
Console.WriteLine("Forceful: {0}", (result & ProcessEndMode.Forceful) != 0);
}
Now it shows the Id
of a process that was ended together with a graceful/forceful classification of the result.
What if we want to limit the End()
method to only perform a graceful process termination?
Let's use the End(ProcessEndMode)
method overload:
foreach (var process in Process.GetProcessesByName("notepad"))
{
var result = process.End(ProcessEndMode.Graceful);
Console.WriteLine("PID {0}", process.Id);
Console.WriteLine(result);
}
Now the result will only be graceful, or have ProcessEndMode.None
value if a process could not be gracefully ended.
But what if we want to limit the End()
method to only perform a graceful process termination via Ctrl+C (SIGINT) signal and forceful kill?
No problem:
foreach (var process in Process.GetProcessesByName("notepad"))
{
var result = process.End(ProcessEndMode.Interrupt | ProcessEndMode.Kill);
Console.WriteLine("PID {0}", process.Id);
Console.WriteLine(result);
}
As you can see, despite a simple-looking signature, the End(…)
method gives enormous possibilities for achieving a specific goal.
</details>
EndAsync()
The method is similar to End()
but has an async implementation.
It can be used to efficiently handle dozens of processes in a bulk.
For example, there is a need to shut down quite a few processes, say 20. One possible solution is to shut down the processes sequentially, one by one. But this may take quite a few moments to complete, up to several dozen seconds. On a positive side, it only takes one CPU thread. The second solution is to shut down the processes in parallel. This solution will reduce the overall time significantly, but that reduction will come at the expense of 20 wasted CPU threads. What if we could have the benefits of both solutions at the same time?
We can achieve that by using asynchronous code, like so:
static Task<ProcessEndMode[]> EndProcessesAsync(IEnumerable<Process> processesToEnd) =>
Task.WhenAll(processesToEnd.Select(x => x.EndAsync()));
Even if you write a single-threaded app, you still get the benefits of asynchronous code here: the processes are shut down in parallel and no CPU threads are wasted.
Here is a full example that demonstrates that:
using Gapotchenko.FX.Diagnostics;
using Gapotchenko.FX.Threading.Tasks;
using System.Diagnostics;
class Program
{
static void Main()
{
var processEndModes = TaskBridge.Execute(
EndProcessesAsync(
Process.GetProcessesByName("notepad"));
Console.WriteLine(
"Notepads were ended with the following results: {0}.",
string.Join(", ", processEndModes.Select(x => x.ToString())));
}
static Task<ProcessEndMode[]> EndProcessesAsync(IEnumerable<Process> processesToEnd) =>
Task.WhenAll(processesToEnd.Select(x => x.EndAsync()));
}
(Reminder: the correct way to wait for the completion of an asynchronous task in synchronous code is to use TaskBridge
)
Other Modules
Let's continue with a look at some other modules provided by Gapotchenko.FX:
- Gapotchenko.FX
- Gapotchenko.FX.AppModel.Information
- Gapotchenko.FX.Collections
- Gapotchenko.FX.Console
- Gapotchenko.FX.Data
- Gapotchenko.FX.Diagnostics
- Gapotchenko.FX.IO
- Gapotchenko.FX.Linq
- Gapotchenko.FX.Math
- Gapotchenko.FX.Memory
- Gapotchenko.FX.Security.Cryptography
- Gapotchenko.FX.Text
- Gapotchenko.FX.Threading
- Gapotchenko.FX.Tuples
Or look at the full list of modules.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 is compatible. net5.0-windows was computed. net5.0-windows7.0 is compatible. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net6.0-windows7.0 is compatible. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net7.0-windows7.0 is compatible. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net8.0-windows7.0 is compatible. net9.0 is compatible. net9.0-windows7.0 is compatible. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 is compatible. netcoreapp2.2 was computed. netcoreapp3.0 is compatible. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
.NET Framework | net461 is compatible. net462 was computed. net463 was computed. net47 was computed. net471 is compatible. net472 is compatible. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETCoreApp 2.1
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
.NETCoreApp 3.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
.NETFramework 4.6.1
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
.NETFramework 4.7.1
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
.NETFramework 4.7.2
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
.NETStandard 2.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
.NETStandard 2.1
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
net5.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
net5.0-windows7.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
net6.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
net6.0-windows7.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
net7.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
net7.0-windows7.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
net8.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
net8.0-windows7.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
net9.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
-
net9.0-windows7.0
- Gapotchenko.FX (>= 2024.1.3)
- Gapotchenko.FX.Diagnostics.CommandLine (>= 2024.1.3)
- Gapotchenko.FX.Threading (>= 2024.1.3)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on Gapotchenko.FX.Diagnostics.Process:
Package | Downloads |
---|---|
IoFluently.NetStandard
Package Description |
|
Gapotchenko.FX.Profiles.Core
Represents the Core profile of Gapotchenko.FX. |
|
Gapotchenko.FX.Console
Provides virtual terminal functionality, console traits, and other useful primitives for .NET console apps. |
|
BlossomiShymae.GrrrLCU
A simple wrapper for the LCU. Grrr. x3 |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on Gapotchenko.FX.Diagnostics.Process:
Repository | Stars |
---|---|
blish-hud/Blish-HUD
A Guild Wars 2 overlay with extreme extensibility through compiled modules.
|
Version | Downloads | Last updated |
---|---|---|
2024.1.3 | 287 | 11/10/2024 |
2022.2.7 | 38,361 | 5/1/2022 |
2022.2.5 | 1,516 | 5/1/2022 |
2022.1.4 | 1,543 | 4/6/2022 |
2021.2.21 | 1,732 | 1/21/2022 |
2021.2.20 | 1,513 | 1/17/2022 |
2021.1.5 | 8,041 | 7/6/2021 |
2020.2.2-beta | 1,011 | 11/21/2020 |
2020.1.15 | 4,959 | 11/5/2020 |
2020.1.9-beta | 1,050 | 7/14/2020 |
2020.1.8-beta | 1,037 | 7/14/2020 |
2020.1.7-beta | 1,110 | 7/14/2020 |
2020.1.1-beta | 1,111 | 2/11/2020 |
2019.3.7 | 1,909 | 11/4/2019 |
2019.2.20 | 1,313 | 8/13/2019 |
2019.1.151 | 26,615 | 3/30/2019 |