【问题标题】:How do I get the process ID of a process that is started by cmd line (which is started by me)?如何获取由 cmd 行(由我启动)启动的进程的进程 ID?
【发布时间】:2013-09-06 23:01:12
【问题描述】:

所以,我使用自己的 .NET 进程来启动命令行进程,如下所示: 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();

该过程执行得很好,我得到了它的输出/错误。当我想在它完成执行之前将其杀死时,问题就来了。由于 cmd 行在技术上启动了“PYTHON_SCRIPT”进程本身,我不知道该进程的进程 ID 是什么!因为那是我真正想要杀死的人(不是 cmd 行),所以我搞砸了。我实际上已经关闭了 cmd 行进程以查看它是否有任何效果,但它没有。

任何帮助将不胜感激。

如果不清楚,问题是:“如何终止 PYTHON_SCRIPT(或任何其他)进程?”

编辑:对不起,我不清楚...我正在使用 PYTHON_SCRIPT 作为填充符。我以这种方式启动了许多不同的进程,并非所有进程都是 python 脚本。有些是批处理文件,有些是 python 脚本,有些是 perl 脚本等。我更喜欢这里的通用解决方案。

编辑 2:情况比问题中可能出现的要复杂一些。例如,我正在使用 scons 来构建一些代码。使用“cmd /C scons”很容易。然而,启动 scons 进程要困难得多,因为它是一个 python 脚本。我传入了一个不同的工作目录,所以“python.exe scons.py scons”根本不起作用,“scons.bat scons”也不会,因为 scons.bat 需要找到 scons.py,而 scons.py 是不在我的工作目录中。

【问题讨论】:

  • 有类似的问题。我使用 TASKKILL 通过 PID 杀死进程。我的问题是如何找到由 CMD 启动的进程的 PID。有什么想法吗?

标签: c# .net process cmd


【解决方案1】:

经过一番坚持和google foo,终于找到了答案!这是stackoverflow答案的链接:

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

以下是为我指明方向的网站:

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

看起来他在这方面做了很多研究。绝对要给他所有的功劳。希望此页面对尚未找到它的其他人有所帮助!

我在为 WinAPI 方法找出一些 D11Import 内容时遇到了一些麻烦,所以这是我使用的代码以防其他人挂断:



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

附:如果从代码中看不出来,我将存储同时运行的多个进程的列表,然后一个一个地循环遍历它们以将它们全部杀死。

【讨论】:

    【解决方案2】:

    如果您可以运行 CMD 进程,并且您知道您的进程 PID,为什么不简单地使用 TASKKILL /PID 1234 ?

    我在这里没有得到的是你从哪里获取 PID。

    【讨论】:

      【解决方案3】:

      这个link很有用

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

      【讨论】:

      • 我看过这个页面,它对我想要完成的事情没有用。不过还是谢谢。
      【解决方案4】:

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

      【讨论】:

      • 这是一个黑客。我可以运行其他 python 进程,我不想杀死它们。另外,请参阅我的编辑。我不只是在运行 python 进程。
      • 好吧,如果你不知道它是哪个进程,你就不能杀死它。进程名称是您拥有的唯一信息。如果您不知道,则需要从批处理文件中找到它。 Windows 批处理文件不“拥有”它们启动的 Windows 进程。
      • 我想要的正是 Ctrl-C 在 cmd 行上所做的。 cmd 行是否拥有它产生的所有进程?
      • 至少不是 Windows 进程。如果您已经尝试杀死 cmd 并且它失败了,那么这些进程不属于它。 Windows 不是一个非常友好的脚本环境...
      • 嗯,我想知道你为什么不直接调用应用程序,而不是通过'cmd /c'?
      猜你喜欢
      • 2013-02-07
      • 1970-01-01
      • 2013-08-02
      • 2011-07-19
      • 2020-05-29
      • 2018-09-30
      • 1970-01-01
      • 2017-08-07
      • 1970-01-01
      相关资源
      最近更新 更多