如何用C#实现Windows非系统用户应用程序的获取与关闭?
获取Windows非系统用户应用进程的C#实现方法
要筛选出Word、FoxitReader这类用户级应用进程,核心是区分系统进程和用户交互进程,可以从「窗口存在性」「进程路径」「进程所有者」三个维度组合判断,以下是具体实现方案:
基础过滤方案(适合多数考试场景)
通过筛选有主窗口的进程,并排除系统目录下的进程,快速定位用户应用:
using System.Diagnostics; using System.IO; using System.Linq; List<Process> GetUserApplications() { var userApps = new List<Process>(); // 定义系统进程常见路径 var systemDirs = new[] { Environment.GetFolderPath(Environment.SpecialFolder.Windows), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "System32"), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "SysWOW64") }; foreach (var process in Process.GetProcesses()) { try { // 跳过无主窗口的进程(多数系统进程/后台服务无窗口) if (process.MainWindowHandle == IntPtr.Zero) continue; // 获取进程文件路径,跳过无权限访问的进程 var procPath = process.MainModule.FileName; // 判断进程是否位于系统目录 bool isSystemProc = systemDirs.Any(dir => procPath.StartsWith(dir, StringComparison.OrdinalIgnoreCase)); if (!isSystemProc) userApps.Add(process); } catch { // 捕获权限异常,跳过无法访问的系统核心进程 continue; } } return userApps; }
方案说明
- 优点:实现简单,性能开销小,能覆盖绝大多数带UI的用户应用。
- 局限性:会漏掉无窗口的用户后台进程,部分进程因权限问题无法获取路径。
进阶精确过滤方案
通过判断进程的所有者账户,进一步排除系统账户运行的进程,过滤更精准:
首先需要引入P/Invoke代码获取进程所有者:
using System.Security.Principal; using System.Runtime.InteropServices; [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); // 获取进程的所有者身份 private static WindowsIdentity GetProcessOwner(Process process) { IntPtr tokenHandle = IntPtr.Zero; try { // 申请查询进程令牌的权限 if (!OpenProcessToken(process.Handle, 0x0008 /* TOKEN_QUERY */, out tokenHandle)) return null; return new WindowsIdentity(tokenHandle); } catch { return null; } finally { // 释放令牌句柄 if (tokenHandle != IntPtr.Zero) CloseHandle(tokenHandle); } } // 判断是否为系统内置账户 private static bool IsSystemAccount(SecurityIdentifier sid) { return sid.IsWellKnown(WellKnownSidType.LocalSystemSid) || sid.IsWellKnown(WellKnownSidType.NetworkServiceSid) || sid.IsWellKnown(WellKnownSidType.LocalServiceSid); }
然后修改筛选方法,加入所有者判断:
List<Process> GetUserApplications() { var userApps = new List<Process>(); var systemDirs = new[] { Environment.GetFolderPath(Environment.SpecialFolder.Windows), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "System32"), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "SysWOW64") }; var currentUserSid = WindowsIdentity.GetCurrent().User.Value; foreach (var process in Process.GetProcesses()) { try { if (process.MainWindowHandle == IntPtr.Zero) continue; var procPath = process.MainModule.FileName; bool isSystemPath = systemDirs.Any(dir => procPath.StartsWith(dir, StringComparison.OrdinalIgnoreCase)); if (isSystemPath) continue; // 获取进程所有者,排除系统账户 var owner = GetProcessOwner(process); if (owner == null || !IsSystemAccount(owner.User)) userApps.Add(process); } catch { continue; } } return userApps; }
方案说明
- 优点:结合路径和账户双重判断,能排除系统账户运行的非系统目录进程,过滤更准确。
- 注意:需要以管理员权限运行程序,否则无法获取部分进程的令牌信息。
额外注意事项
- 权限要求:程序必须以管理员身份启动,否则无法访问多数系统进程和部分用户进程的信息。
- 白名单机制:建议添加白名单,将自己的考试安全程序排除在关闭列表之外,避免误杀。
- 友好关闭流程:优先调用
Process.CloseMainWindow()发送关闭请求,等待3-5秒后再调用Process.Kill(),减少用户数据丢失风险。 - 多进程应用处理:部分用户应用(如Chrome)会启动多个进程,需要遍历所有匹配进程并关闭。
内容的提问来源于stack exchange,提问作者Khaled El Attar
相关产品推荐
相关产品推荐

