使用Process.Start与Process.CloseMainWindow处理PDF的关闭异常问题
解决Edge打开PDF时无法通过启动进程关闭窗口的问题
针对你遇到的Edge多进程导致无法通过Process.CloseMainWindow()关闭PDF窗口的问题,以下是几种实用的解决思路和代码实现:
方法一:通过进程命令行识别并关闭目标PDF进程
Edge打开PDF时,实际承载PDF的子进程命令行会包含该PDF的路径,我们可以通过枚举Edge进程并匹配命令行来定位并关闭目标进程:
using System.Diagnostics; using System.Linq; using System.Management; // 保存当前打开的PDF路径 private string _currentPdfPath; public void OpenNewPdf(string filePath) { // 先关闭已打开的PDF CloseCurrentPdf(); // 启动新PDF Process.Start(filePath); _currentPdfPath = filePath; } private void CloseCurrentPdf() { if (string.IsNullOrEmpty(_currentPdfPath)) return; // 枚举所有Edge主进程(进程名为msedge.exe) var edgeProcesses = Process.GetProcessesByName("msedge"); foreach (var proc in edgeProcesses) { try { // 获取进程的命令行参数 var cmdLine = GetProcessCommandLine(proc); // 匹配PDF路径(兼容本地路径和file:///格式) var targetPath = _currentPdfPath.Replace("\\", "/"); if (cmdLine.Contains(targetPath) || cmdLine.Contains(_currentPdfPath)) { // 尝试优雅关闭窗口 if (proc.CloseMainWindow()) { proc.WaitForExit(1000); } else { // 关闭失败则强制终止进程 proc.Kill(); } } } catch (Exception ex) { Debug.WriteLine($"处理进程出错: {ex.Message}"); } } } // 获取进程命令行的辅助方法 private string GetProcessCommandLine(Process process) { string cmdLine = string.Empty; try { using (var searcher = new ManagementObjectSearcher( $"SELECT CommandLine FROM Win32_Process WHERE ProcessId = {process.Id}")) { foreach (var obj in searcher.Get()) { cmdLine = obj["CommandLine"]?.ToString() ?? string.Empty; break; } } } catch { // 权限不足时返回空字符串 } return cmdLine; }
注意:需要添加
System.Management程序集引用,该方法准确性较高,但可能存在权限限制。
方法二:通过窗口标题匹配关闭PDF窗口
如果Edge打开PDF的窗口标题为[文件名] - Microsoft Edge,可以通过枚举系统窗口并匹配标题来关闭目标窗口:
using System.Runtime.InteropServices; using System.Text; // 导入Windows API [DllImport("user32.dll")] private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam); [DllImport("user32.dll")] private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); [DllImport("user32.dll")] private static extern int GetWindowTextLength(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); private const uint WM_CLOSE = 0x0010; private void ClosePdfByWindowTitle() { if (string.IsNullOrEmpty(_currentPdfPath)) return; string pdfFileName = Path.GetFileName(_currentPdfPath); string targetTitle = $"{pdfFileName} - Microsoft Edge"; EnumWindows((hWnd, lParam) => { int titleLength = GetWindowTextLength(hWnd); if (titleLength > 0) { StringBuilder sb = new StringBuilder(titleLength + 1); GetWindowText(hWnd, sb, sb.Capacity); if (sb.ToString().Equals(targetTitle, StringComparison.OrdinalIgnoreCase)) { // 发送关闭窗口消息 PostMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); } } return true; }, IntPtr.Zero); }
优点是实现简单,无需额外引用;缺点是如果存在同名PDF文件,可能会误关其他窗口。
方法三:复用Edge窗口打开新PDF(减少进程数量)
如果只是想避免产生大量Edge实例,可以直接通过Edge的协议打开PDF,让其在现有窗口的新标签页中加载,而非新建进程:
public void OpenPdfInSameEdgeWindow(string filePath) { // 先关闭已打开的PDF(可选) CloseCurrentPdf(); // 使用microsoft-edge协议打开PDF var pdfUri = new Uri(filePath).AbsoluteUri; Process.Start(new ProcessStartInfo($"microsoft-edge:{pdfUri}")); _currentPdfPath = filePath; }
此方法可以有效减少Edge进程数量,适合不需要单独关闭窗口,仅需避免多实例的场景。
内容的提问来源于stack exchange,提问作者CBFT
相关产品推荐
相关产品推荐

