2025-11-28 00:35:46 +09:00

744 lines
18 KiB
C++

//+----------------------------------------------------------------------------
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Abstract:
// A sample demonstrating use of the XPS Object Model with the XPS Print
// API.
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <comdef.h>
#include <windows.h>
#include <t2embapi.h>
#include <XpsObjectModel.h>
#include <XpsPrint.h>
// The font to use for the page text. Needs to be a TrueType font.
const wchar_t g_fontName[] = L"Arial";
// This function creates a font resource for the given font name with the
// embedding type set appropriately for the licensing intent of the font.
HRESULT
CreateFontResourceForFont(
IXpsOMObjectFactory* xpsFactory,
LPCWSTR fontName,
IXpsOMFontResource **fontResource
)
{
HRESULT hr = S_OK;
HDC hDC = NULL;
LOGFONT logFont = {};
HGDIOBJ hFont = NULL;
ULONG privStatus = 0;
LONG ttStatus;
XPS_FONT_EMBEDDING embedding = XPS_FONT_EMBEDDING_NORMAL;
DWORD fontDataLen = GDI_ERROR;
HGLOBAL hGlobal = NULL;
LPVOID ptr = NULL;
IStream *fontStream = NULL;
GUID fontObfuscationGuid = {};
IOpcPartUri* partUri = NULL;
wchar_t fontPartName[60];
hDC = CreateDC(L"DISPLAY", NULL, NULL, NULL);
if (!hDC)
{
fwprintf(stderr, L"ERROR: Could not create device context\n");
hr = E_UNEXPECTED;
}
if (SUCCEEDED(hr))
{
if (wcscpy_s(logFont.lfFaceName, fontName) != 0)
{
fwprintf(stderr, L"ERROR: Could not copy font name into LOGFONT structure\n");
hr = E_UNEXPECTED;
}
}
if (SUCCEEDED(hr))
{
hFont = CreateFontIndirect(&logFont);
if (!hFont)
{
fwprintf(stderr, L"ERROR: Could not create font\n");
hr = E_UNEXPECTED;
}
}
if (SUCCEEDED(hr))
{
if (!SelectObject(hDC, hFont))
{
fwprintf(stderr, L"ERROR: Could not select object\n");
hr = E_UNEXPECTED;
}
}
if (SUCCEEDED(hr))
{
if ((ttStatus = TTGetEmbeddingType(hDC, &privStatus)) != E_NONE)
{
if (ttStatus == E_NOTATRUETYPEFONT)
{
fwprintf(stderr, L"ERROR: %s is not a TrueType font\n", fontName);
}
else
{
fwprintf(stderr, L"ERROR: Could not get embedding type: %08X\n", ttStatus);
}
hr = E_UNEXPECTED;
}
}
if (SUCCEEDED(hr))
{
switch (privStatus)
{
case EMBED_PREVIEWPRINT:
// Restricted font
embedding = XPS_FONT_EMBEDDING_RESTRICTED;
break;
case EMBED_EDITABLE:
// Editable font - MUST obfuscate
embedding = XPS_FONT_EMBEDDING_OBFUSCATED;
break;
case EMBED_INSTALLABLE:
// Installable font - SHOULD obfuscate
embedding = XPS_FONT_EMBEDDING_OBFUSCATED;
break;
case EMBED_NOEMBEDDING:
fwprintf(stderr, L"ERROR: %s may not be embedded\n", fontName);
hr = E_UNEXPECTED;
break;
default:
fwprintf(stderr, L"ERROR: Unrecognized embedding privileges: %08X\n", privStatus);
hr = E_UNEXPECTED;
break;
}
}
if (SUCCEEDED(hr))
{
fontDataLen = GetFontData(hDC, 0, 0, NULL, 0);
if (fontDataLen == GDI_ERROR)
{
fwprintf(stderr, L"ERROR: Could not get length of font data\n");
hr = E_UNEXPECTED;
}
}
if (SUCCEEDED(hr))
{
hGlobal = GlobalAlloc(GMEM_MOVEABLE, fontDataLen);
if (!hGlobal)
{
fwprintf(stderr, L"ERROR: Could not allocate memory with GlobalAlloc\n");
hr = E_OUTOFMEMORY;
}
}
if (SUCCEEDED(hr))
{
ptr = GlobalLock(hGlobal);
if (!ptr)
{
hr = HRESULT_FROM_WIN32(GetLastError());
fwprintf(stderr, L"ERROR: Could not lock global memory object: %08X\n", hr);
}
else
{
if (GetFontData(hDC, 0, 0, ptr, fontDataLen) == GDI_ERROR)
{
fwprintf(stderr, L"ERROR: Could not get font data\n");
hr = E_UNEXPECTED;
}
GlobalUnlock(hGlobal);
}
}
// Could perform font subsetting with CreateFontPackage here.
if (SUCCEEDED(hr))
{
if (FAILED(hr = CreateStreamOnHGlobal(hGlobal, TRUE, &fontStream)))
{
fwprintf(stderr, L"ERROR: Could not create font stream: %08X\n", hr);
}
else
{
// If CreateStreamOnHGlobal succeeded, the stream now controls the lifetime of the
// HGLOBAL.
hGlobal = NULL;
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = CoCreateGuid(&fontObfuscationGuid)))
{
fwprintf(stderr, L"ERROR: Could not create GUID for obfuscation: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (swprintf_s(
fontPartName,
sizeof(fontPartName)/sizeof(wchar_t),
L"/Resources/Fonts/%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X.odttf",
fontObfuscationGuid.Data1,
fontObfuscationGuid.Data2,
fontObfuscationGuid.Data3,
fontObfuscationGuid.Data4[0],
fontObfuscationGuid.Data4[1],
fontObfuscationGuid.Data4[2],
fontObfuscationGuid.Data4[3],
fontObfuscationGuid.Data4[4],
fontObfuscationGuid.Data4[5],
fontObfuscationGuid.Data4[6],
fontObfuscationGuid.Data4[7]
) == -1)
{
fwprintf(stderr, L"ERROR: Could not format GUID into part name\n");
hr = E_UNEXPECTED;
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = xpsFactory->CreatePartUri(
fontPartName,
&partUri)))
{
fwprintf(stderr, L"ERROR: Could not create part URI: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = xpsFactory->CreateFontResource(
fontStream,
embedding,
partUri,
FALSE,
fontResource
)))
{
fwprintf(stderr, L"ERROR: Could not create font resource: %08X\n", hr);
}
}
if (fontStream)
{
fontStream->Release();
fontStream = NULL;
}
if (partUri)
{
partUri->Release();
partUri = NULL;
}
if (hGlobal)
{
GlobalFree(hGlobal);
}
if (hFont)
{
DeleteObject(hFont);
}
if (hDC)
{
DeleteDC(hDC);
}
return hr;
}
HRESULT
AddGlyphs(
IXpsOMObjectFactory* xpsFactory,
IXpsOMPage* page,
IXpsOMFontResource* font,
LPCWSTR text,
XPS_POINT *origin,
FLOAT fontSize,
XPS_STYLE_SIMULATION sims
)
{
HRESULT hr = S_OK;
IXpsOMGlyphs* glyphs = NULL;
IXpsOMGlyphsEditor* glyphsEditor = NULL;
IXpsOMSolidColorBrush* solidColorBrush = NULL;
IXpsOMVisualCollection* visuals = NULL;
if (FAILED(hr = xpsFactory->CreateGlyphs(
font,
&glyphs
)))
{
fwprintf(stderr, L"ERROR: Could not create glyphs: %08X\n", hr);
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = glyphs->GetGlyphsEditor(&glyphsEditor)))
{
fwprintf(stderr, L"ERROR: Could not get glyphs editor: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = glyphsEditor->SetUnicodeString(
text
)))
{
fwprintf(stderr, L"ERROR: Could not set UnicodeString: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = glyphsEditor->ApplyEdits()))
{
fwprintf(stderr, L"ERROR: Could not apply edits: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
XPS_COLOR color;
color.colorType = XPS_COLOR_TYPE_SRGB;
color.value.sRGB.alpha = 255;
color.value.sRGB.red = 0;
color.value.sRGB.green = 0;
color.value.sRGB.blue = 0;
if (FAILED(hr = xpsFactory->CreateSolidColorBrush(
&color,
NULL,
&solidColorBrush
)))
{
fwprintf(stderr, L"ERROR: Could not create solid color brush: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = glyphs->SetFillBrushLocal(solidColorBrush)))
{
fwprintf(stderr, L"ERROR: Could not set fill brush: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = glyphs->SetOrigin(origin)))
{
fwprintf(stderr, L"ERROR: Could not set origin: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = glyphs->SetFontRenderingEmSize(fontSize)))
{
fwprintf(stderr, L"ERROR: Could not set font size: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = glyphs->SetStyleSimulations(sims)))
{
fwprintf(stderr, L"ERROR: Could not set style simulations: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = page->GetVisuals(&visuals)))
{
fwprintf(stderr, L"ERROR: Could not get visuals collection: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = visuals->Append(glyphs)))
{
fwprintf(stderr, L"ERROR: Could not add glyphs to page: %08X\n", hr);
}
}
if (visuals)
{
visuals->Release();
visuals = NULL;
}
if (solidColorBrush)
{
solidColorBrush->Release();
solidColorBrush = NULL;
}
if (glyphsEditor)
{
glyphsEditor->Release();
glyphsEditor = NULL;
}
if (glyphs)
{
glyphs->Release();
glyphs = NULL;
}
return hr;
}
void Usage(wchar_t *argv0)
{
fwprintf(stderr, L"XPS Object Model Printing Sample\n\n");
fwprintf(stderr, L"\tUsage: %s <printer name> [<output file name>]\n", argv0);
}
int wmain(int argc, wchar_t* argv[])
{
HRESULT hr = S_OK;
HANDLE completionEvent = NULL;
IXpsPrintJob* job = NULL;
IXpsPrintJobStream* jobStream = NULL;
IXpsOMObjectFactory* xpsFactory = NULL;
IOpcPartUri* partUri = NULL;
IXpsOMPackageWriter* packageWriter = NULL;
XPS_SIZE pageSize = {816, 1056};
IXpsOMPage* xpsPage = NULL;
IXpsOMFontResource* fontResource = NULL;
XPS_POINT origin = {50.0f, 200.0f};
XPS_JOB_STATUS jobStatus = {};
if (argc < 2 || argc > 3)
{
Usage(argv[0]);
return 1;
}
if (FAILED(hr = CoInitializeEx(0, COINIT_MULTITHREADED)))
{
fwprintf(stderr, L"ERROR: CoInitializeEx failed with HRESULT 0x%X\n", hr);
return 1;
}
if (SUCCEEDED(hr))
{
completionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!completionEvent)
{
hr = HRESULT_FROM_WIN32(GetLastError());
fwprintf(stderr, L"ERROR: Could not create competion event: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = StartXpsPrintJob(
argv[1],
NULL,
argc == 3 ? argv[2] : NULL,
NULL,
completionEvent,
NULL,
0,
&job,
&jobStream,
NULL
)))
{
fwprintf(stderr, L"ERROR: Could not start XPS print job: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = CoCreateInstance(
__uuidof(XpsOMObjectFactory),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IXpsOMObjectFactory),
reinterpret_cast<void**>(&xpsFactory)
)
)
)
{
fwprintf(stderr, L"ERROR: Could not create XPS OM Object Factory: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = xpsFactory->CreatePartUri(L"/FixedDocumentSequence.fdseq", &partUri)))
{
fwprintf(stderr, L"ERROR: Could not create part URI: %08X\n", hr);
}
}
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);
}
}
if (partUri)
{
partUri->Release();
partUri = NULL;
}
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);
}
}
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);
}
}
if (partUri)
{
partUri->Release();
partUri = NULL;
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = xpsFactory->CreatePartUri(L"/Documents/1/Pages/1.fpage", &partUri)))
{
fwprintf(stderr, L"ERROR: Could not create part URI: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = xpsFactory->CreatePage(&pageSize, L"en-US", partUri, &xpsPage)))
{
fwprintf(stderr, L"ERROR: Could not create page: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = CreateFontResourceForFont(xpsFactory, g_fontName, &fontResource)))
{
// Error already reported.
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = AddGlyphs(
xpsFactory,
xpsPage,
fontResource,
L"XPS",
&origin,
72.0f,
XPS_STYLE_SIMULATION_NONE)))
{
// Error already reported.
}
}
if (SUCCEEDED(hr))
{
origin.x = 420.0f;
origin.y = 300.0f;
if (FAILED(hr = AddGlyphs(
xpsFactory,
xpsPage,
fontResource,
L"Print with Confidence",
&origin,
36.0f,
XPS_STYLE_SIMULATION_ITALIC)))
{
// Error already reported.
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = packageWriter->AddPage(
xpsPage,
&pageSize,
NULL,
NULL,
NULL,
NULL
)))
{
fwprintf(stderr, L"ERROR: Could not add page to document: %08X\n", hr);
}
}
if (SUCCEEDED(hr))
{
if (FAILED(hr = packageWriter->Close()))
{
fwprintf(stderr, L"ERROR: Could not close package writer: %08X\n", hr);
}
}
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 one in the first place.
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);
}
}
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 (SUCCEEDED(hr))
{
wprintf(L"Done!\n");
}
if (fontResource)
{
fontResource->Release();
fontResource = NULL;
}
if (xpsPage)
{
xpsPage->Release();
xpsPage = NULL;
}
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();
return SUCCEEDED(hr) ? 0 : 1;
}