生成基本的 v4 打印机驱动程序-PThandler.cpp
- PThandler.cpp
//
// File Name:
//
// PThandler.cpp
//
// Abstract:
//
// Print Ticket Handler class definition.
//
#include "precomp.h"
#include "WppTrace.h"
#include "CustomWppCommands.h"
#include "Exception.h"
#include "filtertypes.h"
#include "UnknownBase.h"
#include "OMConvertor.h"
#include "RenderFilter.h"
#include "PTHandler.h"
#include "PThandler.tmh"
namespace MyV4PrintDriver_Render_Filter
{
//
//Routine Name:
//
// PrintTicketHandler::CreatePrintTicketHandler
//
//Routine Description:
//
// Static factory method that creates an instance of
// PrintTicketHandler.
//
//Arguments:
//
// pPropertyBag - Property Bag
//
//Return Value:
//
// PrintTicketHandler_t (smart ptr)
// The new PrintTicketHandler.
//
PrintTicketHandler_t
PrintTicketHandler::CreatePrintTicketHandler(
const IPrintPipelinePropertyBag_t &pPropertyBag
)
{
//
// Create MSXML DOM document
//
IXMLDOMDocument2_t pDOMDoc;
THROW_ON_FAILED_HRESULT(
::CoCreateInstance(
__uuidof(DOMDocument60),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IXMLDOMDocument2),
reinterpret_cast<LPVOID*>(&pDOMDoc)
)
);
//
// Get the default user Print Ticket Stream Factory
//
Variant_t varUserPrintTicket;
THROW_ON_FAILED_HRESULT(
pPropertyBag->GetProperty(
XPS_FP_USER_PRINT_TICKET,
&varUserPrintTicket
)
);
IUnknown_t pUnk = varUserPrintTicket.punkVal;
IPrintReadStreamFactory_t pStreamFactory;
THROW_ON_FAILED_HRESULT(
pUnk.QueryInterface(&pStreamFactory)
);
//
// Get the default user Print Ticket stream
// and wrap it in an IStream
//
IPrintReadStream_t pUserPrintTicketStream;
THROW_ON_FAILED_HRESULT(
pStreamFactory->GetStream(&pUserPrintTicketStream)
);
IStream_t pUserPrintTicket =
CreateIStreamFromIPrintReadStream(pUserPrintTicketStream);
//
// Get the Printer Name
//
Variant_t varPrinterName;
THROW_ON_FAILED_HRESULT(
pPropertyBag->GetProperty(
XPS_FP_PRINTER_NAME,
&varPrinterName
)
);
BSTR_t pPrinterName(varPrinterName.bstrVal);
//
// Get the User Security Token
// Avoid CComVariant if getting the XPS_FP_USER_TOKEN property.
// Please refer to http://go.microsoft.com/fwlink/?LinkID=255534 for detailed information.
//
SafeVariant varUserSecurityToken;
THROW_ON_FAILED_HRESULT(
pPropertyBag->GetProperty(
XPS_FP_USER_TOKEN,
&varUserSecurityToken
)
);
//
// Open the Print Ticket Provider
//
SafeHPTProvider_t pHProvider(
new SafeHPTProvider(
pPrinterName,
varUserSecurityToken.byref
)
);
PrintTicketHandler_t toReturn(
new PrintTicketHandler(
pDOMDoc,
pHProvider,
pUserPrintTicket
)
);
return toReturn;
}
//
//Routine Name:
//
// PrintTicketHandler::PrintTicketHandler
//
//Routine Description:
//
// Constructor for the Print Ticket Handler.
//
//Arguments:
//
// pDoc - initialized MSXML DOM document
// pHProvider - handle to the Print Ticket Provider
//
PrintTicketHandler::PrintTicketHandler(
const IXMLDOMDocument2_t &pDoc,
SafeHPTProvider_t pHProvider,
const IStream_t &pUserPrintTicket
) : m_pDOMDoc(pDoc),
m_pHProvider(pHProvider),
m_pDefaultUserPrintTicket(pUserPrintTicket)
{
}
//
//Routine Name:
//
// PrintTicketHandler::ProcessPrintTicket
//
//Routine Description:
//
// Gets the print ticket from the part, merges with
// the base ticket, and returns the result.
//
//Arguments:
//
// pBasePrintTicket - Base Print Ticket
// pDeltaPrintTicketPart - Delta Print Pipeline Print Ticket Part
// scope - Scope of the merged Print Ticket
//
//Return Value:
//
// IStream_t (smart pointer)
// Merged stream
//
IStream_t
PrintTicketHandler::ProcessPrintTicket(
const IStream_t &pBasePrintTicket,
const IPartPrintTicket_t &pDeltaPrintTicketPart,
EPrintTicketScope scope
)
{
IStream_t pMergedPrintTicket;
IStream_t pDeltaPrintTicket;
pDeltaPrintTicket = GetStreamFromPart(
static_cast<IPartBase_t>(pDeltaPrintTicketPart)
);
//
// Before calling PTMergeAndValidatePrintTicket, both input
// Print Ticket streams MUST be at position 0. The temp Print
// Ticket stream is already at position 0, but the Base Print
// Ticket may not be. Seek it to 0 to be sure.
//
LARGE_INTEGER zero;
zero.QuadPart = 0;
THROW_ON_FAILED_HRESULT(
pBasePrintTicket->Seek(zero, SEEK_SET, NULL)
);
//
// Merge the delta Print Ticket with the
// base Print Ticket
//
THROW_ON_FAILED_HRESULT(
::CreateStreamOnHGlobal(
NULL,
TRUE, // delete on release
&pMergedPrintTicket
)
);
m_pHProvider->PTMergeAndValidatePrintTicket(
pBasePrintTicket,
pDeltaPrintTicket,
scope,
pMergedPrintTicket
);
return pMergedPrintTicket;
}
//
//Routine Name:
//
// PrintTicketHandler::ProcessPart
//
//Routine Description:
//
// Merges the Fixed Document Sequence Print Ticket with
// the default user Print Ticket and caches the result.
//
//Arguments:
//
// pFDS - Fixed Document Sequence part
//
void
PrintTicketHandler::ProcessPart(
const IFixedDocumentSequence_t &pFDS
)
{
IPartPrintTicket_t pPrintTicket;
HRESULT hr = pFDS->GetPrintTicket(&pPrintTicket);
//
// E_ELEMENT_NOT_FOUND means that this Fixed Document Sequence
// does not have a Print Ticket. Propagate the Default User
// Print Ticket.
// All other failed HRESULTs should be thrown.
//
if (hr == E_ELEMENT_NOT_FOUND)
{
m_pJobPrintTicket = m_pDefaultUserPrintTicket;
return;
}
THROW_ON_FAILED_HRESULT(hr);
m_pDocumentPrintTicket = NULL;
m_pPagePrintTicket = NULL;
m_pJobPrintTicket = ProcessPrintTicket(
m_pDefaultUserPrintTicket,
pPrintTicket,
kPTJobScope
);
}
//
//Routine Name:
//
// PrintTicketHandler::ProcessPart
//
//Routine Description:
//
// Merges the Fixed Document Print Ticket with the
// Fixed Document Sequence Print Ticket and caches
// the result. The tickets are merged at the Document
// scope, so the result contains no job-level features.
//
//Arguments:
//
// pFD - Fixed Document part
//
void
PrintTicketHandler::ProcessPart(
const IFixedDocument_t &pFD
)
{
IPartPrintTicket_t pPrintTicket;
HRESULT hr = pFD->GetPrintTicket(&pPrintTicket);
//
// E_ELEMENT_NOT_FOUND means that this Fixed Document
// does not have a Print Ticket. Propagate the Job
// Print Ticket.
// All other failed HRESULTs should be thrown.
//
if (hr == E_ELEMENT_NOT_FOUND)
{
m_pDocumentPrintTicket = m_pJobPrintTicket;
return;
}
THROW_ON_FAILED_HRESULT(hr);
m_pPagePrintTicket = NULL;
m_pDocumentPrintTicket = ProcessPrintTicket(
m_pJobPrintTicket,
pPrintTicket,
kPTDocumentScope
);
}
//
//Routine Name:
//
// PrintTicketHandler::ProcessPart
//
//Routine Description:
//
// Merges the Fixed Page Print Ticket with the
// Fixed Document Print Ticket and caches the result.
// The tickets are merged at the Page scope, so the
// result contains no job-level or document-level features.
//
//Arguments:
//
// pFP - Fixed Page part
//
void
PrintTicketHandler::ProcessPart(
const IFixedPage_t &pFP
)
{
IPartPrintTicket_t pPrintTicket;
HRESULT hr = pFP->GetPrintTicket(&pPrintTicket);
//
// E_ELEMENT_NOT_FOUND means that this Fixed Page
// does not have a Print Ticket. Propagate the Document
// Print Ticket.
// All other failed HRESULTs should be thrown.
//
if (hr == E_ELEMENT_NOT_FOUND)
{
m_pPagePrintTicket = m_pDocumentPrintTicket;
return;
}
THROW_ON_FAILED_HRESULT(hr);
m_pPagePrintTicket = ProcessPrintTicket(
m_pDocumentPrintTicket,
pPrintTicket,
kPTPageScope
);
}
} // namespace MyV4PrintDriver_Render_Filter
文件概述
- 功能:定义了
PrintTicketHandler类,负责从打印管道属性包中创建打印票据处理对象,并处理不同层级(作业、文档、页面)的打印票据合并和缓存。 - 主要内容:
提供静态工厂方法 CreatePrintTicketHandler 创建PrintTicketHandler实例。
实现构造函数和处理不同部件(如固定文档序列、固定文档、固定页面)的打印票据合并逻辑。
使用 WPP(Windows 软件跟踪预处理器)记录日志,结合异常处理确保代码健壮性。 - 命名空间:
MyV4PrintDriver_Render_Filter,用于组织代码并避免符号冲突。
代码结构与功能详解
- 头文件与预处理器
- 作用:
包含必要的头文件,提供预编译宏、WPP 跟踪、自定义 WPP 命令、异常处理(Exception.h)、过滤器类型(filtertypes.h)、COM 基类(UnknownBase.h)、对象模型转换(OMConvertor.h)、渲染过滤器(RenderFilter.h)和打印票据处理声明(PTHandler.h)。
PThandler.tmh是 WPP 跟踪生成的头文件,用于日志记录。
- 命名空间
namespace MyV4PrintDriver_Render_Filter
- 作用: 使用命名空间
MyV4PrintDriver_Render_Filter组织代码,避免符号冲突。
- 类
PrintTicketHandler及其方法
静态工厂方法 CreatePrintTicketHandler
PrintTicketHandler_t PrintTicketHandler::CreatePrintTicketHandler(
const IPrintPipelinePropertyBag_t &pPropertyBag
)
- 功能: 静态工厂方法,创建并初始化
PrintTicketHandler实例。 - 参数:
pPropertyBag: 打印管道属性包(IPrintPipelinePropertyBag),包含打印票据、打印机名称和用户安全令牌等信息。 - 逻辑:
1.创建 MSXML DOM 文档:
使用 CoCreateInstance 创建 MSXML DOM 文档对象(IXMLDOMDocument2),用于处理 XML 格式的打印票据。
CLSID 为 DOMDocument60,表示使用 MSXML 6.0。
2.获取默认用户打印票据流:
从属性包中获取XPS_FP_USER_PRINT_TICKET属性,得到IPrintReadStreamFactory。
调用GetStream获取用户打印票据的流(IPrintReadStream)。
使用CreateIStreamFromIPrintReadStream(定义在omconvertor.cpp中)将其转换为 COM 的IStream。
3.获取打印机名称:
从属性包中获取XPS_FP_PRINTER_NAME属性,得到打印机名称(BSTR)。
4.获取用户安全令牌:
从属性包中获取XPS_FP_USER_TOKEN属性,使用SafeVariant避免直接使用CComVariant(可能因 COM 兼容性问题)。
5.创建打印票据提供者:
使用SafeHPTProvider创建打印票据提供者(IPrintTicketProvider),传入打印机名称和用户安全令牌。
6.创建PrintTicketHandler实例:
使用 DOM 文档、打印票据提供者和用户打印票据流构造PrintTicketHandler对象。 返回智能指针PrintTicketHandler_t(可能是基于CComPtr或类似 RAII 机制)。 - 异常处理:
使用THROW_ON_FAILED_HRESULT宏(调用ThrowHRException)抛出 HRESULT 异常。 - 作用:
初始化打印票据处理的核心对象,准备处理后续的打印票据合并操作。
构造函数 PrintTicketHandler
PrintTicketHandler::PrintTicketHandler(
const IXMLDOMDocument2_t &pDoc,
SafeHPTProvider_t pHProvider,
const IStream_t &pUserPrintTicket
) : m_pDOMDoc(pDoc),
m_pHProvider(pHProvider),
m_pDefaultUserPrintTicket(pUserPrintTicket)
- 功能:
PrintTicketHandler的构造函数,初始化成员变量。 - 参数:
pDoc: MSXML DOM 文档对象,用于处理 XML 格式的打印票据。
pHProvider: 打印票据提供者(SafeHPTProvider),用于合并和验证打印票据。
pUserPrintTicket: 默认用户打印票据的流(IStream)。 - 逻辑:
初始化成员变量m_pDOMDoc、m_pHProvider和m_pDefaultUserPrintTicket。 - 异常处理:
异常处理: 使用 THROW_ON_FAILED_HRESULT 确保操作成功。 - 作用:
设置类的内部状态,准备处理打印票据。
方法 ProcessPrintTicket
IStream_t PrintTicketHandler::ProcessPrintTicket(
const IStream_t &pBasePrintTicket,
const IPartPrintTicket_t &pDeltaPrintTicketPart,
EPrintTicketScope scope
)
- 功能: 合并基础打印票据(
pBasePrintTicket)和增量打印票据(pDeltaPrintTicketPart),返回合并后的打印票据流。 - 参数:
pBasePrintTicket: 基础打印票据流(IStream),可能是作业、文档或页面级别的票据。
pDeltaPrintTicketPart: 增量打印票据部件(IPartPrintTicket),包含特定层级的设置。
scope: 合并的作用域(EPrintTicketScope),如kPTJobScope(作业)、kPTDocumentScope(文档)或kPTPageScope(页面)。 - 逻辑:
1.从增量打印票据部件获取流(pDeltaPrintTicket),使用GetStreamFromPart(定义在omconvertor.cpp中)。
2.确保基础打印票据流位置为 0(使用Seek)。
3.创建一个新的全局内存流(pMergedPrintTicket)用于存储合并结果,使用CreateStreamOnHGlobal。
4.调用m_pHProvider->PTMergeAndValidatePrintTicket合并并验证打印票据,传入基础流、增量流、作用域和输出流。
5.返回合并后的流(IStream_t)。 - 异常处理:
异常处理: 使用 THROW_ON_FAILED_HRESULT。 - 作用:
实现打印票据的合并和验证,确保设置在指定作用域内有效。
方法 ProcessPart(重载 1:处理固定文档序列)
void PrintTicketHandler::ProcessPart(const IFixedDocumentSequence_t &pFDS)
- 功能: 处理固定文档序列(IFixedDocumentSequence)的打印票据,合并默认用户打印票据并缓存结果。
- 参数:
pFDS: 固定文档序列部件。 - 逻辑:
1.尝试获取文档序列的打印票据(pPrintTicket)。
2.如果返回E_ELEMENT_NOT_FOUND(表示无打印票据),将默认用户打印票据(m_pDefaultUserPrintTicket)缓存到m_pJobPrintTicket。
3.如果有其他错误,抛出异常。
4.清空文档和页面级别的缓存(m_pDocumentPrintTicket和m_pPagePrintTicket)。
5.调用ProcessPrintTicket合并默认用户打印票据和文档序列的打印票据,作用域为kPTJobScope,并缓存结果到m_pJobPrintTicket。 - 异常处理:
异常处理: 使用 THROW_ON_FAILED_HRESULT。 - 作用:
处理作业级别的打印票据,确保作业设置正确应用。
方法 ProcessPart(重载 2:处理固定文档)
void PrintTicketHandler::ProcessPart(const IFixedDocument_t &pFD)
- 功能: 处理固定文档(IFixedDocument)的打印票据,合并作业级打印票据并缓存结果。
- 参数:
pFD: 固定文档部件 - 逻辑:
1.尝试获取文档的打印票据(pPrintTicket)。
2.如果返回E_ELEMENT_NOT_FOUND(表示无打印票据),将作业级打印票据(m_pJobPrintTicket)缓存到m_pDocumentPrintTicket。
3.如果有其他错误,抛出异常。
4.清空页面级别的缓存(m_pPagePrintTicket)。
5.调用ProcessPrintTicket合并作业级打印票据和文档的打印票据,作用域为kPTDocumentScope,并缓存结果到m_pDocumentPrintTicket。 - 异常处理:
异常处理: 使用 THROW_ON_FAILED_HRESULT。 - 作用:
理文档级别的打印票据,去除作业级别的特性,仅保留文档级设置。
方法 ProcessPart(重载 3:处理固定页面)
void PrintTicketHandler::ProcessPart(const IFixedPage_t &pFP)
- 功能: 处理固定页面(IFixedPage)的打印票据,合并文档级打印票据并缓存结果。
- 参数:
pFP: 固定页面部件。 - 逻辑:
1.尝试获取页面的打印票据(pPrintTicket)。
2.如果返回E_ELEMENT_NOT_FOUND(表示无打印票据),将文档级打印票据(m_pDocumentPrintTicket)缓存到m_pPagePrintTicket。
3.如果有其他错误,抛出异常。
4.调用ProcessPrintTicket合并文档级打印票据和页面的打印票据,作用域为kPTPageScope,并缓存结果到m_pPagePrintTicket。 - 异常处理:
异常处理: 使用 THROW_ON_FAILED_HRESULT。 - 作用:
处理页面级别的打印票据,去除作业和文档级别的特性,仅保留页面级设置。
代码总结
- 主要功能:
PrintTicketHandler类负责管理打印票据的创建、合并和缓存,支持作业(kPTJobScope)、文档(kPTDocumentScope)和页面(kPTPageScope)三个层级。- 提供静态工厂方法创建实例,初始化 MSXML DOM、打印票据提供者和默认用户打印票据。
- 通过
ProcessPart重载方法处理不同层级的打印票据,合并并验证后缓存结果。
- 关键点:
- 使用 MSXML DOM(
IXMLDOMDocument2)处理 XML 格式的打印票据。 - 使用
SafeHPTProvider(打印票据提供者)执行合并和验证操作。 - 智能指针(如
PrintTicketHandler_t、IStream_t)简化 COM 对象管理。 - 异常处理(
THROW_ON_FAILED_HRESULT)和 WPP 日志确保代码健壮性和可调试性。 - 如果部件缺少打印票据,继承上一级票据(如页面继承文档,文档继承作业)。
- 应用场景:
- 该类用于 Windows 打印管道中的 XPS 渲染过滤器,处理打印票据以确保打印设置(如纸张大小、方向、分辨率等)正确应用于作业、文档或页面。
- 与
omconvertor.cpp和RenderFilter协作,RenderFilter可能调用PrintTicketHandler处理打印票据后再进行对象模型转换。
- 打印票据层级:
- 作业级(Job Scope): 包含整个打印作业的设置(如打印机选择、份数)。
- 文档级(Document Scope): 包含文档特定设置(如页面布局),不包含作业级特性。
- 页面级(Page Scope): 包含页面特定设置(如页面方向),不包含作业或文档级特性。
原始资料地址:
生成基本的 v4 打印机驱动程序
如有侵权联系删除 仅供学习交流使用