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

开发类Windows内置打印作业监视器:如何获取打印作业使用的端口?

获取Windows打印作业端口信息的可行方案

方法1:通过WMI关联打印机与打印作业

Win32_PrintJob的PortName字段在部分场景下可能为空或未正确填充,此时可以通过打印作业关联的打印机对象(Win32_Printer)获取端口信息:

using System.Management;

var printJobsQuery = new ObjectQuery("SELECT * FROM Win32_PrintJob");
using (var searcher = new ManagementObjectSearcher(printJobsQuery))
{
    foreach (ManagementObject job in searcher.Get())
    {
        // 获取关联的打印机名称
        string printerName = job["PrinterName"].ToString();
        // 查询对应打印机的端口信息(处理单引号转义避免语法错误)
        var printerQuery = new ObjectQuery($"SELECT * FROM Win32_Printer WHERE Name = '{printerName.Replace("'", "''")}'");
        using (var printerSearcher = new ManagementObjectSearcher(printerQuery))
        {
            foreach (ManagementObject printer in printerSearcher.Get())
            {
                string portName = printer["PortName"].ToString();
                Console.WriteLine($"作业ID: {job["JobId"]}, 使用端口: {portName}");
            }
        }
    }
}

方法2:调用Windows打印后台处理服务原生API(P/Invoke)

如果WMI仍无法获取,可直接调用Win32 API的GetJob函数,获取包含端口信息的JOB_INFO_2结构体:

using System;
using System.Runtime.InteropServices;
using System.Text;

public class PrintJobHelper
{
    [DllImport("winspool.drv", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern bool OpenPrinter(string pPrinterName, out IntPtr phPrinter, IntPtr pDefault);

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

    [DllImport("winspool.drv", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern bool GetJob(IntPtr hPrinter, int JobId, int Level, IntPtr pJob, int cbBuf, out int pcbNeeded);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    private struct JOB_INFO_2
    {
        public uint JobId;
        public string pPrinterName;
        public string pMachineName;
        public string pUserName;
        public string pDocument;
        public string pDatatype;
        public string pStatus;
        public uint Status;
        public uint Priority;
        public uint Position;
        public uint TotalPages;
        public uint PagesPrinted;
        public SYSTEMTIME Submitted;
        public SYSTEMTIME StartTime;
        public SYSTEMTIME UntilTime;
        public uint TotalBytes;
        public uint BytesPrinted;
        public string pPortName; // 端口信息字段
        // 省略其他未用到的字段
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct SYSTEMTIME
    {
        public ushort wYear;
        public ushort wMonth;
        public ushort wDayOfWeek;
        public ushort wDay;
        public ushort wHour;
        public ushort wMinute;
        public ushort wSecond;
        public ushort wMilliseconds;
    }

    public static string GetPrintJobPort(int jobId, string printerName)
    {
        IntPtr hPrinter = IntPtr.Zero;
        try
        {
            if (!OpenPrinter(printerName, out hPrinter, IntPtr.Zero))
                throw new System.ComponentModel.Win32Exception();

            int bufferSize = 0;
            // 先获取所需缓冲区大小
            GetJob(hPrinter, jobId, 2, IntPtr.Zero, 0, out bufferSize);
            if (bufferSize == 0)
                return null;

            IntPtr jobInfoPtr = Marshal.AllocHGlobal(bufferSize);
            try
            {
                if (GetJob(hPrinter, jobId, 2, jobInfoPtr, bufferSize, out _))
                {
                    JOB_INFO_2 jobInfo = Marshal.PtrToStructure<JOB_INFO_2>(jobInfoPtr);
                    return jobInfo.pPortName;
                }
                else
                {
                    throw new System.ComponentModel.Win32Exception();
                }
            }
            finally
            {
                Marshal.FreeHGlobal(jobInfoPtr);
            }
        }
        finally
        {
            if (hPrinter != IntPtr.Zero)
                ClosePrinter(hPrinter);
        }
    }
}

使用示例:

string port = PrintJobHelper.GetPrintJobPort(123, "MyPrinter");
Console.WriteLine($"作业端口: {port}");

方法3:检查打印后台处理程序的日志

如果以上方法都失败,可启用打印后台处理程序的日志记录:

  • 打开事件查看器 → 展开应用程序和服务日志 → Microsoft → Windows → PrintService
  • 启用Operational日志,打印作业的详细信息(包括端口)会被记录在事件ID为307的事件中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 16:45:01