如何:使用 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;
}