Windows:如何告诉打印机在打印过程中发出 FormFeed?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4565679/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 15:52:40  来源:igfitidea点击:

Windows: How to tell printer to issue a FormFeed during printing?

windowsprintingxps

提问by Ian Boyd

i need to tell a printer driver to issue a form feed.

我需要告诉打印机驱动程序发出换页。

i'm printing directly to a printer using the:

我正在使用以下方法直接打印到打印机:

set of API calls.

一组 API 调用。

A lot of the inspiration came from KB138594 - HOWTO: Send Raw Data to a Printer by Using the Win32 API. An important point to note in that KB article is that they (and my copied code) start the document in RAWmode:

许多灵感来自KB138594 - HOWTO:使用 Win32 API 将原始数据发送到打印机。在那篇知识库文章中需要注意的一个重要点是它们(和我复制的代码)以RAW模式启动文档:

// Fill in the structure with info about this "document."
docInfo.pDocName = "My Document";
docInfo.pOutputFile = NULL;
docInfo.pDatatype = "RAW";
StartDocPrinter(hPrinter, 1, docInfo);

Note:RAWmode (as opposed to TEXTmode) means we are issuing raw bytes to the printer driver. We promise to talk in the language it understands.

注意:RAW模式(与模式相反TEXT)意味着我们向打印机驱动程序发出原始字节。我们承诺用它理解的语言交谈。

We can then use WritePrinterto write everything we want:

然后我们可以用它WritePrinter来写我们想要的一切:

WritePrinter(hPrinter, "Hello, world!"); //note, extra parameters removed for clarity
WritePrinter(hPrinter, 0x0c); //form-feed

The problem here is the 0x0cform-feed character. Because we've opened the printer in RAWmode, we are promising we will send the printer driver bytes it can process. The drivers of mostprinters take 0x0Cto mean you want to issue a form-feed.

这里的问题是0x0c换页符。因为我们已经在RAW模式下打开了打印机,所以我们承诺我们将发送它可以处理的打印机驱动程序字节。大多数打印机的驱动程序0x0C意味着您要进行换页。

The problem is that other printers (PDF printer, Microsoft XPS Printers) expect RAWprint jobs to be in their own printer language. If you use the above to print to an XPS or PDF printer: nothing happens (i.e. no save dialog, nothing printed).

问题是其他打印机(PDF 打印机Microsoft XPS 打印机)希望RAW打印作业使用他们自己的打印机语言。如果您使用上述方法打印到 XPS 或 PDF 打印机:没有任何反应(即没有保存对话框,没有打印任何内容)。

i asked for a solution to this question a while ago, and a response was that you have to change the document mode from RAW:

不久前要求解决这个问题,得到的答复是您必须从RAW以下位置更改文档模式:

docInfo.pDatatype = "RAW";

to TEXT:

TEXT

docInfo.pDataType = "TEXT";

Well this probably is because you send "RAW" data directly to the printer, and RAW can be any PDL. But the XPS driver will probably only understands XPS, and it will probably just ignore your "unknown: Hello, world!0xFF" PDL. The XPS driver will probably, if any, only accept XPS data when you write directly to it.

If you want to render text on the XPS driver, you should use GDI. You might be able to send plain text to the driver if you specify "TEXT" as the datatype. The print processor attached to the driver will then "convert" the plaintext for you by rendering the job via GDI to the driver.

嗯,这可能是因为您将“RAW”数据直接发送到打印机,而 RAW 可以是任何 PDL。但是 XPS 驱动程序可能只会理解 XPS,它可能只会忽略您的“未知:你好,世界!0xFF”PDL。XPS 驱动程序可能(如果有)仅在您直接写入时才接受 XPS 数据。

如果要在 XPS 驱动程序上呈现文本,则应使用 GDI。如果您指定“TEXT”作为数据类型,您或许能够向驱动程序发送纯文本。然后,连接到驱动程序的打印处理器将通过 GDI 将作业呈现给驱动程序,从而为您“转换”纯文本。

So that worked, i changed my code to declare the print document as TEXT:

这样有效,我更改了代码以将打印文档声明为TEXT

// Fill in the structure with info about this "document."
docInfo.pDocName = "My Document";
docInfo.pOutputFile = NULL;
docInfo.pDatatype = "TEXT";
StartDocPrinter(hPrinter, 1, docInfo);
WritePrinter(hPrinter, "Hello, world!");
WritePrinter(hPrinter, 0x0c); //form-feed

And then the Save Asdialog for XPS and PDF printers appear, and it saves correctly. And i thought all was fixed.

然后出现 XPS 和 PDF 打印机的另存为对话框,并正确保存。我以为一切都已解决。

Except months later, when i tried to print to a <quote>real</quote> printer: the form-feed doesn't happen - presumably because i am no longer printing in "raw printer commands" mode.

除了几个月后,当我尝试打印到 <quote>real</quote> 打印机时:不会发生换页 - 大概是因为我不再以“原始打印机命令”模式打印。

So what i need is the Windows-ishway of issuing a form feed. i need the API call that will tell printer driver that i want the printer to perform a form-feed.

所以我需要的是发布换页的Windows 式方式。我需要 API 调用来告诉打印机驱动程序我希望打印机执行换页。

My question:How to tell a printer to issue a Form-Feed during printing?

我的问题:如何告诉打印机在打印过程中发出换页符?



Background on Data Types

数据类型的背景

The print processor tells the spooler to alter a job according to the document data type. It works in conjunction with the printer driver to send the spooled print jobs from the hard drive to the printer.

打印处理器告诉假脱机程序根据文档数据类型更改作业。它与打印机驱动程序协同工作,将假脱机的打印作业从硬盘驱动器发送到打印机。

Software vendors occasionally develop their own print processors to support custom data types. Normally, the print processor does not require any settings or intervention from administrators.

软件供应商有时会开发自己的打印处理器来支持自定义数据类型。通常,打印处理器不需要管理员的任何设置或干预。

Data types

数据类型

The Windows printing process normally supports five data types. The two most commonly used data types, enhanced metafile (EMF) and ready to print (RAW), affect performance in different ways on both the client computer and the print server computer.

Windows 打印过程通常支持五种数据类型。两种最常用的数据类型,增强型图元文件 (EMF) 和准备打印 (RAW),以不同方式影响客户端计算机和打印服务器计算机的性能。

RAWis the default data type for clients other than Windows-based programs. The RAW data type tells the spooler not to alter the print job at all prior to printing. With this data type, the entire process of preparing the print job is done on the client computer.

RAW是基于 Windows 的程序以外的客户端的默认数据类型。RAW 数据类型告诉后台打印程序在打印之前根本不要更改打印作业。使用这种数据类型,准备打印作业的整个过程都在客户端计算机上完成。

EMF, or enhanced metafile, is the default datatype with most Windows-based programs. With EMF, the printed document is altered into a metafile format that is more portable than RAW files and usually can be printed on any printer. EMF files tend to be smaller than RAW files that contain the same print job. Regarding performance, only the first portion of a print job is altered, or rendered on the client computer, but most of the impact is on the print server computer, which also helps the application on the client computer to return control to the user faster.

EMF,或增强的元文件,是大多数基于 Windows 的程序的默认数据类型。使用 EMF,打印的文档被更改为元文件格式,该格式比 RAW 文件更便于携带,并且通常可以在任何打印机上打印。EMF 文件往往比包含相同打印作业的 RAW 文件小。关于性能,只有打印作业的第一部分被更改或呈现在客户端计算机上,但大部分影响是在打印服务器计算机上,这也有助于客户端计算机上的应用程序更快地将控制权返回给用户。

The following table (taken from MSDN) shows the five different data types supported by the default Windows print processor:

下表(取自 MSDN)显示了默认 Windows 打印处理器支持的五种不同数据类型:

Data type: RAW
Directions to spooler: Print the document with no changes.
Use: This is the data type for all clients not based on Windows.

数据类型RAW
假脱机程序的说明:不加更改地打印文档。
使用:这是所有不基于 Windows 的客户端的数据类型。

Data type: RAW [FF appended]
Directions to spooler: Append a form-feed character (0x0C), but make no other changes. (A PCL printer omits the document's last page if there is no trailing form-feed.)
Use: Required for some applications. Windows does not assign it, but it can be set as the default in the Print Processor dialog box.

数据类型RAW [FF appended]
假脱机程序的说明:附加换页符 (0x0C),但不做其他更改。(如果没有尾随换页,PCL 打印机会忽略文档的最后一页。)
用途:某些应用程序需要。Windows 不会分配它,但可以在“打印处理器”对话框中将其设置为默认值。

Data type: RAW [FF auto]
Directions to spooler: Check for a trailing form-feed and add one if it is not already there, but make no other changes.
Use: Required for some applications. Windows does not assign it, but it can be set as the default in the Print Processor dialog box.

数据类型RAW [FF auto]
假脱机程序的说明:检查尾随换页,如果不存在则添加,但不进行其他更改。
用途:某些应用程序需要。Windows 不会分配它,但可以在“打印处理器”对话框中将其设置为默认值。

Data type: NT EMF 1.00x
Directions to spooler: Treat the document as an enhanced metafile (EMF) rather than the RAW data that the printer driver puts out.
Use: EMF documents are created by Windows.

数据类型NT EMF 1.00x
后台处理程序的说明:将文档视为增强型图元文件 (EMF),而不是打印机驱动程序输出的 RAW 数据。
用途: EMF 文件是由 Windows 创建的。

Data type: TEXT
Directions to spooler: Treat the entire job as ANSI text and add print specifications using the print device's factory defaults. Use: This is useful when the print job is simple text and the target print device cannot interpret simple text.

数据类型TEXT
假脱机程序说明:将整个作业视为 ANSI 文本,并使用打印设备的出厂默认设置添加打印规范。 用途:当打印作业是简单文本且目标打印设备无法解释简单文本时,这很有用。

You can see the print processors available for a printer, and the data types that each processor supports, through the properties of a printer in the control panel:

您可以通过控制面板中的打印机属性查看打印机可用的打印处理器以及每个处理器支持的数据类型:

alt text

替代文字

See also

也可以看看

采纳答案by Hans Passant

Yeah, that doesn't work. You are intentionally bypassing the printer driver, the chunk of code that presents a universal interface to any printer. Which leaves you to deal with the peculiarities of each specific printer model.

是的,那行不通。您故意绕过打印机驱动程序,这是为任何打印机提供通用接口的代码块。这让您需要处理每个特定打印机型号的特性。

There are some common interfaces, the one you used in your code is the one that dot matrix printers of old used. PCL is common on Hewlett Packard laser printers. Postscript is common on high-end printers. The latter two have their own incantations to get a form feed.

有一些通用接口,您在代码中使用的接口是旧点阵打印机使用的接口。PCL 在 Hewlett Packard 激光打印机上很常见。Postscript 在高端打印机上很常见。后两者有自己的咒语来获取换页符。

Then there's the ocean of cheap laser and ink jet printers. They often don't have a well defined interface at all. Instead of having a processor inside the printer that translates printer commands to dots on paper, they let the printer driver do all the hard work. You'll never get one of those going, the interface is proprietary and undocumented.

然后是廉价的激光和喷墨打印机的海洋。它们通常根本没有定义明确的接口。打印机内部没有处理器将打印机命令转换为纸上的点,而是让打印机驱动程序完成所有繁重的工作。你永远不会得到其中一个,界面是专有的并且没有记录。

The printer driver is your friend here. PrintDocument the class to use it. Getting a form feed is easy, just set e.HasMorePages = true and exit the PrintPage event handler. You already saw the StreamPrinter class I linked.

打印机驱动程序是您的朋友。PrintDocument 类来使用它。获取换页很容易,只需设置 e.HasMorePages = true 并退出 PrintPage 事件处理程序。您已经看到了我链接的 StreamPrinter 类。

回答by Mark Ransom

I'm unfamiliar with the TEXTdocument type, but I presume it's just a lowest common denominator "dumb printer" representation. If so, it might recognize a form-feed character, except you've been using the wrong character - it's not 0x12or 0xFF, it's 0x0c. See http://en.wikipedia.org/wiki/Ascii

我不熟悉TEXT文档类型,但我认为它只是最低公分母“哑打印机”表示。如果是的话,它可能会识别换页符,除非你已经使用了错误的字符-这不是0x12或者0xFF,它的0x0c。见http://en.wikipedia.org/wiki/Ascii

回答by Mark Ransom

Since my last answer was no help, lets try the obvious. Have you tried doing EndPagePrinterfollowed by StartPagePrinterwhenever you need a page break?

由于我的最后一个答案没有帮助,让我们尝试一下显而易见的。你有没有试过在需要分页符时EndPagePrinter紧跟其后StartPagePrinter

If that still doesn't work you may need to do it the hard way, using GDI. The stack looks just slightly different from the one you're using:

如果这仍然不起作用,您可能需要使用 GDI 以艰难的方式来完成。堆栈看起来与您使用的堆栈略有不同:

  • CreateDC
  • CreateFont
  • SelectObject
  • StartDoc
    • StartPage
      • TextOut
    • EndPage
  • EndDoc
  • DeleteDC
  • CreateDC
  • CreateFont
  • SelectObject
  • StartDoc
    • StartPage
      • TextOut
    • EndPage
  • EndDoc
  • DeleteDC

You'll be required to manage a font and place the text on the page yourself at each line position.

您将需要管理字体并将文本自己放置在页面上的每一行位置。