Windows如何获取已在运行的进程的进程组?

时间:2015-05-14 23:25:16

标签: c# c++ wpf windows

我有一个WPF应用程序,它使用Process.Start(ProcessStartInfo info)启动一个新进程。

如何获取流程的组进程ID,以便我可以使用GenerateConsoleCtrlEvent发送 Ctrl + C 信号? https://msdn.microsoft.com/en-us/library/windows/desktop/ms683155%28v=vs.85%29.aspx

但是,我似乎无法在创建的新进程中找到控制台窗口的组进程ID。它具有cur窗口用户的会话ID和进程ID。

编辑:我终于得到了我的计划,但我仍然没有找到真正问题的真实答案。

我能够通过使用GenerateConsoleCtrlEvent向控制台中的所有进程广播来将ctrl c发送到进程。

但是,我无法弄清楚如何获取正在运行的进程的进程组。如果创建新进程,您当然可以保存进程组(它应该是使用create new process group的creation标志调用createprocess的进程的ID)。但是,如果您不是自己创建一个新组并且只是想知道一个进程所属的组,我找不到与实际获取此ID相关的任何内容。当然,这些信息存储在某处,可以检索!

我可以使用此函数获取Windows NT版本中的父ID: Fetching parent process Id from child process

但是,这并不能保证同一个流程组。我开始得出结论,Windows没有从进程ID函数获取进程组ID。

Linux有一个简单的getpgrp函数,它确实需要我。我不明白为什么Windows有一个进程组,如果我无法获得它的价值

2 个答案:

答案 0 :(得分:1)

GenerateConsoleCtrlEvent州的文件(强调我的):

  

接收信号的进程组的标识符。在对CreateProcess函数的调用中指定CREATE_NEW_PROCESS_GROUP标志时,将创建进程组。 新流程的流程标识符也是新流程组的流程组标识符。

因此,如果您的进程位于组中,则WPF应用程序的PID应为组ID。

答案 1 :(得分:0)

我没有使用GenerateConsoleCtrlEvent,而是找到了将CTRL-C发送到进程的方法。仅供参考,在这种情况下,我并不需要找到组进程ID。

using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

public class ConsoleAppManager
{
    private readonly string appName;
    private readonly Process process = new Process();
    private readonly object theLock = new object();
    private SynchronizationContext context;
    private string pendingWriteData;

    public ConsoleAppManager(string appName)
    {
        this.appName = appName;

        this.process.StartInfo.FileName = this.appName;
        this.process.StartInfo.RedirectStandardError = true;
        this.process.StartInfo.StandardErrorEncoding = Encoding.UTF8;

        this.process.StartInfo.RedirectStandardInput = true;
        this.process.StartInfo.RedirectStandardOutput = true;
        this.process.EnableRaisingEvents = true;
        this.process.StartInfo.CreateNoWindow = true;

        this.process.StartInfo.UseShellExecute = false;

        this.process.StartInfo.StandardOutputEncoding = Encoding.UTF8;

        this.process.Exited += this.ProcessOnExited;
    }

    public event EventHandler<string> ErrorTextReceived;
    public event EventHandler ProcessExited;
    public event EventHandler<string> StandartTextReceived;

    public int ExitCode
    {
        get { return this.process.ExitCode; }
    }

    public bool Running
    {
        get; private set;
    }

    public void ExecuteAsync(params string[] args)
    {
        if (this.Running)
        {
            throw new InvalidOperationException(
                "Process is still Running. Please wait for the process to complete.");
        }

        string arguments = string.Join(" ", args);

        this.process.StartInfo.Arguments = arguments;

        this.context = SynchronizationContext.Current;

        this.process.Start();
        this.Running = true;

        new Task(this.ReadOutputAsync).Start();
        new Task(this.WriteInputTask).Start();
        new Task(this.ReadOutputErrorAsync).Start();
    }

    public void Write(string data)
    {
        if (data == null)
        {
            return;
        }

        lock (this.theLock)
        {
            this.pendingWriteData = data;
        }
    }

    public void WriteLine(string data)
    {
        this.Write(data + Environment.NewLine);
    }

    protected virtual void OnErrorTextReceived(string e)
    {
        EventHandler<string> handler = this.ErrorTextReceived;

        if (handler != null)
        {
            if (this.context != null)
            {
                this.context.Post(delegate { handler(this, e); }, null);
            }
            else
            {
                handler(this, e);
            }
        }
    }

    protected virtual void OnProcessExited()
    {
        EventHandler handler = this.ProcessExited;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }

    protected virtual void OnStandartTextReceived(string e)
    {
        EventHandler<string> handler = this.StandartTextReceived;

        if (handler != null)
        {
            if (this.context != null)
            {
                this.context.Post(delegate { handler(this, e); }, null);
            }
            else
            {
                handler(this, e);
            }
        }
    }

    private void ProcessOnExited(object sender, EventArgs eventArgs)
    {
        this.OnProcessExited();
    }

    private async void ReadOutputAsync()
    {
        var standart = new StringBuilder();
        var buff = new char[1024];
        int length;

        while (this.process.HasExited == false)
        {
            standart.Clear();

            length = await this.process.StandardOutput.ReadAsync(buff, 0, buff.Length);
            standart.Append(buff.SubArray(0, length));
            this.OnStandartTextReceived(standart.ToString());
            Thread.Sleep(1);
        }

        this.Running = false;
    }

    private async void ReadOutputErrorAsync()
    {
        var sb = new StringBuilder();

        do
        {
            sb.Clear();
            var buff = new char[1024];
            int length = await this.process.StandardError.ReadAsync(buff, 0, buff.Length);
            sb.Append(buff.SubArray(0, length));
            this.OnErrorTextReceived(sb.ToString());
            Thread.Sleep(1);
        }
        while (this.process.HasExited == false);
    }

    private async void WriteInputTask()
    {
        while (this.process.HasExited == false)
        {
            Thread.Sleep(1);

            if (this.pendingWriteData != null)
            {
                await this.process.StandardInput.WriteLineAsync(this.pendingWriteData);
                await this.process.StandardInput.FlushAsync();

                lock (this.theLock)
                {
                    this.pendingWriteData = null;
                }
            }
        }
    }
}

然后,在实际运行该过程并在我的主应用程序中发送CTRL-C:

            DateTime maxStartDateTime = //... some date time;
            DateTime maxEndDateTime = //... some later date time
            var duration = maxEndDateTime.Subtract(maxStartDateTime);
            ConsoleAppManager appManager = new ConsoleAppManager("myapp.exe");
            string[] args = new string[] { "args here" };
            appManager.ExecuteAsync(args);
            await Task.Delay(Convert.ToInt32(duration.TotalSeconds * 1000) + 20000);

            if (appManager.Running)
            {
                // If stilll running, send CTRL-C
                appManager.Write("\x3");
            }

有关详细信息,请参阅Redirecting standard input of console application