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日

相关文章

  • ASP.NET Core获取正确查询字符串参数示例

    标题:ASP.NET Core获取正确查询字符串参数示例 前言: 在Web应用程序中,查询字符串是一种常用的传递参数的方式。然而在ASP.NET Core中,获取查询字符串时需要特别注意一些情况,否则就可能出现获取不到参数值或者获取到错误参数值的问题。本文将详细讲解ASP.NET Core获取正确查询字符串参数的示例。 一、在Controller中获取查询字…

    C# 2023年6月3日
    00
  • C#文件操作类分享

    C#文件操作类分享 本文将分享C#中常见的文件操作类以及它们的使用方法,帮助开发者更好地处理文件输入输出。 StreamReader类 StreamReader类可以用于读取文本文件中的数据。 读取整个文件 string path = @"C:\data.txt"; using (StreamReader sr = new StreamR…

    C# 2023年5月31日
    00
  • C#预处理指令之#line,#pragma warning 详细解析

    C#预处理指令之#line,#pragma warning 详细解析 在C#中,预处理指令(Preprocessor directives)是以井号 (#) 开头的,用于控制编译过程的指令。预处理指令会在编译代码之前就被处理,与实际代码无关。这些指令用于给编译器提供附加的信息或指令,以执行不同的编译选项。 本文将详细讲解两条常用的预处理指令:#line 和 …

    C# 2023年6月1日
    00
  • C#控制台程序使用Log4net日志组件详解

    C#控制台程序使用Log4net日志组件详解 Log4net是一个用于记录日志的流行的开源框架,它可以帮助开发者方便地记录应用程序的运行日志,并且支持在运行时动态地控制日志等级和输出目标。本篇攻略将从以下几个方面详细讲解如何在C#控制台程序中使用Log4net日志组件: 安装Log4net并添加配置文件 创建Logger对象 记录日志信息 控制日志等级和输出…

    C# 2023年5月15日
    00
  • C#数组应用分析第1/2页

    C#数组应用分析攻略 什么是C#数组 C#中的数组是一种数据结构,用于存储相同类型的固定大小的元素序列。数组在编程中非常常见,可以提高代码运行效率,也方便了数据的管理。 如何声明C#数组 在C#中声明数组需要指定元素的数据类型和数组的名称,如下所示: int[] numbers = new int[5]; 其中,int[]代表int类型的数组,numbers…

    C# 2023年6月7日
    00
  • 如何运行编译.NetCore的源码?

    作为.net的开发人员,为了能更好的code,我们要知其然并知其所以然,了解.netcore的源码是我们的基本素养✊ 源码地址 .NET Platform (github.com) 这个是.net在github上开源的源码地址aspnetcore 这个是.netcore的源码地址 构建方法 构建有几点需要注意一下: 构建比较费时间,可以摸个?; 同时构建还需…

    C# 2023年4月18日
    00
  • C#获取所有SQL Server数据库名称的方法

    下面是针对“C#获取所有SQL Server数据库名称的方法”的完整攻略: 目录 需求 步骤 步骤1:引入命名空间 步骤2:创建连接对象 步骤3:打开数据库连接 步骤4:获取数据库列表 步骤5:关闭连接 示例1 示例2 需求 在使用C#编写SQL Server相关应用时,有时需要获取服务器上所有存在的数据库名称。本攻略将详细讲解如何使用C#获取SQL Ser…

    C# 2023年6月2日
    00
  • C#异步编程Task的创建方式

    C#中的异步编程是为了方便对于耗时操作的处理,而Task是一种比较常用的异步编程工具,在这里,我将为您提供完整的C#异步编程Task的创建方式攻略。 示例一:使用Task.Run()方法创建一个异步任务 在C#中,可以使用Task.Run()方法创建一个异步任务,在这个异步任务中,我们可以执行需要异步处理的操作。 async Task Method1() {…

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