Click here to Skip to main content
15,881,763 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Yes, I have a question. I have googled around, seen some suggestions on StackOverflow, but I just feel like there needs to be a nicer solution (plus, it needs to work on Windows 7).

I have a "Job Manager" that kicks off processes, controls how many are run at a time, their timeouts, kills them, etc, it basically steers a bunch of applications that it calls.

Anyways, I want to be able to kill all process (by process id would be fine, I manage them via id) when it is ungracefully shut down. Not errored out, but actually has the console close. People like to just close the console for some reason and now I have to account for it. I have tried this:

C#
using System;
class Test {
    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.ProcessExit += new EventHandler (OnProcessExit); 
        // Do something here
    }

    static void OnProcessExit (object sender, EventArgs e)
    {
        Console.WriteLine ("I'm out of here");
    }
}


Heck, I even have a KillAllProc app that just needs a string passed to it, just can't get it to run.
Posted
Comments
PIEBALDconsult 12-Feb-13 18:47pm    
I don't follow you. Are there 158 orphaned processes?

By "when it is ungracefully shut down" do you mean the bartender (the Job Manager)?
wizardzz 12-Feb-13 19:15pm    
Yeah, literally clicking X on the console window of the Job Manager.
Alan N 12-Feb-13 21:08pm    
Would it be possible to rewrite the Job Manager as a GUI app. You would then have more control over it's shutdown.
wizardzz 12-Feb-13 21:50pm    
I started going that route as a backup. Unfortunately, the Job Manager is often called via bat file that redirects the console output to a log. I could still make it work, but due to pressure from people running the application, have put that approach on hold.

It turns out there is some Windows API trickery for this situation.

See the response by Willy Denoyette in http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/tree/browse_frm/thread/c72efe6c358eca9e/588a7bf4cfb4832[^]

C#
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace DetectNaughtyUser {
  class Program {
    // http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/tree/browse_frm/thread/c72efe6c358eca9e/588a7bf4cfb4832

    public enum CtrlType {
      CTRL_C_EVENT = 0,
      CTRL_BREAK_EVENT = 1,
      CTRL_CLOSE_EVENT = 2,
      CTRL_LOGOFF_EVENT = 5,
      CTRL_SHUTDOWN_EVENT = 6
    }

    public delegate Boolean HandlerRoutine(CtrlType sig);

    [DllImport("kernel32.dll", EntryPoint = "SetConsoleCtrlHandler", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern Boolean SetConsoleCtrlHandler(
      HandlerRoutine handlerRoutine,
      [MarshalAs(UnmanagedType.Bool)] Boolean add);

    private static Boolean Handler(CtrlType sig) {
      Console.WriteLine("CtrlHandler {0}", sig);
      if (sig == CtrlType.CTRL_CLOSE_EVENT) {
        Console.WriteLine("Performing cleanup, please wait...");
        Thread.Sleep(2000);
      }
      return false;
    }

    static void Main() {
      SetConsoleCtrlHandler(Handler, true);
      Console.WriteLine("Click the Close button {X] or Press Enter to end...");
      Console.ReadLine();
    }
  }
}


It's advisable to make the "cleanup" quiet, as there is a warning on MSDN that console functions called from the handler may not work properly.

HandlerRoutine[^]
SetConsoleCtrlHandler[^]

Alan.
 
Share this answer
 
Comments
wizardzz 13-Feb-13 10:00am    
I'm going to try this right now.
wizardzz 13-Feb-13 10:20am    
Hi Alan, I see that in your main() example code there is no += subscription to an event. However in the sample code after the jump, I see a line:
// Install handler
_handler += new EventHandler(Handler);
However, I don't know what _handler is supposed to be. As it is, your code doesn't work without the subscription part. I'll keep looking into it, thank you.
Alan N 13-Feb-13 11:15am    
My code didn't work, rats! Over here it does and I've just checked and can confirm that it a exact copy of my test code. Did you copy and paste it into a new solution or do a modified version?

The apparent event subscription in the original link is not required as the compiler does an implicit 'new' when assigning a method to a delegate type parameter.
SetConsoleCtrlHandler(Handler, true);

is equivalent to
SetConsoleCtrlHandler(new HandlerRoutine(Handler), true);

I'm on Windows XP and MSDN says nothing about problems in later versions.
If I understand you correctly, you are trying to run some procedure after the user kills your process. Is that right?

In C++, I'd try executing the clean up procedure in the destructor of a global static object. But I don't know if that would even work, and there is no equivalent in C#.

I'm not sure that a properly design operating system should even allow that.

After all, if the user wants your process dead, he should be able to terminate it without letting it do anything else.

That said, the only way I could see to do it, would be to fire off a seperate watchdog process that monitors your main process and then does clean up if the main process is killed.

You'd have to implement some sort of interprocess communication. Maybe just a file that the main process writes a list of process id's to, and then deletes if it exits gracefully. Then if your watchdog process saw the main process was gone, it could check for the existence of the file and use the list in the file to kill all the other processes.
 
Share this answer
 
Comments
Manfred Rudolf Bihy 12-Feb-13 19:09pm    
That just about wraps it up nicely! 5+
wizardzz 12-Feb-13 19:27pm    
Thank you. I tried to 5 vote, but clicked 4, and dont seem to be able to change it to 5. =(

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900