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

Posted

技术标签:

【中文标题】如何将打印机驱动程序转换为可以生成包含要发送到打印机的字节的打印机文件的独立控制台应用程序?【英文标题】: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? 【发布时间】:2011-02-11 04:43:06 【问题描述】:

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

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

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


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


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

【问题讨论】:

文件格式是什么,是基于文本的数据文件吗? @Stobor。关闭:“鉴于文件系统中的这个 Visio 文件,我如何以编程方式打印它,并捕获本应发送到打印机的字节?”。 @Thorbjørn:是的,我跳过了细节,但我就是这么读的。嗯...您所追求的比您预期的要困难,而不是因为打印机驱动程序的东西...您还需要能够阅读和理解 Visio 文件格式的东西...文件不正常传递给打印机驱动程序 - Visio 将文件呈现为标准的中间格式,然后打印机驱动程序将其结果转换为您要捕获的打印机的字节...... Stobor,在这种情况下,我可以接受“当用户将任何文件打印到此特定 Windows 打印机时,然后自动捕获本应发送到打印机的字节”。 @Thorbjørn:在您对 Oleg 的回复中,您提到您正在使用 AFP 打印机进行打印。对 AFP 打印文件以及文本和图像的提取有一些经验。没有包装打印机,但处理了文件。更新了我的答案和经验 【参考方案1】:

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

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

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

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

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

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

对于简单文档的打印,您可以使用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)。

这个解决方案看起来不像编写打印机驱动程序组件或模拟打印机驱动程序的假脱机环境那样非常壮观,但它会工作,会安全工作,并且会得到驱动程序制造商的全力支持。

【讨论】:

啊,不知道你可以给它一个文件名:) 谢谢你的提示。 @Oleg。有问题的驱动程序是bit.ly/byiZ8a 提供的 AFP 驱动程序,它显然会创建 MO:DCA-P 输出。我相信实际的驱动程序很老,所以界面可能很简单。 这篇文章看起来是关于这个主题的最完整的答案。我可以编译 Localmon 示例,但不知道如何根据需要更改它。我需要创建驱动程序(或监视器......这里的行仍然有点模糊)来生成 PostScript 文件并将其发送到服务器。我找到了创建打印机端口的代码,但这似乎只是故事的一半。是否有任何资源详细说明创建 INF、所需的 dll 和监视驱动程序的端口监视器需要做什么?【参考方案2】:

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

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

【讨论】:

我想了解更多关于这种方法的信息。如果有人有实际经验,请创建一个新答案。 @Thorbjørn。如果您从microsoft.com/whdc/DevTools/WDK/WDKpkg.mspx 安装 Windows Driver Kit (WDK) 7.1.0,您将在目录 C:\WinDDK\7600.16385.1\src\print\genprint 中找到示例打印处理器的示例。您可以在msdn.microsoft.com/en-us/library/ff563807%28v=VS.85%29.aspx 中找到文档。另请参阅 msdn.microsoft.com/en-us/library/ff561035%28v=VS.85%29.aspx 以了解打印机架构。【参考方案3】:

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

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

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

【讨论】:

感谢您使用 SnowBound 进行更新。我也发现了这一点,发现他们的定价不太适合“从小做起”的方法。因此提出了这个问题。 @Thorbjørn:是的,我同意他们的定价不太适合大众市场。我希望他们能改变这一点,尤其是运行时费用。 @Kb,实际上是相反的。我想创建 AFP 文档 - 不使用它们。【参考方案4】:

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

您的 Windows 系统上有一个特殊的打印机驱动程序,它被配置为打印到一个文件中。 您喜欢有一个简单的批处理程序,可以为该打印机驱动程序提供一些东西以输出二进制文件。 您有一个工具链,可以在其中进一步处理此文件。

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

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

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

更新

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

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

一些入门示例也可以在 MSDN 中找到,名称为 overview 或更准确地说是 here。

但是事先说一下:这不是一件容易或简单的任务,而且付出的努力是相当大的。也许尝试通过已经给定的批次或简单的应用程序(使用AutoIt 编写)来操作您的特殊驱动程序的驱动程序设置,也可以通过(自动)与驱动程序的设置进行交互来解决您的问题。

【讨论】:

这对于编写打印过程的脚本非常有用(而不是用户必须推送打印),但不处理捕获(这是现在的关键部分)。 但我还是不明白你喜欢拍什么。 我想捕获打印机驱动程序生成的字节,这些字节将被发送到打印机。 关于“这实际上很难”。我知道情况可能是这样,但现在我有兴趣亲自看看有多困难。感谢您直接指向 MSDN。【参考方案5】:

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

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

【讨论】:

【参考方案6】:

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

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

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

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

【讨论】:

【参考方案7】:

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

您通过操作系统打印。

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

【讨论】:

了解问题是提出解决方案的最佳第一步。推断意图的能力是一大优势。无论哪种方式,您的回答都不会对对话产生任何积极影响。

以上是关于如何将打印机驱动程序转换为可以生成包含要发送到打印机的字节的打印机文件的独立控制台应用程序?的主要内容,如果未能解决你的问题,请参考以下文章

如何将word,excel转换成pdf格式

怎样将word,excel文件转换为PDF文件

如何在 macOS 上使用 python 将图片发送到打印机

如何将Echarts的图表导出到PDF

Windows打印体系结构之打印驱动框架

将 UIScrollView 发送到打印机