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

.NET/C#中如何高效获取PrintDocument的打印任务ID?

高效获取PrintDocument打印任务ID的方案

首先明确:PrintDocument的BeginPrint事件无法直接获取打印任务ID——这个事件触发时,打印任务还未提交到打印队列,系统尚未分配Job ID。下面是两种更高效的实现方式:

方法一:用PrintQueue.AddJob替代PrintDocument.Print()

这种方式能直接拿到任务ID,完全不需要遍历队列,步骤清晰:

  1. 获取目标打印机的PrintQueue实例
  2. 调用AddJob()创建打印任务,直接得到包含JobIdentifier的PrintSystemJobInfo对象
  3. 将PrintDocument的输出定向到该任务的打印流
  4. 启动打印并获取任务ID用于后续跟踪

代码示例:

using System.Drawing.Printing;
using System.Printing;

public int PrintAndGetJobId(PrintDocument pd, string printerName)
{
    using (var printServer = new LocalPrintServer())
    {
        // 获取目标打印机队列
        var printQueue = printServer.GetPrintQueue(printerName);
        
        // 创建打印任务,直接拿到任务信息
        using (var printJob = printQueue.AddJob(pd.DocumentName))
        {
            // 将PrintDocument的输出写入任务流
            using (var jobStream = printJob.JobStream)
            {
                pd.PrintController = new StandardPrintController();
                pd.PrintToStream(jobStream);
            }
            
            // 返回任务ID
            return printJob.JobIdentifier;
        }
    }
}

注意:需确保打印机队列有足够权限,且PrintDocument的纸张大小、分辨率等设置与打印机队列匹配,避免打印异常。

方法二:直接调用Win32打印池API(StartDocPrinter)

如果需要更底层的控制,可以通过P/Invoke调用Win32打印池API,在提交任务时同步获取Job ID。核心是用StartDocPrinter函数启动任务,该函数的返回值就是任务ID。

代码示例:

using System;
using System.Drawing.Printing;
using System.Runtime.InteropServices;

public class PrintJobTracker
{
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    private struct DOC_INFO_1
    {
        public string pDocName;
        public string pOutputFile;
        public string pDataType;
    }

    [DllImport("winspool.drv", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern int OpenPrinter(string pPrinterName, out IntPtr hPrinter, IntPtr pDefault);

    [DllImport("winspool.drv", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern int StartDocPrinter(IntPtr hPrinter, int level, ref DOC_INFO_1 pDocInfo);

    [DllImport("winspool.drv", SetLastError = true)]
    private static extern int EndDocPrinter(IntPtr hPrinter);

    [DllImport("winspool.drv", SetLastError = true)]
    private static extern int ClosePrinter(IntPtr hPrinter);

    public int PrintWithDirectJobId(PrintDocument pd, string printerName)
    {
        IntPtr hPrinter = IntPtr.Zero;
        int jobId = 0;
        
        try
        {
            // 打开打印机
            if (OpenPrinter(printerName, out hPrinter, IntPtr.Zero) == 0)
                throw new System.ComponentModel.Win32Exception();

            // 准备文档信息
            var docInfo = new DOC_INFO_1
            {
                pDocName = pd.DocumentName,
                pDataType = "RAW"
            };

            // 启动打印任务,获取Job ID
            jobId = StartDocPrinter(hPrinter, 1, ref docInfo);
            if (jobId == 0)
                throw new System.ComponentModel.Win32Exception();

            // 关联PrintDocument到当前打印机句柄并启动打印
            pd.PrinterSettings.PrinterName = printerName;
            pd.Print();
        }
        finally
        {
            // 释放打印机资源
            if (hPrinter != IntPtr.Zero)
            {
                EndDocPrinter(hPrinter);
                ClosePrinter(hPrinter);
            }
        }

        return jobId;
    }
}

注意:必须妥善处理打印机句柄的释放,避免资源泄漏;同时要保证PrintDocument的打印流程与Win32 API调用同步。

后续进度查询

拿到Job ID后,无需遍历队列,直接通过PrintQueue.GetJob(jobId)获取PrintSystemJobInfo对象,实时查询JobStatus、NumberOfPagesPrinted等进度信息:

public PrintSystemJobInfo GetPrintJobStatus(int jobId, string printerName)
{
    using (var printServer = new LocalPrintServer())
    {
        var printQueue = printServer.GetPrintQueue(printerName);
        return printQueue.GetJob(jobId);
    }
}

内容的提问来源于stack exchange,提问作者Alejandro Mendez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 10:55:11