我如何确定C#中的进程的所有者?
我正在寻找一个名为“MyApp.exe”的进程,我想确保我得到了一个特定用户拥有的进程。
我使用下面的代码来获取进程的列表:
Process[] processes = Process.GetProcessesByName("MyApp");
这给了我一个进程列表,但是在Process类中似乎没有确定谁拥有这个进程的方法? 任何想法,我怎么能做到这一点?
您可以使用WMI来获取拥有某个特定进程的用户。 要使用WMI,您需要将对System.Management.dll
的引用添加到您的项目中。
按进程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"; }
按进程名称 (仅查找第一个进程,相应调整):
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"; }
由于WMI并不总是一种快速检索信息的方法,下面是本地P / Invoke方法:
失败时返回值为null
。 为了获得在SYSTEM用户下运行的进程的名字,你需要以pipe理员身份执行这个代码。
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);
这里是非C#扬声器的VB版本:
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
不幸的是,没有原生的.Net方法来获得stream程所有者。
看看这些可能的解决scheme:
添加对您的项目的引用:
System.Management
然后将以下方法添加到您的项目中:
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; }
然后添加这个方法:
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; }
调用GetProcessTable()为您提供了所有正在运行的进程的DataTable以及它们的Id和Name,这很方便,因为它可以用作DataGridView的Datasource参数。
让我知道如果你需要更多的领域添加到表中。
System.Security.Principal.WindowsIdentity.GetCurrent().Name
这是我发现的最简单的方法:
Process[] processes = Process.GetProcessesByName("MyApp"); foreach (Process process in processes) { string username = process.StartInfo.Environment["USERNAME"]; // do some stuff }