Can we create an XPS file from Direct2D without print queue
See the question and my original answer on StackOverflowIt's not magic, but almost. You can implement IPrintDocumentPackageTarget COM interface yourself and use it when calling the ID2D1Device::CreatePrintControl method.
In your implementation you can delegate the work to the IXpsOMObjectFactory::CreatePackageWriterOnStream method, so, it can be something like this:
CTarget *target = new CTarget();
auto hr = d2dDevice->CreatePrintControl(
wicFactory,
target, // use my own target
nullptr,
&printControl
);
delete target;
This is the CTarget
sample class that implements IPrintDocumentPackageTarget
, and IXpsDocumentPackageTarget
:
// needs <initguid.h>, <shlwapi.h> and shlwapi.lib
class CTarget : public IPrintDocumentPackageTarget, IXpsDocumentPackageTarget
{
// make sure this get release *before* CoUninitialize call
CComPtr<IXpsOMObjectFactory> _factory; // uses ATL needs <atlbase.h>
public:
CTarget() {}
STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
{
static QITAB rgqit[] =
{
QITABENT(CTarget, IPrintDocumentPackageTarget),
QITABENT(CTarget, IXpsDocumentPackageTarget),
{ 0},
};
return QISearch(this, rgqit, riid, ppv);
}
// for testing we just send something static
STDMETHODIMP_(ULONG) AddRef() { return 1; }; STDMETHODIMP_(ULONG) Release() { return 1; };
// IPrintDocumentPackageTarget
STDMETHODIMP GetPackageTargetTypes(UINT32* targetCount, GUID** targetTypes)
{
if (!targetCount || !targetTypes) return E_INVALIDARG;
*targetTypes = (GUID*)CoTaskMemAlloc(sizeof(GUID));
if (!*targetTypes)
{
*targetCount = 0;
return E_OUTOFMEMORY;
}
*targetCount = 1;
**targetTypes = ID_DOCUMENTPACKAGETARGET_MSXPS;
return S_OK;
}
STDMETHODIMP GetPackageTarget(REFGUID guidTargetType, REFIID riid, void** ppvTarget)
{
if (guidTargetType == ID_DOCUMENTPACKAGETARGET_MSXPS)
return QueryInterface(riid, ppvTarget);
return E_FAIL;
}
STDMETHODIMP Cancel()
{
return S_OK;
}
// IXpsDocumentPackageTarget
STDMETHODIMP GetXpsOMPackageWriter(IOpcPartUri* documentSequencePartName, IOpcPartUri* discardControlPartName, IXpsOMPackageWriter** packageWriter)
{
// here you can create your own stream, file, memory, etc.
CComPtr<IStream> stream;
SHCreateStreamOnFile(L"c:\\temp\\d2d1.xps", STGM_CREATE | STGM_WRITE, &stream);
// ... and delegate to factory w/o more effort
// you can also configure custom properties, etc.
return _factory->CreatePackageWriterOnStream(stream, FALSE, XPS_INTERLEAVING_OFF, documentSequencePartName, nullptr, nullptr, nullptr, discardControlPartName, packageWriter);
}
STDMETHODIMP GetXpsOMFactory(IXpsOMObjectFactory** xpsFactory)
{
HRESULT hr = S_OK;
if (!_factory)
{
if (FAILED(hr = _factory.CoCreateInstance(CLSID_XpsOMObjectFactory)))
return hr;
}
return _factory.QueryInterface(xpsFactory);
}
STDMETHODIMP GetXpsType(XPS_DOCUMENT_TYPE* documentType)
{
if (!documentType) return E_INVALIDARG;
*documentType = XPS_DOCUMENT_TYPE_XPS;
return S_OK;
}
};