Open
Description
Background and motivation
AFAIK there's currently no solution to print without a PrintQueue
in case an application already has an instance of IXpsDocumentPackageTarget
.
This scenario occurs when implementing the WinRT PrintManager
(The modern print dialog) for a WPF app.
See PrintCompat.cs and WpfPrintDocumentSource.cs for context.
API Proposal
See XpsSerializationHelper.il for a minimal code flow.
New class XpsSerializationManagerInterop
using System.Windows.Xps.Serialization.RCW;
using System.Windows.Xps.Packaging;
namespace System.Windows.Xps.Serialization;
public sealed class XpsSerializationManagerInterop
{
readonly XpsOMSerializationManager _serializer;
readonly IXpsOMPackageWriter _writer;
private XpsSerializationManagerInterop(...);
public static XpsSerializationManagerInterop CreateFromXpsDocumentPackageTarget(object target)
{
// https://github.com/dotnet/wpf/blob/7b755d2bbcc9d77760f68b5e738b2587cabe1a37/src/Microsoft.DotNet.Wpf/src/System.Printing/CPP/src/PrintQueue.cpp#L4723-L4734
XpsOMPackagingPolicy policy = new((IXpsDocumentPackageTarget)target);
policy.EnsureXpsOMPackageWriter();
// Internally expose XpsOMPackagingPolicy._currentFixedDocumentSequenceWriter
var writer = policy.XpsOMPackageWriter;
XpsOMSerializationManager serializer = new(policy);
return new(serializer, )
}
// Proxy events from XpsOMSerializationManager
public event XpsSerializationPrintTicketRequiredEventHandler? PrintTicketRequired;
public event XpsSerializationProgressChangedEventHandler? ProgressChanged;
public void Print(object serializedObject)
{
_serializer.SaveAsXaml(serializedObject);
_serializer.Commit();
// Close writer to flush to printer
// Only close on success (no exception)
// https://github.com/dotnet/wpf/blob/906eb2878bbe4d5f86e77e9a0d4f85815e9f5aaf/src/Microsoft.DotNet.Wpf/src/System.Printing/CPP/src/XpsCompatiblePrinter.cpp#L125
_writer.Close();
}
}
Internally expose IXpsOMPackageWriter
from XpsOMPackagingPolicy
namespace System.Windows.Xps.Packaging
{
internal class XpsOMPackagingPolicy : BasePackagingPolicy
{
...
+ public IXpsOMPackageWriter XpsOMPackageWriter => _currentFixedDocumentSequenceWriter;
...
private IXpsOMPackageWriter _currentFixedDocumentSequenceWriter;
}
}
API Usage
object target = ...; // IXpsDocumentPackageTarget com object
var serializer = XpsSerializationManagerInterop.CreateFromXpsDocumentPackageTarget(target);
serializer.PrintTicketRequired += ...;
serializer.Print(paginator); // Might throw
Alternative Designs
Create an alternative interop PrintQueue
implementation:
object target = ...; // IXpsDocumentPackageTarget com object
var queue = PrintQueueInterop.CreateFromXpsOMPackageWriter(target);
var writer = PrintQueue.CreateXpsDocumentWriter(queue);
writer.Write(paginator, printTicket);
This has less new public api surface (only one new method CreateFromXpsOMPackageWriter
) but might require a lot more internal api changes / abstractions.
Risks
Both solutions can likely only be used for a single print, as the IXpsOMPackageWriter
has to be closed to flush the buffered data to the printer.