【问题标题】:How to read print job content using ReadPrinter method如何使用 ReadPrinter 方法读取打印作业内容
【发布时间】:2017-10-07 15:42:38
【问题描述】:

我想获取发送到打印的文档内容。 谷歌表示,唯一的方法是使用 WinAPI 方法 ReadPrinter()。 我已经实现了一个草图,但无法让它工作。 一个问题是 ReadPrinter() 方法总是什么都不返回。

请给我提示有什么问题。

下面的简化代码:

string printerName = "Microsoft XPS Document Writer";
const uint firstJob = 0u;
const uint noJobs = 10u;
const uint level = 1u;
uint bytesNeeded;
uint returned;
uint bytesCopied;
uint structsCopied;

// Open printer
IntPtr printerHandle = OpenPrinterW(printerName.Normalize(), out printerHandle, IntPtr.Zero);

// Get byte size required for a data
EnumJobsW(printerHandle, firstJob, noJobs, level, IntPtr.Zero, 0, out bytesNeeded, out returned);

// Now we know how much memory we need to read the data (bytesNeeded value)
IntPtr pJob = Marshal.AllocHGlobal((int)bytesNeeded);

// Read the data
EnumJobsW(printerHandle, firstJob, noJobs, level, pJob, bytesNeeded, out bytesCopied, out structsCopied);

// Convert pJob to jobInfos
JOB_INFO_1W[] jobInfos = null;

// ... actual convert code missed ...

//  Iterate through the jobs and try to get their content
foreach (JOB_INFO_1W jobInfo in jobInfos)
{
    // Open print job
    string printJobName = string.Format("{0}, Job {1}", printerName, jobInfo.JobId);
    IntPtr printJobHandle;

    OpenPrinterW(printJobName.Normalize(), out printJobHandle, IntPtr.Zero);

    // Read print job
    const int printJobBufLen = 1024;
    StringBuilder printJobSb = new StringBuilder(printJobBufLen);
    int printJobBytesRead = 0;

    while (printJobBytesRead == 0)
    {
        ReadPrinter(printJobHandle, printJobSb, printJobBufLen, out printJobBytesRead);

        // !!! printJobBytesRead is 0 and printJobSb is empty
    }

    // Close print job
    ClosePrinter(printJobHandle);
}

// Close printer
ClosePrinter(printerHandle);

P/Invoke 签名:

[DllImport("winspool.drv", EntryPoint = "OpenPrinterW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int OpenPrinterW(
    [In] string pPrinterName,
    [Out] out IntPtr phPrinter,
    [In] IntPtr pDefault);

[DllImport("spoolss.dll", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int ClosePrinter(
    [In] IntPtr hPrinter);

[DllImport("winspool.drv", EntryPoint = "EnumJobsW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int EnumJobsW(
    [In] IntPtr hPrinter,
    [In] uint FirstJob,
    [In] uint NoJobs,
    [In] uint Level,
    [Out] IntPtr pJob,
    [In] uint cbBuf,
    [Out] out uint pcbNeeded,
    [Out] out uint pcReturned);

[DllImport("spoolss.dll", EntryPoint = "ReadPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int ReadPrinter(
    [In] IntPtr hPrinter,
    [Out] StringBuilder data,
    [In] Int32 cbBuf,
    [Out] out Int32 pNoBytesRead);

【问题讨论】:

  • 我们看不到您的任何 P/Invoke 签名。默认情况下这些是错误的。
  • 我的错,对不起。添加签名。

标签: c# .net winapi print-spooler-api


【解决方案1】:

此代码是否在 driver's Print Processor component 中?如果没有,我认为它不会起作用。

因此,您要么使用打印驱动程序组件,要么从磁盘上的假脱机文件中读取。 See here.

【讨论】:

  • 感谢链接到 undocprint,尼克!我不熟悉 Windows 打印体系结构。那是我的问题。现在我看到我需要开发自定义打印处理器来做我想做的事。
  • 回答你的第一个问题:我的代码在普通的控制台应用程序中。
  • 在我的情况下,spool 被禁用,所以通信应该直接到打印机
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-06
  • 1970-01-01
  • 2011-10-20
  • 2019-05-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多