如何在C#中确定进程的所有者?

ade*_*825 41 .net c# process

我正在寻找名为"MyApp.exe"的进程,我想确保获得特定用户拥有的进程.

我使用以下代码获取进程列表:

Process[] processes = Process.GetProcessesByName("MyApp");
Run Code Online (Sandbox Code Playgroud)

这给了我一个进程列表,但是在Process类中似乎没有办法确定谁拥有该进程?有关如何做到这一点的任何想法?

Dir*_*mar 63

您可以使用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";
}
Run Code Online (Sandbox Code Playgroud)

按进程名称(仅查找第一个进程,相应地调整):

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";
}
Run Code Online (Sandbox Code Playgroud)

  • 提示:此类WMI查询仅在具有适当特权的情况下可用。非管理员帐户通常无权访问WMI提供程序,包括Win32_Process。http://msdn.microsoft.com/zh-CN/library/windows/desktop/aa394603%28v=vs.85%29.aspx (2认同)
  • WMI 很慢。特别是必须查找系统上的每个进程,然后对由于安全原因而被拒绝的进程进行异常处理。如果您想按用户过滤进程,您可以尝试 pinvoking WTSQuerySessionInformationW()。 (2认同)

byt*_*e77 25

由于WMI并不总是快速检索信息的方式,因此这是本机P/Invoke的方式:

返回值是null不成功的.要获取在SYSTEM用户下运行的进程的名称,您需要以管理员身份执行此代码.

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);
Run Code Online (Sandbox Code Playgroud)

  • 注意:“WindowsIdentity”是一次性的,因此当您新建“WindowsIdentity”时,您需要使用 using 语句。像这样:`using var wi = new WindowsIdentity(processHandle);` (4认同)
  • 我同意,感谢这个替代方案,在内部业务库存应用程序之外使用 WMI 是不健康的(它很慢,并且在整个世界中经常损坏/损坏)。 (2认同)

小智 8

这是非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
Run Code Online (Sandbox Code Playgroud)

  • 问题不要求VB.如果您感到渴望,请尝试提出一个新问题("如何在VB中执行此操作")并自行回答 - "非C#扬声器"将查找VB以外的标签. (8认同)
  • 实际上,我是一个C#dev,必须在VB.NET中编写它.我搜索了C#,所以我可以很快理解它.在这里使用VB代码也节省了我很多时间.谢谢. (6认同)