windows 如何将打印机驱动程序转换为独立的控制台应用程序,该应用程序可以生成包含要发送到打印机的字节的打印机文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2693133/
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 14:19:47  来源:igfitidea点击:

How to convert a printer driver to a stand-alone console application which can generate a printer file containing the bytes to be sent to the printer?

c#windowsvisual-studiosdkprinting

提问by Thorbj?rn Ravn Andersen

I have a situation where the onlyway to generate a certain datafile is to print it manually to FILE: under Windows and save it in a file for further processing.

我有一种情况,生成某个数据文件的唯一方法是手动将其打印到 FILE: 在 Windows 下并将其保存在文件中以供进一步处理。

I would really like to have a small stand-alone program which embeds this binary printer driver so I can run it from a batch file and have it generate that binary file for me, as we can then fully automate the "save file in Visio, 'print' it and upload it to the final destination and trigger a remote test".

我真的很想拥有一个嵌入这个二进制打印机驱动程序的小型独立程序,这样我就可以从批处理文件中运行它并让它为我生成那个二进制文件,因为我们可以完全自动化“在 Visio 中保存文件, '打印'它并将其上传到最终目的地并触发远程测试”。

Is this possible with a suitable Windows SDK? I am a Java programmer, so I do not know Visual Studio and the possibilities with MSDN - yet! - but I'd appreciate pointers.

这可以通过合适的 Windows SDK 实现吗?我是一名 Java 程序员,所以我不知道 Visual Studio 和 MSDN 的可能性 - 还没有!- 但我很感激指针。



EDIT: I have the installation files for that printer driver, both 32 and 64 bit. Older versions may include a 16 bit driver.

编辑:我有该打印机驱动程序的安装文件,包括 32 位和 64 位。旧版本可能包含 16 位驱动程序。



EDIT: The "print to FILE:" functionality is just what was recommended by the documentation. I have played a little bit with using the LPR-protocol to see what it can do. I'd still prefer the "invoke small binary" approach.

编辑:“打印到文件:”功能正是文档所推荐的。我已经使用 LPR 协议玩了一点,看看它可以做什么。我仍然更喜欢“调用小二进制”方法。

采纳答案by Oleg

The general problem which you formulate is difficult to solve. Mostly a printer driver consists from some well known components like Print Monitor, Print Processor etc. which are well documented in Windows Driver Kit http://msdn.microsoft.com/en-us/library/ff560885%28v=VS.85%29.aspx. Some years ago I wrote a Print Monitor. It worked many years at a customer. So I know exactly what I writing about. A Print Monitor is nothing more as a DLL with well documented functions. The same is about most other printer components. Those DLLs will be loaded and called from Spooler. If you have a modern printer driver it has no components which run in kernel mode. So one can load most of DLLs from which consist every printer driver and call corresponding function.

你提出的一般问题很难解决。大多数打印机驱动程序由一些众所周知的组件组成,如打印监视器、打印处理器等,这些组件在 Windows 驱动程序工具包中有详细记录http://msdn.microsoft.com/en-us/library/ff560885%28v=VS.85% 29.aspx。几年前我写了一个打印监视器。它在一个客户身上工作了很多年。所以我确切地知道我在写什么。打印监视器只不过是一个具有详细记录功能的 DLL。大多数其他打印机组件也是如此。这些 DLL 将从 Spooler 加载和调用。如果您有现代打印机驱动程序,它没有在内核模式下运行的组件。这样就可以加载大部分的DLL,其中包含每个打印机驱动程序并调用相应的函数

You are interesting for using one concert printer driver. So the first what one should do is to examine howthis driver is implemented. If you find out which component do the job which you need, you will be probably able to load this DLL in your process and produce output which you need. It is possible that you post an URL where I could download this driver?

您对使用一个 Concert 打印机驱动程序很感兴趣。所以第一个应该做的是检查这个驱动程序是如何实现的。如果您找出哪个组件完成您需要的工作,您可能能够在您的过程中加载这个 DLL 并生成您需要的输出。您可以发布一个可以下载此驱动程序的 URL 吗?

UPDATED: I though a little more about your requirements. It seems to me you can goes with the way suggested by developer of the printer driver. If the driver can print to a local port FILE, then it can print in anyprinter port. So you can give src of a Port Monitor Server driver from C:\WinDDK\7600.16385.1\src\print\monitors\localmon (see also http://msdn.microsoft.com/en-us/library/ff556478%28v=VS.85%29.aspx, http://msdn.microsoft.com/en-us/library/ff549405%28v=VS.85%29.aspxand http://msdn.microsoft.com/en-us/library/ff563806%28v=VS.85%29.aspx). (I is a windows 32/64 DLL, not a real driver) and makes small modification. Instead of saving results to a file you can dispatch the results to your application. It will be work with 100% without any tricks. If you will have some problem to understand localmonI can give you some tips. It is really not complex. The main changes which you have to do is to modify LcmStartDocPortLcmWritePortLcmReadPortLcmEndDocPortfunctions from localmon.c. Some easy thing which is distinguish Port DLL from a typical DLL, that instead of exporting all DLL's functions it export only one InitializePrintMonitor2with pointers to all other functions.

更新:我想更多关于你的要求。在我看来,您可以按照打印机驱动程序开发人员建议的方式进行操作。如果驱动程序可以打印到本地端口 FILE,那么它可以在任何打印机端口打印。因此,您可以从 C:\WinDDK\7600.16385.1\src\print\monitors\localmon 提供端口监视器服务器驱动程序的 src(另请参见http://msdn.microsoft.com/en-us/library/ff556478%28v =VS.85%29.aspxhttp://msdn.microsoft.com/en-us/library/ff549405%28v=VS.85%29.aspxhttp://msdn.microsoft.com/en-us /library/ff563806%28v=VS.85%29.aspx)。(我是一个 windows 32/64 DLL,不是一个真正的驱动程序)并做了一些小的修改。您可以将结果发送到您的应用程序,而不是将结果保存到文件中。它将在没有任何技巧的情况下 100% 工作。如果您在理解localmon 时遇到问题,我可以给您一些提示。其实并不复杂。您必须做的主要更改是修改localmon.c 中的LcmStartDocPortLcmWritePortLcmReadPortLcmEndDocPort函数。一些简单的事情是将端口 DLL 与典型的 DLL 区分开来,它不是导出所有 DLL 的函数,而是仅导出一个带有指向所有其他函数的指针。InitializePrintMonitor2

UPDATED 2: One more tip for usage of "Local Port" monitor. If goes in printer configuration, then choose "Add Port...", select "Local Port" and click "New Port..." you can type any file name like "C:\temp\my.bin". Then all what you print through a printer will be printed in this file without any user iteration. The name can be anywin32 file name (UNC names or Named pipes are also allowed). With this way you can realize some scenarios without any programming with DDK.

更新 2:关于使用“本地端口”监视器的另一个提示。如果进入打印机配置,则选择“添加端口...”,选择“本地端口”并单击“新端口...”,您可以键入任何文件名,例如“C:\temp\my.bin”。然后,您通过打印机打印的所有内容都将打印在此文件中,而无需任何用户迭代。该名称可以是任何win32 文件名(也允许使用 UNC 名称或命名管道)。通过这种方式,您可以在不使用 DDK 进行任何编程的情况下实现一些场景。

UPDATED 3: I looked at the printer driver from different sides and looked one more time in the API in DDK. Now I want recommend you to choose the easiest way, and the way which will be full supported from the driver manufacturer. I suggest following:

更新 3:我从不同方面查看了打印机驱动程序,并在 DDK 中的 API 中又看了一遍。现在我想推荐您选择最简单的方式,并且驱动程序制造商将全力支持的方式。我建议如下:

You install a printer with the driver which you need and choose as the output port a Local Portwith a fixed file name (see Update 2). I named here the destination filename as C:\TEMP\Output.afp. So you receive exactly the same situation like recommend you driver manufacturer. Fixed file name is absolutelythe same as FILE:port. So if you print to the printer you receive in Output.afpfile in the C:\TEMPdirectory. To be sure the end of writing you can use ReadDirectoryChangesWor FindNextChangeNotification/ FindFirstChangeNotificationfunctions with dwNotifyFilterequal to FILE_NOTIFY_CHANGE_LAST_WRITE. Then you receive notification after last write-time of the file. It means after the end of writing and after FileCloseand after the cache is sufficiently flushed. So the file Output.afpis not locked and you can really safe read the results.

您安装带有所需驱动程序的打印机,并选择具有固定文件名的本地端口作为输出端口(请参阅更新 2)。我在这里将目标文件名命名为C:\TEMP\Output.afp。因此,您会收到与推荐您的驱动程序制造商完全相同的情况。固定的文件名是完全一样的FILE:端口。因此,如果您打印到打印机,您会收到C:\TEMP目录中的Output.afp文件。为确保写入结束,您可以使用或/函数与等于. 然后您会在最后一次写入文件后收到通知。这意味着在写作结束之后和之后ReadDirectoryChangesWFindNextChangeNotificationFindFirstChangeNotificationdwNotifyFilterFILE_NOTIFY_CHANGE_LAST_WRITEFileClose并在缓存充分刷新后。所以文件Output.afp没有被锁定,你可以真正安全地读取结果。

For printing of simple documents you can use WritePrinterfunction (see http://msdn.microsoft.com/en-us/library/dd162959%28VS.85%29.aspxand remark in the documentation http://msdn.microsoft.com/en-us/library/dd145226%28VS.85%29.aspx). Writing of complex files with bitmaps, color and different fonts you have to use typical GDI API like one this in Windows (see http://msdn.microsoft.com/en-us/library/dd162865%28v=VS.85%29.aspx).

对于简单文档的打印,您可以使用WritePrinter功能(参见http://msdn.microsoft.com/en-us/library/dd162959%28VS.85%29.aspx并在文档http://msdn.microsoft.com 中备注/en-us/library/dd145226%28VS.85%29.aspx)。编写带有位图、颜色和不同字体的复杂文件,您必须在 Windows 中使用典型的 GDI API(参见http://msdn.microsoft.com/en-us/library/dd162865%28v=VS.85%29 .aspx)。

This solution looks not very spectacular like writing a printer driver component or a simulation of spooler environment for printer driver, but it will work, will safe work and will be full supported from the driver manufacturer.

该解决方案看起来不像编写打印机驱动程序组件或为打印机驱动程序模拟假脱机程序环境那样引人注目,但它可以工作,安全工作,并且将得到驱动程序制造商的全力支持。

回答by 500 - Internal Server Error

(It's been 10 years since I did anything like this, but I don't think the overall concepts have changed all that much:)

(我已经有 10 年没有做这样的事情了,但我认为整体概念并没有发生太大变化:)

What you want to do is implement a custom print processor. A print processor is the piece of code that takes the output that the printer driver generates and transports it to the output device. Print processors are implemented as regular user-mode DLLs. You should be able to find everything you need, including samples, in the Windows DDK.

您想要做的是实现自定义打印处理器。打印处理器是一段代码,它获取打印机驱动程序生成的输出并将其传输到输出设备。打印处理器是作为常规用户模式 ​​DLL 实现的。您应该能够在 Windows DDK 中找到您需要的一切,包括示例。

回答by Kb.

A while ago we made a commercial application which captured print streams from any windows application and converted the result to XML and tiff images
We did make a prototype with the DDK, but ended up buying a SDK for the print capturing
The SDK was from BlackIce. Although it wasn′t a free SDK, the distribution of the runtimes were royalty free.

不久前,我们制作了一个商业应用程序,它从任何 Windows 应用程序捕获打印流并将结果转换为 XML 和 tiff 图像
我们确实使用 DDK 制作了原型,但最终购买了用于打印捕获
的 SDK 。该 SDK 来自BlackIce。虽然它不是免费的 SDK,但运行时的分发是免版税的。

Implementation was done with Visual C (unmanaged) and VB6. The printer driver had to be installed on the server/PC that drove the printing process.
I remember that the tricky part was to control the printer settings in runtime (keep the tiffs compressed, output directory for the files, paper size:A4 or Letter and other settings that were defined in the DEVMODEprint control structure).

实现是用 Visual C(非托管)和 VB6 完成的。打印机驱动程序必须安装在驱动打印过程的服务器/PC 上。
我记得棘手的部分是在运行时控制打印机设置(保持 tiffs 压缩、文件的输出目录、纸张大小:A4 或 Letter 以及在DEVMODE打印控制结构中定义的其他设置)。

UPDATE:(Your comment to @Oleg about MO:DCA P triggered my memory. Although it is not about a printer driver...)
For our commercial product, we also had to make a customization to convert MO:DCA (AFP) documents to tiffs and XML.
This SDK had to be able to extract both images and ascii text to enable later conversions
Conversion where then made in batch from AFP documents in one folder to XML and tiffs.
We chose to convert the AFP file after it had been printed (not during print).
The SDK is SnowBound RasterMasterand is available in different flavours (we used the Windows API with ActiveX, and I see now that it is available for Java)
So if your requirement is to convert an AFP document to someting else (extract images and extract ascii text) you could try out the software from SnowBound. Make sure you also get the Optional Featureto be able to extract ASCII text from the MO DCA documents.
This software SDK is more expensive, but it did the job.
They offer a trial version here.

更新:(你对@Oleg 的关于 MO:DCA P 的评论触发了我的记忆。虽然它不是关于打印机驱动程序......)
对于我们的商业产品,我们还必须进行自定义以转换 MO:DCA (AFP) 文档到 tiffs 和 XML。
该 SDK 必须能够提取图像和 ascii 文本,以支持稍后的转换
,然后将一个文件夹中的 AFP 文档批量转换为 XML 和 tiff。
我们选择在打印后(而不是在打印期间)转换 AFP 文件。
SDK 是SnowBound RasterMaster并且有不同的版本(我们使用 Windows API 和 ActiveX,现在我看到它可用于Java
因此,如果您的要求是将 AFP 文档转换为其他内容(提取图像和提取 ascii 文本),您可以尝试使用 SnowBound 的软件。确保您还获得了能够从 MO DCA 文档中提取 ASCII 文本的可选功能
这个软件 SDK 更贵,但它完成了这项工作。
他们在这里提供试用版。

回答by Oliver

At the moment i have one missing link in your explanation, so let me rephrase what i understood:

目前我在你的解释中缺少一个链接,所以让我重新表述我的理解:

  • You have a special printer driver on your windows system, that is configured to print into a file.
  • You like to have a simple batch program that can give something to this printer driver to output a binary file.
  • You have a toolchain where this file can be further processed.
  • 您的 Windows 系统上有一个特殊的打印机驱动程序,它被配置为打印到文件中。
  • 你喜欢有一个简单的批处理程序,它可以给这个打印机驱动程序一些东西来输出一个二进制文件。
  • 您有一个可以进一步处理此文件的工具链。

Now my missing part is, what do you want to give to your little batch script, so that it produces your binary file? Do you have a Visio file which should be automatically printed through this driver?

现在我缺少的部分是,你想给你的小批处理脚本什么,以便它生成你的二进制文件?您是否有应该通过此驱动程序自动打印的 Visio 文件?

If yes, you should take a look into this little batch script. It is able to take any file with a registered file extension and send it to the default printer with its default settings. By using these settingsyou are able to change the printer settings within your windows system from a batch file to make your special driver the default one and putting the output into a file.

如果是,你应该看看这个小批处理脚本。它能够获取具有注册文件扩展名的任何文件,并将其发送到具有默认设置的默认打印机。通过使用这些设置,您可以从批处理文件更改 Windows 系统中的打印机设置,使您的特殊驱动程序成为默认驱动程序并将输出放入文件中。

So if i understood you correctly i didn't had the complete solution but i think a good starting point to accomplish your task.

因此,如果我理解正确的话,我没有完整的解决方案,但我认为这是完成任务的一个很好的起点。

Update

更新

Ok, after reading your comment, i fully understood what you like to achieve. To get this to work you have to follow Per Larsens advice to write your own driver with the windows ddk (or to be more precise the Windows Driver Kit [WDK]) and encapsulate the already existing driver.

好的,阅读您的评论后,我完全理解您想要实现的目标。为了让它工作,你必须遵循 Per Larsens 的建议,用 windows ddk 编写你自己的驱动程序(或者更准确地说是Windows Driver Kit [WDK])并封装已经存在的驱动程序。

So in short and simple: Your driver signs up as new printer driver. When it is called it gets all the raw bytes from the application. Passes it into the driver that can generate your datafile. Get the output from that driver back and do with it whatever you like.

简而言之:您的驱动程序注册为新的打印机驱动程序。当它被调用时,它从应用程序中获取所有原始字节。将其传递到可以生成数据文件的驱动程序中。取回该驱动程序的输出,然后随心所欲地处理它。

Some samples to get started can also be found in MSDN as overviewor more precisely here.

一些入门示例也可以在 MSDN 中作为概述或更准确地在此处找到

But just to say it right beforehand: This is not an easy or simple task and the effort is quite high. Maybe trying to manipulate the driver settings of your special driver through the already given batches or a simple application (written with AutoIt) can also solve your problem, by just interacting (automatically) with the settings of the driver.

但是提前说一句:这不是一件容易的事,也不是一件容易的事,而且工作量很大。也许尝试通过已经给定的批处理或简单的应用程序(用AutoIt编写)来操纵您的特殊驱动程序的驱动程序设置也可以解决您的问题,只需(自动)与驱动程序的设置交互。

回答by Stobor

I can live with "When a user prints any file to this particular Windows printer, then automatically capture the bytes that would have been sent to the printer".

我可以忍受“当用户将任何文件打印到此特定的 Windows 打印机时,然后自动捕获本应发送到打印机的字节”。

In that case, you want something like RedMon, which redirects the bytes which would have gone to the printer into the input for another program.

在这种情况下,您需要像RedMon这样的东西,它将本来会进入打印机的字节重定向到另一个程序的输入中。

回答by Eric

Just to reiterate, probably the simplest capture method is using a new Local Port configured as a filename. You can to monitor the output file as previously discussed to catch the output.

重申一下,可能最简单的捕获方法是使用配置为文件名的新本地端口。您可以像前面讨论的那样监视输出文件以捕获输出。

Otherwise, you want to write your own port monitor - not a printer driver or a print processor. All a port monitor does is receive the already rendered data from the printer driver, and sends it to the output device. So writing your own port monitor will allow you to go in and change the output port associated with the existing printer driver to be your own output port, and your port monitor can simply write the data to a file, probably one with a unique filename in a dedicated directory.

否则,您需要编写自己的端口监视器——而不是打印机驱动程序或打印处理器。端口监视器所做的就是从打印机驱动程序接收已经渲染的数据,并将其发送到输出设备。因此,编写您自己的端口监视器将允许您进入并将与现有打印机驱动程序关联的输出端口更改为您自己的输出端口,并且您的端口监视器可以简单地将数据写入一个文件,可能是一个具有唯一文件名的文件专用目录。

Printer drivers are far too complicated for what you want to do, and while a print processor could also capture the output data, you'd probably get entangled in some scantily documented system issues you won't want to have to figure out.

打印机驱动程序对于您想要做的事情来说太复杂了,虽然打印处理器也可以捕获输出数据,但您可能会陷入一些您不想弄清楚的文档不足的系统问题中。

The LocalMon sample in the Windows Driver Kit is THE starting point for writing a port monitor. However, it manages all the system local ports and is quite a bit more complex than you need. In fact, much of it is just likely to confuse you. I'd recommend you start with LocalMon, and compare it to the Redmon source, which is much simpler because it manages a dedicated port. Beware that the Redmon source was taken from localmon long ago and appears to have a few bugs, so use Redmon as a reference and pare back the LocalMon code to what's needed to just write the output to a file.

Windows 驱动程序工具包中的 LocalMon 示例是编写端口监视器的起点。但是,它管理所有系统本地端口,并且比您需要的要复杂得多。事实上,其中大部分内容可能会让您感到困惑。我建议您从 LocalMon 开始,并将其与 Redmon 源进行比较,后者更简单,因为它管理一个专用端口。请注意,Redmon 源很久以前取自 localmon 并且似乎有一些错误,因此使用 Redmon 作为参考并将 LocalMon 代码缩减为仅将输出写入文件所需的内容。

回答by Mesh

You don't embed drivers in executables- drivers are for the operating system to communicate with the hardware.

您不会在可执行文件中嵌入驱动程序 - 驱动程序用于操作系统与硬件进行通信。

You print via the Operating system.

您通过操作系统打印。

Your 'batch' needs to select the correct printer, and print...

您的“批次”需要选择正确的打印机,然后打印...