Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to know if external application was closed?

Tags:

c#

.net

winforms

How can I say if a winform whas closed do ...?

bool isRunning = false;
foreach (Process clsProcess in Process.GetProcesses()) 
{
    if (clsProcess.ProcessName.Contains("Notepad"))
    {
        isRunning = true;
        break;
    }
}

The code above always checks if the process exists but the code is slow for what I want it to do.So is there a way to check if the Notepad process was actually closed instead of always looping to see if its there?

like image 640
John Pietrar Avatar asked Sep 26 '16 12:09

John Pietrar


2 Answers

You can use Win32_ProcessStopTrace which indicates that a process is terminated.

ManagementEventWatcher watcher;
protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    watcher = new ManagementEventWatcher("Select * From Win32_ProcessStopTrace");
    watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
    watcher.Start();
}

void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
    if ((string)e.NewEvent["ProcessName"] == "notepad.exe")
        MessageBox.Show("Notepad closed");
}

protected override void OnFormClosed(FormClosedEventArgs e)
{
    watcher.Stop();
    watcher.Dispose();
    base.OnFormClosed(e);
}

Don't forget to add a reference to System.Management and add using System.Management;

Note

  • If you want to monitor closing of an specific instance of notepad which you know, you can use such criteria:

    if ((UInt32)e.NewEvent["ProcessID"]==knownProcessId)
    
  • If you want to check if any instance of notepad is open, you can use such criteria:

    if (System.Diagnostics.Process.GetProcessesByName("notepad").Any())
    
  • The EventArrived will raise in a different thread than UI thread and if you need to manipulate UI, you need to use Invoke.

  • Above method notifies you about closing of all processes, regardless of the time they are opened, before or after your application run. If you don't want to notified about the processes which may be opened after your application starts, you can get existing notepad processes and subscribe to their Exited event:

    private void Form1_Load(object sender, EventArgs e)
    {
        System.Diagnostics.Process.GetProcessesByName("notepad").ToList()
              .ForEach(p => {
                  p.EnableRaisingEvents = true;
                  p.Exited += p_Exited;
              });
    }
    void p_Exited(object sender, EventArgs e)
    {
        MessageBox.Show("Notepad closed");
    }
    
like image 187
Reza Aghaei Avatar answered Oct 26 '22 23:10

Reza Aghaei


This should do the trick. It will create a event for you when the process dies. No need to loop through all the process.

public static event EventHandler ProcessDied;
public void CheckForProcess()
{

    InitializeComponent();
    ProcessDied += new EventHandler(Process_Died);
    AttachProcessDiedEvent("notepad", ProcessDied);

}

private  void AttachProcessDiedEvent( string processName,EventHandler e )
{
    Process isSelectedProcess=null;
    foreach (Process clsProcess in Process.GetProcesses())
    {
        if (clsProcess.ProcessName.Contains(processName))
        {
            isSelectedProcess = clsProcess;
            break;
        }
    }
    if(isSelectedProcess!=null)
    {
         isSelectedProcess.WaitForExit();
    }
    if(e!=null)
    {
        e.Invoke(processName, new EventArgs());
    }
}

private void Process_Died(object sender, EventArgs e)
{
    //Do Your work
}

Let me know if there are any issues.

like image 25
XYZ Avatar answered Oct 27 '22 00:10

XYZ