Introduction
Controls in Windows Forms are bound to a specific thread and are not thread safe. Therefore, if you are calling a control's method from a different thread, you must use one of the control's invoke methods to marshal the call to the proper thread.
Background
Windows Forms uses the single-threaded apartment (STA) model because Windows Forms is based on native Win32 windows that are inherently apartment-threaded. The STA model implies that a window can be created on any thread, but it cannot switch threads once created, and all function calls to it must occur on its creation thread. Outside Windows Forms, classes in the .NET Framework use the free threading model.
The STA model requires that any method on a control that needs to be called from outside the control's creation thread must be marshaled to (executed on) the control's creation thread. The base class Control
provides several methods (Invoke
, BeginInvoke
, and EndInvoke
) for this purpose. Invoke
makes synchronous method calls, and BeginInvoke
makes asynchronous method calls.
Using the code
Use the property 'InvokeRequired
' to indicate whether the caller must call an invoke method when making method calls to the control because the caller is on a different thread than the one the control was created on.
public static class Utility
{
public static void SynchronizeInvokeEvent(object sender,
Delegate TargetEvent, EventArgs e)
{
if (TargetEvent != null)
{
Delegate[] InvocationList = TargetEvent.GetInvocationList();
foreach (Delegate TargetDelegate in InvocationList)
{
try
{
System.ComponentModel.ISynchronizeInvoke Target =
TargetDelegate.Target
as System.ComponentModel.ISynchronizeInvoke;
if (Target != null)
{
if (Target.InvokeRequired)
Target.Invoke(TargetDelegate, new object[] { sender, e });
else
TargetDelegate.DynamicInvoke(new object[] { sender, e });
}
else
{
TargetDelegate.DynamicInvoke(new object[] { sender, e });
}
}
catch (Exception ex)
{
throw ex;
}
}
}
}
}
public class ProcessWatcher : IDisposable
{
public delegate void TaskManagerEventHandler(object sender,
TaskManagerEventArgs e);
public event TaskManagerEventHandler ProcessCreated;
private bool m_StartedWatcher;
private System.Management.ManagementEventWatcher m_CreateProcessWatcher;
public ProcessWatcher()
{
m_StartedWatcher = false;
}
public void Dispose()
{
StopWatcher();
GC.Collect();
GC.WaitForPendingFinalizers();
}
public void StartWatcher()
{
if (m_StartedWatcher)
return;
m_StartedWatcher = true;
System.Management.EventWatcherOptions eventOptions =
new System.Management.EventWatcherOptions();
eventOptions.BlockSize = 1;
eventOptions.Timeout = new TimeSpan(0, 0, 2);
m_CreateProcessWatcher = new System.Management.ManagementEventWatcher
(
"root\\CIMV2",
"SELECT * FROM __InstanceCreationEvent WITHIN 1 " +
"WHERE TargetInstance ISA \"Win32_Process\"",
eventOptions
);
m_CreateProcessWatcher.EventArrived +=
new System.Management.EventArrivedEventHandler(
OnCreateProcessWatcher_EventArrived);
m_CreateProcessWatcher.Start();
}
public void StopWatcher()
{
if (!m_StartedWatcher)
return;
m_StartedWatcher = false;
m_CreateProcessWatcher.Stop();
m_CreateProcessWatcher.EventArrived -=
new System.Management.EventArrivedEventHandler(
OnCreateProcessWatcher_EventArrived);
m_CreateProcessWatcher.Dispose();
m_CreateProcessWatcher = null;
}
void OnCreateProcessWatcher_EventArrived(object sender,
System.Management.EventArrivedEventArgs e)
{
int ProcessID;
if (int.TryParse(((System.Management.ManagementBaseObject)
e.NewEvent["TargetInstance"])["ProcessId"].ToString(),
out ProcessID))
{
OnCreateProcess(new TaskManagerEventArgs(
System.Diagnostics.Process.GetProcessById(ProcessID)));
}
}
private void OnCreateProcess(TaskManagerEventArgs e)
{
Utility.SynchronizeInvokeEvent(this, ProcessCreated, e);
}
public class TaskManagerEventArgs : EventArgs
{
private System.Diagnostics.Process m_Process;
public TaskManagerEventArgs(System.Diagnostics.Process Process)
{
m_Process = Process;
}
public System.Diagnostics.Process Process
{
get { return m_Process; }
}
}
}
public partial class Form1 : Form
{
private ProcessWatcher m_ProcessWatcher;
public Form1()
{
InitializeComponent();
m_ProcessWatcher = new ProcessWatcher();
m_ProcessWatcher.ProcessCreated += new
ProcessWatcher.TaskManagerEventHandler(
m_ProcessWatcher_ProcessCreated);
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
m_ProcessWatcher.Dispose();
base.OnFormClosing(e);
}
private void m_ProcessWatcher_ProcessCreated(object sender,
ProcessWatcher.TaskManagerEventArgs e)
{
this.listBox1.Items.Add(e.Process.ProcessName);
}
private void m_StartProcessWatcherButton_Click(object sender, EventArgs e)
{
m_ProcessWatcher.StartWatcher();
}
private void m_StopProcessWatcherButton_Click(object sender, EventArgs e)
{
m_ProcessWatcher.StopWatcher();
}
}