如何:使用 XPS 列印 API 列印
本主題描述如何使用 XPS 列印 API 從 Windows 應用程式列印。
XPS 列印 API 可讓原生 Windows 應用程式列印 XPS 檔。 應用程式可以使用 XPS 檔案 API來建立 XPS 檔。 一般 XPS 文件程式設計任務 說明主題描述如何執行這項作業。 建立 XPS 檔案之後,應用程式就可以使用 XPS 列印 API 來列印它。
使用 XPS 列印 API 從應用程式列印檔牽涉到下列步驟。
- 初始化 COM 介面
- 建立完成事件
- 啟動 XPS 列印作業
- 建立IXpsOMPackageWriter 介面
- 關閉 IXpsOMPackageWriter 介面
- 關閉列印作業數據流
- 等候完成事件
- 發行資源
XPS 列印 API 需要 XPS 檔才能列印。 在下列範例中,XPS 檔會在 XPS 印表 API 傳送至印表機時建立。 您也可以使用 XPS 檔 API 來建立 XPS 檔,而不需要將它傳送至印表機, 並將它維持為 XPS OM,或將 XPS OM 儲存為 XPS 檔。 如需使用 XPS OM 的詳細資訊,請參閱 XPS 檔 API。
初始化 COM 介面
如果應用程式尚未這麼做,請初始化 COM 介面。
// Initialize the COM interface, if the application has not
// already done so.
if (FAILED(hr = CoInitializeEx(0, COINIT_MULTITHREADED)))
{
fwprintf(stderr,
L"ERROR: CoInitializeEx failed with HRESULT 0x%X\n", hr);
return 1;
}
建立完成事件
建立一個打印完成事件,XPS 列印 API 會在印列緩衝區從應用程式接收到整個檔案時,通知應用程式。 XPS 列印 API 也支援進度事件,讓應用程式可以知道其他的緩衝處理活動。
// Create the completion event
completionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!completionEvent)
{
hr = HRESULT_FROM_WIN32(GetLastError());
fwprintf(stderr,
L"ERROR: Could not create completion event: %08X\n", hr);
}
啟動 XPS 列印作業
呼叫 StartXpsPrintJob來啟動 XPS 列印作業。 StartXpsPrintJob 會傳回應用程式將傳送要列印之文件的數據流。
// Start an XPS Print Job
if (FAILED(hr = StartXpsPrintJob(
printerName,
NULL,
NULL,
NULL,
completionEvent,
NULL,
0,
&job,
&jobStream,
NULL
)))
{
fwprintf(stderr,
L"ERROR: Could not start XPS print job: %08X\n", hr);
}
建立IXpsOMPackageWriter 介面
在 StartXpsPrintJob所傳回的數據流上,呼叫 IXpsOMObjectFactory::CreatePackageWriterOnStream,以建立 IXpsOMPackageWriter 介面。
// Create an XPS OM Object Factory. If one has already been
// created by the application, a new one is not necessary.
if (SUCCEEDED(hr))
{
if (FAILED(hr = CoCreateInstance(
__uuidof(XpsOMObjectFactory),
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&xpsFactory))))
{
fwprintf(
stderr,
L"ERROR: Could not create XPS OM Object Factory: %08X\n",
hr);
}
}
// Create the Part URI for the Fixed Document Sequence. The
// Fixed Document Sequence is the top-level element in the
// package hierarchy of objects. There is one Fixed Document
// Sequence in an XPS document.
//
// The part name is not specified by the XML Paper Specification,
// however, the name used in this example is the part name
// used by convention.
//
if (SUCCEEDED(hr))
{
if (FAILED(hr = xpsFactory->CreatePartUri(
L"/FixedDocumentSequence.fdseq",
&partUri)))
{
fwprintf(stderr,
L"ERROR: Could not create part URI: %08X\n", hr);
}
}
// Create the package writer on the print job stream.
if (SUCCEEDED(hr))
{
if (FAILED(hr = xpsFactory->CreatePackageWriterOnStream(
jobStream,
TRUE,
XPS_INTERLEAVING_ON,
partUri,
NULL,
NULL,
NULL,
NULL,
&packageWriter
)
)
)
{
fwprintf(
stderr,
L"ERROR: Could not create package writer: 0x%X\n",
hr);
}
}
// Release the part URI interface.
if (partUri)
{
partUri->Release();
partUri = NULL;
}
針對此列印作業中的每個文件,啟動新的檔,然後將頁面新增至該檔。
啟動新檔
呼叫 IXpsOMPackageWriter::StartNewDocument,在封裝寫入器中啟動新檔。 如果在呼叫此方法時開啟檔,則會關閉檔,並開啟新的檔。
// Create the Part URI for the Fixed Document. The
// Fixed Document part contains the pages of the document.
// There can be one or more Fixed Documents in an XPS document.
//
// The part name is not specified by the XML Paper Specification,
// however, the name format used in this example is the format
// used by convention. The number "1" in this example must be
// changed for each document in the package. For example, 1
// for the first document, 2 for the second, and so on.
//
if (SUCCEEDED(hr))
{
if (FAILED(hr = xpsFactory->CreatePartUri(
L"/Documents/1/FixedDocument.fdoc",
&partUri)))
{
fwprintf(
stderr,
L"ERROR: Could not create part URI: %08X\n",
hr);
}
}
// Start the new document.
//
// If there was already a document started in this page,
// this call will close it and start a new one.
if (SUCCEEDED(hr))
{
if (FAILED(hr = packageWriter->StartNewDocument(
partUri,
NULL,
NULL,
NULL,
NULL)))
{
fwprintf(
stderr,
L"ERROR: Could not start new document: 0x%X\n",
hr);
}
}
// Release the part URI interface
if (partUri)
{
partUri->Release();
partUri = NULL;
}
新增頁面
呼叫 IXpsOMPackageWriter::AddPage,將應用程式的每一個頁面寫入封裝寫入器中的新檔。
注意
假設應用程式已在此步驟之前建立頁面。 如需建立檔案頁面並新增內容的詳細資訊,請參閱 Common XPS 檔案程式設計工作。
if (SUCCEEDED(hr))
{
// Add the current page to the document.
if (FAILED(hr = packageWriter->AddPage(
xpsPage,
&pageSize,
NULL,
NULL,
NULL,
NULL
)))
{
fwprintf(
stderr,
L"ERROR: Could not add page to document: %08X\n",
hr);
}
}
關閉IXpsOMPackageWriter 介面
撰寫完成此列印作業的所有文件之後,請呼叫 IXpsOMPackageWriter::Close 來關閉封裝。
if (SUCCEEDED(hr))
{
if (FAILED(hr = packageWriter->Close()))
{
fwprintf(
stderr,
L"ERROR: Could not close package writer: %08X\n",
hr);
}
}
關閉列印作業數據流
透過呼叫 Close來關閉列印作業數據流,這會告訴列印後台處理程式整個列印作業已經由應用程式傳送完畢。
if (SUCCEEDED(hr))
{
if (FAILED(hr = jobStream->Close()))
{
fwprintf(
stderr,
L"ERROR: Could not close job stream: %08X\n",
hr);
}
}
else
{
// Only cancel the job if we succeeded in creating a job.
if (job)
{
// Tell the XPS Print API that we're giving up.
// Don't overwrite hr with the return from this function.
job->Cancel();
}
}
等候完成事件
等候列印作業的完成事件。
if (SUCCEEDED(hr))
{
wprintf(L"Waiting for job completion...\n");
if (WaitForSingleObject(completionEvent, INFINITE) !=
WAIT_OBJECT_0)
{
hr = HRESULT_FROM_WIN32(GetLastError());
fwprintf(
stderr,
L"ERROR: Wait for completion event failed: %08X\n",
hr);
}
}
完成事件發出訊號之後,請呼叫 getJobStatus 以取得作業狀態。
if (SUCCEEDED(hr))
{
if (FAILED(hr = job->GetJobStatus(&jobStatus)))
{
fwprintf(
stderr,
L"ERROR: Could not get job status: %08X\n",
hr);
}
}
if (SUCCEEDED(hr))
{
switch (jobStatus.completion)
{
case XPS_JOB_COMPLETED:
break;
case XPS_JOB_CANCELLED:
fwprintf(stderr, L"ERROR: job was cancelled\n");
hr = E_FAIL;
break;
case XPS_JOB_FAILED:
fwprintf(
stderr,
L"ERROR: Print job failed: %08X\n",
jobStatus.jobStatus);
hr = E_FAIL;
break;
default:
fwprintf(stderr, L"ERROR: unexpected failure\n");
hr = E_UNEXPECTED;
break;
}
}
發行資源
作業狀態指出完成之後,請釋放用於此列印作業的介面和資源。
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;
}