打印 XPS OM
介绍如何将 XPS OM 作为 XPS 文档发送到打印机。
有关如何打印包含完整 XPS 文档的 XPS OM 的说明,请参阅打印完整的 XPS OM。 若要包含 XPS 文档,XPS OM 必须包含创建空白 XPS OM中列出的项。
有关如何打印一次创建或处理一页的 XPS OM 的说明,请参阅增量打印 XPS OM。
在程序中使用这些代码示例之前,请阅读常见的 XPS 文档编程任务中的免责声明。
本主题介绍如何执行以下任务:
打印完整的 XPS OM
当 XPS OM 包含完整的 XPS 文档时,IXpsOMPackage 接口的 WriteToStream 方法可以将 XPS OM 的内容发送到打印机或打印队列。
若要检测打印作业何时完成,请创建事件句柄,如以下示例所示。
HANDLE completionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (NULL == completionEvent)
{
hr = HRESULT_FROM_WIN32(GetLastError());
// The method can continue, but print spooling completion
// cannot be checked without a valid event handle.
}
打印完整 XPS OM:
- 通过调用 StartXpsPrintJob 创建新的打印作业流。
- 通过调用包的 WriteToStream 方法将 XPS OM 的内容发送到流。
- 通过调用流的“Close”方法关闭打印作业流。
- 等待打印作业发出已完成的信号。
- 检查完成状态。
- 关闭并释放资源。
IXpsPrintJob *job = NULL;
IXpsPrintJobStream *jobStream = NULL;
hr = StartXpsPrintJob(
printerName,
NULL,
NULL,
NULL,
completionEvent,
NULL,
0,
&job,
&jobStream,
NULL);
// Write package to print job stream
hr = package->WriteToStream (jobStream, FALSE);
// Close the stream to tell the print job
// that the entire document has been sent.
hr = jobStream->Close();
// Wait for the print job to finish spooling...
if (NULL != completionEvent) {
if (WaitForSingleObject(completionEvent, INFINITE) == WAIT_OBJECT_0)
{
// Get the print job status to see why the wait completed.
// Note that without waiting for a completion event,
// the print job may not be complete when the status is queried.
XPS_JOB_STATUS jobStatus;
hr = job->GetJobStatus(&jobStatus);
// Evaluate the job status returned.
switch (jobStatus.completion)
{
case XPS_JOB_COMPLETED:
// The job completed as expected.
hr = S_OK;
break;
case XPS_JOB_CANCELLED:
// The job was canceled.
hr = E_FAIL;
break;
case XPS_JOB_FAILED:
// The job failed,
// jobStatus.jobStatus has the reason.
hr = E_FAIL;
break;
default:
// An unexpected value was returned.
hr = E_UNEXPECTED;
break;
}
// Release completion event handle
CloseHandle(completionEvent);
}
else
{ // there was a problem, set hr to error status
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
// hr contains the result of the print operation
CoUninitialize(); // if COM is no longer needed in this thread
以增量方式打印 XPS OM
可以通过创建 XPS 打印作业流,然后将单个文档组件一次一个传递给打印作业流,以增量方式将 XPS OM 的文档组件发送到打印机作业。 发送文档组件的顺序决定了文档组件在完成文档中的显示方式。 因此,在程序可以调用此示例中的代码之前,它必须正确组织文档组件。
在使用 XPS OM 接口之前,请初始化线程中的 COM,如以下示例代码所示。
HRESULT hr;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
若要监视打印作业完成,请创建一个事件句柄,如以下示例代码所示。
HANDLE completionEvent = NULL;
completionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (NULL == completionEvent)
{
hr = HRESULT_FROM_WIN32(GetLastError());
// The method can continue, but print spooling completion
// cannot be checked without a valid event handle.
}
创建新的打印作业流和新包编写器。 将每个文档组件以与在完成的文档中显示的顺序相同的顺序将每个文档组件传递给相应的包编写器方法。
从新开始每个文档,然后向其中添加页面。 将所有文档组件传递到打印作业流后,关闭流,等待打印作业完成,然后关闭并释放打开的资源。
- 通过调用 StartXpsPrintJob 创建新的打印作业流。
- 为 FixedDocumentSequence 部件创建部件 URI。
- 在打印作业流上创建新的包编写器。
- 要写入的每个文档:
- 为 FixedDocument 部件创建新的部件 URI。
- 在包编写器中启动新文档。
- 对于当前文档中的每一页,请为 FixedPage 部件创建一个部件 URI,并将页面添加到包编写器。
- 将所有页面添加到包编写器后,请将其关闭。
- 关闭打印作业流。
- 等待打印作业完成。
- 检查完成状态。
- 关闭并释放打开的资源。
IXpsPrintJob* job = NULL;
IXpsPrintJobStream* jobStream = NULL;
hr = StartXpsPrintJob(
argv[1],
NULL,
NULL,
NULL,
completionEvent,
NULL,
0,
&job,
&jobStream,
NULL);
// Note the implicit requirement that CoInitializeEx
// has previously been called from this thread.
IXpsOMObjectFactory *xpsFactory = NULL;
hr = CoCreateInstance(
__uuidof(XpsOMObjectFactory),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IXpsOMObjectFactory),
reinterpret_cast<void**>(&xpsFactory)
);
// Create part URI for FixedDocumentSequence part
// This can use a static string because there is only one
// FixedDocumentSequence part in the print job.
IOpcPartUri *partUri = NULL;
hr = xpsFactory->CreatePartUri(L"/FixedDocumentSequence.fdseq", &partUri);
// Create the package writer on the print job stream
// Note that the interleaving parameter set to
// XPS_INTERLEAVING_ON, the package writer will create
// empty print ticket parts when a NULL pointer is
// passed in the print ticket argument of this method,
// the StartNewDocument method, and the AddPage method.
// For more information, see the help for these methods.
IXpsOMPackageWriter *packageWriter = NULL;
hr = xpsFactory->CreatePackageWriterOnStream(
jobStream,
TRUE,
XPS_INTERLEAVING_ON, // to create blank print ticket objects
partUri,
NULL,
NULL,
NULL,
NULL,
&packageWriter);
// release partUri after it's been used to create new doc. seq.
if (partUri)
{
partUri->Release();
partUri = NULL;
}
// Add document content to the print job stream.
int docNumber = 1;
int docsInPackage = 1; // Change this value as required.
while (docNumber <= docsInPackage) {
// Create a unique part URI for the current document.
WCHAR DocPartUri[MAX_PATH];
hr = MakeDocumentPartUri (docNumber, MAX_PATH, DocPartUri);
hr = xpsFactory->CreatePartUri(DocPartUri, &partUri);
// Initialize the new document in the package writer.
hr = packageWriter->StartNewDocument(partUri, NULL, NULL, NULL, NULL);
// release part URI after it's been used to create new doc.
if (partUri)
{
partUri->Release();
partUri = NULL;
}
// Add the pages
int pageNumber = 1;
int pagesInDocument = 1; // Change this value as required.
while (pageNumber <= pagesInDocument) {
// Create a unique part URI for the current page
WCHAR PagePartUri[MAX_PATH];
hr = MakePagePartUri (
docNumber,
pageNumber,
MAX_PATH,
PagePartUri);
hr = xpsFactory->CreatePartUri(PagePartUri, &partUri);
// create page in OM
XPS_SIZE pageSize = {816, 1056};
IXpsOMPage *xpsPage = NULL;
hr = xpsFactory->CreatePage(
&pageSize,
L"en-US",
partUri,
&xpsPage);
// release pagePartUri after it's been used to create the page
if (partUri)
{
partUri->Release();
partUri = NULL;
}
// add content to the page or retrieve
// the page from the XPS OM.
// (not shown in this example)
// add page to document
hr = packageWriter->AddPage(
xpsPage,
&pageSize,
NULL,
NULL,
NULL,
NULL);
if (xpsPage)
{
xpsPage->Release();
xpsPage = NULL;
}
// go to the next page
pageNumber++;
}
// the fixed document does not need to be closed.
// it will be closed when a new fixed doc is opened
// or the package is closed.
// go to the next document
docNumber++;
}
// Close the package writer when finished
hr = packageWriter->Close();
if (SUCCEEDED(hr))
{
// Close the print stream to tell the print
// job that the all document contents have
// been sent
hr = jobStream->Close();
// Wait for the print job to finish spooling...
if (NULL != completionEvent) {
if (WaitForSingleObject(completionEvent, INFINITE) == WAIT_OBJECT_0)
{
// Get the print job status to see why the wait completed.
// Note that without waiting for a completion event,
// the print job may not be complete when the status is queried.
XPS_JOB_STATUS jobStatus;
hr = job->GetJobStatus(&jobStatus);
// Evaluate the job status returned.
switch (jobStatus.completion)
{
case XPS_JOB_COMPLETED:
// The job completed as expected.
hr = S_OK;
break;
case XPS_JOB_CANCELLED:
// The job was canceled.
hr = E_FAIL;
break;
case XPS_JOB_FAILED:
// The job failed,
// jobStatus.jobStatus has the reason.
hr = E_FAIL;
break;
default:
// An unexpected value was returned.
hr = E_UNEXPECTED;
break;
}
// Release completion event handle
CloseHandle(completionEvent);
}
else
{ // there was a problem, set hr to error status
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
}
else
{
// cancel the job, if one exists, because
// the close call returned an error
if (job) job->Cancel();
}
// hr contains the result of the print operation
// free/release pointers and handles used.
if (packageWriter)
{
packageWriter->Release();
packageWriter = NULL;
}
if (partUri)
{
partUri->Release();
partUri = NULL;
}
if (xpsFactory)
{
xpsFactory->Release();
xpsFactory = NULL;
}
if (jobStream)
{
jobStream->Release();
jobStream = NULL;
}
if (job)
{
job->Release();
job = NULL;
}
if (completionEvent)
{
CloseHandle(completionEvent);
completionEvent = NULL;
}
CoUninitialize(); // If done with COM in this thread.
当程序以增量方式编写文档组件时,如本示例所示,它必须为其发送到打印作业流的每个文档部件生成部件名称。 在前面的示例中,FixedDocumentSequence 部件 URI 是从静态字符串创建的,因为 XPS 文档中只有一个这样的部分。 每个 FixedPage 和 FixedDocument 部件的 URI 在 XPS 文档中必须是唯一的。 使用这些组件的索引生成部件 URI 有助于确保生成的 URI 字符串在 XPS 文档中是唯一的。
HRESULT MakeDocumentPartUri (
__in int docNumber,
__in DWORD partUriStringLength,
__inout LPWSTR partUriStringBuffer
)
{
// create a Part URI string using the document number
// that was passed as an argument
// for example, "/Documents/1/FixedDocument.fdoc"
// where "1" specifies the document number, which would
// change with each document printed
return S_OK;
}
HRESULT MakePagePartUri (
__in int docNumber,
__in int pageNumber,
__in DWORD partUriStringLength,
__inout LPWSTR partUriStringBuffer
)
{
// create a Part URI string using the document number
// and page number that were passed as an argument
// for example: "/Documents/1/Pages/1.fpage"
// where the first "1" between Documents and Pages
// specifies the document number, which would change with
// each document. The second "1" specifies the page number,
// which would change with each page in the document.
return S_OK;
}
有关 XPS 文档结构的详细信息,请参阅 XML 纸张规范。
相关主题
-
后续步骤
-
本部分使用的内容
-
详细信息