1

So, I use my own .NET Process to start up a command line process like so: ProcessStartInfo startInfo = new ProcessStartInfo();

        Process p = new Process();
        startInfo.CreateNoWindow = true;
        startInfo.RedirectStandardOutput = redirectOutput;
        startInfo.RedirectStandardError = redirectError;
        //startInfo.WindowStyle = ProcessWindowStyle.Hidden; //is this necessary for cmd line commands?
        startInfo.RedirectStandardInput = false;
        startInfo.UseShellExecute = false;
        String arguments = "/C PYTHON_SCRIPT";
        startInfo.Arguments = arguments;
        String pathToProcess = "cmd.exe";
        startInfo.FileName = pathToProcess;
        startInfo.WorkingDirectory = workingDirectory;
        p.StartInfo = startInfo;
        p.Start();

The process executes just fine, and I get its output/errors. The problem comes when I want to kill it off before it is finished executing. Since cmd line technically started off the "PYTHON_SCRIPT" process itself, I don't know what the Process ID of that process is! Since that's the one I really want to kill off (not cmd line), I'm screwed. I have in fact killed off the cmd line process to see if it has any effect, and it doesn't.

Any help would be appreciated.

In case it wasn't clear, the question is: "How do I kill off the PYTHON_SCRIPT (or any other) process?"

EDIT: I'm sorry I wasn't clear... I'm using PYTHON_SCRIPT as a filler. I am starting many different processes this way, not all of which are python scripts. Some are batch files, some are python scripts, some are perl scripts, etc. I would much prefer a generalized solution here.

EDIT 2: The situation is a little more complex than it might appear from the question. For instance, I am using scons to build some code. Using "cmd /C scons" is easy. However, starting the scons process is much more difficult, because it is a python script. I pass in a different working directory, so "python.exe scons.py scons" won't work at all, and neither will "scons.bat scons" since scons.bat needs to find scons.py, and scons.py isn't in my working directory.

Darkhydro
  • 1,992
  • 4
  • 24
  • 43
  • Have a similar problem. I use TASKKILL to kill processes by PID. My problem is how to find the PID of a process started by CMD. Any idea? – MrE Nov 26 '15 at 23:19

4 Answers4

2

Finally found the answer through much perseverance and google foo! Here is a link to the stackoverflow answer:

https://stackoverflow.com/a/15281070/476298

And here is the website that pointed me in that direction:

http://stanislavs.org/stopping-command-line-applications-programatically-with-ctrl-c-events-from-net/

Looks like he did a whole bunch of research on this. Definitely want to give him all the credit. Hope this page helps others who haven't found it yet!

I had a little trouble figuring out some of the D11Import stuff for the WinAPI methods, so here's the code I used in case anyone else gets hung up:



        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool AttachConsole(uint dwProcessId);

        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
        static extern bool FreeConsole();

        // Delegate type to be used as the Handler Routine for SCCH
        delegate Boolean ConsoleCtrlDelegate(CtrlTypes CtrlType);

        [DllImport("kernel32.dll")]
        static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);

        // Enumerated type for the control messages sent to the handler routine
        enum CtrlTypes : uint
        {
            CTRL_C_EVENT = 0,
            CTRL_BREAK_EVENT,
            CTRL_CLOSE_EVENT,
            CTRL_LOGOFF_EVENT = 5,
            CTRL_SHUTDOWN_EVENT
        }

        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId);

        /// 
        /// Immediately halts all running processes under this ProcessManager's control.
        /// 
        public static void HaltAllProcesses()
        {
            for (int i = 0; i < runningProcesses.Count; i++)
            {
                Process p = runningProcesses[i];
                uint pid = (uint)p.Id;
                //This does not require the console window to be visible.
                if (AttachConsole(pid))
                {
                    //Disable Ctrl-C handling for our program
                    SetConsoleCtrlHandler(null, true);
                    GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);

                    //Must wait here. If we don't and re-enable Ctrl-C
                    //handling below too fast, we might terminate ourselves.
                    p.WaitForExit(2000);

                    FreeConsole();

                    //Re-enable Ctrl-C handling or any subsequently started
                    //programs will inherit the disabled state.
                    SetConsoleCtrlHandler(null, false);
                }

                if (!p.HasExited)
                { //for console-driven processes, this won't even do anything... (it'll kill the cmd line, but not the actual process)
                    try
                    {
                        p.Kill();
                    }
                    catch (InvalidOperationException e) 
                    {
                        controller.PrintImportantError("Process " + p.Id + " failed to exit! Error: " + e.ToString());
                    }
                }
            }
         }

P.S. If it's not obvious from the code, I'm storing a list of multiple processes that are running simultaneously, and just looping through them one by one to kill them all.

Community
  • 1
  • 1
Darkhydro
  • 1,992
  • 4
  • 24
  • 43
1

if you can run a CMD process, and you know your processes PIDs, why don't you simply use TASKKILL /PID 1234 ?

What I didn't get here is where you're getting the PID from.

MrE
  • 19,584
  • 12
  • 87
  • 105
0

This link is very useful

                     // Get the current process.
                Process currentProcess = Process.GetCurrentProcess();


                // Get all instances of Notepad running on the local 
                // computer.
                Process [] localByName = Process.GetProcessesByName("notepad");


                // Get all instances of Notepad running on the specifiec 
                // computer. 
                // 1. Using the computer alias (do not precede with "\\").
                Process [] remoteByName = Process.GetProcessesByName("notepad", "myComputer");

                // 2. Using an IP address to specify the machineName parameter. 
                Process [] ipByName = Process.GetProcessesByName("notepad", "169.0.0.0");


                // Get all processes running on the local computer.
                Process [] localAll = Process.GetProcesses();


                // Get all processes running on the remote computer.
                Process [] remoteAll = Process.GetProcesses("myComputer");


                // Get a process on the local computer, using the process id.
                Process localById = Process.GetProcessById(1234);


                // Get a process on a remote computer, using the process id.
                Process remoteById = Process.GetProcessById(2345,"myComputer");
Dan Hunex
  • 5,172
  • 2
  • 27
  • 38
0

Use GetProcessesByName() and look for the "python.exe" or "pythonw.exe" process.

Jouni Aro
  • 2,099
  • 14
  • 30
  • 2
    This is a hack. I could have other python processes running, and I don't want to kill them off. Also, see my edit. I'm not just running python processes. – Darkhydro Sep 06 '13 at 23:47
  • Well, you cannot kill a process if you don't know which process it is. The process name is the only info you have. If you don't know that, you will need to find it out from the batch file. Windows batch files do not "own" the Windows processes they start. – Jouni Aro Sep 06 '13 at 23:53
  • what I want is exactly what Ctrl-C does on cmd line. Does the cmd line own all processes it spawns? – Darkhydro Sep 07 '13 at 00:10
  • Not Windows processes at least. And if you have already tried killing cmd and it failed, those processes were not owned by it. Windows is not a very friendly scripting environment... – Jouni Aro Sep 07 '13 at 00:17
  • Also avoid using 'start' in your batch, since it will detach the process explicitly. – Jouni Aro Sep 07 '13 at 00:21
  • 1
    Hmm, I was wondering why don't you call the apps directly, instead of via 'cmd /c'? – Jouni Aro Sep 07 '13 at 00:26
  • Well, it doesn't matter too much I would think, since I would be starting up BAT files which would kick off separate process (python scripts for example). I could do everything else by calling them directly, but bat files make it difficult – Darkhydro Sep 07 '13 at 00:31