25

I'm running .exe file using this code:

Process proc = Process.Start("c:\program.exe");
proc.WaitForExit();

If I start Stopwatch before starting the process and stop it after proc.WaitForExit(); line, I can get the time that user was using that particular program.

The problem I'm facing is that some programs (and games) use launchers - some small .exe file that usually checks something and then launches another .exe file that is actually the program/game that the user wants to run. In these cases the code above doesn't work because it returns after launcher exists.

How can I track all processes that proc runs, and wait unitl all of them are terminated?

ANeves
  • 6,219
  • 3
  • 39
  • 63
xx77aBs
  • 4,678
  • 9
  • 53
  • 77
  • @NoIdeaForName: Unfortunately not :( I don't know process's name. – xx77aBs Jul 31 '13 at 10:28
  • +1 for the extension method. – JoanComasFdz Oct 17 '14 at 08:08
  • @xx77aBs you should post your solution as an answer, and not as part of the question. I'm posting it as a community-wiki, feel free to post your own "duplicate" answer and leave a comment under the community-wiki answer asking it to be deleted as it is a dup of your own. – ANeves Jul 27 '16 at 13:30

3 Answers3

33

Here is the solution that the asker found:

// using System.Management;
public static class ProcessExtensions
{
    public static IEnumerable<Process> GetChildProcesses(this Process process)
    {
        List<Process> children = new List<Process>();
        ManagementObjectSearcher mos = new ManagementObjectSearcher(String.Format("Select * From Win32_Process Where ParentProcessID={0}", process.Id));

        foreach (ManagementObject mo in mos.Get())
        {
            children.Add(Process.GetProcessById(Convert.ToInt32(mo["ProcessID"])));
        }

        return children;
    }
}

[Updated]

Slightly more modern code:

// using System.Management;
public static class ProcessExtensions
{
    public static IList<Process> GetChildProcesses(this Process process) 
        => new ManagementObjectSearcher(
                $"Select * From Win32_Process Where ParentProcessID={process.Id}")
            .Get()
            .Cast<ManagementObject>()
            .Select(mo =>
                Process.GetProcessById(Convert.ToInt32(mo["ProcessID"])))
            .ToList();
}
ANeves
  • 6,219
  • 3
  • 39
  • 63
6

Take a look at this - Find all child processes of my own .NET process / find out if a given process is a child of my own? or http://social.msdn.microsoft.com/Forums/vstudio/en-US/d60f0793-cc92-48fb-b867-dd113dabcd5c/how-to-find-the-child-processes-associated-with-a-pid. They provide ways to find child processes by a parent PID (which you have).

You can write monitor the process you create and also get its children. You could then track everything, and wait for them all to finish. I say "try" because I'm not sure you could catch very rapid changes (a process starting others and then dying before you get his children).

Community
  • 1
  • 1
Vadim
  • 2,847
  • 15
  • 18
  • Thanks, I've checked the links that you gave me and managed to create good solution using PIDs :) – xx77aBs Jul 31 '13 at 14:58
1

you can't wait for process(B) another process(A) is running, if that process(A) isn't waiting for the process(B). what you can do is track the process using Process.GetProcessesByName() if you know it's name

No Idea For Name
  • 11,411
  • 10
  • 42
  • 70
  • Thanks, but that doesn't help me. I don't know the name of the exe file that is going to be run. That's why I need to somehow get all processes that proc has started. – xx77aBs Jul 31 '13 at 10:25
  • in that case you can track the active processes before and after you ran the program... it's not a good way, but it's the only one you can use – No Idea For Name Jul 31 '13 at 10:28
  • I've thought of that, but it's not very reliable. I'll try to find a better solution, and if I don't find it, I'll maybe track just the processes whose executable file is located in the same folder as the launcher, or something like that. – xx77aBs Jul 31 '13 at 10:30