|
Overview
You can use the Process component to start and stop processes and to retrieve
information about your running processes on a computer. For example, you might use an
instance of the Process component to determine whether a process had stopped
responding. If the value returned true, you could have the component force the
process to stop or prompt the user with the information and offer a choice of
options.
Starting Processes
You can use the Process component to start processes on your system by calling the
Start method. Before you call Start, you must specify the file name of the
process to start by setting the FileName property to either the fully
qualified path to the target process, or in the case of qualified Windows
applications such as Notepad, simply the process name.
// Start a Program forever
private void btnStartPgm_Click(object sender, System.EventArgs e)
{
Process myProcess = new Process();
myProcess.StartInfo.FileName = "Notepad";
myProcess.StartInfo.WindowStyle =
ProcessWindowStyle.Maximized;
myProcess.Start();
}
Stopping Processes
You can use the Responding property to determine if the user interface of a
process is responding. When you attempt to read the Responding property, a request is
sent to the user interface of the target process. If there is an immediate response,
the return property value is true; a false property value is returned if there is no
response from the interface. This property is useful if you need to force a frozen
application to close.
There are two methods you can use to stop a process with a Process component.
The method you use depends on the type of process being stopped:
-
If the process has a graphical user interface, call the
CloseMainWindow method. This method sends a close request to the main
window of the process and behaves in the same manner as selecting the Close
command from the user interface. Using this method gives the target program a
chance to prompt the user to save any unsaved data during the cleanup
operation.
|
-
If the process does not have a user interface, call the Kill method.
|
The following example shows how to determine if Notepad is responding. If the
Response property is true, call the CloseMainWindow method to close the application.
If the Response property is false, the Kill method is called to force the process to
close.
// Stop Notepad if running
private void btnStopPgm_Click(object sender, System.EventArgs e)
{
Process[] myProcesses;
// Returns array containing all instances
of Notepad.
myProcesses = Process.GetProcessesByName("Notepad");
foreach(Process myProcess in myProcesses)
{
myProcess.CloseMainWindow();
}
}
Waiting for Processes to Complete Actions
A process is said to be idle when its main window is waiting for input from the
system. In order to test the process for its idle state, you must first bind a
Process component to it. You can call the WaitForInputIdle method before
having the target process perform an action.
The WaitForInputIdle method instructs a Process component to wait for the associated
process to enter an idle state. The method is useful, for example, when your
application waits for a process to finish creating its main window before
communicating with that window. The WaitForInputIdle method only works with
processes that have a user interface.
// Start a Program some Sec
private void btnStartPgmShort_Click(object sender, System.EventArgs e)
{
Process process = new Process();
process.StartInfo.FileName = "Notepad";
process.Start();
process.WaitForInputIdle();
Thread.Sleep(5000);
if(!process.CloseMainWindow())
{
process.Kill();
}
}
Print a File
The only necessary StartInfo member to set is the FileName property. Starting a process by specifying the FileName
property is similar to typing the information in the Run dialog box of the Windows
Start menu. Therefore, the FileName property does not need to represent an executable
file. It can be of any file type for which the extension has been associated with an
application installed on the system. For example the FileName can have a .txt
extension if you have associated text files with an editor, such as Notepad, or
it can have a .doc if you have associated .doc files with a word processing tool,
such as Microsoft Word. Similarly, in the same way that the Run dialog box can accept
an executable file name with or without the .exe extension, the .exe extension is
optional in the FileName member. For example, you can set the FileName property to
either "Notepad.exe" or "Notepad".
If the file name involves a nonexecutable file, such as a .doc file, you can include
a verb specifying what action to take on the file. For example, you could set the
Verb to "Print" for a file ending in the .doc extension.
// Print a File using the associated Programm
private void btnPrintFile_Click(object sender, System.EventArgs e)
{
const int ERROR_FILE_NOT_FOUND =2;
const int ERROR_ACCESS_DENIED = 5;
Process myProcess = new Process();
try
{
// Get the path
that stores user documents.
string myDocumentsPath =
Environment.GetFolderPath(Environment.SpecialFolder.Personal);
myProcess.StartInfo.FileName =
myDocumentsPath + "\\Document.txt";
myProcess.StartInfo.Verb = "Print";
myProcess.StartInfo.CreateNoWindow =
true;
myProcess.Start();
}
catch (Win32Exception ex)
{
if(ex.NativeErrorCode ==
ERROR_FILE_NOT_FOUND)
{
String msg =
ex.Message + ". Check the path.";
MessageBox.Show(msg, "Validation",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
else if (ex.NativeErrorCode ==
ERROR_ACCESS_DENIED)
{
// Note that if your word processor might generate exceptions
// such as this,
which are handled first.
String msg =
ex.Message + ". Permission denied";
MessageBox.Show(msg, "Validation",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
}
Update a Windows Form Control from a Background Thread
Windows Forms controls can only execute on the thread on which they were created,
that is, they are not thread-safe. If you want to get or set properties, or
call methods, on a control from a background thread, the call must be marshaled to
the thread that created the control.
When a thread is created, a new instance of the Thread class is
created using a constructor that takes the ThreadStart delegate as its
only parameter. However, the thread does not begin executing until the Start
method is invoked. When Start is called, execution begins at the first line of the
method referenced by the ThreadStart delegate.
private Thread timerThread;
timerThread = new Thread(new ThreadStart(ThreadProc));
timerThread.IsBackground = true;
timerThread.Start();
MethodInvoker provides a simple delegate that is used to invoke a method with
a void parameter list. This delegate can be used when making calls to a control's
invoke method, or when you need a simple delegate but don't want to define one
yourself. When you create a MethodInvoker delegate, you identify the method
that will handle the event. To associate the event with your event handler, add an
instance of the delegate to the event. The event handler is called whenever the event
occurs, unless you remove the delegate.
BeginInvoke executes the given delegate on the
thread that owns this Control's underlying window handle. The delegate is called
asynchronously and this method returns immediately. You can call this from any
thread, even the thread that owns the control's handle. If the control's handle does
not exist yet, this will follow up the control's parent chain until it finds a
control or form that does have a window handle. If no appropriate handle can be
found, BeginInvoke will throw an exception. Exceptions within the delegate
method are considered untrapped and will be sent to the application's untrapped
exception handler.
// This Background Thread is called from the
ThreadStart Delegate.
public void ThreadProc()
{
try
{
MethodInvoker mi = new
MethodInvoker(this.UpdateProgress);
while (true)
{
this.BeginInvoke(mi);
Thread.Sleep(500)
;
}
}
}
// This function is called from the Background Thread
private void UpdateProgress()
{
if (progressBar1.Value == progressBar1.Maximum)
{
progressBar1.Value = progressBar1.Minimum
;
}
progressBar1.PerformStep() ;
}
Full Example
The following example demonstrates the above discussed samples
and how to create a background thread that uses a MethodInvoker to
update a ProgressBar control at regular intervals.
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;
using System.Diagnostics;
namespace Akadia.ManagingProcesses
{
public class ManagingProcesses : System.Windows.Forms.Form
{
private System.Windows.Forms.Button
btnStartPgm;
private System.Windows.Forms.Button
btnStartPgmShort;
private System.Windows.Forms.Button
btnPrintFile;
private System.Windows.Forms.Button
btnStopPgm;
private System.Windows.Forms.Button
btnShowProcesses;
private System.Windows.Forms.ProgressBar
progressBar1;
private System.Windows.Forms.GroupBox
groupBox1;
private System.Windows.Forms.GroupBox
groupBox2;
private System.Windows.Forms.Button
btnStartThread;
private System.Windows.Forms.Button
btnStopThread;
private System.ComponentModel.Container
components = null;
private Thread timerThread;
public ManagingProcesses()
{
InitializeComponent();
}
protected override void Dispose( bool
disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(
disposing );
}
....
// The main entry
point for the application.
[STAThread]
static void Main()
{
Application.Run(new
ManagingProcesses());
}
// Start a Program
forever
private void btnStartPgm_Click(object
sender, System.EventArgs e)
{
Process myProcess =
new Process();
myProcess.StartInfo.FileName = "Notepad";
myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Maximized;
myProcess.Start();
}
// Start a Program
some Sec
private void btnStartPgmShort_Click(object
sender, System.EventArgs e)
{
Process process =
new Process();
process.StartInfo.FileName = "Notepad";
process.Start();
process.WaitForInputIdle();
Thread.Sleep(5000);
if(!process.CloseMainWindow())
{
process.Kill();
}
}
// Print a File using
the associated Programm
private void btnPrintFile_Click(object
sender, System.EventArgs e)
{
const int
ERROR_FILE_NOT_FOUND =2;
const int
ERROR_ACCESS_DENIED = 5;
Process myProcess =
new Process();
try
{
// Get the path that stores user documents.
string myDocumentsPath =
Environment.GetFolderPath(Environment.SpecialFolder.Personal);
myProcess.StartInfo.FileName = myDocumentsPath + "\\Document.txt";
myProcess.StartInfo.Verb = "Print";
myProcess.StartInfo.CreateNoWindow = true;
myProcess.Start();
}
catch
(Win32Exception ex)
{
if(ex.NativeErrorCode == ERROR_FILE_NOT_FOUND)
{
String msg = ex.Message + ". Check the path.";
MessageBox.Show(msg, "Validation",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
else if (ex.NativeErrorCode == ERROR_ACCESS_DENIED)
{
// Note that if your word processor might generate exceptions
// such as this, which are handled first.
String msg = ex.Message + " Permission denied";
MessageBox.Show(msg, "Validation",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
}
// Stop Notepad if
running
private void btnStopPgm_Click(object
sender, System.EventArgs e)
{
Process[]
myProcesses;
// Returns array containing all instances of Notepad.
myProcesses =
Process.GetProcessesByName("Notepad");
foreach(Process
myProcess in myProcesses)
{
if (myProcess.Responding)
{
myProcess.CloseMainWindow();
}
else
{
myProcess.Kill();
}
}
}
// Show all running
Processes
private void btnShowProcesses_Click(object
sender, System.EventArgs e)
{
Process[]
myProcesses = Process.GetProcesses();
String msg =
"";
foreach(Process
myProcess in myProcesses)
{
msg += myProcess.ProcessName + "\n";
}
MessageBox.Show(msg, "Processes running",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
// Start the
background thread to update the progress bar
private void btnStartThread_Click(object
sender, System.EventArgs e)
{
StopThread();
timerThread = new
Thread(new ThreadStart(ThreadProc));
timerThread.IsBackground = true;
timerThread.Start();
}
private void btnStopThread_Click(object
sender, System.EventArgs e)
{
StopThread();
}
// This function is
executed on a background thread.
// It marshalls calls to update the UI back
to the
// foreground thread
public void ThreadProc()
{
try
{
MethodInvoker mi = new MethodInvoker(this.UpdateProgress);
while (true)
{
// Call BeginInvoke on the Form
this.BeginInvoke(mi);
Thread.Sleep(500) ;
}
}
// Thrown when the thread is interupted by
// the main thread
- exiting the loop
catch
(ThreadInterruptedException)
{
// Simply exit....
}
catch
(Exception)
{
}
}
// This function is
called from the background thread
private void UpdateProgress()
{
// Reset to start if required
if
(progressBar1.Value == progressBar1.Maximum)
{
progressBar1.Value = progressBar1.Minimum ;
}
progressBar1.PerformStep() ;
}
// Stop the
background thread
private void StopThread()
{
if (timerThread !=
null)
{
timerThread.Interrupt();
timerThread = null;
}
}
}
}
|