C# 获取系统进程的用户名

下面是关于如何用C#获取系统进程的用户名的完整攻略。

1. 获取系统进程列表

首先,我们需要获取当前系统中的进程列表。可以使用Process类的GetProcesses()方法来完成这个任务。该方法会返回一个Process类型的数组,其中每个元素表示一个系统进程。

下面是一个简单的示例代码:

Process[] processlist = Process.GetProcesses();
foreach (Process process in processlist)
{
    Console.WriteLine("Process: {0}  ID: {1}", process.ProcessName, process.Id);
}

上述代码将会打印出系统中当前运行的每个进程的名称和ID。

2. 获取进程的安全描述符

然后,我们需要获取每个进程的安全描述符,以便进一步获得进程所属的用户或组。

首先,我们需要声明必要的API函数和结构体。这些函数和结构体在System.DiagnosticsSystem.Security.Principal命名空间下都有定义。

using System.Diagnostics;
using System.Security.Principal;
using System.Runtime.InteropServices;

public static class ProcessUtils
{
    // 获取进程的安全描述符
    [DllImport("kernel32.dll")]
    public static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);

    // 获得普通用户的SID
    [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
    public static extern bool ConvertSidToStringSid(IntPtr pSid, out string strSid);

    // 根据指定的用户名和计算机名获取用户的SID
    public static SecurityIdentifier GetSid(string userName, string computerName)
    {
        NTAccount account = new NTAccount(computerName, userName);
        return (SecurityIdentifier)account.Translate(typeof(SecurityIdentifier));
    }
}

接下来,我们可以使用OpenProcessToken函数通过进程句柄获取进程的安全描述符。此函数的输入参数DesiredAccess将指定所需的访问级别。在本例中,我们需要读取进程的安全描述符,因此我们将使用TOKEN_QUERY。目前需要使用以下常量:

const uint TOKEN_QUERY = 0x0008;
const int ERROR_NO_TOKEN = 1008;
const int ERROR_INSUFFICIENT_BUFFER = 122;

下面是示例代码:

// 获得进程的安全描述符
IntPtr tokenHandle;
if (OpenProcessToken(process.Handle, TOKEN_QUERY, out tokenHandle))
{
    try
    {
        // 获取安全描述符的长度
        int tokenInfLength = 0;
        if (!GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenUser, IntPtr.Zero, 0, out tokenInfLength) && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
        {
            IntPtr tokenInformation = Marshal.AllocHGlobal(tokenInfLength);
            try
            {
                // 获取安全描述符
                bool success = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenUser, tokenInformation, tokenInfLength, out tokenInfLength);
                if (success)
                {
                    // 获取安全描述符中的用户SID
                    TOKEN_USER tokenUser = (TOKEN_USER)Marshal.PtrToStructure(tokenInformation, typeof(TOKEN_USER));
                    string sidString;
                    if (ConvertSidToStringSid(tokenUser.User.Sid, out sidString))
                    {
                        SecurityIdentifier sid = new SecurityIdentifier(sidString);
                        Console.WriteLine("Process {0} belongs to user {1}", process.ProcessName, sid.Translate(typeof(NTAccount)).Value);
                    }
                    else
                    {
                        Console.WriteLine("Error converting SID to string: {0}", Marshal.GetLastWin32Error());
                    }
                }
                else
                {
                    Console.WriteLine("Error getting token information: {0}", Marshal.GetLastWin32Error());
                }
            }
            finally
            {
                Marshal.FreeHGlobal(tokenInformation);
            }
        }
        else
        {
            Console.WriteLine("Error getting token information: {0}", Marshal.GetLastWin32Error());
        }
    }
    finally
    {
        CloseHandle(tokenHandle);
    }
}
else
{
    Console.WriteLine("Error opening process token: {0}", Marshal.GetLastWin32Error());
}

上面这段代码将会获取进程的安全描述符,并将其转换为可读的SecurityIdentifier,然后将其转换为用户帐户。

3. 示例代码

最后,让我们来看一下两个具体的样例代码。第一个示例代码将遍历系统中的所有进程,并输出每个进程所属的用户。

Process[] processlist = Process.GetProcesses();
foreach (Process process in processlist)
{
    IntPtr tokenHandle;
    if (OpenProcessToken(process.Handle, TOKEN_QUERY, out tokenHandle))
    {
        try
        {
            int tokenInfLength = 0;
            if (!GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenUser, IntPtr.Zero, 0, out tokenInfLength) && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
            {
                IntPtr tokenInformation = Marshal.AllocHGlobal(tokenInfLength);
                try
                {
                    bool success = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenUser, tokenInformation, tokenInfLength, out tokenInfLength);
                    if (success)
                    {
                        TOKEN_USER tokenUser = (TOKEN_USER)Marshal.PtrToStructure(tokenInformation, typeof(TOKEN_USER));
                        string sidString;
                        if (ConvertSidToStringSid(tokenUser.User.Sid, out sidString))
                        {
                            SecurityIdentifier sid = new SecurityIdentifier(sidString);
                            Console.WriteLine("Process {0} belongs to user {1}", process.ProcessName, sid.Translate(typeof(NTAccount)).Value);
                        }
                    }
                }
                finally
                {
                    Marshal.FreeHGlobal(tokenInformation);
                }
            }
        }
        finally
        {
            CloseHandle(tokenHandle);
        }
    }
}

第二个示例代码则是查找某个指定进程的用户。在这个样例中,我们将从命令行接收一个进程名称,然后输出它所属的用户。

string processName = args.Length > 0 ? args[0] : null;
if (processName != null)
{
    Process[] processlist = Process.GetProcessesByName(processName);
    if (processlist.Length > 0)
    {
        Process process = processlist[0];
        IntPtr tokenHandle;
        if (OpenProcessToken(process.Handle, TOKEN_QUERY, out tokenHandle))
        {
            try
            {
                int tokenInfLength = 0;
                if (!GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenUser, IntPtr.Zero, 0, out tokenInfLength) && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
                {
                    IntPtr tokenInformation = Marshal.AllocHGlobal(tokenInfLength);
                    try
                    {
                        bool success = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenUser, tokenInformation, tokenInfLength, out tokenInfLength);
                        if (success)
                        {
                            TOKEN_USER tokenUser = (TOKEN_USER)Marshal.PtrToStructure(tokenInformation, typeof(TOKEN_USER));
                            string sidString;
                            if (ConvertSidToStringSid(tokenUser.User.Sid, out sidString))
                            {
                                SecurityIdentifier sid = new SecurityIdentifier(sidString);
                                Console.WriteLine("Process {0} belongs to user {1}", process.ProcessName, sid.Translate(typeof(NTAccount)).Value);
                            }
                        }
                    }
                    finally
                    {
                        Marshal.FreeHGlobal(tokenInformation);
                    }
                }
            }
            finally
            {
                CloseHandle(tokenHandle);
            }
        }
        else
        {
            Console.WriteLine("Error opening process token: {0}", Marshal.GetLastWin32Error());
        }
    }
    else
    {
        Console.WriteLine("Process {0} not found.", processName);
    }
}
else
{
    Console.WriteLine("Please specify a process name.");
}

这个样例代码将会查找指定进程名的进程,然后输出它所属的用户。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C# 获取系统进程的用户名 - Python技术站

(0)
上一篇 2023年6月7日
下一篇 2023年6月7日

相关文章

  • C# GetTypeCode():获取此实例的类型代码

    C#中的GetTypeCode()方法是返回值类型的枚举值,它指示指定对象的基础类型。 该方法的完整格式如下: public virtual TypeCode GetTypeCode (); 它是System.Object类型的一个实例方法,可以用于在运行时获取对象的类型信息。该方法返回一个System.TypeCode值,该值指示对象的类型。 下面是两个示…

    C# 2023年4月19日
    00
  • C#表达式树讲解

    C# 表达式树讲解 在 C# 中,表达式树(Expression Tree)是一个类似于代码的树形数据结构,可以表示出一个语法树、一个 lambda 表达式、一个 LINQ 查询等等。 表达式树是由表达式节点构成的,每个节点代表一个表达式或语句。 表达式树的语法 表达式树和 C# 中的 lambda 表达式比较类似,都是由参数、箭头符号和表达式组成。例如以下…

    C# 2023年6月1日
    00
  • c# 使用线程对串口serialPort进行收发数据(四种)

    下面将给出“C# 使用线程对串口SerialPort进行收发数据(四种)”的详细攻略。 一、准备工作 在进行串口收发数据的处理前,需要进行一些准备工作: 引入System.IO.Ports命名空间; 创建SerialPort对象,配置串口参数; 确保串口已正常打开。 二、使用线程进行串口数据收发 1. 使用Thread类 使用Thread类可以使代码执行在一…

    C# 2023年6月7日
    00
  • C# 7.0 使用下划线忽略使用的变量的原因分析

    C#7.0使用下划线忽略使用的变量的原因分析 在C#7.0中,我们可以使用一个特殊的下划线符号(_)来忽略我们不需要使用的变量,这在代码中并不会引起编译器的警告或错误提示,那么为什么需要使用这个符号,本文将对此进行详细讲解。 忽略变量的原因 在我们的应用程序和代码中,常常会出现我们所不需要的变量、返回值或者方法参数,但在某种情况下,我们又不得不使用这些变量或…

    C# 2023年5月15日
    00
  • 基于C#实现一个简单的FTP操作工具

    基于C#实现一个简单的FTP操作工具可以分为以下步骤: 1. 引入FTP库 首先需要在项目中安装FTP库,最常用的是System.Net.FtpClient,可以通过NuGet进行安装。 2. 建立FTP连接 使用FTP操作前需要与FTP服务器建立连接,需要使用FtpClient类创建一个实例,然后使用Connect()方法连接到FTP服务器。连接需要指定F…

    C# 2023年6月2日
    00
  • C#自定义异常就这么简单

    C#是一种强类型语言,可以捕获和处理各种异常,从而帮助我们发现程序中出现的错误。在程序开发过程中,如果需要找到特定的错误情况并处理,这时就需要创建自定义异常。本文将介绍如何在C#中创建和使用自定义异常。 1、什么是异常? 异常是指在程序执行期间发生的错误或异常情况,例如除法中除以0、文件不存在、内存不足等。当发生异常时,程序会停止执行当前的操作,并抛出一个异…

    C# 2023年5月9日
    00
  • 详解.NET数据库连接池

    详解.NET数据库连接池 在.NET应用程序中,数据库连接池是一种重要的技术,它可以提高应用程序的性能和可伸缩性。本攻略将深入讲解.NET数据库连接池的工作原理、配置和最佳实践,并提供两个示例说明。 工作原理 当.NET应用程序需要与数据库进行通信时,它会从连接池中获取一个可用的连接。如果连接池中没有可用的连接,则应用程序将等待,直到有可用的连接为止。当应用…

    C# 2023年5月17日
    00
  • C#中的DateTime是值类型还是引用类型

    C#中的DateTime是值类型还是引用类型是一个常见的问题,它的答案是:DateTime是值类型。以下是详细的解释: 在C#中,类型可以被分为值类型和引用类型两种。值类型在栈上分配内存并且存储它们的实例,它们之间没有共享数据的方式。引用类型在堆上分配内存并且存储一个指向它们的实例的引用。值类型的示例包括:int、double、bool、struct、enu…

    C# 2023年6月1日
    00
合作推广
合作推广
分享本页
返回顶部