实例介绍
讲解如何开发虚拟打印机的文档,有原理有实践,图文并茂,一共17页,百度上要5个下载券
pplication A GDI YES EMF Is Output Format EMF? Print Processor DLL NO RAW data stream Printer Graphics DLl Print Spooler Printer Interface dll Language Monitor DLL Port Monitor dll Kernel-Mode Port Driver Stack PRINTER 图1-1打印体系结构图 在进行打印机驱动程序开发之前,首先需要明确的是:打印机驱动程序仅仅 是 Windows打印流程屮的一个屮间环节。一个打印机驱动程序是对一种特定打印 机提供了·个图形函数集的动态链接库(DL),它所提供的接山函数可以将与设 备无关的输岀信息转变为与设备相关的输出信息(指令和数据流)。为了能够充分 理解打印机驱动程序在一个实际打印作业中的地位与功能,从而很好的完成其设 计与开发,对 Windows整个打印流程有一个系统的分析是非常必要的。卜面的流 程图(图1-2)给出的便是从一个应用程序发出打印请求开始,到本地的打印提供 者将假脱杋文件写到磁盘,然后该假脱杋文件将在合适的吋间被解析成具体的指 令和数据,最后由本地端口监视器将解析过的数据流通过它所控制的端口发送到 与之相连的打印机并最终完成打印的完整过程。 打印应用程序 打印假脱机系统5 CreateD创建设备上下文 打印请求处理器发送打印请求 本地打印提供者 图形设备接口GD调用4 相应的打印机驱动程序 一判断打印作业7, 打印机驱动程序量 是否直接打印? 打印数据存盘 打印接口DLL 8 Start Doc启动打印线程 打印图形DLL 9 ReadPrinter激活本地打印提供者 10 WritePrinter激活打印监视器 内核端口驱动程序 通信端口(举例) 语言监视器 USB囗LP口coM口 t12 13 端口监视器 打印机硬件设备 Enddoc打印作业完成 图1-2 windows打印流程图 卜面步驟详细描述整个打印流程: 1:应用程序创建一个设备上下文并在其上绘制一个对象,然后调用GDI 中相应的函数接凵向与此设备上下文相对应的打印机发出个打印请求。 2:GDI调用相应的打印机驱动程序来处理打印请求 3:打印驱动程序创建一个打印作业,并调用GDI函数将处理结果返回GDI。 4:GDI调用打卬假脱机系统。 5:打印假脱机调用打印请求处理器以便将打印作业发送到应用程序指定的 打印机上 6:打印请求处理器将打印作业发送到本地打印提供者(目标打印机在本地) 或者网络打印打印提供者(目标打印机在网络中) 7:如果打印作业的类型是非直接打印,那么本地打印提供者就将打印作业以 原始假脱机文件的格式存放在磁盘上,并且将后来的打印片段不断的附加到假脱 机文件中,直到应用程序调用了 EndDoc函数终止一个打印作业为止。以上第一到 第七步可能是重复多次来产生一个完整的假脱机文件 8:本地打印提供者启动一个后台线程,打印主线程根据对打印假脱机子系统 资源的监视情况,选定一个最佳的时刻触发假脱机文件的解析过程。此时,打印主 线程将调用 StartOr函数启动打印处理器中的一个线程来开始解析工作 9:打印机处理器线程调用 ReadPrinter调用来激活本地打印提供者以便从 磁盘读取前面所生成的打印假脱机文件。 10:打印处理器同时还调用了 WritePrinter函数来激活打印机作业的语言 监视器以便将数据通过物理端凵发送到相应的打印机上。 11:打印语言监视器调用打印端口监视器的功能来给打印机发送数据。 I2:打印端口监视器监测物理端口,通过物理端口给打印机发送数据 13:端口监视器调用内核端口驱动程序完成物理端口与打印机间的通信。 14:完成打印作业后解析线程终止。 1.2虚拟打印机 虚拟打卬机同真实打卬杋一样,安装完毕,打开“控制面板”中的“打印机 和传真”,会看到所安裝的虚拟打印机,可以像使用一台打印机一样使用它们 鼠标双击将其打开,可以对其“打印首选项”和“属性”进行修改,从而设定是 否共享、可使用时间、是否后台打印和优先级,以及纸张大小、版式安排等。它 同样能截获所有 Windows程序的打印操作,或模拟打印效果,或完成某一特殊 功能。有些软件自带虚拟打印机,有些则是专门的虚拟打印机,利用这些虚拟打 印机,可以帮助我们完成很多特殊的任务。虚拟打印机的打印文件是以某种特定 的格式保存在电脑上 打印机是比较重要的输岀设备,但有些时候,我们并不需要把东西真实地打 印出来,而只是想通过打印预览功能来看看输出的效果。但如果计算机中没有安 装打印机,那么打印预览也不能实现,就不能够观看到打印的效果,这给我们这 些没有打印机的朋友们带来∫很多不便。 但在实际应用中我们更经常的可能会遇到这样的问题:我们有打印机,但是 我们所使用的软件只提供给我们“打印”的功能,我们在打卬之前不能预览。如 果我们不想浪费纸、墨,一次又一次试验调用效果,那么解决办法只有一个:安 装一个虚拟打印机。 简单地说,虚拟打印机就是在你的机器中添加一个虚拟的打印机让你可以使 用它来打印。我说的这个虚拟打印机可不同于你以往添加的像 hp laserJet2000 那些只能用于打印预览的“虚拟打印机”:你可以用它来打印文件,即使软件并 不支持打印预览的功能!使用的方法就和你使用正常的打印机一样 当然,你不可能用虚拟打印机把文件直接打印到纸上(否则打印机卖给谁), 用虚拟打印机打印的结果是硬榀上的一个文件,你可以用专门的阅读器打开那个 文件以查看打印的效果。 虚拟打印机实际上并不存在的,只是为了工作需要而安装的打印机。 虚拟打印机有三种定制方法 l、驱动层( Driver)一种。修改 Render plug-in,对渲染绘制过程进行特 姝的处理。 2、打印假脱机( slower)层两种。 (1)自定义打印处理器( PrintProcessor),般是修改DD中 genprint 的例子。将自定义的代码加入到 Print DocumentonPrintProcessor中。 (2)在监视( Monitor)层。作者采用的方法,在后面介绍中读者会看到。 打卬假脱札(sυ lover)层两种的两种实现方法驱动层一般都用微软统一驱 动程序( Lnidry)。通过打印测试页可以了解安装的打印驱动的各个方面:驱动 程序、端凵等。也可以通过打印机的属性查看。作者就是在监视器层进行的。 第二章准备工作 工欲善其事,必先利其器。同样在开发时也要选择合适的集成环境。作者在 虚拟打印开发任务中先后用过多款开发工具。如何选择合适的集成环境,相信没 有唯一的答案。每个人都有自己偏好和标准。在这里作者会介绍自己的开发工具。 希望大家在以后的开发中能得到启发和帮助。下面,作者一一介绍下工具 2.1安装软件 NSIS( Nullsoft Scriptable Install system)是一个开源的 Windows系 统下安装程序制作程序。它提供了安装、卸载、系统设置、文件解压缩等功能 这如其名字所指出的那样,NSIS是通过它的脚本语言来描述安装程序的行为和 逻辑的。NSIS的脚本语言和通常的编程语言有类似的结构和语法,但它是为安 装程序这类应用所设计的。在虚拟打印开发中,它创建安装包,它里面调用了 windows自带的功能安装INF,完成虚拟打印机的安装任务。NSIS软件下载地址 shF:http://www.flightycn/htm1/book/2010020718.htm1) 2.2集成开发工具 以前很多人一直都是用VS2008+ DDKWizard+ WinDbg来进行驱动程序 的开发调试的,使用⑩ DKWizard来搭配调试环境,在VS2008下还算方便,因 为不需要自己去设置一些什么包含文件和源代码路径之类的就可以直接编译驱 动程序源码,安装好 DDKWizard后在Vs2008中就会自动出现个开发驱动程 序的项日框架,就跟选择创建 Winform应用程序一样的,创建好DK项日后也 是可以直接在VS2008下编译的,所以在开发上方便,但是在调试上的话,就麻 烦了,在 WinDbg中有大堆东西要设置,在虚拟机上也要设置些命令。 但是在使用 DDKWizard+WS2008进行驱动开发时,是不能够直接通过 VS2008来调试的,而一般都是在 Windbg中设置好符号文件的路径以及源代码 的路径,然后再驱动程序的源代码中嵌入一些汇编代码,当然这些汇编代码只是 简单的用来实现一个中断,从而在 WinDbg调试器中会生成一个断点。这样调试 起来速度慢,也不好控制,所以有时候觉得在做丌发的吋候,在调试上花去的吋 间太多了,会不爽。 在本项目中,将要介绍的是一个开源项目 VirtualDDK,通过这个开源项目 即可以很好的实现在ws2010以及VS2008下直接调试驱动程序,同时对于 Virtualdub的环境搭配也是很简单的,下面提供的链接直接上一些图片以及 些注解来说明,由于文章存在大量的截图,所以读者只要按着截图来做基木上都 可以成功的。VS2010+ VMware+DDK(安装参 Ul:http://techird.blog163.com/blog/static/12156403620111123852415 68/) Deⅴ-c+开发工具不是必须的,读者可自行选择。下载地址: http://pan.baiducom/share/link?sharcid-524654&uk-3241605080) 2.3端口监视器 由于作者采用第三种方法来进行虚拟打印开发,因此作者要重点介绍 Monitor层方面的知识点 2.3.1打印监视器介绍 在第一章曾经提到了打印监视器的概念。打印监视器主要负贲把打卬数据流 从打印假脱机传送到合适的端口驱动程序。打印监视器分为语言监视器和端口监 视器两种。其中语言监视器的主要作用是支持打印机的双向通讯,监视打印机的 状态,获取并处理一些事件;端口监视器的主要作用是管理配置打印端口并控制 打印机和物理端口之间的通讯。在打印机驱动系统体系中,这两个监视器都是可 替换的,即开发人员可以根据需要编写自己的语言和端口监视器。比如编写语言 监视器提供对打卬机双向通讯的支持等。 在基于NT的操作系统下,用户所看到的打印机视图其实是一个打印队列, 个或者多个物理打印机设备可以与该队列相连。端口就是打印队列和一个打印 设备之间的物理连接。打印机驱动程序中端口监视器模块负责和端口相关的操作。 何一个端口监视器支持一种或者多种端口类型的实例。当需要给打印机添加新类 型的端凵实例时,就需要提供新的端凵监视器。打印假脱机通过调用 AddPrinier 函数来把一个端口指派到端口监视器中。在打印过程中,各种类型的打印设备都 被列在打印队列中,打印假脱机把打印作业发送到第一个可用的端口。如果端口 监视器指小这个端口正忙或者发生错误,打印假脱机把打印作业重新提交到打印 队列,并指定该端口监视器支持的另外一个端口发送打印数据。 2.3.2端凵监视器构成 个端口监视器由一些用户模式下的动态链接库组成。它的职责有两方面, 一是负责管理和配置服务器端的和打印机硬件连接的打印端口;二是为运行在用 户模式卜的打印假脱机和运行在内核模式卜的可以直接访问FO硬件端口的端口 驱动之间建立通信链接。 对 Windows20和以后的操作系统而言,每个端凵监视器都被分为两个 动态链接库 1: Port Monitor ul dll 端口监视器的接口动态链接库包括功能性的用户接口。这个动态链接库存放 在客户系统的 System32文件夹中并且在打印机的客户端系统上执行 2: PortMonitor ServerDll 端口监视器的服务动态链接库包括端口的通信功能并且在打印机的服务器 端系统上执行。 以上两个动杰链接库之间通过打印假脱机的 CdATa函数通信。需要说明的 是:虽然端口监视器被分成了两个动态链接库,但是在具体编写端口监视器的过 程中,却可以有两种方法:一是为新编写的端口服务动态链接库编写全新的接口 动态链接库,而这样的接口动态链接库提供给用户的管理界面只能对新添加的端 口类型迣行管理;第二种方法是使用原来的接口动态链接库,这种情况下,新添加 的端口类型会直接添加到原来的接口动态链接库的打印队列中,只需要为新添加 的端口提供一个可以修改配置信息的弹出对话框即可。这两种方法在功能的实现 方面没有区別。第一种方法可能复杂一些,但是界面简单整洁。下面两幅图描述 了打印监视器在整个打印流程中所处的位置。其中图2-1左侧的是有语言监视器 的情况,图右侧的是没有语言监视器的情况 Print processor Print processor Language monitor Port moinitor Port monitor Port driver Port driver Printers Printers 图21打印处理机到打印机的数据流程图 2.3.3数据通信模块 当一个打印监视器进行了正确的初始化并且正确添加了打印端口之后,监视 器就可以开始与打印机物理端口的数据通信工作。下面介绍数据通信模垬的核心 工作。 每一个打印作业都会首先被打印假脱机划归到某个语言或者端口监视器的 StartDocPort和 EndDocPort函数中。这两个函数也就成了完成一个打印作 业的开始和结束数。这里的开始和结束,仅仅是针对一个打印作业的,并不是指 整个打印流程。所以在 StartDocPort函数之前和 EndDocport之后,假脱机还会 调用其他的函数来完成整个打印流程。下面图2-2展示了完成·个打印作业的基 本流程.如图所示,要完成一个打印作业需要经过以下几个步骤: 1:打开端口 打印假脱札首先要调用端口监视器的 OpenpOrt数,该函数的主要功能是打 开一个端口并返回一个标识该端口的句柄。在假脱机的后续调用中,该句炳将作 为其他处理函数的输入参数使用。针对某些端凵, Open0rt函数还可以在打印假 8 打印假脱机 OpenPore打开端口 StartDoc Porto Create Filed创建文件句柄 向打印机写还是 从打印机读数据? WritePorto □ WriteR写数据 ReadPorto ReadFile读数据 GetPrinter Porto evicelocontrolo传送数据 EndDoc Porto 打印队列中是苦Y 还有作业待打印? N ClosePorto关闭端口 图2-2端口监视器数据通信流程图 脱机读端口或写端口之前完成一些初始化的工作,比如对那些攴持可修改超时值 的端口而言,每次端口超时值的设定就由 Openport函数完成。当一个端口被正确 打开之后,该端口就可以被写入信息。打印假脱机在同一时问只允许一条可用的 通信链路和一个打卬端口连接。因此当假脱机在端口监视器中调用了 OpenPort 函数之后,在关闭这个端口之前,它不会再次尝试去打开这个端口。而在端口被关 闭之前,假脱机可以发送多个打印作业到这个端口。 2:开始打印作业 个端口被打开之后,打印假脱机接着调用 startDocPort函数来开始一个打 印作业。 StartDocPort函数主要通过调用 WindowsaPi提供的 Createfile函数 来建立一条和内核端口驱动之间的数据链接。 3:读/写端口 岀数据链接建立之后,打印假脱机可以根据需要进行双向操作,一种是向打 印机写数据,这种情况下打印假脱机先调用端口监视器的 Writeport函数然后会 多次调用 WindowsAPI提供的 Writefile函数来向内核端山驱动发送数据;另种 是从打印机读数据,此时打印假脱机先调用端口监视器的 RcadPort函数然后再 调用 WindowsAPI提供的 ReadFile函数从内核端口驱动那里读取硬件信息、。 4:数据传送 不管是向打印机写数据还是从打印机读数据,打印假脱机后面都会调用 GetPrinterDataFromPort函数,该函数的主要功能是通过调用 WindowsaPi提供 的 Deviceiocontrol函数来最终实现打印驱动程序和内核端口驱动之间的数据 传输 5:结束打印作业 以上操作完成之后,打印假脱机调用 EndDoc port函数来结束一个打印作业 该函数的主要作用是释放 Createfile函数建立的数据链接和 StartDocPort函数 中中请的所有资源。 EndDoc port函数和 StartDocport函数总是成对出现的。 6:循环检测 当按照上述过程完成了一个打印作业之后,打印假脱机查看和这个端口相连 的打印队列中还有没有其他的文件需要打印。如果有,则程序返回到 StartDocPort函数重复执行上述过程,如果没有,打印假脱机就关闭这个端口。 7:关闭端凵 端口监视器的 Closeport函数用来关闭端口。该函数的主要作用是释放在 0 penPort函数中申请的所有系统资源。 ClosePort函数和 OpenPort函数也总是 成对出现。当与一个端口相关的打印队列中所有的打印作业都完成之后,或者由 于其他情况需要退岀该端口的时候, Closeport函数就被打印假脱机调用 第三章开发 3.1项目源代码 项目源代码可自行选择,网上有很多代码可供下载,比如大家常用的就是在 DDK(WIN2000)里面有一个例子 genprint,它是一个打印机驱动,只要我们在 这个例子的代码中进行修改就可以实现自己想要的功能。但是木人采用的是 ImagePrinter的源代码。下载虚拟打印源代码 Imageprinter,下载地 tIl:http://code-industry.net/downloads.php 3.2配置开发环境 3.2.Ⅰ若选用VS2010开发,参数配置较繁琐,可参见: http://jingyan.baiducom/articlc/b2c186c8cac112c46cf6ffb8.htm1 3.2.2若选用Devc++配置简单,在此不复述。 3.3编译调试 开发并编译源代码,生成 import.d1l文件 开发时候会出现各种bug,希望大家有效地利用MSDN和论坛来解决各种问 第四章安装虚拟打印机 4.1安装厂商和打印机 4.1.1安装前系统配置 安装之前,电脑里面没有端∏ Imageprinter port和厂商 ode- industry及其打印札 ImagePrinter的驱动程序,如卜图4-1到图4-2: 【实例截图】
【核心代码】
标签:
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论