Практическое руководство. Печать с помощью API печати XPS
В этом разделе описывается использование API печати XPS для печати из приложения Windows.
API печати XPS позволяет собственным приложениям Windows печатать документы XPS. Приложение может создать документ XPS с помощью API документов XPS. В разделе справки Common XPS Document Programming Tasks (Общие задачи программирования документов XPS ) описано, как это сделать. После создания документа XPS приложение может напечатать его с помощью API печати XPS.
Использование API печати XPS для печати документа из приложения включает следующие действия.
- Инициализация COM-интерфейса
- Создание события завершения
- Запуск задания печати XPS
- Создание интерфейса IXpsOMPackageWriter
- Закрытие интерфейса IXpsOMPackageWriter
- Закрытие потока задания печати
- Ожидание события завершения
- Ресурсы по выпуску
Для печати API печати XPS требуется документ XPS. В следующем примере документ XPS создается по мере его отправки на принтер с помощью API печати XPS. Кроме того, можно создать документ XPS, не отправляя его на принтер, используя API документов XPS и поддерживая его в качестве xps OM или сохраняя xps OM в качестве документа XPS. Дополнительные сведения об использовании XPS OM см. в разделе API документов XPS.
Инициализация 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;
}
Создание события завершения
Создайте событие завершения, которое API печати XPS использует для уведомления приложения о получении очередью печати всего документа из приложения. API печати XPS также поддерживает событие хода выполнения, чтобы приложение знали о других действиях spooling.
// 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
Запустите задание печати XPS, вызвав StartXpsPrintJob. 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
Создайте интерфейс IXpsOMPackageWriter , вызвав IXpsOMObjectFactory::CreatePackageWriterOnStream в потоке, возвращенном командой StartXpsPrintJob.
// 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 , чтобы записать каждую страницу документа из приложения в новый документ в средстве записи пакетов.
Примечание
Предполагается, что приложение создало страницу до этого шага. Дополнительные сведения о создании страниц документов и добавлении к ним содержимого см. в статье Общие задачи программирования документов 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;
}