【问题标题】:Printing a PDF Silently with Adobe Acrobat使用 Adob​​e Acrobat 静默打印 PDF
【发布时间】:2011-02-01 23:03:31
【问题描述】:

尝试使用 adobe acrobat 在 C# 中静默打印 pdf 时遇到两个问题。我正在使用 Process.Start() 打印 pdf。

第一个问题是如果不指定可执行文件的完整路径,我将无法启动 Adob​​e Acrobat。我假设它在安装时不会将其添加到您的路径中。 是否有一种简单的方法可以在不指定完整路径名的情况下在机器上启动最新版本的 acrobat? 我担心客户端会进行更新并破坏启动它的代码。我还担心他们将其安装在具有不同版本 Windows 的机器上(安装路径在 64 位环境与 32 位环境中不同)。

我的第二个问题是,每当我启动 acrobat 并打印它时,acrobat 窗口仍然处于打开状态。我认为我使用的命令行参数会抑制所有这些,但显然不是。

我正在尝试使用以下语法从命令行启动 adobe acrobat:

C:\Program Files (x86)\Adobe\Reader 10.0\Reader>AcroRd32.exe /t "Label.pdf" "HP4000" "HP LaserJet 4100 系列 PCL6" "out.pdf"

打印效果很好,但仍然会打开 acrobat 窗口。 除了以编程方式退出并杀死进程之外,还有其他解决方案吗?

【问题讨论】:

    标签: c# acrobat


    【解决方案1】:

    我最终选择了 Adob​​e Acrobat,并使用 FoxIt Reader(免费 pdf 阅读器)进行我的 pdf 打印。这是我在 C# 中通过 FoxIt 打印的代码:

    Process pdfProcess = new Process();
    pdfProcess.StartInfo.FileName = @"C:\Program Files (x86)\Foxit Software\Foxit Reader\Foxit Reader.exe";
    pdfProcess.StartInfo.Arguments = string.Format(@"-p {0}", fileNameToSave);
    pdfProcess.Start();
    

    上述代码打印到默认打印机,但您可以使用命令行参数来指定文件和打印机。您可以使用以下语法:

    Foxit Reader.exe -t "pdf 文件名" "打印机名"

    更新:

    显然,早期版本的 acrobat 也没有上述问题。如果您使用更旧的版本(4.x 或类似版本),则不会出现此问题。

    某些打印机也确实支持原生 pdf 打印,因此可以将原始 pdf 数据发送到打印机并打印出来。请参阅https://support.microsoft.com/en-us/kb/322091 将原始数据发送到打印机。

    更新 2

    在我们软件的更高版本中,我们最终使用了付费产品:

    http://www.pdfprinting.net/

    【讨论】:

    • 这救了我的命!我已经尝试了很多东西来静默打印 PDF ......通过命令行的 Adob​​e Reader、调用 Adob​​e Reader 的 Windows 服务、一些 WinAPI 技巧。使用任何方法,要么出现 Adob​​e Reader 窗口,要么根本没有打印。非常感谢这个提示!
    • 我很确定 FoxIt 的最新版本不再受支持。我认为他们此时已将其集成到付费版本中。
    • 从 Foxit PDF Reader 11.1 版本开始,免费版仍然支持使用 /t 开关打印到特定打印机。
    【解决方案2】:

    Nick 的回答对我来说很好,所以我把它翻译成 c#。有效!

    using System.Diagnostics;
    
    namespace Whatever
    {
    static class pdfPrint
    {
        public static void pdfTest(string pdfFileName)
        {
           string processFilename = Microsoft.Win32.Registry.LocalMachine
                .OpenSubKey("Software")
                .OpenSubKey("Microsoft")
                .OpenSubKey("Windows")
                .OpenSubKey("CurrentVersion")
                .OpenSubKey("App Paths")
                .OpenSubKey("AcroRd32.exe")
                .GetValue(String.Empty).ToString();
    
            ProcessStartInfo info = new ProcessStartInfo();
            info.Verb = "print";
            info.FileName = processFilename;
            info.Arguments = String.Format("/p /h {0}", pdfFileName);
            info.CreateNoWindow = true;
            info.WindowStyle = ProcessWindowStyle.Hidden; 
            //(It won't be hidden anyway... thanks Adobe!)
            info.UseShellExecute = false;
    
            Process p = Process.Start(info);
            p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    
            int counter = 0;
            while (!p.HasExited)
            {
                System.Threading.Thread.Sleep(1000);
                counter += 1;
                if (counter == 5) break;
            }
            if (!p.HasExited)
            {
                p.CloseMainWindow();
                p.Kill();
            }
        }
    }
    

    }

    【讨论】:

    • 你可以使用 process.WaitForExit(timeout) 而不是轮询。
    • 当您使用打印动词时,您可以在 FileName 中使用 pdf 的路径,并且只使用打印机名称(用引号括起来)作为参数。
    【解决方案3】:

    我试过 Adob​​e Reader 和 Foxit 都没有运气。两者的当前版本都非常喜欢弹出窗口并让进程运行。最终使用了Sumatra PDF,这非常不显眼。这是我使用的代码。打印完成后,没有任何窗口和进程的痕迹很好地退出。

        public static void SumatraPrint(string pdfFile, string printer)
        {
            var exePath = Registry.LocalMachine.OpenSubKey(
                @"SOFTWARE\Microsoft\Windows\CurrentVersion" +
                @"\App Paths\SumatraPDF.exe").GetValue("").ToString();
    
            var args = $"-print-to \"{printer}\" {pdfFile}";
    
            var process = Process.Start(exePath, args);
            process.WaitForExit();
        }
    

    【讨论】:

    • 使用 Sumatra PDF 对我有用。我在 Foxit 让进程处于打开状态时遇到了问题。谢谢!
    • 感谢您的建议。它完美运行,甚至是开源的!
    • 使用 Sumatra PDF 提示用户按下打印按钮。就我而言,我想自动化它。有没有办法做到这一点?提前致谢
    • 可以,但是打印质量不是很好。与 Adob​​e Reader 相比。
    【解决方案4】:

    在 Acrobat Reader 8.1.3 和 Acrobat Pro 11.0.06 中测试了以下功能,并确认了以下功能:

    1. 在系统上找到默认的 Acrobat 可执行文件
    2. 将文件发送到本地打印机
    3. 关闭 Acrobat,无论版本如何

    string applicationPath;
    
    var printApplicationRegistryPaths = new[]
    {
        @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Acrobat.exe",
        @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRD32.exe"
    };
    
    foreach (var printApplicationRegistryPath in printApplicationRegistryPaths)
    {
        using (var regKeyAppRoot = Registry.LocalMachine.OpenSubKey(printApplicationRegistryPath))
        {
            if (regKeyAppRoot == null)
            {
                continue;
            }
    
            applicationPath = (string)regKeyAppRoot.GetValue(null); 
    
            if (!string.IsNullOrEmpty(applicationPath))
            {
                return applicationPath;
            }
        }
    }
    
    // Print to Acrobat
    const string flagNoSplashScreen = "/s";
    const string flagOpenMinimized = "/h";
    
    var flagPrintFileToPrinter = string.Format("/t \"{0}\" \"{1}\"", printFileName, printerName); 
    
    var args = string.Format("{0} {1} {2}", flagNoSplashScreen, flagOpenMinimized, flagPrintFileToPrinter);
    
    var startInfo = new ProcessStartInfo
    {
        FileName = printApplicationPath, 
        Arguments = args, 
        CreateNoWindow = true, 
        ErrorDialog = false, 
        UseShellExecute = false, 
        WindowStyle = ProcessWindowStyle.Hidden
    };
    
    var process = Process.Start(startInfo);
    
    // Close Acrobat regardless of version
    if (process != null)
    {
        process.WaitForInputIdle();
        process.CloseMainWindow();
    }
    

    【讨论】:

    • 这不会在打印后关闭adobe阅读器窗口,它总是留下一个。不确定 Acrobat,它的工作方式可能不同。
    • 这对我使用 Foxit Reader 很有效。版本 7 出现静默打印问题,因此我使用了 WaitForExit(5000) 和 process.Kill()。
    【解决方案5】:

    得到了另一个解决方案 .. 它结合了来自 stackOverflow 的其他 sn-ps。当我调用 CloseMainWindow,然后调用 Kill .. adobe 关闭

        Dim info As New ProcessStartInfo()
        info.Verb = "print"
        info.FileName = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Microsoft").OpenSubKey("Windows").OpenSubKey("CurrentVersion").OpenSubKey("App Paths").OpenSubKey("AcroRd32.exe").GetValue(String.Empty).ToString()
        info.Arguments = String.Format("/p /h {0}", "c:\log\test.pdf")
        info.CreateNoWindow = True
        info.WindowStyle = ProcessWindowStyle.Hidden
        info.UseShellExecute = False
    
        Dim p As Process = Process.Start(info)
        p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
    
        Dim counter As Integer = 0
        Do Until p.HasExited
            System.Threading.Thread.Sleep(1000)
            counter += 1
            If counter = 5 Then
                Exit Do
            End If
        Loop
        If p.HasExited = False Then
            p.CloseMainWindow()
            p.Kill()
        End If
    

    【讨论】:

      【解决方案6】:

      问题 1

      您也许可以在注册表中使用自己的方式。在HKEY_CLASSES_ROOT\.pdf\PersistentHandler\(Default) 中,您应该找到一个指向在两个位置之一中找到的值的 CLSID。相同密钥的 CLSID 文件夹,或者(对于 64 位系统)在 Wow6432Node\CLSID 中向下一步,然后在 那个 CLSID 的密钥中。

      在该键中,您可以查找 LocalServer32 并找到指向当前 exe 路径的默认字符串值。

      我不是 100% 相信这一切,但似乎是合理的(尽管您必须在多个环境中进行验证以确认实际上找到了您正在寻找的过程)。

      (这是registry keys involved 上关于PersistentHandlers 的文档)

      问题 2

      可能使用 Process StartInfo 的CreateNoWindow

      Process p = new Process();
      p.StartInfo.FileName = @"C:\Program Files (x86)\Adobe\Reader 10.0\Reader\AcroRd32.exe";
      p.StartInfo.Arguments = "/t \"Label.pdf\" \"HP4000\" \"HP LaserJet 4100 Series PCL6\" \"out.pdf\"";
      p.CreateNoWindow = true;
      p.Start();
      p.WaitForExit();
      

      (不过只是一个猜测,但我确信一些测试会证明它有效/无效)

      【讨论】:

      • 但是,即使确实阻止了显示,该进程是否仍在运行(例如,您可以在 TaskManager 中看到它)?
      • @Chad:我从来没有在打印 PDF 时遇到过好运,我在 Google 上广泛搜索了各种解决方案。我想使用您基本上尝试做的事情来自动化内部任务,但由于缺乏文档、关闭应用程序的问题或需要寻找的变体太多而最终放弃。您可能只能获得一个 PDF 库,该库可以“内部渲染”文件并直接通过应用程序将其发送到打印,但大多数对这类事情有好处的库都需要花钱。
      • 对于问题 2,我试过了,但它并没有按照我想要的方式工作。它基本上挂在 WaitForExit() 上,直到我手动关闭 acrobat 窗口。我尝试使用 WaitForInputIdle() ,然后在进程对象上执行 Kill() ,但它在打印发生之前将其杀死。 CreateNoWindow 似乎对它是否显示窗口也没有影响。
      • @Cole W,是的,WaitForInputIdle() 技巧适用于 X 之前的版本,但他们“修复”了这个问题。我认为他们是认真的希望他们的窗口打开并保持打开直到用户关闭它。
      【解决方案7】:

      如果您使用 Acrobat reader 4.0,您可以执行以下操作: "C:\Program Files\Adobe\Acrobat 4.0\Reader\Acord32.exe" /t /s "U:\PDF_MS\SM003067K08.pdf" Planning_H2 但是如果 PDF 文件是在较新版本的 Acrobat 中创建的,则会打开一个不可见的窗口

      【讨论】:

        【解决方案8】:

        对于问题 2

        使用 /h 参数将在最小化窗口中打开 Acrobat 或 Adob​​e Reader。

        示例: C:\Program Files (x86)\Adobe\Reader 10.0\Reader>AcroRd32.exe **/h** /t "Label.pdf" "HP4000" "HP LaserJet 4100 Series PCL6" "out.pdf"

        相关文档:https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/Acrobat_SDK_developer_faq.pdf#page=24

        【讨论】:

          【解决方案9】:

          您已经尝试过与 Acrobat Reader 不同的东西,所以我的建议是忘记 GUI 应用程序并使用像 RawFilePrinter.exe 这样的第 3 方命令行工具

          private static void ExecuteRawFilePrinter() {
              Process process = new Process();
              process.StartInfo.FileName = "c:\\Program Files (x86)\\RawFilePrinter\\RawFilePrinter.exe";
              process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
              process.StartInfo.Arguments = string.Format("-p \"c:\\Users\\Me\\Desktop\\mypdffile.pdf\" \"Canon Printer\"");
          
              process.Start();
              process.WaitForExit();
              if (process.ExitCode == 0) {
                      //ok
              } else {
                      //error
              }
          }
          

          要下载的最新版本:https://bigdotsoftware.pl/rawfileprinter

          【讨论】:

            猜你喜欢
            • 2020-05-26
            • 2019-01-20
            • 2019-02-16
            • 1970-01-01
            • 2018-12-06
            • 2012-03-09
            • 2015-01-28
            • 1970-01-01
            • 2013-04-08
            相关资源
            最近更新 更多