2009-02-13 8 views
3

Je cherche un moyen facile de trouver l'arbre de processus (comme indiqué par des outils comme Process Explorer), en C# ou autre langage .Net. Il serait également utile de trouver les arguments de la ligne de commande d'un autre processus (le StartInfo sur System.Diagnostics.Process semble invalide pour un processus autre que le processus en cours).arbre de processus

Je pense que ces choses ne peuvent être faites qu'en invoquant l'API win32, mais je serais heureux d'avoir tort.

Merci!

Robert

Répondre

4

Si vous ne voulez pas P/Invoke, vous pouvez saisir les parents ids avec un compteur de performance:

foreach (var p in Process.GetProcesses()) 
{ 
    var performanceCounter = new PerformanceCounter("Process", "Creating Process ID", p.ProcessName); 
    var parent = GetProcessIdIfStillRunning((int)performanceCounter.RawValue); 
    Console.WriteLine(" Process {0}(pid {1} was started by Process {2}(Pid {3})", 
       p.ProcessName, p.Id, parent.ProcessName, parent.ProcessId); 
} 

//Below is helper stuff to deal with exceptions from 
//looking-up no-longer existing parent processes: 

struct MyProcInfo 
{ 
    public int ProcessId; 
    public string ProcessName; 
} 

static MyProcInfo GetProcessIdIfStillRunning(int pid) 
{ 
    try 
    { 
     var p = Process.GetProcessById(pid); 
     return new MyProcInfo() { ProcessId = p.Id, ProcessName = p.ProcessName }; 
    } 
    catch (ArgumentException) 
    { 
     return new MyProcInfo() { ProcessId = -1, ProcessName = "No-longer existant process" }; 
    } 
} 

maintenant il suffit de mettre dans quelle structure d'arbre voulez et vous fait.

0

Je suis sûr que vous aurez besoin d'aller avec le WinAPI pour cela. Voir this code snippet à titre d'exemple. Ce sera un algorithme assez standard pour construire un arbre à partir d'une liste d'objets et de leurs objets parents.

2

Vous pouvez également essayer de regarder dans WMI (classe Win32_Process par exemple).

Voici un exemple pour obtenir la ligne de commande d'un processus par son ID de processus:

   using (var mos = new ManagementObjectSearcher(
        "SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + pid)) 
       { 
        foreach (var obj in mos.Get()) 
        { 
         object data = obj.Properties["CommandLine"].Value; 
         if (data != null) 
         { 
          Console.WriteLine("{0}: commandline = {1}", pid, data.ToString()); 
         } 
        } 
       } 
      } 
     } 

J'arraché ce billet depuis un code que j'ai récemment écrit. Pour vos besoins, vous pouvez utiliser d'autres techniques (comme obtenir plusieurs propriétés et/ou processus à la fois). Mais vous avez l'idée.

EDIT: L'ID du processus parent, dont vous aurez besoin pour construire l'arborescence, est la propriété "ParentProcessId", par exemple.

Je suppose, cependant, en utilisant l'API Win32 est plus rapide. Notez que toutes les fonctionnalités dont vous avez besoin ne sont pas disponibles correctement. Pour certaines choses, vous auriez recours à la fonction NtQueryProcessInformation() (un peu) non prise en charge ou à d'autres de NTDLL.

2

Je ne vois pas pourquoi vous ne voulez pas p/invoquer. Si vous regardez System.Diagnostics dans Reflector, vous verrez qu'il utilise p/invoke en interne. Quoi qu'il en soit, la classe Process et non permet de récupérer un PID parent d'un processus. Au lieu de cela:

La définition struct:

[StructLayout(LayoutKind.Sequential)] 
struct PROCESS_BASIC_INFORMATION 
{ 
    public int ExitStatus; 
    public int PebBaseAddress; 
    public int AffinityMask; 
    public int BasePriority; 
    public int UniqueProcessId; 
    public int InheritedFromUniqueProcessId; 
} 

La fonction d'importation (simplifiée):

[DllImport("ntdll.dll")] 
static extern int NtQueryInformationProcess(
    IntPtr ProcessHandle, 
    int ProcessInformationClass, 
    out PROCESS_BASIC_INFORMATION ProcessInformation, 
    int ProcessInformationLength, 
    out int ReturnLength 
    ); 

Le code:

Process p = Process.GetProcessById(1234); 
PROCESS_BASIC_INFORMATION pbi; 
int size; 

NtQueryInformationProcess(p.Handle, 0, out pbi, Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)), out size); 
// pbi.InheritedFromUniqueProcessId now contains the process' parent PID 

Vous devez insérer ces usings à en haut de votre fichier:

using System.Runtime.InteropServices; 
using System.Diagnostics; 

Si vous voulez énumérer des processus, il serait préférable d'utiliser NtQuerySystemInformation - bien que ce code soit un peu long à publier ici.