See the question and my original answer on StackOverflow

It'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;
    }
};