web-dev-qa-db-fra.com

Comment déterminer le propriétaire d'un processus en C #?

Je suis à la recherche d'un processus portant le nom "MyApp.exe" et je souhaite m'assurer d'obtenir le processus appartenant à un utilisateur particulier. 

J'utilise le code suivant pour obtenir une liste des processus:

Process[] processes = Process.GetProcessesByName("MyApp");

Cela me donne une liste de processus, mais il ne semble pas y avoir de moyen dans la classe Process de déterminer à qui appartient ce processus. Des idées sur comment je peux faire ça?

38
adeel825

Vous pouvez utiliser WMI pour que l'utilisateur possède un certain processus. Pour utiliser WMI, vous devez ajouter une référence au System.Management.dll à votre projet.

Par identifiant de processus:

public string GetProcessOwner(int processId)
{
    string query = "Select * From Win32_Process Where ProcessID = " + processId;
    ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
    ManagementObjectCollection processList = searcher.Get();

    foreach (ManagementObject obj in processList)
    {
        string[] argList = new string[] { string.Empty, string.Empty };
        int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList));
        if (returnVal == 0)
        {
            // return DOMAIN\user
            return argList[1] + "\\" + argList[0];
        }
    }

    return "NO OWNER";
}

Par nom de processus (recherche uniquement le premier processus, ajustez en conséquence):

public string GetProcessOwner(string processName)
{
    string query = "Select * from Win32_Process Where Name = \"" + processName + "\"";
    ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
    ManagementObjectCollection processList = searcher.Get();

    foreach (ManagementObject obj in processList)
    {
        string[] argList = new string[] { string.Empty, string.Empty };
        int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList));
        if (returnVal == 0)
        {
            // return DOMAIN\user
            string owner = argList[1] + "\\" + argList[0];
            return owner;       
        }
    }

    return "NO OWNER";
}
58
Dirk Vollmar

Comme WMI n’est pas toujours un moyen rapide de récupérer des informations, voici le moyen natif de le faire/invoquer:

La valeur de retour est null en cas d'échec. Pour obtenir les noms des processus en cours d'exécution sous l'utilisateur SYSTEM, vous devez exécuter ce code en tant qu'administrateur.

private static string GetProcessUser(Process process)
{
    IntPtr processHandle = IntPtr.Zero;
    try
    {
        OpenProcessToken(process.Handle, 8, out processHandle);
        WindowsIdentity wi = new WindowsIdentity(processHandle);
        string user = wi.Name;
        return user.Contains(@"\") ? user.Substring(user.IndexOf(@"\") + 1) : user;
    }
    catch
    {
        return null;
    }
    finally
    {
        if (processHandle != IntPtr.Zero)
        {
            CloseHandle(processHandle);
        }
    }
}

[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
20
bytecode77

Voici la version VB des haut-parleurs autres que C #:

Function GetProcessOwner(ProcessName As String) As String
    Dim query = "Select * from Win32_Process Where Name = """ + ProcessName + """"
    Dim searcher = New ManagementObjectSearcher(query)
    Dim processList = searcher.Get()

    For Each obj As ManagementObject In processList
      Dim argList As String() = {String.Empty, String.Empty}
      Dim returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList))
      If returnVal = 0 Then
        ' return DOMAIN\user
        Dim owner = argList(1) + "\\" + argList(0)
        Return owner
      End If
    Next

    Return "NO OWNER"
  End Function

  Function GetProcessOwner(processId As Integer) As String
    Dim query = "Select * From Win32_Process Where ProcessID = " & processId
    Dim searcher = New ManagementObjectSearcher(query)
    Dim processList = searcher.Get()

    For Each obj As ManagementObject In processList
      Dim argList As String() = {String.Empty, String.Empty}
      Dim returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList))
      If returnVal = 0 Then
        ' return DOMAIN\user
        Return argList(1) + "\\" + argList(0)
      End If
    Next

    Return "NO OWNER"
  End Function
7
Stefano

Malheureusement, il n’existe aucun moyen .Net natif d’obtenir le propriétaire du processus.

Jetez un coup d'oeil à ceux-ci pour une solution potentielle:

4
Damovisa

Ajoutez une référence à votre projet:

System.Management

Ajoutez ensuite la méthode suivante à votre projet:

    public string GetProcessOwner(int processId)
    {
        string MethodResult = null;
        try
        {
            StringBuilder sb = new StringBuilder();

            sb.Append(" SELECT ");
            sb.Append("     * ");
            sb.Append(" FROM ");
            sb.Append("     WIN32_PROCESS");
            sb.Append(" WHERE ");
            sb.Append("     ProcessId = " + processId);

            string Query = sb.ToString();

            ManagementObjectCollection Processes = new ManagementObjectSearcher(Query).Get();

            foreach (ManagementObject Process in Processes)
            {
                string[] Args = new string[] { "", "" };

                int ReturnCode = Convert.ToInt32(Process.InvokeMethod("GetOwner", Args));

                switch(ReturnCode)
                {
                    case 0:
                        MethodResult = Args[1] + "\\" + Args[0];
                        break;

                    default:
                        MethodResult = "None";
                        break;

                }

            }

        }
        catch //(Exception ex)
        {
            //ex.HandleException();
        }
        return MethodResult;
    }

Puis ajoutez cette méthode:

    public DataTable GetProcessTable()
    {
        DataTable MethodResult = null;
        try
        {
            List<Process> Processes = Process.GetProcesses().ToList<Process>();

            DataTable dt = new DataTable();
            dt.Columns.Add("Name", typeof(string));
            dt.Columns["Name"].ReadOnly = true;

            dt.Columns.Add("Id", typeof(string));
            dt.Columns["Id"].ReadOnly = true;

            dt.Columns.Add("Owner", typeof(string));
            dt.Columns["Owner"].ReadOnly = true;

            foreach (Process p in Processes)
            {
                DataRow r = dt.NewRow();

                bool Match = false;

                r["Id"] = p.Id.ToString();
                r["Name"] = p.ProcessName;
                r["Owner"] = GetProcessOwner(p.Id);

                dt.Rows.Add(r);

            }

            MethodResult = dt;

        }
        catch //(Exception ex)
        {
            //ex.HandleException();
        }
        return MethodResult;
    }

L'appel de GetProcessTable () vous donne un DataTable de tous les processus en cours d'exécution avec leur ID et leur nom, ce qui est pratique car il peut être utilisé comme paramètre Datasource de DataGridView.

Faites-moi savoir si vous avez besoin d'ajouter d'autres champs à la table.

0
Knickerless-Noggins
System.Security.Principal.WindowsIdentity.GetCurrent().Name
0
Ben Lin