C#实现PDF同文档跳转指定页码而非打开新实例
问题描述
我用以下C#代码打开PDF文件并定位到指定页码:
void ShowPDF(SomeObject _obj) { // System.Diagnostics.Process process = new System.Diagnostics.Process(); ProcessStartInfo startInfo = new ProcessStartInfo("D:\\Program Files\\Adobe\\Acrobat 9.0\\Acrobat\\Acrobat.exe", "/A page=" + _obg.PageNo + " /n " + _obj.FilePath); startInfo.WindowStyle = ProcessWindowStyle.Maximized; try { System.Diagnostics.Process.Start(startInfo); } catch { System.Windows.MessageBox.Show("Page Not Found", "SmartPlant", MessageBoxButton.OK, MessageBoxImage.Warning); } }
代码能正常运行,但跳转已打开文档的新页码时,会打开该文档的新实例并定位到目标页码。我需要在同一文档实例内跳转至新页码,而非打开新文档。
解决方案
方案1:移除强制新实例的参数
你的命令里的/n参数是强制Acrobat打开新文档实例的关键,直接去掉这个参数,Acrobat会优先复用已打开的文档窗口:
void ShowPDF(SomeObject _obj) { try { // 拼接参数时给文件路径加引号,避免路径含空格出错 string arguments = $"/A page={_obj.PageNo} \"{_obj.FilePath}\""; ProcessStartInfo startInfo = new ProcessStartInfo( "D:\\Program Files\\Adobe\\Acrobat 9.0\\Acrobat\\Acrobat.exe", arguments ); startInfo.WindowStyle = ProcessWindowStyle.Maximized; System.Diagnostics.Process.Start(startInfo); } catch { System.Windows.MessageBox.Show("Page Not Found", "SmartPlant", MessageBoxButton.OK, MessageBoxImage.Warning); } }
注意:如果用户手动在Acrobat中开启了“在新窗口中打开文档”的设置,该方法可能失效,需确保Acrobat默认设置为复用窗口。
方案2:使用DDE命令控制已打开实例
若方案1不生效,可通过DDE(动态数据交换)直接向已运行的Acrobat实例发送跳转命令:
using System.Runtime.InteropServices; void ShowPDF(SomeObject _obj) { try { // 尝试连接已运行的Acrobat实例 if (DdeHelper.ConnectToAcrobat()) { // 发送页码跳转命令,文档路径需匹配 DdeHelper.ExecuteCommand($"[DocGoTo({_obj.PageNo}, \"{_obj.FilePath}\")]"); DdeHelper.Disconnect(); } else { // 无运行实例则启动新窗口 string arguments = $"/A page={_obj.PageNo} \"{_obj.FilePath}\""; ProcessStartInfo startInfo = new ProcessStartInfo( "D:\\Program Files\\Adobe\\Acrobat 9.0\\Acrobat\\Acrobat.exe", arguments ); startInfo.WindowStyle = ProcessWindowStyle.Maximized; System.Diagnostics.Process.Start(startInfo); } } catch { System.Windows.MessageBox.Show("Page Not Found", "SmartPlant", MessageBoxButton.OK, MessageBoxImage.Warning); } } // DDE操作辅助类 public static class DdeHelper { [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern bool SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); private const uint WM_DDE_INITIATE = 0x03E0; private const uint WM_DDE_EXECUTE = 0x03E8; private const uint WM_DDE_TERMINATE = 0x03E1; private static IntPtr _acroWnd; public static bool ConnectToAcrobat() { // 查找Acrobat的窗口句柄(兼容SDI/MDI模式) _acroWnd = FindWindow("AcrobatSDIWindow", null); if (_acroWnd == IntPtr.Zero) _acroWnd = FindWindow("AcrobatMDIWindow", null); if (_acroWnd == IntPtr.Zero) return false; // 发送DDE初始化命令 SendMessage(_acroWnd, WM_DDE_INITIATE, IntPtr.Zero, (IntPtr)(("acroview".Length << 16) | "control".Length)); return true; } public static bool ExecuteCommand(string command) { if (_acroWnd == IntPtr.Zero) return false; // 把命令包装成DDE要求的格式 byte[] commandBytes = System.Text.Encoding.Unicode.GetBytes($"[{command}]\0"); IntPtr commandPtr = Marshal.AllocHGlobal(commandBytes.Length); Marshal.Copy(commandBytes, 0, commandPtr, commandBytes.Length); bool result = SendMessage(_acroWnd, WM_DDE_EXECUTE, IntPtr.Zero, commandPtr); Marshal.FreeHGlobal(commandPtr); System.Threading.Thread.Sleep(500); return result; } public static void Disconnect() { if (_acroWnd != IntPtr.Zero) SendMessage(_acroWnd, WM_DDE_TERMINATE, IntPtr.Zero, IntPtr.Zero); } }
方案3:使用Acrobat Interop API(最可靠)
如果环境允许引用Acrobat的COM组件,可以直接通过API完全控制文档实例:
- 右键项目 → 添加引用 → COM → 找到Adobe Acrobat 9.0 Type Library并添加
- 使用以下代码:
using Acrobat; using System.Runtime.InteropServices; void ShowPDF(SomeObject _obj) { CAcroApp acroApp = null; CAcroAVDoc avDoc = null; try { // 获取已运行的Acrobat实例,无实例则创建新的 acroApp = (CAcroApp)Marshal.GetActiveObject("AcroExch.App") ?? new CAcroApp(); acroApp.Show(); // 检查目标文档是否已打开 bool isDocOpen = false; foreach (CAcroAVDoc openDoc in acroApp.OpenDocs) { if (openDoc.GetPath().Equals(_obj.FilePath, StringComparison.OrdinalIgnoreCase)) { avDoc = openDoc; isDocOpen = true; break; } } // 未打开则启动文档 if (!isDocOpen) { avDoc = new CAcroAVDoc(); avDoc.Open(_obj.FilePath, ""); } // 跳转至指定页码(Acrobat API中页码从0开始计数) CAcroPDDoc pdDoc = avDoc.GetPDDoc(); CAcroPDPage pdPage = (CAcroPDPage)pdDoc.AcquirePage(_obj.PageNo - 1); avDoc.ShowPage(pdPage); // 释放COM资源 Marshal.ReleaseComObject(pdPage); Marshal.ReleaseComObject(pdDoc); } catch { System.Windows.MessageBox.Show("Page Not Found", "SmartPlant", MessageBoxButton.OK, MessageBoxImage.Warning); } finally { // 确保释放所有COM对象 if (avDoc != null) Marshal.ReleaseComObject(avDoc); if (acroApp != null) Marshal.ReleaseComObject(acroApp); } }
该方案能精准控制Acrobat实例,但需确保客户端安装了对应版本的Acrobat,且项目能正确引用COM组件。
内容的提问来源于stack exchange,提问作者Hussein
相关产品推荐
相关产品推荐

