Thread: WaitForExit(); Works, but C# WinForm disappears.

  1. #1
    Slime Dragoon_42's Avatar
    Join Date
    Feb 2003
    Location
    Vancouver
    Posts
    90

    Question WaitForExit(); Works, but C# WinForm disappears.

    I have a WinForms program that launches another program and then waits for it to exit before moving on. This launched program may run for an hour or so. After the user exits my form disappears from the screen AND the taskbar. When we opened the Task Manager it was still there and when we clicked the Switch To button it popped right back on the screen and continued on its way.

    Code:
    System.Diagnostics.ProcessStartInfo p = new System.Diagnostics.ProcessStartInfo(@"C:\OtherProgram.exe") ;
    p.Arguments="-RunForever";
    System.Diagnostics.Process proc = new System.Diagnostics.Process();
    proc.StartInfo = p;
    
    proc.Start();
    proc.WaitForExit();
    this.button3.BackColor=Color.LightGreen;  //success indicator
    My question is: Is there a way to make sure the poor C# program doesn't disappear when control is returned from the OtherProgram.exe? It could be a best practice type thing as I've never used this sort of thing before. Thanks for any help!

  2. #2
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    I can't reproduce your behavior.
    In any case, a few additions to your code:

    - Call proc.Close() after WaitForExit() to clear any resources left from Start().
    - Try some method to call your system attention back to your application like Form.Refresh(), BringToFront(), Form.Invalidate(), or anything similar.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  3. #3
    Slime Dragoon_42's Avatar
    Join Date
    Feb 2003
    Location
    Vancouver
    Posts
    90
    Awesome, thanks for the ideas. I'll give them a shot and post the results.

    Quote Originally Posted by Mario F. View Post
    I can't reproduce your behavior.
    In any case, a few additions to your code:

    - Call proc.Close() after WaitForExit() to clear any resources left from Start().
    - Try some method to call your system attention back to your application like Form.Refresh(), BringToFront(), Form.Invalidate(), or anything similar.

  4. #4
    Slime Dragoon_42's Avatar
    Join Date
    Feb 2003
    Location
    Vancouver
    Posts
    90
    Das funktioniert wunderbar!
    Code:
    private void frmMain_Shown(object sender, EventArgs e)
    {
    this.TopMost = true;
    this.Focus();
    this.BringToFront();
    this.TopMost = false;
    }

  5. #5
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Well, best practice is never to do anything long inside an event handler (I'm assuming from context that this code is likely inside something like a button's click method, right?)

    The reason is, WaitForExit() will stall the thread that calls it, and in this case it's the main GUI thread for your winform. That means, among other things, it won't even redraw your winform while the GUI's message pump is blocked. Really, you should handle this in one of two ways:

    1. Move the process creation and waiting into another thread. This is how you normally need to handle time-consuming operations (and this is an excellent post on this board about how to do that, otherwise if you need more than BackgroundWorker can do, you can roll your own with Thread & BeginInvoke/Invoke), but in this case there's a better answer because all you're doing is waiting for a process to end:

    2. Rather than use WaitForExit(), handle the process's exit event. Your code would then look like this (writing from memory so may not be 100% accurate but should be close):

    Code:
    // Inside the form class:
    
    private System.Diagnostics.Process proc;
    
    private void myProcess_Exited(object sender, System.EventArgs e)
    {
        button3.BackColor=Color.LightGreen;  //success indicator
    }

    Code:
    // In whatever method was spawning the process:
    
    System.Diagnostics.ProcessStartInfo p = new System.Diagnostics.ProcessStartInfo(@"C:\OtherProgram.exe") ;
    p.Arguments="-RunForever";
    proc = new System.Diagnostics.Process();
    proc.StartInfo = p;
    proc.EnableRaisingEvents = true;
    proc.Exited += new EventHandler(myProcess_Exited);
    proc.Start();
    This way, your GUI thread never stalls at all -- it simply continues its message pump until it receives a message that the other thread ended. Previously, the entire message pump would grind to a halt until the other process exited.

    You may find that you now need to disable certain UI elements (buttons, menus, etc.) while the other process runs (previously, none of them would work because the wait was blocking new input from being processed at all).

    Personally, my rules-of-thumb on any event handler are:
    * Prefer events to waits whenever possible. The message pump does a great job at waiting until something happened and then dealing with it. Use it, don't duplicate it and certainly don't break it.
    * Anything (including a wait, when necessary) which takes longer than a few seconds should be moved into its own thread (preferably also giving the user regular status updates on its progress).

    The first is just better practice in general; the second is simply a promise I make to the users of my app: any application I make should never stall for more than a few seconds while processing your last request.
    Last edited by Cat; 12-22-2009 at 03:30 PM.
    You ever try a pink golf ball, Wally? Why, the wind shear on a pink ball alone can take the head clean off a 90 pound midget at 300 yards.

  6. #6
    Registered User
    Join Date
    Mar 2009
    Location
    england
    Posts
    209
    Quote Originally Posted by Dragoon_42 View Post
    Das funktioniert wunderbar!
    Code:
    private void frmMain_Shown(object sender, EventArgs e)
    {
    this.TopMost = true;
    this.Focus();
    this.BringToFront();
    this.TopMost = false;
    }
    There's win32 function which you could use instead:

    Code:
    [DllImport("user32.dll")]
    public static extern IntPtr SetForegroundWindow(IntPtr hwnd);
    Code:
    SetForegroundWindow(yourForm.Handle);

  7. #7
    Slime Dragoon_42's Avatar
    Join Date
    Feb 2003
    Location
    Vancouver
    Posts
    90
    Thanks, Cat. Your method is awesome. This being my first WinForm, I generally make web apps, I haven't had to deal with threading issues in C#. I'll implement your method for the next revision.

  8. #8
    Slime Dragoon_42's Avatar
    Join Date
    Feb 2003
    Location
    Vancouver
    Posts
    90

    Resolved

    Cat,

    I just wanted to report back that your method works flawlessly. Thank you very much!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. how to Ensure my program works across platforms??
    By hanhao in forum C++ Programming
    Replies: 8
    Last Post: 07-09-2005, 03:43 AM
  2. Pressing a button works sometimes
    By johny145 in forum Windows Programming
    Replies: 14
    Last Post: 05-18-2005, 11:53 AM
  3. The Bludstayne Open Works License
    By frenchfry164 in forum A Brief History of Cprogramming.com
    Replies: 8
    Last Post: 11-26-2003, 11:05 AM
  4. Programs works one way, not another. VC++ 6.0 help.
    By Cheeze-It in forum Windows Programming
    Replies: 4
    Last Post: 12-10-2002, 10:29 PM
  5. Pls explain how this program works...
    By Unregistered in forum C Programming
    Replies: 9
    Last Post: 01-05-2002, 09:53 AM