在Mac系统下使用C#如何区分不同运行进程的所属用户?
解决方案
.NET 中 Process.SessionId 属性是为 Windows 终端服务会话设计的平台专属属性,在 macOS 等类 Unix 系统中没有对应的原生概念映射,所以跨平台实现会固定返回默认值0,该属性无法满足 macOS 下多用户区分需求,你可以通过以下两种方案实现进程所属用户的获取:
方法1:调用系统ps命令解析输出(实现最简单)
macOS 原生 ps 命令可以直接返回进程对应的所属用户信息,你可以通过.NET 调用该命令并解析输出即可快速实现需求,参考代码如下:
using System.Diagnostics; public static List<(int Pid, string ProcessName, string UserName)> GetProcessesWithUser() { var result = new List<(int, string, string)>(); var psi = new ProcessStartInfo { FileName = "ps", Arguments = "-axo user,pid,comm", // 输出格式:用户名 进程ID 进程名 RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true }; using var proc = Process.Start(psi); proc.WaitForExit(); using var reader = proc.StandardOutput; // 跳过第一行表头 reader.ReadLine(); while (!reader.EndOfStream) { var line = reader.ReadLine().Trim(); if (string.IsNullOrWhiteSpace(line)) continue; // 按空白字符分割,最多分割3段避免进程名带空格的问题 var parts = line.Split(new[] {' '}, 3, StringSplitOptions.RemoveEmptyEntries); if (parts.Length != 3) continue; if (int.TryParse(parts[1], out int pid)) { result.Add((pid, parts[2], parts[0])); } } return result; }
该方法不需要处理平台底层调用,代码兼容性高,适合大多数普通监控场景。
方法2:P/Invoke 调用系统原生接口(性能更高)
如果你需要高频获取进程信息,不想额外启动子进程,可以直接调用 macOS 系统 libproc.dylib 提供的接口获取进程UID,再转换为用户名,参考实现如下:
using System.Runtime.InteropServices; using System.Text; public static class MacProcInfo { private const int PROC_PIDTASKINFO = 4; private const int MAXPATHLEN = 1024; [StructLayout(LayoutKind.Sequential)] private struct proc_bsdinfo { public uint pbi_flags; public uint pbi_status; public uint pbi_xstatus; public uint pbi_pid; public uint pbi_ppid; public uint pbi_uid; public uint pbi_gid; public uint pbi_ruid; public uint pbi_rgid; public uint pbi_svuid; public uint pbi_svgid; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)] public string pbi_comm; // 省略其他不需要的字段 } [DllImport("libproc.dylib")] private static extern int proc_pidinfo(int pid, int flavor, ulong arg, IntPtr buffer, int buffersize); [DllImport("libc.dylib")] private static extern IntPtr getpwuid(uint uid); [StructLayout(LayoutKind.Sequential)] private struct passwd { public IntPtr pw_name; public IntPtr pw_passwd; public uint pw_uid; public uint pw_gid; public IntPtr pw_gecos; public IntPtr pw_dir; public IntPtr pw_shell; } public static string GetProcessUser(int pid) { var bsdInfoSize = Marshal.SizeOf<proc_bsdinfo>(); var buffer = Marshal.AllocHGlobal(bsdInfoSize); try { var ret = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, buffer, bsdInfoSize); if (ret <= 0) return null; var bsdInfo = Marshal.PtrToStructure<proc_bsdinfo>(buffer); var pwPtr = getpwuid(bsdInfo.pbi_uid); if (pwPtr == IntPtr.Zero) return bsdInfo.pbi_uid.ToString(); var pw = Marshal.PtrToStructure<passwd>(pwPtr); return Marshal.PtrToStringAnsi(pw.pw_name); } finally { Marshal.FreeHGlobal(buffer); } } }
使用时遍历所有进程PID,调用MacProcInfo.GetProcessUser(pid)即可获取对应的所属用户名,该方法性能远高于调用外部命令,适合高频率的监控场景使用。
注意:两种方法都需要以管理员权限运行才能获取所有进程的所属用户信息,普通用户权限下仅能获取自身启动进程的相关信息。
内容的提问来源于stack exchange,提问作者Roberto
相关产品推荐
相关产品推荐

