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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment