C#控制台程序在Windows任务计划中打印PDF的开源方案咨询
适用于Windows任务计划的C# PDF打印解决方案
问题根源
你遇到的核心问题是System.Drawing.Common和基于它的PDF打印库(比如你使用的PdfiumViewer)依赖GDI+图形环境,而Windows任务计划在无桌面会话的后台运行时,无法提供完整的图形上下文,导致程序挂起、无响应甚至无限循环。
推荐的开源解决方案
1. 调用Windows打印池API(无GDI+依赖)
直接调用Win32打印池底层接口,绕开图形环境依赖,将PDF文件以RAW格式发送至打印机驱动:
using System; using System.Runtime.InteropServices; using System.IO; public class RawPdfPrinter { [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool OpenPrinter(string pPrinterName, out IntPtr hPrinter, IntPtr pDefault); [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool ClosePrinter(IntPtr hPrinter); [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool StartDocPrinter(IntPtr hPrinter, int Level, [In] ref DOCINFOA di); [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool EndDocPrinter(IntPtr hPrinter); [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool StartPagePrinter(IntPtr hPrinter); [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool EndPagePrinter(IntPtr hPrinter); [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBuf, int cbBuf, out int pcWritten); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct DOCINFOA { [MarshalAs(UnmanagedType.LPStr)] public string pDocName; [MarshalAs(UnmanagedType.LPStr)] public string pOutputFile; [MarshalAs(UnmanagedType.LPStr)] public string pDataType; } public bool PrintPdf(string printerName, string pdfPath) { IntPtr printerHandle = IntPtr.Zero; try { if (!OpenPrinter(printerName, out printerHandle, IntPtr.Zero)) throw new System.ComponentModel.Win32Exception(); byte[] pdfBytes = File.ReadAllBytes(pdfPath); DOCINFOA docInfo = new DOCINFOA { pDocName = "Auto PDF Print Job", pDataType = "RAW" }; if (!StartDocPrinter(printerHandle, 1, ref docInfo)) throw new System.ComponentModel.Win32Exception(); if (!StartPagePrinter(printerHandle)) throw new System.ComponentModel.Win32Exception(); IntPtr pdfPtr = Marshal.AllocHGlobal(pdfBytes.Length); Marshal.Copy(pdfBytes, 0, pdfPtr, pdfBytes.Length); if (!WritePrinter(printerHandle, pdfPtr, pdfBytes.Length, out _)) throw new System.ComponentModel.Win32Exception(); Marshal.FreeHGlobal(pdfPtr); EndPagePrinter(printerHandle); EndDocPrinter(printerHandle); return true; } catch (Exception ex) { SentrySdk.CaptureException(ex); return false; } finally { if (printerHandle != IntPtr.Zero) ClosePrinter(printerHandle); } } }
2. 使用Ghostscript.NET(命令行级底层处理)
Ghostscript是老牌开源PDF处理工具,其.NET封装Ghostscript.NET可在无图形界面环境下直接调用,通过命令行模式完成打印:
using Ghostscript.NET; using Ghostscript.NET.Processor; public bool PrintPdfWithGhostscript(string printerName, string pdfPath) { try { using (var processor = new GhostscriptProcessor()) { var settings = new GhostscriptSettings(GhostscriptVersion.Latest); settings.Device = GhostscriptDeviceName.mswinpr2; settings.OutputFile = $"\\\\spool\\{printerName}"; processor.StartProcessing( new string[] { "-dBATCH", "-dNOPAUSE", "-dNOSAFER", $"-sDEVICE={settings.Device}", $"-sOutputFile={settings.OutputFile}", pdfPath }, null ); } return true; } catch (Exception ex) { SentrySdk.CaptureException(ex); return false; } }
任务计划配置关键注意事项
- 运行程序的用户账户必须拥有目标打印机的访问权限,建议使用本地管理员或域账户(避免SYSTEM账户,可能存在权限限制)。
- 任务计划中勾选**“不管用户是否登录都要运行”**,按需勾选“使用最高权限运行”。
- 程序放置目录需授予读写权限,避免放在C:\Program Files这类受系统保护的路径。
内容的提问来源于stack exchange,提问作者lucario
相关产品推荐
相关产品推荐

