Processes


A process in the Framework APIs is the same thing as an OS process. We don't cover them in great detail here; your favorite Windows book should do a great job at that. There are a number of interesting things you can do with a process and quite a bit of statistical information available for processes running inside your system. All of this functionality is available through the use of the Process class in the System.Diagnostics namespace. These APIs enable you to work with existing (already running) processes or to create and manage your own.

Existing Processes

The Process class has a set of static methods that will return you one or more instances with which to work. The most straightforward is the static GetCurrentProcess method, which returns an instance referring to the currently executing process. GetProcessById obtains a single process using its unique OS process identifier (PID) or throws an ArgumentException if no active process is found with the specified PID. The GetProcessByName method returns an array of Process objects executing under the given name. Lastly, Process.GetProcesses returns an array of all currently active processes.

This code demonstrates the use of these methods by simply printing out some information about active processes in the system:

 void ListProcesses() {     Console.WriteLine("Current process:");     PrintProcess(Process.GetCurrentProcess());     Console.WriteLine("IE processes:");     Process[] iexplorerProcs = Process.GetProcessesByName("iexplore");     foreach (Process p in iexplorerProcs) PrintProcess(p);     Console.WriteLine("All active processes:");     Process[] allProcs = Process.GetProcesses();     foreach (Process p in allProcs) PrintProcess(p); } void PrintProcess(Process p) {     Console.WriteLine("-> {0} - {1}", p.ProcessName, p.PeakWorkingSet64); } 

You can also access processes on other machines on which the current authorization identity has administrative access. All of the aforementioned methods also have an overload that takes an extra machineNamestring argument. Assuming that you had access and privileges to do so on a machine DevelopmentBox1, this code would list all active processes on it:

 Process[] allProcs = Process.GetProcesses("DevelopmentBox1"); foreach (Process p in allProcs) PrintProcess(p); 

Each Process object has a set of statistical state associated with it. Here are just a few of the more interesting properties:

 public int BasePriority { get; } public int ExitCode { get; } public DateTime ExitTime { get; } public bool HasExited { get; } public int Id { get; } public string MachineName { get; } public IntPtr MaxWorkingSet { get; set; } public IntPtr MinWorkingSet { get; set; } public long NonpagedSystemMemorySize64 { get; } public long PagedMemorySize64 { get; } public long PagedSystemMemorySize64 { get; } public long PeakPagedMemorySize64 { get; } public long PeakVirtualMemorySize64 { get; } public long PeakWorkingSet64 { get; } public bool PriorityBoostEnabled { get; set; } public ProcessPriorityClass PriorityClass { get; set; } public long PrivateMemorySize64 { get; } public TimeSpan PrivilegedProcessorTime { get; } public string ProcessName { get; } public IntPtr ProcessorAffinity { get; set; } public bool Responding { get; } public DateTime StartTime { get; } public TimeSpan TotalProcessorTime { get; } public TimeSpan UserProcessorTime { get; } public long VirtualMemorySize64 { get; } public long WorkingSet64 { get; } 

Any data obtained by these methods is a snapshot in time. To obtain the latest statistics, you must execute the void Refresh method on a Process instance. For remote processes, this will result in a network round trip, and so should be used sparingly.

Interacting with a Process

Each process has three primary pipes that you can use to communicate with the process. These are standard input, error, and output. Standard input (a.k.a. stdin) is the keyboard input to a process and is what the Console.In.* family of methods interact with by default. Standard output and error (a.k.a. stdout and stderr), on the other hand, are for the process to communicate with the outside world. For console-based applications, for example, these are used to print to the screen during Console.Out.* and Console.Error.* operations. Refer to Chapter 7 for more details on the I/O system.

While a process is executing, you will often want to either provide data to it or read data that it is outputting. The Process class exposes these pipes so that you can do so: StandardInput, StandardOutput, and StandardError. StandardInput is a StreamWriter while the others are StreamReaders. You can work with these as you would any other Stream-based class.

In order for output to be readable, you will need to start your process with output redirected. To do this, construct a ProcessStartInfo instance, set its UseShellExecute property to false and its RedirectStandardOutput (and/or RedirectStandardError) property to true, and pass this to the Process constructor:

 // Construct our process start information: ProcessStartInfo pi = new ProcessStartInfo("path_to_exe.exe"); pi.UseShellExecute = false; pi.RedirectStandardOutput = true; // Kick off the new process: Process p = Process.Start(pi); StreamReader sr = p.StandardOutput; // And read some output from its stdout stream: String line; while ((line = sr.ReadLine()) != null) {     Console.WriteLine("Read line: {0}", line); } p.WaitForExit(); 

You can perform asynchronous reads of both the stdout and stderr streams through the use of the BeginErrorReadLine and BeginOutputReadLine methods. These operations will both occur asynchronously, making a callback to the events ErrorDataReceived and OutputDataReceived, respectively, when data is available. Both of these events are delegates that provide event arguments containing a string Data property, representing the data that was read from the process. There are also Cancel*ReadLine methods to stop the requested asynchronous read operation.

Creation

The Process class offers static Start factory methods to create a new process. There are several overloads, the simplest of which just takes an executable's filename. There is also an overload that takes a ProcessStartInfo argument, enabling you to specify several interesting settings to control the resulting process (e.g., window style, environment variables, output redirection, etc.). Start creates a new process to execute the program, starts it, and returns the Process instance corresponding to the newly created process. For those programs that are located in a directory found in the current environment's PATH variable, it is not necessary to fully qualify the executable's filename. For example, this simple line of code will create a new Internet Explorer instance:

 Process p = Process.Start("iexplore.exe"); 

Your executable will sometimes require that arguments are passed to it when it is being started. To do so, you can use the overload which takes a string-based arguments parameter. The value of arguments will be passed to the executable as would be the case if running from a command line or shortcut. For example, this code opens up a new IE window that navigates to a specific web site:

 Process p = Process.Start("iexplore.exe",     "http://www.bluebytesoftware.com/blog/"); 

The rules for passing arguments are the same as in a command-line window. For arguments that contain spaces, surround them with double quotation marks.

Process also contains overloads that take three additional arguments: string userName, SecureString password, and string domain. These can be used to create a new process running under a different account. For example, this code will launch a program running under the local guest account:

 SecureString password = GetSecurePassword(); // Custom function Process p = Process.Start("iexplore",     "http://www.bluebytesoftware.com/blog/", "Guest", password, "MyMachine"); 

Notice that for a local user account, we pass in the local machine's name for the domain. If we wanted to use a network account, we would pass in the appropriate domain value here. Also notice that we must use a SecureString instance to represent passwords. The GetSecurePassword() method is not something the Framework provides — you will normally have to create such methods to look up and generate SecureString instances for you.

Termination

There are several ways to monitor for, and indeed even cause, the termination of a process. The HasExited property of a Process instance will return true to indicate that it has exited. Further, the ExitCode property will obtain the process's exit code (where non-0 is customarily used to indicate abrupt and unexpected termination), and ExitTime will return a DateTime representing the time at which the process exited.

The instance method WaitForExit on Process blocks execution of the current thread until the target process has exited. There is also an overload that will time out after a timeout period, returning false if the process does not exit within this period. The Exited event is also available to notify your program asynchronously of a process exit. For this event to be raised properly, however, you must set the EnableRaisingEvents property on the target Process to true.

This code demonstrates setting up an event handler that will be called upon process termination:

 public void WatchProcess(Process p) {     p.Exited += ExitHandler;     p.EnableRaisingEvents = true; } void ExitHandler(object sender, EventArgs e) {     Process p = (Process)sender;     Console.WriteLine("{0} exited with code {1}", p.ProcessName, p.ExitCode); } 

The Process class has an instance Kill method, which abruptly terminates the target process. This is the equivalent to calling the Win32 TerminateProcess function. This forces the program to exit immediately without any orderly unwind and can lead to system-wide corruption. The process exit code will be set to -1 (non-zero to indicate failure).




Professional. NET Framework 2.0
Professional .NET Framework 2.0 (Programmer to Programmer)
ISBN: 0764571354
EAN: 2147483647
Year: N/A
Pages: 116
Authors: Joe Duffy

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net