下面是关于如何用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.Diagnostics
和System.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技术站