简体   繁体   中英

How do I get the process ID of a process that is started by cmd line (which is started by me)?

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.

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());
                    }
                }
            }
         }

PS 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.

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.

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");

使用GetProcessesByName()并查找“ python.exe”或“ pythonw.exe”进程。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM