You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Windows服务中C#打印PDF功能失效,窗体程序可正常运行

解决Windows服务中调用Acrobat打印PDF失效的问题

这问题我之前帮同事排查过类似的,Windows服务里用Acrobat打印PDF确实有不少坑,咱们一步步来拆解:

问题根源

Windows服务默认运行在Session 0这个隔离的会话环境里,它没有用户交互式桌面。而Acrobat这类桌面应用程序依赖用户桌面环境才能正常启动和执行打印操作——当你在Windows窗体里调用时,是在用户会话(比如Session 1)里运行,有桌面支持,所以没问题;但放到服务里后,Acrobat进程要么根本启动不起来,要么启动后卡在等待桌面交互的状态,导致你的代码卡在WaitForInputIdle()或者Thread.Sleep()这一步,既不抛出异常,也不继续执行,所以日志只输出到"Stepping into print."就没下文了。

可行的解决方案

方案1:改用无桌面依赖的PDF打印库(推荐)

放弃依赖Acrobat,改用专门支持后台打印的PDF处理库,比如Ghostscript、iTextSharp或者PdfSharp。这些库不需要桌面环境,能在Windows服务里正常运行。

以Ghostscript为例,你可以这样实现打印:

public void PrintPdfWithGhostscript(string filePath, string printerName)
{
    // 根据你的Ghostscript安装路径调整
    string gsPath = @"C:\Program Files\gs\gs9.55.0\bin\gswin64c.exe"; 
    string arguments = $"-dPrinted -dBATCH -dNOPAUSE -dNOSAFER -q -dNumCopies=1 -sDEVICE=mswinpr2 -sOutputFile=\"%printer%{printerName}\" \"{filePath}\"";

    try
    {
        ProcessStartInfo psi = new ProcessStartInfo(gsPath, arguments)
        {
            CreateNoWindow = true,
            WindowStyle = ProcessWindowStyle.Hidden,
            UseShellExecute = false
        };

        using (Process process = Process.Start(psi))
        {
            process.WaitForExit();
            if (process.ExitCode == 0)
            {
                WriteToFile($"Printed successfully at {DateTime.Now}");
            }
            else
            {
                WriteToFile($"Print failed with exit code {process.ExitCode} at {DateTime.Now}");
            }
        }
    }
    catch (Exception ex)
    {
        WriteToFile($"Print error: {ex.ToString()}");
        throw;
    }
}

方案2:配置服务允许与桌面交互(不推荐,仅用于临时测试)

在Windows服务的属性里,找到"登录"选项卡,勾选"允许服务与桌面交互"。但注意:

  • 这个功能在Windows Vista及以后的系统里有安全限制,微软不推荐用于生产环境
  • 只有当服务运行在本地系统账户下时,这个选项才可用
  • 如果服务器有多个用户登录,打印可能会出现在随机用户的桌面上

方案3:拆分打印逻辑到桌面应用,通过IPC调用

把打印PDF的逻辑放到一个独立的Windows窗体应用里,然后Windows服务通过命名管道(Named Pipe)、WCF或者其他IPC方式调用这个桌面应用来执行打印。这样桌面应用运行在用户会话里,有桌面环境支持,能正常调用Acrobat。

针对你现有代码的问题点说明

你的代码里有几个地方在服务环境下会出问题:

  • 使用Verb = "print"启动进程:这个依赖Shell的关联程序(Acrobat),而Session 0里的Shell环境和用户会话不同,可能无法正确关联
  • WaitForInputIdle():Acrobat在Session 0里无法初始化桌面窗口,永远不会进入空闲状态,导致代码一直卡在这里
  • Thread.Sleep(5000):即使Sleep结束,Acrobat进程可能还是没正常运行,打印操作根本没执行

内容的提问来源于stack exchange,提问作者alan Fitzgerald

火山引擎 最新活动