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




