Windows 11下C#代码无法最小化所有记事本实例的问题求助
Windows 11下以管理员权限运行时无法最小化所有记事本实例的解决方案
问题描述
我编写了一段C#代码用于最小化所有打开的记事本实例,在Windows 10上运行正常,但在Windows 11中以管理员权限运行生成的EXE时,仅能最小化3个打开实例中的一个。代码如下:
class Program { private const int SW_SHOWNORMAL = 1; private const int SW_SHOWMINIMIZED = 2; private const int SW_SHOWMAXIMIZED = 3; [DllImport("user32.dll")] private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow); [DllImport("user32.dll")] private static extern bool MinimizeWindow(System.IntPtr hwnd); static void Main(string[] args) { System.Diagnostics.Process thisProcess = System.Diagnostics.Process.GetCurrentProcess(); System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName("notepad"); foreach (System.Diagnostics.Process process in processes) { if (process == thisProcess) continue; System.IntPtr handle = process.MainWindowHandle; if (handle == System.IntPtr.Zero) continue; IntPtr s1 = process.MainWindowHandle; ShowWindowAsync(s1, SW_SHOWMINIMIZED); } } }
问题原因
Windows 11的UAC权限隔离机制比Windows 10更严格:当程序以管理员权限运行时,它只能直接访问同权限级别的进程,普通权限启动的记事本进程会被系统隔离。这导致Process.GetProcessesByName("notepad")要么只能获取到同权限的实例,要么无法获取到普通权限进程的有效MainWindowHandle(返回IntPtr.Zero),最终只能最小化其中一个实例。
解决方案
改用EnumWindows枚举系统所有顶级窗口,通过窗口关联的进程ID判断是否为记事本,再执行最小化操作。这种方式不受权限隔离限制,能覆盖所有可见的记事本窗口。
修正后的代码:
using System; using System.Diagnostics; using System.Runtime.InteropServices; class Program { private const int SW_SHOWMINIMIZED = 2; [DllImport("user32.dll")] private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam); [DllImport("user32.dll")] private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); [DllImport("user32.dll")] private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow); [DllImport("user32.dll")] private static extern bool IsWindowVisible(IntPtr hWnd); private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); static void Main(string[] args) { EnumWindows((hWnd, lParam) => { if (IsWindowVisible(hWnd)) { GetWindowThreadProcessId(hWnd, out uint processId); try { using (var process = Process.GetProcessById((int)processId)) { if (string.Equals(process.ProcessName, "notepad", StringComparison.OrdinalIgnoreCase)) { ShowWindowAsync(hWnd, SW_SHOWMINIMIZED); } } } catch (ArgumentException) { // 进程已退出,忽略该窗口 } } return true; }, IntPtr.Zero); } }
关键说明
EnumWindows:遍历系统所有顶级窗口,不受权限隔离影响,能获取到所有可见窗口的句柄。IsWindowVisible:过滤不可见窗口,避免处理后台或隐藏的窗口。GetWindowThreadProcessId:通过窗口句柄获取对应的进程ID,进而验证进程是否为记事本。- 使用
using语句管理Process对象:确保资源及时释放,避免内存泄漏。 - 捕获
ArgumentException:处理枚举过程中进程已退出的情况,防止程序崩溃。
内容的提问来源于stack exchange,提问作者Pankaj
相关产品推荐
相关产品推荐

