定制微软的打印机驱动程序(二)
2010年11月10日
转载:http://fengpeng.net.blog.163.com/blog/static/28227481200912481824831/#
7.2.4定制的DDI函数
一个绘制插件可以分出一些DDI函数,提供这些函数的定制实现。为提供定制的函数,绘制插件 必须实现IPrintOemUni::EnableDriver或IPrintOemPS::EnableDriver方法,这两个方法被填写在 DRVENABLEDDATA结构并具有每一个函数的地址。
一个绘制插件可以分出一个DDI函数,但只是在该函数是由Unidrv或Pscript驱动程序定义时。对这些函数的列表,参考DDK中包括的IPrintOemUni::EnableDriver或IPrintOemPS::EnableDriver。
如果提供一个特殊的定制的分出函数,该函数优先于驱动程序的等同DDI函数。当设计一个定制的分出函数,可以有下面的选项:
分出函数可以完全在内部处理DDI操作。
分出函数可以回调打印机驱动程序等同的DDI函数。
通过调用驱动程序的DDI函数,分出函数可以执行预处理或后处理的函数参数,但是仍然允许驱 动程序实际执行DDI操作。对绘制插件的IPrintOemUni::EnableDriver或IPrintOemPS::EnableDriver方 法的一个参数是DRVENABLEDDATA 结构包含的指向驱动程序DDI函数的指针。如果想回调这些函数,应当存储这些结构的内容。
对来说,也许有必要提供一个定制的PDEV结构。可以通过每一个分出函数作为输入接收的 SURFOBJ结构指针,从一个DDI的分出函数中引用这一结构。特定地,SURFOBJ结构的dhpdev成员指向一个DEVOBJ结构,并且 DEVOBJ结构的pdevOEM成员指向定制的PDEV结构。
7.2.5定制的PDEV结构
绘制插件通过实现下面的方法来支持私有的PDEV结构:
IPrintOemUni::EnablePDEV或IPrintOemPS::EnablePDEV
IPrintOemUni::DisablePDEV或IPrintOemPS::DisablePDEV
IPrintOemUni::ResetPDEV或IPrintOemPS::ResetPDEV
PDEV结构是一个一般的项目,它指向一个私有的,本地定义的结构并由定义它的模块来使用。通常,它用于存储物理设备特征。每一个打印机驱动程序,以及每一个绘制插件,定义它自已的PDEV结构。没有被定义的全局范围的“PDEV”类型的结构。
7.2.6从绘制插件存取驱动程序设置
一个绘制插件可以获取打印机特性的当前状态及其他内部驱动程序信息。下面的COM接口方法在微软打印机驱动程序内实现在方法可以被绘制插件来调用:
由Unidrv实现的方法:
IPrintOemDriverUni::DrvGetDriverSetting
IPrintOemDriverUni::DrvGetStandardVariable
IPrintOemDriverUni::DrvGetGPDData
由Pscript实现的方法:
IPrintOemDriverPS::DrvGetDriverSetting
7.2.7特定Pscript的定制绘制
Pscirpt允许特定设备的定制代码注入Postscript命令到Pscript发送给打印机设备的数据流中。如果想提供这种类型的定制代码,必须提供一个绘制插件以实现IPrintOemPS::Command方法。
Pscript在打印机作业数据流的很多点调用IPrintOemPS::Command方法。函数的参数之一指定了一个表示当前在数据流中点的位置的索引值。函数的每次调用,它可以检验索引的值并提供另外的数据流或者不提供。
7.2.8特定Unidrv的定制绘制
下面的主题提供了关于Unidrv允许绘制插件执行的操作的类型的信息:
7.2.8.1定制的色彩格式
7.2.8.2定制的过渡调色
7.2.8.3定制的数据流压缩
7.2.8.4定制的数据流过滤
7.2.8.5定制的字体管理
7.2.8.6动态产生的打印机命令
7.2.8.7处理设备管理的表面
7.2.8.1定制的色彩格式
Unidrv支持好几种色彩格式,这些色彩格式在微软统一打印机驱动程序一章的处理色彩格式 中列出。对这些格式来说,Unidrv在向打印机发送之前,转换GDI位图到正确的格式。如果打印机接受Unidrv不支持的格式,必须提供一个交换插件 以实现IPrintOemUni::ImageProcessing方法。
如果实现IPrintOemUni::ImageProcessing方法,并且用户已经选 择了Unidrv不能处理的色彩格式(色彩模式选项),这样,每次一个缓冲区中的GDI位图数据准备打印时,Unidrv调用该方法并传寄位图的地址作为 一个输入的参数。该方法必须转换位图到专用的格式,如果需要,将执行定制的过渡调色操作,并调用 IPrintOemUni::DrvWriteSpoolBuf方法以发送被修改了的位图到打印机假脱机。它也必须调用 IPrintOemUni::DrvXMoveTo及IPrintOemUni::DrvYMoveTo方法以修改光标的位置。更多的关于这些操作的信 息,参考关于IPrintOemUni::ImageProcessing的描述。
如果一个绘制插件实现IPrintOemUni::ImageProcessing,它也能实现IPrintOemUni::MemoryUsage方法。
7.2.8.2定制的过渡调色
如在微软统一打印机驱动程序一章中的用Unidrv过渡调色部分所解释的,Unidrv允许GDI执行过渡调色操作,也可以由打印机设备、或由定制的驱动程序代码来执行。本部分解释了怎样在定制的驱动程序代码中执行过渡调色的操作。
有两种类型可用的定制:
定制的过渡调色模式
定制的过渡调色方法
定制的过渡调色模式
过渡调色模式可以在资源DLL中指定,或者它们可以由一个实现 IPrintOemUni::HalftonePattern方法的绘制插件来产生。如在微软统一驱动程序一章用Unidrv过渡调色中所解释的,实现 IPrintOemUni::HalftonePattern有两个原因:
1.定制的模式是在一个资源DLL中提供的,并且该模式是加密的。
2.定制的模式不是在资源DLL中提供的,相反,是由IPrintOemUni::HalftonePattern产生的。
IPrintOemUni::HalftonePattern方法的目的是给Unidrv返回一个可用的取中色模式,它按次序传递给GDI。该方法可以解码一个以加密格式存储于资源DLL中的模式,或者它可以在执行过程中产生一个模式。
如果实现IPrintOemUni::HalftonePattern,GPD文件必须在每 一个取中色的的*Option条目中包括一个*HTCallbackID属性,这一个*Option条目是用于使用哪一种定制的模式时指定过渡调色的方 法。更多的关于这一属性的信息,可参考第4章微软统一打印机驱动程序的取中色间特性的选项属性部分。
定制的过渡调色方法
对一个使用Unidrv的打印机来说,提供实现定制的过渡调色的方法的代码需要下面的步骤:
提供一个实现IPrintOemUni::ImageProcessing方法的绘制插件。
在打印机的GPD文件中包括一个过渡调色的*Feature条目,用每一个包含*Option的条目表示一个过渡调色方法。(也可以包括标准的或定制的过渡调色方法)
IPrintOemUni::ImageProcessing方法作为输入收到GDI位图,该方法必须执行过渡调色操作,基于当前选择的过渡调色方法,并返回结果位图到Unidrv。
如果一个绘制插件这现了IPrintOemUni::ImageProcessing,它也可以实现IPrintOemUni::MemoryUsage。
更多的关于过渡调色的信息,参考第4章微软统一打印机驱动程序中的用Unidrv过渡调色部分的内容。
7.2.8.3定制的数据流压缩
Unidrv允许数据压缩操作由定制的代码来执行。
为执行定制的压缩操作,必须做下面的内容:
提供一个实现IPrintOemUni::Compression方法的绘制插件。
在GPD文件中包括一个CmdEnableOEMComp命令条目。更多的关于这一命令的信息,参考第4章微软统一打印机驱动程序中的光栅数据压缩命令部分的内容。
IPrintOemUni::Compression方法作为输入收到扫描行数据。该方法必 须压缩数据并将结果返回到Unidrv。CmdEnableOEMComp命令条目指定必须发送到打印机的命令,从而使打印机可以接收这些压缩数据的命 令。对要发送到打印机的每一个扫描行,Unidrv调用IPrintOemUni::Compression以压缩这些扫描行,然后,如果这是唯一可用的 压缩方法,Unidrv在压缩数据之后,向打印机发送由CmdEnableOEMComp命令条目指定的命令。
如果打印机小驱动程序包括允许Unidrv支持的压缩方法的GPD条目,则Unidrv将对每一个扫描行数据试用每一种压缩算法并选择产生最好结果的压缩算法。更多的关于Unidrv的压缩能力的信息,参考第4章微软统一打印机驱动程序中的压缩光栅数据部分的内容。
在同一时间,只能有一种定制压缩算法被允许。
7.2.8.4定制的数据流过滤
Unidrv允许定制的代码执行最终图像数据的后处理,并在其被送至假脱机之前。这样的处理包括删除相邻的点或者其他任何类型的Unidrv不能提供的数据过滤操作。
为执行最终的图像数据的后处理,必须提供一个实现IPrintOemUni::FilterGraphics方法的绘制插件。
IPrintOemUni::FilterGraphics方法接收扫描行数据作为输入,该 方法必须处理数据并将数据通过调用IPrintOemUni::DrvWriterSpoolBuf发送到假脱机。如果 IPrintOemUni::FilterGraphics方法被实现,Unidrv不支持假脱打印机数据。相反,它发送每一个数据块到 IPrintOemUni::FilterGraphics方法。
7.2.8.5定制的字体管理
Unidrv对PCL打印机支持下载的软字体作为位图或TrueType字体的轮廓。对设备 字体,Unidrv支持PCL、CAPSL以及PPDS打印机命令格式。对其他格式,定制的字体管理代码必须被在一个绘制插件中提供,下面的一系列 IPrintOemUni方法,可以被实现。
IPrintOemUni::DownloadFontHeader
用于从Unidrv获得软字体的头信息并将信息下载到打印机
IPrintOemUni::DownloadCharGlyph
用于给打印机下载一个软件字体的字符集
IPrintOemUni::OutputCharStr
用于控制字母的打印
IPrintOemUni::SendFontCmd
用于修改一个打印机的设备字体选择命令,如果必要,然后就发送它到打印机。
IPrintOemUni::TextOutAsBitmap
用于创建文本字符串的位图图像
IPrintOemUni::TTDownloadMethod
用于指定Unidrv在向打印机发送专用的软件字体时应当使用的符号格式。
Unidrv提供了一个回调函数,UNIFONTOBJ_ GetInfo,那个绘制的插件可以调用获得字体或字符的信息。
对设备字体,字体描述必须被以Unidrv字体规格文件(.ufm文件)及翻译表文件(.gtt文件)的格式来提供。
对Cartridge字体,可以在资源DLL中提供字体描述并在GPD文件中用Cartridge字体条目来指定。字体描述可以Unidrv字体格式文件(.uff文件)的形式提供。
对可下载的PCL软件字,字体描述必须以Unidrv字体格式文件(.uff文件)来提供。
Unidrv字体规格文件
打印机支持的每一种设备字体必须用Unidrv字体规格文件(.ufm文件)来表 示。.ufm文件是一个用在DDK的打印机驱动程序函数及结构一章中的Unidrv字体规格中描述的结构组建的二进制文件。.ufm中的第一个结构是 UNIFM_HDR,它包含有到文件的其他结构的偏移量。
更多的关于创建.ufm文件的信息,可参考第四章中的微软小驱动程序开发工具部分的内容。
Unidrv也支持.ifi文件,是一种为Windows NT 4.0创建的字体规格文件。
字符翻译表文件
打印机支持的每一种设备字体文件必须用一个字符翻译表文件(.gtt文件)来表示,一 个.gtt文件是一个用在Unidrv字符翻译表一章中的打印机驱动程序函数及结构部分中描述的结组构建的二进制文件。.gtt中的的第一个结构是 UNI_GLYPHSETDATA,它包含有到文件的其他结构的偏移量。
更多的关于创建.gtt文件信息,参考第4章中的微软小驱动程序开发工具部分的内容。
Unidrv也支持为Windows NT 4.0创建的字符翻译文件,它用RLE压缩并具有一个.rle的扩展名。
Unidrv字体格式文件
对那些没有在GPD文件中用字体Cartridge条目指定的Cartridge字体来说,该字体必须以Unidrv字体格式文件(.uff文件)来描述。另外,下载的PCL软字体必须用.uff文件来指定。
一个.uff二进制文件是用下面的结构组建起来的。
Unidrv字体格式结构。它定义了内容及.uff文件的结构。
Unidrv字体规格结构。它定义了每种字体的规格。
Unidrv字符翻译表结构。它定义了字体所用的字符集。
另外,对下载的PCL软字体来说,二进制数据存储于.ufm文件中。
创建.uff文件是商家提供的字体安装软件的责任。Unidrv读取一个打印机的.uff文件以获得字体及字符信息。字体安装程序应当在字体被增加或删除时修改.uff文件内容。更多的关于创建字体安装程序的信息,参考定制的Unidrv的字体安装程序部分的内容。
打印机的所有.uff文件必须被保存在%SystemRoot%\System32 \Spool\Drivers\Unifont目录中。为关联单独的.uff文件与专用的打印机,安装软件必须调用SetPrinterData函数(在 平台的SDK文档中有描述)以在每一个打印机的注册关键字中创建注册值,并指明每一个值的维持者。
注册表值名称及类型 值定义 维持者
“ExternalFontFile”
REG_SZ
一个.uff文件的文件名,指定当前被安装的字体。字体可以被下载或者包含在一个Cartridge中
字体安装程序
“ExtFontCartFile”
REG_SZ
一个.uff文件的文件名,指定所有所有包含在字体Cartridge中为“ExtFontCartNames”列出的所有字体
字体安装程序
“ExtFontCartNames”
REG_MULTI_SZ
所有的可以被安装在一个打印机上的Cartridge字体
字体安装程序
“FontCart”
REG_MULTI_SZ
当前安装在一个打印机上的所有的字体Cartridge
Unidrv用户接口
在给一个打印机增加了字体Cartridge之后,系统管理者将运行字体安装程序,它负责从 由“ExtFontCartFile”指定的.uff文件中拷贝字体描述到由“ExternalFontFile”指定的.uff文件中。同样,字体安装 程序必须删除.uff中在一个Cartridge字体被删除时由“ExtFontCartFile”指定的字体描述。
7.2.8.6动态产生的打印机命令
每一次在一个GPD文件中为一个Unidrv的小驱动程序指定打印机命令时,可以采用下面两种方法中的一种:
把命令字符串放于GPD文件中
当将命令字符串放于GPD文件中时,Unidrv在适当的时间发送命令到打印机假脱机。这些命令字符串可以包括标准变量,这些变量在Unidrv发送命令之前都会进行求值。
提供一个回调函数
如果提供一个回调函数,Unidrv在它发送命令时调用该函数,该函数主要负责发送命令到打印机假脱机。这就使得可以包括那些动态产生的命令字符串并然后将它送往打印机。
为设置一个命令字符串在GPD文件中,需要在命令的*Command条目中包括一个*Cmd属性。
为提供动态产生的命令字符串的代码,必须做下面的事情:
提供一个绘制的插件以实现IPrintOemUni::CommandCallback方法。
包括一个*CallbackID命令属性,并包括一个可选的*Param属性,在GPD文件的命令的*Command条目中。
当Unidrv准备发布一个打印机命令,它检查小驱动程序的数据库以确定是否该命令已经用一 个*Cmd属性或一个*CallbackID属性指定。在前一种情况下,Unidrv发送命令字符串到打印假脱机;在后一种情况,Unidrv调用 IPrintOemUni::CommandCallback方法,传递*CallbackID及*Params值作为输入参数。
打印机命令被在第4章微软打印机驱动程序中讨论过。更多的关于*Cmd、*Callback及*Params属性的信息,同样参考第4章中的命令属性部分。
7.2.8.7处理设备管理的表面
当Unidrv绘制器打印页面图像时,它用GDI管理的绘制表面。所有的图像被作为位图绘制。对设备提供能力不能在此种情形下采用,如绘制向量等。可以对一个设备管理的绘制表面提供定制的驱动程序支持。为支持一个设备管理的表面,必须提供一个插件以实现下面的内容:
对所有的Unidrv支持的DDI绘制函数的一套分出函数。必须能分出下面的这些函数
DrvAlphaBlend
DrvBitBlt
DrvCopyBits
DrvDitherColor
DrvFillPath
DrvGradientFill
DrvLintTo
DrvPlgBlt
DrvRealizeBrush
DrvStretchBlt
DrvStretchBltROP
DrvStrokeAndFillPath
DrvStrokePath
DrvTextOut
DrvTransparentBlt
IPrintOemUni::EnableDriver方法,它用于向Unidrv提供指向DDI分出函数的指针。
IPrintOemUni::DriverDMS方法,它通知Unidrv一个设备管理的表面被应用,并指定对这一表面哪一个被定义的分出函数将被用到。
当绘制一个设备管理的表面时,分出函数不能回调GDI的以Eng-为前缀的支持服务。但是,它们可以创建一个临时的位图表面,并传递那个表面的句柄到以Eng-为前缀的函数(参考第3章中的绘制一个打印作业部分)。
一个打印作业要被绘制的每一次,都要调用IPrintOemUni::DriverDMS方法,因此绘制插件可以指定对每个作业绘制表面的类型(GDI管理或设备管理)。基于所需要的用户接口上的可选择的选项或者是提供一个用户接口插件以进行表面选择。
在设备管理的表面上绘制文本
绘制插件必须分出Unidrv的DrvTextOut函数(以及其他DDI绘制函数)。为一个设备管理的表面创建文本并包括在以下四个函数之间的相互作用:
Unidrv的DrvTextOut函数
绘制插件的DrvTextOut分出函数
Unidrv的IPrintOemUni::DrvUniTextOut方法
绘制插件的IPrintOemUni::TextOutAsBitmap方法
步骤包括在设备管理的表面上显示文本,如下:
1.GDI调用Unidrv的DrvTextOut函数。
2.Unidrv调用绘制插件的DrvTextOut分出函数。
3.分出函数发送命令到设备以指定文本刷、旋转及裁剪区域。
4.分出函数调用Unidrv的IPrintOemUni::DrvUniTextOut方法,它试图使用可下载的字体到输出文本。这一方法也处理基于字符的剪贴。
5.如果IPrintOemUni::DrvUniTextOut不能用可下载的字体(由于该字体不能获得或者旋转),它调用插件的IPrintOemUni::TextOutAsBitmap方法,它当绘制一个位图来绘制文本。
6.在IPrintOemUni::DrvUniTextOut返回后,DrvTextOut分出函数必须绘制下划线及中横线,基于由DrvTextOut函数的prclExtra参数指定的距形,并使用矢量命令(如果支持)。
7.3实现打印机驱动程序的COM接口
这一部分解释了怎样基于DDK提供的示例代码构建一个插件。也解释了用于打印机驱动程序及插件通讯的调用顺序。提供了下面的主题:
打印机驱动程序的接口标识符
创建插件
从打印机驱动程序存取插件接口
从插件存取打印机驱动程序接口
7.3.1 打印机驱动程序的接口标识符
在prcomoem.h中定义了一套GUID结构,在这些GUID结构中的每一个都是用于打印机驱动程序(Unidrv及Pscript)及插件之间通讯的一个COM接口的接口标识符。
对Windows 2000,定义了下面的GUID:
IDD_IPrintOemUI
IDD_IPrintOemDriverUI
IDD_IPrintOemUni
IDD_IPrintOemDriverUni
IDD_IPrintOemPS
IDD_IPrintOemDriverPS
每一个GUID标识一个接口的版本。对Windows 2000,每一个接口只有一个版本,随着未来的一些版本的操作系统的发布,也许需要去修改一个或多个接口。如果定义了一个新版本的接口,一个新的GUID将被加入到这一列表中。
用户接口插件及绘制插件必须鉴别它们支持的接口版本。打印机驱动程序(Unidrv或 Pscript)将调用一个插件的IUnknown::QueryInterface方法(在平台的SDK文档中有描述),指定一个接口标识符作为输入。 如果插件支持专用的版本,方法必须返回一个接口的指针并返回有S_OK的状态值。否则,它必须返回E_NOINTERFACE。驱动程序用一个对最新版本 的接口标识符开始并继续使用以前版本的标识符调用QueryInterface,直到方法返回S_OK或者驱动程序穷举完列表中的版本标识符为止。
同样,Unidrv及Pscript为IPrintOemDriver、 IPrintOemDriverUni及IPrintOemDriverPS COM接口提供IUnknown::QueryInterface方法。插件则应当调用合适的接口的QueryInterface方法以确定驱动程序的支 持接口版本并接收一个接口指针。
7.3.2创建插件
所有的打印机驱动程序插件必须定义DllMain,DllGetClassObject及 DllCanUnloadNow函数。他们也必须实现IclassFactory COM接口及IPrintOemUI,IPrintOemUni或IPrintOemPS COM接口中之一。
当创建一个用户接口插件或者一个绘制插件,必须使代码基于这一DDK提供的UI插件的实例或绘制插件的实例。
定义一个DllMain函数(在平台的SDK文档中有描述),这是所有Win32 DLL的入口点。
定义并导出一个DllGetClassObject函数(在平台的SDK文档中有描述)。
打印机驱动程序调用这一函数以获得对插件实现的IClassFactory接口(在平台的SDK文档中有描述)的存取。当驱动程序调用DllGetClassObject,它指定下面一类的标识符(在prcomoem.h中定义)
CLSID_OEMNI――对UI插件
CLSID_OEMRENDER――对绘制插件
驱动程序也指定IID_IClassFactory的接口标识符。
DllGetClassObject函数必须创建一个它的IclassFactory接口的实例并为它返回一个指针,如在示例代码所示。
实现IClassFactory COM接口
IClassFactory接口的CreateInstance方法应当创建一个下面的COM接口的插件实现的实例:
IPrintOemUI COM接口
IPrintOemUni COM接口
IPrintOemPS COM接口
CreateInstance方法的一个输入是接口的标识符。驱动程序用 IID_Iunknown的一个接口标识符调用CreateInstance,意思是CreateInstance方法必须为被创建的实例的 IUnknown接口(在平台的SDK文档中描述)返回一个指针,如在示例代码中所示。
实现IPrintOemUI,IPrintOemUni或者IPrintOemPS COM接口中的一种,包括标准的IUnknown接口,如在例子代码中所示。
由驱动程序调用的第一个被实现的方法是IUnknown接口的QueryInterface方法(在平台SDK文档中有描述)。这一方法为打印机以一个输入参数收到一个接口的标识符,驱动程序调用该方法以确定插件支持那一个版本的接口并收到指向支持接口的指针。
定义并导出DllCanUnloadNow函数(在平台的SDK文档中有描述)。
如果所有被实现的插件的IPrintOemUI,IPrintOemUni或者IPrintOemPS接口的实例已经被发布,DllCanUnloadNow函数必须返回S_OK,返回S_OK意指对驱动程序来说,插件不能被加载。
7.3.3从打印机驱动程序存取插件接口
如果一个UI插件或绘制插件已经被安装,打印机驱动程序(Unidrv或Pscript)将使用下面的调用序列以获取对插件的IPrintOemUI,IPrintOemUni或者IPrintOemPS接口的存取。
1.驱动程序调用LoadLibrary以加载插件的DLL,它引起插件的DllMain函数被调用。
2.驱动程序调用插件的DllGetClassObject函数,它返回一个指向插件的IDlassFactory接口的指针。
3.驱动程序调用IClassFactory接口的CreateInstance方法,指定 一个IID_Unknown的接口标识符,它引起方法创建插件的IPrintOemUI,IPrintOemUni或者IPrintOemPS接口的实例 并返回指向实例的IUnknown接口的指针。
4.驱动程序调用IUnknown接口的QueryInterface方法以确定插件支持IPrintOemUI,IPrintOemUni或者IPrintOemPS接口的那一版本,并接收一个指向支持接口的指针。
5.驱动程序调用插件的接口的PublishDriverInterface方法以使得驱动程序的IPrintOemUI,IPrintOemUni或者IPrintOemPS接口对插件可用。
6.如果插件已经实现了IPrintOemUni接口,驱动程序调用IPrintOemUni::GetImplementedMethod以确定哪一个接口方法已经被实现。
7.3.4从插件存取打印机驱动程序接口
如果一个插件能够调用属于驱动程序的IPrintOemUI,IPrintOemUni或者IPrintOemPS接口,它必须从驱动程序获得一个指针,如下:
1. 插件必须实现IPrintOemUI,IPrintOemUni或者IPrintOemPS接口的PublishDriverInterface方法。
2. 当驱动程序(Unidrv或Pscript)调用插件的PublishDriverInterface方法,它提供一个指向IPrintOemUI,IPrintOemUni或者IPrintOemPS实例的IUnknow接口。
3. 插件必须使用IUnknown接口指针去调用Iunknown::QueryInterface,指定表示是期望的版本的 IPrintOemUI,IPrintOemUni或者IPrintOemPS接口的接口标识符(更多的信息,可参考打印机驱动程序的接口标识符部分)。
4. 如果插件指定一个接口的标识符表示一个驱动程序支持的接口,QueryInterface返回一个指向IPrintOemUI,IPrintOemUni 或者IPrintOemPS接口的指针。注意,驱动程序在返回对插件的接口指针之前调用接口的AddRef方法(在平台的SDK文档中描述)。插件应当保 存该指针,这样它可以在以后被用于调用接口方法。
5. 当IPrintOemUI,IPrintOemUni或者IPrintOemPS接口指针不再需要时,插件必须调用接口的Release方法(在平台的SDK文档中有描述)。
7.4安装定制的驱动程序组件
当为微软打印机驱动程序提供定制的组件时,必须为组件的安装提供一个.ini文件(如果打印机不被ntprint.inf支持,必须提供一个printer.inf文件)。
.ini文件必须包含一个OEMFiles部分,在这一部分,每一个定制的组件是用下面之一的条目来描述的:
OEMDriverFilen
命名一个绘制插件
OEMConfigFilen
命名一个用户接口插件
这时,n指定了安装程序安装文件的顺序,对所有类型的插件来说,为n指定的数字必须是连续的,从1开始。
例如,如果提供两个绘制插件及一个用户接口插件,打印机模型是XYZ,.ini文件必须如下所示:
[OEMFiles]
OEMDriverFile1=XYZDRV1.DLL
OEMConfigFile1=XYZUI1.DLL
OEMDriverFile2=XYZDRV2.DLL
在等号(=)之前或之后,都不允许有空格,文件名不能名含路径说明。
在例子中,指定了两个绘制插件,基于为OEMDriverFilen指定的n值。 xyzdrv1.dll在xyzdrv2.dll之前被安装。Unidrv及Pscript驱动程序调用插件,并按其安装的顺序,此后,当一个驱动程序需 要调用DDI分出函数及由这些插件提供的COM方法时,xyzdrv1.dll将在xyzdrv2.dll之前被调用。
.ini文件名应当反映打印机产品名称并且是唯一的以避免在.ini文件中与其他打印机名称 相冲突。注意如果提供一个与Windows NT 4.0后端口(Back-Porting)通信的绘制插件或用户接口插件。.ini文件名必须与.gpd及.ppd文件匹配。(即xyz.ini必须用于 xyz.gpd或xyz.ppd)。这一限制对Windows 2000及以后版本不适用。
一个.ini文件可以包含ANSI或UNICODE文本,但是推荐使用UNICODE文本。在一个.ini文件中,每行以#开始的是注解的内容。
更多的关于.inf及.ini文件的信息,参考Windows 2000驱动程序开发指南中的第一卷,即插即用,电源管理及建立设计指南部分。也可参考第4章微软统一打印机驱动程序中的安装一个Unidrv小驱动程序部分。
7.4.1Unidrv的定制的字体安装程序
对没有在打印机的GPD文件中通过字体Cartridge条目描述的Cartridge字体,需要厂商提供的字体安装程序软件。这些字体需要用Unidrv字体格式文件(.uff文件)来描述,而厂商提供的字体安装程序就负责创建.uff文件。
厂商提供的字体安装程序应当提供对下载的PCL软字体的支持。
下面两种技能为创建定制的安装程序提供:
提供一个用户接口插件
插件必须实现下面的COM接口方法:
IPrintOemUI::FontInstallerDlgProc
IPrintOemUI::UpdateExternalFonts
提供一个单独的执行文件
在字体安装时,可执行文件必须通过调用SetPrinterData(在平台的SDK文档中描述)存储它的名字在注册表中,并为“FontInstaller”关键字指定一个值。
Unidrv用下面的算法定位字体安装程序:
1.如果字体安装程序可执行文件的名字被存储于注册表中,Unidrv不允许系统管理员从打印机的属性表单中选择字体安装程序。相反,管理员必须运行提供的可执行文件。
2.如果一个安装程序执行文件不可用,Unidrv允许从打印机的属性表单中选择字体安装操 作。Unidrv确定是否一个用户接口插件已经被安装。如果是,它的字体安装方法被调用。如果一个用户接口插件没有被安装,或者它的字体安装方法返回了 E_NOTIMPL,则驱动程序使用它自已的容错安装程序。
2010年11月10日
转载:http://fengpeng.net.blog.163.com/blog/static/28227481200912481824831/#
7.2.4定制的DDI函数
一个绘制插件可以分出一些DDI函数,提供这些函数的定制实现。为提供定制的函数,绘制插件 必须实现IPrintOemUni::EnableDriver或IPrintOemPS::EnableDriver方法,这两个方法被填写在 DRVENABLEDDATA结构并具有每一个函数的地址。
一个绘制插件可以分出一个DDI函数,但只是在该函数是由Unidrv或Pscript驱动程序定义时。对这些函数的列表,参考DDK中包括的IPrintOemUni::EnableDriver或IPrintOemPS::EnableDriver。
如果提供一个特殊的定制的分出函数,该函数优先于驱动程序的等同DDI函数。当设计一个定制的分出函数,可以有下面的选项:
分出函数可以完全在内部处理DDI操作。
分出函数可以回调打印机驱动程序等同的DDI函数。
通过调用驱动程序的DDI函数,分出函数可以执行预处理或后处理的函数参数,但是仍然允许驱 动程序实际执行DDI操作。对绘制插件的IPrintOemUni::EnableDriver或IPrintOemPS::EnableDriver方 法的一个参数是DRVENABLEDDATA 结构包含的指向驱动程序DDI函数的指针。如果想回调这些函数,应当存储这些结构的内容。
对来说,也许有必要提供一个定制的PDEV结构。可以通过每一个分出函数作为输入接收的 SURFOBJ结构指针,从一个DDI的分出函数中引用这一结构。特定地,SURFOBJ结构的dhpdev成员指向一个DEVOBJ结构,并且 DEVOBJ结构的pdevOEM成员指向定制的PDEV结构。
7.2.5定制的PDEV结构
绘制插件通过实现下面的方法来支持私有的PDEV结构:
IPrintOemUni::EnablePDEV或IPrintOemPS::EnablePDEV
IPrintOemUni::DisablePDEV或IPrintOemPS::DisablePDEV
IPrintOemUni::ResetPDEV或IPrintOemPS::ResetPDEV
PDEV结构是一个一般的项目,它指向一个私有的,本地定义的结构并由定义它的模块来使用。通常,它用于存储物理设备特征。每一个打印机驱动程序,以及每一个绘制插件,定义它自已的PDEV结构。没有被定义的全局范围的“PDEV”类型的结构。
7.2.6从绘制插件存取驱动程序设置
一个绘制插件可以获取打印机特性的当前状态及其他内部驱动程序信息。下面的COM接口方法在微软打印机驱动程序内实现在方法可以被绘制插件来调用:
由Unidrv实现的方法:
IPrintOemDriverUni::DrvGetDriverSetting
IPrintOemDriverUni::DrvGetStandardVariable
IPrintOemDriverUni::DrvGetGPDData
由Pscript实现的方法:
IPrintOemDriverPS::DrvGetDriverSetting
7.2.7特定Pscript的定制绘制
Pscirpt允许特定设备的定制代码注入Postscript命令到Pscript发送给打印机设备的数据流中。如果想提供这种类型的定制代码,必须提供一个绘制插件以实现IPrintOemPS::Command方法。
Pscript在打印机作业数据流的很多点调用IPrintOemPS::Command方法。函数的参数之一指定了一个表示当前在数据流中点的位置的索引值。函数的每次调用,它可以检验索引的值并提供另外的数据流或者不提供。
7.2.8特定Unidrv的定制绘制
下面的主题提供了关于Unidrv允许绘制插件执行的操作的类型的信息:
7.2.8.1定制的色彩格式
7.2.8.2定制的过渡调色
7.2.8.3定制的数据流压缩
7.2.8.4定制的数据流过滤
7.2.8.5定制的字体管理
7.2.8.6动态产生的打印机命令
7.2.8.7处理设备管理的表面
7.2.8.1定制的色彩格式
Unidrv支持好几种色彩格式,这些色彩格式在微软统一打印机驱动程序一章的处理色彩格式 中列出。对这些格式来说,Unidrv在向打印机发送之前,转换GDI位图到正确的格式。如果打印机接受Unidrv不支持的格式,必须提供一个交换插件 以实现IPrintOemUni::ImageProcessing方法。
如果实现IPrintOemUni::ImageProcessing方法,并且用户已经选 择了Unidrv不能处理的色彩格式(色彩模式选项),这样,每次一个缓冲区中的GDI位图数据准备打印时,Unidrv调用该方法并传寄位图的地址作为 一个输入的参数。该方法必须转换位图到专用的格式,如果需要,将执行定制的过渡调色操作,并调用 IPrintOemUni::DrvWriteSpoolBuf方法以发送被修改了的位图到打印机假脱机。它也必须调用 IPrintOemUni::DrvXMoveTo及IPrintOemUni::DrvYMoveTo方法以修改光标的位置。更多的关于这些操作的信 息,参考关于IPrintOemUni::ImageProcessing的描述。
如果一个绘制插件实现IPrintOemUni::ImageProcessing,它也能实现IPrintOemUni::MemoryUsage方法。
7.2.8.2定制的过渡调色
如在微软统一打印机驱动程序一章中的用Unidrv过渡调色部分所解释的,Unidrv允许GDI执行过渡调色操作,也可以由打印机设备、或由定制的驱动程序代码来执行。本部分解释了怎样在定制的驱动程序代码中执行过渡调色的操作。
有两种类型可用的定制:
定制的过渡调色模式
定制的过渡调色方法
定制的过渡调色模式
过渡调色模式可以在资源DLL中指定,或者它们可以由一个实现 IPrintOemUni::HalftonePattern方法的绘制插件来产生。如在微软统一驱动程序一章用Unidrv过渡调色中所解释的,实现 IPrintOemUni::HalftonePattern有两个原因:
1.定制的模式是在一个资源DLL中提供的,并且该模式是加密的。
2.定制的模式不是在资源DLL中提供的,相反,是由IPrintOemUni::HalftonePattern产生的。
IPrintOemUni::HalftonePattern方法的目的是给Unidrv返回一个可用的取中色模式,它按次序传递给GDI。该方法可以解码一个以加密格式存储于资源DLL中的模式,或者它可以在执行过程中产生一个模式。
如果实现IPrintOemUni::HalftonePattern,GPD文件必须在每 一个取中色的的*Option条目中包括一个*HTCallbackID属性,这一个*Option条目是用于使用哪一种定制的模式时指定过渡调色的方 法。更多的关于这一属性的信息,可参考第4章微软统一打印机驱动程序的取中色间特性的选项属性部分。
定制的过渡调色方法
对一个使用Unidrv的打印机来说,提供实现定制的过渡调色的方法的代码需要下面的步骤:
提供一个实现IPrintOemUni::ImageProcessing方法的绘制插件。
在打印机的GPD文件中包括一个过渡调色的*Feature条目,用每一个包含*Option的条目表示一个过渡调色方法。(也可以包括标准的或定制的过渡调色方法)
IPrintOemUni::ImageProcessing方法作为输入收到GDI位图,该方法必须执行过渡调色操作,基于当前选择的过渡调色方法,并返回结果位图到Unidrv。
如果一个绘制插件这现了IPrintOemUni::ImageProcessing,它也可以实现IPrintOemUni::MemoryUsage。
更多的关于过渡调色的信息,参考第4章微软统一打印机驱动程序中的用Unidrv过渡调色部分的内容。
7.2.8.3定制的数据流压缩
Unidrv允许数据压缩操作由定制的代码来执行。
为执行定制的压缩操作,必须做下面的内容:
提供一个实现IPrintOemUni::Compression方法的绘制插件。
在GPD文件中包括一个CmdEnableOEMComp命令条目。更多的关于这一命令的信息,参考第4章微软统一打印机驱动程序中的光栅数据压缩命令部分的内容。
IPrintOemUni::Compression方法作为输入收到扫描行数据。该方法必 须压缩数据并将结果返回到Unidrv。CmdEnableOEMComp命令条目指定必须发送到打印机的命令,从而使打印机可以接收这些压缩数据的命 令。对要发送到打印机的每一个扫描行,Unidrv调用IPrintOemUni::Compression以压缩这些扫描行,然后,如果这是唯一可用的 压缩方法,Unidrv在压缩数据之后,向打印机发送由CmdEnableOEMComp命令条目指定的命令。
如果打印机小驱动程序包括允许Unidrv支持的压缩方法的GPD条目,则Unidrv将对每一个扫描行数据试用每一种压缩算法并选择产生最好结果的压缩算法。更多的关于Unidrv的压缩能力的信息,参考第4章微软统一打印机驱动程序中的压缩光栅数据部分的内容。
在同一时间,只能有一种定制压缩算法被允许。
7.2.8.4定制的数据流过滤
Unidrv允许定制的代码执行最终图像数据的后处理,并在其被送至假脱机之前。这样的处理包括删除相邻的点或者其他任何类型的Unidrv不能提供的数据过滤操作。
为执行最终的图像数据的后处理,必须提供一个实现IPrintOemUni::FilterGraphics方法的绘制插件。
IPrintOemUni::FilterGraphics方法接收扫描行数据作为输入,该 方法必须处理数据并将数据通过调用IPrintOemUni::DrvWriterSpoolBuf发送到假脱机。如果 IPrintOemUni::FilterGraphics方法被实现,Unidrv不支持假脱打印机数据。相反,它发送每一个数据块到 IPrintOemUni::FilterGraphics方法。
7.2.8.5定制的字体管理
Unidrv对PCL打印机支持下载的软字体作为位图或TrueType字体的轮廓。对设备 字体,Unidrv支持PCL、CAPSL以及PPDS打印机命令格式。对其他格式,定制的字体管理代码必须被在一个绘制插件中提供,下面的一系列 IPrintOemUni方法,可以被实现。
IPrintOemUni::DownloadFontHeader
用于从Unidrv获得软字体的头信息并将信息下载到打印机
IPrintOemUni::DownloadCharGlyph
用于给打印机下载一个软件字体的字符集
IPrintOemUni::OutputCharStr
用于控制字母的打印
IPrintOemUni::SendFontCmd
用于修改一个打印机的设备字体选择命令,如果必要,然后就发送它到打印机。
IPrintOemUni::TextOutAsBitmap
用于创建文本字符串的位图图像
IPrintOemUni::TTDownloadMethod
用于指定Unidrv在向打印机发送专用的软件字体时应当使用的符号格式。
Unidrv提供了一个回调函数,UNIFONTOBJ_ GetInfo,那个绘制的插件可以调用获得字体或字符的信息。
对设备字体,字体描述必须被以Unidrv字体规格文件(.ufm文件)及翻译表文件(.gtt文件)的格式来提供。
对Cartridge字体,可以在资源DLL中提供字体描述并在GPD文件中用Cartridge字体条目来指定。字体描述可以Unidrv字体格式文件(.uff文件)的形式提供。
对可下载的PCL软件字,字体描述必须以Unidrv字体格式文件(.uff文件)来提供。
Unidrv字体规格文件
打印机支持的每一种设备字体必须用Unidrv字体规格文件(.ufm文件)来表 示。.ufm文件是一个用在DDK的打印机驱动程序函数及结构一章中的Unidrv字体规格中描述的结构组建的二进制文件。.ufm中的第一个结构是 UNIFM_HDR,它包含有到文件的其他结构的偏移量。
更多的关于创建.ufm文件的信息,可参考第四章中的微软小驱动程序开发工具部分的内容。
Unidrv也支持.ifi文件,是一种为Windows NT 4.0创建的字体规格文件。
字符翻译表文件
打印机支持的每一种设备字体文件必须用一个字符翻译表文件(.gtt文件)来表示,一 个.gtt文件是一个用在Unidrv字符翻译表一章中的打印机驱动程序函数及结构部分中描述的结组构建的二进制文件。.gtt中的的第一个结构是 UNI_GLYPHSETDATA,它包含有到文件的其他结构的偏移量。
更多的关于创建.gtt文件信息,参考第4章中的微软小驱动程序开发工具部分的内容。
Unidrv也支持为Windows NT 4.0创建的字符翻译文件,它用RLE压缩并具有一个.rle的扩展名。
Unidrv字体格式文件
对那些没有在GPD文件中用字体Cartridge条目指定的Cartridge字体来说,该字体必须以Unidrv字体格式文件(.uff文件)来描述。另外,下载的PCL软字体必须用.uff文件来指定。
一个.uff二进制文件是用下面的结构组建起来的。
Unidrv字体格式结构。它定义了内容及.uff文件的结构。
Unidrv字体规格结构。它定义了每种字体的规格。
Unidrv字符翻译表结构。它定义了字体所用的字符集。
另外,对下载的PCL软字体来说,二进制数据存储于.ufm文件中。
创建.uff文件是商家提供的字体安装软件的责任。Unidrv读取一个打印机的.uff文件以获得字体及字符信息。字体安装程序应当在字体被增加或删除时修改.uff文件内容。更多的关于创建字体安装程序的信息,参考定制的Unidrv的字体安装程序部分的内容。
打印机的所有.uff文件必须被保存在%SystemRoot%\System32 \Spool\Drivers\Unifont目录中。为关联单独的.uff文件与专用的打印机,安装软件必须调用SetPrinterData函数(在 平台的SDK文档中有描述)以在每一个打印机的注册关键字中创建注册值,并指明每一个值的维持者。
注册表值名称及类型 值定义 维持者
“ExternalFontFile”
REG_SZ
一个.uff文件的文件名,指定当前被安装的字体。字体可以被下载或者包含在一个Cartridge中
字体安装程序
“ExtFontCartFile”
REG_SZ
一个.uff文件的文件名,指定所有所有包含在字体Cartridge中为“ExtFontCartNames”列出的所有字体
字体安装程序
“ExtFontCartNames”
REG_MULTI_SZ
所有的可以被安装在一个打印机上的Cartridge字体
字体安装程序
“FontCart”
REG_MULTI_SZ
当前安装在一个打印机上的所有的字体Cartridge
Unidrv用户接口
在给一个打印机增加了字体Cartridge之后,系统管理者将运行字体安装程序,它负责从 由“ExtFontCartFile”指定的.uff文件中拷贝字体描述到由“ExternalFontFile”指定的.uff文件中。同样,字体安装 程序必须删除.uff中在一个Cartridge字体被删除时由“ExtFontCartFile”指定的字体描述。
7.2.8.6动态产生的打印机命令
每一次在一个GPD文件中为一个Unidrv的小驱动程序指定打印机命令时,可以采用下面两种方法中的一种:
把命令字符串放于GPD文件中
当将命令字符串放于GPD文件中时,Unidrv在适当的时间发送命令到打印机假脱机。这些命令字符串可以包括标准变量,这些变量在Unidrv发送命令之前都会进行求值。
提供一个回调函数
如果提供一个回调函数,Unidrv在它发送命令时调用该函数,该函数主要负责发送命令到打印机假脱机。这就使得可以包括那些动态产生的命令字符串并然后将它送往打印机。
为设置一个命令字符串在GPD文件中,需要在命令的*Command条目中包括一个*Cmd属性。
为提供动态产生的命令字符串的代码,必须做下面的事情:
提供一个绘制的插件以实现IPrintOemUni::CommandCallback方法。
包括一个*CallbackID命令属性,并包括一个可选的*Param属性,在GPD文件的命令的*Command条目中。
当Unidrv准备发布一个打印机命令,它检查小驱动程序的数据库以确定是否该命令已经用一 个*Cmd属性或一个*CallbackID属性指定。在前一种情况下,Unidrv发送命令字符串到打印假脱机;在后一种情况,Unidrv调用 IPrintOemUni::CommandCallback方法,传递*CallbackID及*Params值作为输入参数。
打印机命令被在第4章微软打印机驱动程序中讨论过。更多的关于*Cmd、*Callback及*Params属性的信息,同样参考第4章中的命令属性部分。
7.2.8.7处理设备管理的表面
当Unidrv绘制器打印页面图像时,它用GDI管理的绘制表面。所有的图像被作为位图绘制。对设备提供能力不能在此种情形下采用,如绘制向量等。可以对一个设备管理的绘制表面提供定制的驱动程序支持。为支持一个设备管理的表面,必须提供一个插件以实现下面的内容:
对所有的Unidrv支持的DDI绘制函数的一套分出函数。必须能分出下面的这些函数
DrvAlphaBlend
DrvBitBlt
DrvCopyBits
DrvDitherColor
DrvFillPath
DrvGradientFill
DrvLintTo
DrvPlgBlt
DrvRealizeBrush
DrvStretchBlt
DrvStretchBltROP
DrvStrokeAndFillPath
DrvStrokePath
DrvTextOut
DrvTransparentBlt
IPrintOemUni::EnableDriver方法,它用于向Unidrv提供指向DDI分出函数的指针。
IPrintOemUni::DriverDMS方法,它通知Unidrv一个设备管理的表面被应用,并指定对这一表面哪一个被定义的分出函数将被用到。
当绘制一个设备管理的表面时,分出函数不能回调GDI的以Eng-为前缀的支持服务。但是,它们可以创建一个临时的位图表面,并传递那个表面的句柄到以Eng-为前缀的函数(参考第3章中的绘制一个打印作业部分)。
一个打印作业要被绘制的每一次,都要调用IPrintOemUni::DriverDMS方法,因此绘制插件可以指定对每个作业绘制表面的类型(GDI管理或设备管理)。基于所需要的用户接口上的可选择的选项或者是提供一个用户接口插件以进行表面选择。
在设备管理的表面上绘制文本
绘制插件必须分出Unidrv的DrvTextOut函数(以及其他DDI绘制函数)。为一个设备管理的表面创建文本并包括在以下四个函数之间的相互作用:
Unidrv的DrvTextOut函数
绘制插件的DrvTextOut分出函数
Unidrv的IPrintOemUni::DrvUniTextOut方法
绘制插件的IPrintOemUni::TextOutAsBitmap方法
步骤包括在设备管理的表面上显示文本,如下:
1.GDI调用Unidrv的DrvTextOut函数。
2.Unidrv调用绘制插件的DrvTextOut分出函数。
3.分出函数发送命令到设备以指定文本刷、旋转及裁剪区域。
4.分出函数调用Unidrv的IPrintOemUni::DrvUniTextOut方法,它试图使用可下载的字体到输出文本。这一方法也处理基于字符的剪贴。
5.如果IPrintOemUni::DrvUniTextOut不能用可下载的字体(由于该字体不能获得或者旋转),它调用插件的IPrintOemUni::TextOutAsBitmap方法,它当绘制一个位图来绘制文本。
6.在IPrintOemUni::DrvUniTextOut返回后,DrvTextOut分出函数必须绘制下划线及中横线,基于由DrvTextOut函数的prclExtra参数指定的距形,并使用矢量命令(如果支持)。
7.3实现打印机驱动程序的COM接口
这一部分解释了怎样基于DDK提供的示例代码构建一个插件。也解释了用于打印机驱动程序及插件通讯的调用顺序。提供了下面的主题:
打印机驱动程序的接口标识符
创建插件
从打印机驱动程序存取插件接口
从插件存取打印机驱动程序接口
7.3.1 打印机驱动程序的接口标识符
在prcomoem.h中定义了一套GUID结构,在这些GUID结构中的每一个都是用于打印机驱动程序(Unidrv及Pscript)及插件之间通讯的一个COM接口的接口标识符。
对Windows 2000,定义了下面的GUID:
IDD_IPrintOemUI
IDD_IPrintOemDriverUI
IDD_IPrintOemUni
IDD_IPrintOemDriverUni
IDD_IPrintOemPS
IDD_IPrintOemDriverPS
每一个GUID标识一个接口的版本。对Windows 2000,每一个接口只有一个版本,随着未来的一些版本的操作系统的发布,也许需要去修改一个或多个接口。如果定义了一个新版本的接口,一个新的GUID将被加入到这一列表中。
用户接口插件及绘制插件必须鉴别它们支持的接口版本。打印机驱动程序(Unidrv或 Pscript)将调用一个插件的IUnknown::QueryInterface方法(在平台的SDK文档中有描述),指定一个接口标识符作为输入。 如果插件支持专用的版本,方法必须返回一个接口的指针并返回有S_OK的状态值。否则,它必须返回E_NOINTERFACE。驱动程序用一个对最新版本 的接口标识符开始并继续使用以前版本的标识符调用QueryInterface,直到方法返回S_OK或者驱动程序穷举完列表中的版本标识符为止。
同样,Unidrv及Pscript为IPrintOemDriver、 IPrintOemDriverUni及IPrintOemDriverPS COM接口提供IUnknown::QueryInterface方法。插件则应当调用合适的接口的QueryInterface方法以确定驱动程序的支 持接口版本并接收一个接口指针。
7.3.2创建插件
所有的打印机驱动程序插件必须定义DllMain,DllGetClassObject及 DllCanUnloadNow函数。他们也必须实现IclassFactory COM接口及IPrintOemUI,IPrintOemUni或IPrintOemPS COM接口中之一。
当创建一个用户接口插件或者一个绘制插件,必须使代码基于这一DDK提供的UI插件的实例或绘制插件的实例。
定义一个DllMain函数(在平台的SDK文档中有描述),这是所有Win32 DLL的入口点。
定义并导出一个DllGetClassObject函数(在平台的SDK文档中有描述)。
打印机驱动程序调用这一函数以获得对插件实现的IClassFactory接口(在平台的SDK文档中有描述)的存取。当驱动程序调用DllGetClassObject,它指定下面一类的标识符(在prcomoem.h中定义)
CLSID_OEMNI――对UI插件
CLSID_OEMRENDER――对绘制插件
驱动程序也指定IID_IClassFactory的接口标识符。
DllGetClassObject函数必须创建一个它的IclassFactory接口的实例并为它返回一个指针,如在示例代码所示。
实现IClassFactory COM接口
IClassFactory接口的CreateInstance方法应当创建一个下面的COM接口的插件实现的实例:
IPrintOemUI COM接口
IPrintOemUni COM接口
IPrintOemPS COM接口
CreateInstance方法的一个输入是接口的标识符。驱动程序用 IID_Iunknown的一个接口标识符调用CreateInstance,意思是CreateInstance方法必须为被创建的实例的 IUnknown接口(在平台的SDK文档中描述)返回一个指针,如在示例代码中所示。
实现IPrintOemUI,IPrintOemUni或者IPrintOemPS COM接口中的一种,包括标准的IUnknown接口,如在例子代码中所示。
由驱动程序调用的第一个被实现的方法是IUnknown接口的QueryInterface方法(在平台SDK文档中有描述)。这一方法为打印机以一个输入参数收到一个接口的标识符,驱动程序调用该方法以确定插件支持那一个版本的接口并收到指向支持接口的指针。
定义并导出DllCanUnloadNow函数(在平台的SDK文档中有描述)。
如果所有被实现的插件的IPrintOemUI,IPrintOemUni或者IPrintOemPS接口的实例已经被发布,DllCanUnloadNow函数必须返回S_OK,返回S_OK意指对驱动程序来说,插件不能被加载。
7.3.3从打印机驱动程序存取插件接口
如果一个UI插件或绘制插件已经被安装,打印机驱动程序(Unidrv或Pscript)将使用下面的调用序列以获取对插件的IPrintOemUI,IPrintOemUni或者IPrintOemPS接口的存取。
1.驱动程序调用LoadLibrary以加载插件的DLL,它引起插件的DllMain函数被调用。
2.驱动程序调用插件的DllGetClassObject函数,它返回一个指向插件的IDlassFactory接口的指针。
3.驱动程序调用IClassFactory接口的CreateInstance方法,指定 一个IID_Unknown的接口标识符,它引起方法创建插件的IPrintOemUI,IPrintOemUni或者IPrintOemPS接口的实例 并返回指向实例的IUnknown接口的指针。
4.驱动程序调用IUnknown接口的QueryInterface方法以确定插件支持IPrintOemUI,IPrintOemUni或者IPrintOemPS接口的那一版本,并接收一个指向支持接口的指针。
5.驱动程序调用插件的接口的PublishDriverInterface方法以使得驱动程序的IPrintOemUI,IPrintOemUni或者IPrintOemPS接口对插件可用。
6.如果插件已经实现了IPrintOemUni接口,驱动程序调用IPrintOemUni::GetImplementedMethod以确定哪一个接口方法已经被实现。
7.3.4从插件存取打印机驱动程序接口
如果一个插件能够调用属于驱动程序的IPrintOemUI,IPrintOemUni或者IPrintOemPS接口,它必须从驱动程序获得一个指针,如下:
1. 插件必须实现IPrintOemUI,IPrintOemUni或者IPrintOemPS接口的PublishDriverInterface方法。
2. 当驱动程序(Unidrv或Pscript)调用插件的PublishDriverInterface方法,它提供一个指向IPrintOemUI,IPrintOemUni或者IPrintOemPS实例的IUnknow接口。
3. 插件必须使用IUnknown接口指针去调用Iunknown::QueryInterface,指定表示是期望的版本的 IPrintOemUI,IPrintOemUni或者IPrintOemPS接口的接口标识符(更多的信息,可参考打印机驱动程序的接口标识符部分)。
4. 如果插件指定一个接口的标识符表示一个驱动程序支持的接口,QueryInterface返回一个指向IPrintOemUI,IPrintOemUni 或者IPrintOemPS接口的指针。注意,驱动程序在返回对插件的接口指针之前调用接口的AddRef方法(在平台的SDK文档中描述)。插件应当保 存该指针,这样它可以在以后被用于调用接口方法。
5. 当IPrintOemUI,IPrintOemUni或者IPrintOemPS接口指针不再需要时,插件必须调用接口的Release方法(在平台的SDK文档中有描述)。
7.4安装定制的驱动程序组件
当为微软打印机驱动程序提供定制的组件时,必须为组件的安装提供一个.ini文件(如果打印机不被ntprint.inf支持,必须提供一个printer.inf文件)。
.ini文件必须包含一个OEMFiles部分,在这一部分,每一个定制的组件是用下面之一的条目来描述的:
OEMDriverFilen
命名一个绘制插件
OEMConfigFilen
命名一个用户接口插件
这时,n指定了安装程序安装文件的顺序,对所有类型的插件来说,为n指定的数字必须是连续的,从1开始。
例如,如果提供两个绘制插件及一个用户接口插件,打印机模型是XYZ,.ini文件必须如下所示:
[OEMFiles]
OEMDriverFile1=XYZDRV1.DLL
OEMConfigFile1=XYZUI1.DLL
OEMDriverFile2=XYZDRV2.DLL
在等号(=)之前或之后,都不允许有空格,文件名不能名含路径说明。
在例子中,指定了两个绘制插件,基于为OEMDriverFilen指定的n值。 xyzdrv1.dll在xyzdrv2.dll之前被安装。Unidrv及Pscript驱动程序调用插件,并按其安装的顺序,此后,当一个驱动程序需 要调用DDI分出函数及由这些插件提供的COM方法时,xyzdrv1.dll将在xyzdrv2.dll之前被调用。
.ini文件名应当反映打印机产品名称并且是唯一的以避免在.ini文件中与其他打印机名称 相冲突。注意如果提供一个与Windows NT 4.0后端口(Back-Porting)通信的绘制插件或用户接口插件。.ini文件名必须与.gpd及.ppd文件匹配。(即xyz.ini必须用于 xyz.gpd或xyz.ppd)。这一限制对Windows 2000及以后版本不适用。
一个.ini文件可以包含ANSI或UNICODE文本,但是推荐使用UNICODE文本。在一个.ini文件中,每行以#开始的是注解的内容。
更多的关于.inf及.ini文件的信息,参考Windows 2000驱动程序开发指南中的第一卷,即插即用,电源管理及建立设计指南部分。也可参考第4章微软统一打印机驱动程序中的安装一个Unidrv小驱动程序部分。
7.4.1Unidrv的定制的字体安装程序
对没有在打印机的GPD文件中通过字体Cartridge条目描述的Cartridge字体,需要厂商提供的字体安装程序软件。这些字体需要用Unidrv字体格式文件(.uff文件)来描述,而厂商提供的字体安装程序就负责创建.uff文件。
厂商提供的字体安装程序应当提供对下载的PCL软字体的支持。
下面两种技能为创建定制的安装程序提供:
提供一个用户接口插件
插件必须实现下面的COM接口方法:
IPrintOemUI::FontInstallerDlgProc
IPrintOemUI::UpdateExternalFonts
提供一个单独的执行文件
在字体安装时,可执行文件必须通过调用SetPrinterData(在平台的SDK文档中描述)存储它的名字在注册表中,并为“FontInstaller”关键字指定一个值。
Unidrv用下面的算法定位字体安装程序:
1.如果字体安装程序可执行文件的名字被存储于注册表中,Unidrv不允许系统管理员从打印机的属性表单中选择字体安装程序。相反,管理员必须运行提供的可执行文件。
2.如果一个安装程序执行文件不可用,Unidrv允许从打印机的属性表单中选择字体安装操 作。Unidrv确定是否一个用户接口插件已经被安装。如果是,它的字体安装方法被调用。如果一个用户接口插件没有被安装,或者它的字体安装方法返回了 E_NOTIMPL,则驱动程序使用它自已的容错安装程序。