2009-04-22 12 views
31

Szukam procesu o nazwie "MyApp.exe" i chcę mieć pewność, że otrzymam proces, który jest własnością określonego użytkownika.Jak określić właściciela procesu w języku C#?

używam następujący kod, aby otrzymać listę procesów:

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

To daje mi listę procesów, ale nie wydaje się być sposób, w klasie Process ustalić, kto jest właścicielem, że proces? Wszelkie przemyślenia na temat tego, w jaki sposób mogę to zrobić?

Odpowiedz

53

Możesz użyć usługi WMI, aby użytkownik był właścicielem określonego procesu. Aby korzystać z WMI, musisz dodać do projektu odniesienie do System.Management.dll.

Poprzez proces ID:

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"; 
} 

Według nazwy procesu (znajdzie pierwszy proces tylko, dostosuj odpowiednio):

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"; 
} 
+0

W swojej drugiej metodzie, twój zagnieżdżone jeśli zawiera ciąg, właścicielu. Sądzę, że zamiast tego zamierzałeś zwrócić ten ciąg. – crftr

+0

Dzięki Mike, naprawiłem to. –

+1

Słowo ostrzeżenia: takie kwerendy usługi WMI są dostępne tylko z odpowiednimi uprawnieniami. Konta nieadministracyjne zwykle nie mają dostępu do dostawców WMI, w tym Win32_Process. http://msdn.microsoft.com/en-us/library/windows/desktop/aa394603%28v=vs.85%29.aspx – Korey

7

Oto wersja VB dla non C# głośników:

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 
+8

Pytanie nie pyta o VB. Jeśli masz ochotę, spróbuj postawić nowe pytanie ("jak to zrobić w VB") i sam na nie odpowiesz - "nie C# głośniki" będą szukać tagów innych niż VB. – Superbest

+4

Właściwie jestem deweloperem C#, który musi to napisać w VB.NET. Szukałem C#, więc mogłem szybko to zrozumieć. Posiadanie kodu VB tutaj również zaoszczędziło mi dużo czasu. Dziękuję Ci. –

0

Add odniesienie do twojego projektu:

System.Management 

Następnie dodaj następującą metodę do projektu:

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; 
    } 

Następnie dodać tę metodę:

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; 
    } 

Wywołanie GetProcessTable() daje DataTable wszystkich uruchomionych procesów wraz z ich Id i nazwa, która jest przydatna, ponieważ może być używana jako parametr DataGridView w Datasource.

Daj mi znać, jeśli potrzebujesz więcej pól dodających do tabeli.

12

Od WMI nie zawsze jest szybkim sposobem na zdobycie informacji, tutaj jest rodzimy P/Invoke sposób to zrobić:

Wartością zwracaną jest null gdy nieskuteczne. Aby uzyskać nazwy procesów działających pod użytkownikiem SYSTEM, musisz wykonać ten kod jako administrator.

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); 
+0

Zgadzam się, dziękuję za tę alternatywę, niezdrowe jest korzystanie z usługi WMI poza wewnętrznymi aplikacjami do inwentaryzacji firmy (jest powolna, a na całym świecie często jest uszkodzona/zepsuta). – BTJ

0
System.Security.Principal.WindowsIdentity.GetCurrent().Name 
+0

Pomocne byłoby wyjaśnienie tego. – jHilscher

+0

Niestety, to nie jest odpowiedź na pytanie tego wątku. To po prostu pokazuje identyfikator użytkownika procesu (konto systemu Windows) w aplikacji .NET w czasie wykonywania. –

+0

Jest to przydatne w przypadku zadań pokrewnych, takich jak "pobierz bieżące procesy użytkownika", w ten sposób wylądowałem tutaj – pomeroy

-1

Jest to najprostszy sposób znalazłem to zrobić:

Process[] processes = Process.GetProcessesByName("MyApp"); 
foreach (Process process in processes) 
{ 
    string username = process.StartInfo.Environment["USERNAME"]; 

    // do some stuff 
} 
+3

Zwraca nazwę użytkownika bieżącego procesu. Właściwość Środowisko nie może pobrać zmiennych środowiskowych z innego procesu. – palota

+0

Jak uzyskać nazwę użytkownika innego procesu? –