You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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完全控制文档实例:

  1. 右键项目 → 添加引用 → COM → 找到Adobe Acrobat 9.0 Type Library并添加
  2. 使用以下代码:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 05:07:50