none
How to use Process.OnExited()

    Question

  • I am using processes in my code that I need to generate an event when they are finished.  I am assuming it has something to do with the System.Diagnostics.Process.OnExited() method, but the documentation on it is sparse.  I use code similar to the following:

    System.Diagnostics.Process proc = new System.Diagnostics.Process(); proc.EnableRaisingEvents=false;
    proc.StartInfo.FileName="H:\pebld\wookie.bat";
    proc.StartInfo.Arguments = tbox1.Text.ToString(); proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
    proc.Start();

    How do I know when this process finishes?

    Friday, October 21, 2005 9:57 PM

Answers

  • Great questions!

    To ensure that the Exited event is raised, you should set the EnabledRaisingEvents, on the Process class, to true.
    You can find more information on the Process.EnableRaisingEvents property at: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemDiagnosticsProcessClassEnableRaisingEventsTopic.asp

    I should have been clearer before. Raising the Exited event requires someone to pay attention to the process handle, in this case - a threadpool callback. As such, there is a perf hit, and if you are simply waiting for the process to exit immediately after starting it, you can use WaitForExit indefinitely.

    There are pros and cons to each approach, and it really depends on your specific scenario. For example, if you are starting another process, then performing some other operations, and later sychronizing with the spawned process, I would recommend the callback/event handler solution.
    If you are making a synchronous call to the other process, and waiting for it to finish, then I would recommend WaitForExit.
    Note that if the other process hangs [due to bugs in the process], then your app will also hang. If you are concerned about the other process hanging, then you can poll it very infrequently [using large Sleep values, for example], and terminate it at your discretion.

    Hope that helps,
    Stephen [Microsoft Common Language Runtime: Security - Developer]
    http://blogs.msdn.com/stfisher
    Saturday, October 22, 2005 12:06 AM
    Moderator

All replies

  • Hello,

    Here are the primary methods of determining when a Process class has exited are:

    1) Attaching an event handler to the Process.Exited delegate chain.
    You can find more information on Process.Exited on MSDN at: http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemDiagnosticsProcessClassExitedTopic.asp

    2) Wait on the Process handle.
    Just like in the Win32 programming model, each process has an associated handle, which is "signalled" when the process terminates - at which point, you can check the return code from the process.
    You can find more information on the Process.Handle property (note that it is an unmanaged IntPtr, but you can wrap it in a WaitHandle-derived class) at: http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemDiagnosticsProcessClassHandleTopic.asp

    3) Periodically poll the Process.HasExited property.
    I would strongly recommend AGAINST polling, as waiting on the handle/exited event are more performance friendly and allow threads to idle/release their time slice [unlike polling algorithms, in general].
    However, if you need to check if a Process has exited, this property works very well. You can find more information on Process.HasExited at:
    http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemDiagnosticsProcessClassHasExitedTopic.asp

    The Process.OnExited method is a virtual method that exists on the Process class to allow developers who derive from the Process class to be notified when the Process exits _before_ consumers/instantiators of the Process-derived class. This is probably not useful for you, since do not appear to be deriving from Process in your code snippet. You can find more information on Process.OnExited at: http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemDiagnosticsProcessClassOnExitedTopic.asp

    Hope that helps,
    Stephen [Microsoft Common Language Runtime: Security - Developer]
    http://blogs.msdn.com/stfisher
    Friday, October 21, 2005 11:15 PM
    Moderator
  • I am kind of new to C#, do you happen to have a small code sample?  I looked at these links but I don't know what to make of them.
    Friday, October 21, 2005 11:21 PM
  • There are a number of C# code snippets for using the ProcessStartInfo and Process.Start APIs on MSDN.

    If you are new to C#, I would recommend perusing the C# Samples that ship in the .NET Framework SDK. They will help introduce events, delegates, and classes like WaitHandle.

    As an example of using Process in C#, try http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemdiagnosticsprocessclasstopic.asp

    Hope that helps,
    Stephen [Microsoft Common Language Runtime: Security - Developer]
    http://blogs.msdn/com/stfisher

    Friday, October 21, 2005 11:38 PM
    Moderator
  • I have reviewed that as well.  I tried to do #1 on your list what I have come up with is this:

    System.Diagnostics.Process proc = new System.Diagnostics.Process();

    proc.EnableRaisingEvents=false;

    proc.StartInfo.FileName="H:\pebld\wookie.bat";

    proc.StartInfo.Arguments = tbox1.Text.ToString();

    proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;

    proc.Exited += new System.EventHandler(this.Process1_Exited);

    This should call my Process1_Exited function correct?
    However it doesn't seem to be working...  I have searched all over the place for this answer, and I am not exactly new at this but probably not really experienced either.

    Friday, October 21, 2005 11:47 PM
  • Great questions!

    To ensure that the Exited event is raised, you should set the EnabledRaisingEvents, on the Process class, to true.
    You can find more information on the Process.EnableRaisingEvents property at: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemDiagnosticsProcessClassEnableRaisingEventsTopic.asp

    I should have been clearer before. Raising the Exited event requires someone to pay attention to the process handle, in this case - a threadpool callback. As such, there is a perf hit, and if you are simply waiting for the process to exit immediately after starting it, you can use WaitForExit indefinitely.

    There are pros and cons to each approach, and it really depends on your specific scenario. For example, if you are starting another process, then performing some other operations, and later sychronizing with the spawned process, I would recommend the callback/event handler solution.
    If you are making a synchronous call to the other process, and waiting for it to finish, then I would recommend WaitForExit.
    Note that if the other process hangs [due to bugs in the process], then your app will also hang. If you are concerned about the other process hanging, then you can poll it very infrequently [using large Sleep values, for example], and terminate it at your discretion.

    Hope that helps,
    Stephen [Microsoft Common Language Runtime: Security - Developer]
    http://blogs.msdn.com/stfisher
    Saturday, October 22, 2005 12:06 AM
    Moderator
  • Excellent, that worked.  Thanks for your help.
    Saturday, October 22, 2005 12:11 AM
  • Hi, I've got quite the same problem when I'm trying to start a process with bat file.

    Here's the definition of my Submit.bat file

    SETLOCAL

    set path=%path%;C:\Program files\Sterling commerce\Utilities

    Direct.exe -n%1 -u%2 -p%3 <%4 > d:\Log.txt

    @echo off

    FOR %%A in (0 1 2 3 4 5 6 7 8 9) DO IF ERRORLEVEL %%A SET ERRORCODE=%%A

    echo ERRORCODE: %ERRORCODE

    ENDLOCAL

    As you can see, I should get only 0 -9 as return value...but the problem is, that in the proc.ExitCode is 255 !

    I'm starting new process like this:

    string args1 = "-n"+localhost + " -u"+userName + " -p"+password + " <" + prozessFile + "> D:\\Log.txt";

    Process proc = new Process();

    proc.StartInfo.UseShellExecute = false;

    proc.StartInfo.FileName =  "Direct.exe";

    proc.StartInfo.Arguments = args1;

    proc.Start();

    int testForExit = proc.ExitCode

     

    ......so why do get only 255 as returncode back ?

     

    Do I start the process correct like that ? That Direct.exe application needs the process data (parameter %4) as inpot and should write some output info into D:\\Log.txt.

    Would it be better to do this with process.StandartInput & process.StandartOutput ?

    Please help

    Thursday, September 07, 2006 4:04 PM