Delen via


Ontwerphandleiding voor Print Support Application v3 API

Dit artikel bevat richtlijnen en voorbeelden voor printer-OEM's en IHD's die een v3 Print Support App (PSA) implementeren voor hun apparaat.

Terminologie

Term Definitie
PSA Toepassing voor afdrukondersteuning. UWP-app die gebruikmaakt van de API in dit document.
IPP Internet Printing Protocol. Wordt gebruikt vanaf een clientapparaat om met de printer te communiceren om afdrukvoorkeuren op te halen en in te stellen en om het document te verzenden dat moet worden afgedrukt.
Afdrukondersteuning voor de gekoppelde printer Fysieke IPP-printer die is gekoppeld aan PSA.
IPP-printer Printer die het IPP-protocol ondersteunt.
PDL Taal voor paginabeschrijving. De indeling waarin een document naar de printer wordt verzonden.
Gekoppelde PSA-printer Fysieke IPP-printer die is gekoppeld aan een PSA-toepassing.
Afdrukapparaatmogelijkheden XML-documentindeling voor het definiëren van printermogelijkheden.
PrintSupportExtension PSA-achtergrondtaak die verantwoordelijk is voor het bieden van uitbreidingsmogelijkheden voor printerbeperkingen.

Dit artikel bevat de v3-extensies voor de bestaande openbare API voor printondersteuningstoepassingen die worden beschreven in de ontwerphandleiding voor de printondersteunings-app en Windows.Graphics.Printing.PrintSupport naamruimte. Met de PSA API kunnen printerfabrikanten hardware-ondersteuningsapps ontwikkelen die de afdrukervaring van een Windows-gebruiker kunnen verbeteren wanneer de inbox Microsoft IPP Class Driver wordt gebruikt, zonder een aangepast stuurprogramma te ontwikkelen. Afdrukcomponenten communiceren met de PSA-app via een PSA-brokerproces.

Zie de volgende artikelen voor meer informatie:

Onderwerp Beschrijving
ontwerphandleiding voor Print Support App Biedt richtlijnen en voorbeelden voor printer-OEM's en IHD's die een print support-app (PSA) implementeren voor hun apparaat.
ontwerphandleiding voor Print Support App v4 API Biedt richtlijnen en voorbeelden voor printer-OEM's en IHD's die een v4 Print Support App (PSA) implementeren voor hun apparaat.
MSIX-manifestspecificatie voor virtuele printerondersteuning voor afdrukken Biedt richtlijnen en voorbeelden van MSIX-manifesten voor printer-OEM's en -IHV's die een virtuele printer voor printondersteuning implementeren.
Afdrukondersteuning-app associatie Bevat richtlijnen en voorbeelden voor het koppelen van een print support-app (PSA) aan een printer.

De belangrijke extensies voor de API zijn als volgt:

  • IPP-compressie - PSA v3 API voegt een functie toe om IPP-afdrukken te verbeteren door een IPP-compressiefunctie toe te voegen in een afdruktaak voor IPP-printers die deze functie ondersteunen. Sommige PSA hebben mogelijk aangepaste compressie, wat betekent dat de IPP-taak dubbele compressie heeft die van invloed is op de prestaties. Om dit te verhelpen, introduceert de PSA v3-API een eigenschap IsIppCompressionEnabled en een DisableIppCompressionForJob functie (om compressie voor de huidige taak indien nodig uit te schakelen) in de runtimeklasse PrintWorkflowJobStartingEventArgs (PSA v1 API).

  • IPP-taakfoutafhandeling en fout-toast - PSA v3-API introduceert een JobIssueDetected-gebeurtenis in PrintWorkflowJobBackgroundSession (PSA v1 API)-runtimeklasse. De gebeurtenis wordt aangemaakt telkens wanneer PSA een fout of waarschuwing in de afdruktaak detecteert. PSA is vervolgens verantwoordelijk voor het weergeven van de foutmelding aan de gebruiker. Wanneer PSA zich registreert voor deze gebeurtenis en de eigenschap SkipSystemErrorToast op true instelt in PrintWorkflowJobIssueDetectedEventArgs, geeft het aan het afdruksysteem de instructie om de Windows-afdruksysteemmelding niet weer te geven. De PSA v3-API biedt ook een mechanisme voor PSA om de gebruikersinterface te starten bij interactie van de gebruiker met een melding.

  • Aangepaste IPP-communicatietime-outs - De PSA v3-API biedt een API waarmee een PSA de IPP-timeouts kan overschrijven. Bovendien wordt de runtime-klasse PrintSupportIppCommunicationConfiguration toegevoegd aan PrintSupportPrintDeviceCapabilitiesChangedEventArgs voor het aanpassen van de time-outs voor IPP-communicatie. Bovendien introduceert de PSA v3-API een gebeurtenis, die wordt gegenereerd wanneer er een fout optreedt met de IPP-communicatie. De gebeurtenis is geïntroduceerd zodat IHV de fout kan onderzoeken en de time-outwaarden dienovereenkomstig kan aanpassen.

  • Ondersteuning voor IPPFaxOut - PSA v3 API voegt een functie toe aan het afdruksysteem ter ondersteuning van IPPFaxOut-printers. Ter ondersteuning van fax ondersteunt PSA een renderfilter om XPS te converteren naar Tiff. Aangezien PSA de XPS-inhoud kan manipuleren voordat deze wordt geconverteerd naar TIFF, biedt het de xpsToTiff-enumwaarde in PrintWorkflowPdlConversionType zodat PSA toegang heeft tot XPS naar TIFF-conversieprogramma. Daarnaast biedt het de eigenschap IsIPPFaxOutPrinter aan de runtime-klasse IppPrintDevice, zodat PSA onderscheid kan maken tussen de standaardprinter en IPPFaxOut-printers.

IPP-compressie uitschakelen

IPP-compressie wordt weergegeven in het volgende codevoorbeeld.

public sealed class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{
    public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
    private PrintWorkflowJobBackgroundSession session;

    public void Run(IBackgroundTaskInstance taskInstance)
    {
        TaskInstanceDeferral = taskInstance.GetDeferral();

        if (taskInstance.TriggerDetails is PrintWorkflowJobTriggerDetails jobDetails)
        {
            session = jobDetails.PrintWorkflowJobSession;
            session.JobStarting += OnJobStarting;
            session.PdlModificationRequested += OnPdlModificationRequested;
            session.JobIssueDetected += OnJobIssueDetected;

            // Make sure to register all the event handlers before PrintWorkflowJobBackgroundSession.Start is called.
            session.Start();
        }
    }

    private void OnJobStarting(PrintWorkflowJobBackgroundSession sender, PrintWorkflowJobStartingEventArgs args)
    {
        using (args.GetDeferral())
        {
            // Skip system rendering.
            args.SetSkipSystemRendering();

            // If Ipp compression is enabled by the system, check to see if PSA does custom compression for the printer
            // and disable system compression if required.
            if (args.IsIppCompressionEnabled)
            {
                if (this.HasCustomCompression(args.Printer))
                {
                    args.DisableIppCompressionForJob();
                }
            }
        }
    }

    bool HasCustomCompression(IppPrintDevice device)
    {
        bool hasCustomCompression = false;
        // Check if the PSA does custom compression for the printer
        return hasCustomCompression;
    } 
} 

Foutafhandeling van IPP-taken

In dit voorbeeld ziet u hoe de PSA-app zich kan registreren voor taakfouten, meldingen daarvan kan weergeven en de gebruikersinterface kan starten wanneer de gebruiker de melding activeert.

public sealed class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{
    public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
    private PrintWorkflowJobBackgroundSession session;

    public void Run(IBackgroundTaskInstance taskInstance)
    {
        TaskInstanceDeferral = taskInstance.GetDeferral();

        if (taskInstance.TriggerDetails is PrintWorkflowJobTriggerDetails jobDetails)
        {
            session = jobDetails.PrintWorkflowJobSession;
            session.JobStarting += OnJobStarting;
            session.PdlModificationRequested += OnPdlModificationRequested;
            session.JobIssueDetected += OnJobIssueDetected;

            // Make sure to register all the event handlers before PrintWorkflowJobBackgroundSession.Start is called.
            session.Start();
        }
    }

    private void OnJobIssueDetected (PrintWorkflowJobBackgroundSession sender, PrintWorkflowJobIssueDetectedEventArgs args)
    {
        // Using a deferral to exclude the background process from being suspended while PSA displays UI.
        Deferral deferral = args.GetDeferral();
        var toast = new ToastNotification(GetErrorToastXml(args.ExtendedError,
                args.JobIssueKind, args.PrinterJob, args.Configuration));
        toast.Activated += async (toastSender, e) =>
        {
            // PSA UI application 
            PrintWorkflowUICompletionStatus uiStatus = await args.UILauncher.LaunchAndCompleteUIAsync();
            // Complete deferral
            deferral.Complete();
        };
        toast.Dismissed += async (toastSender, e) => { deferral.Complete(); };
        toast.Failed += async (toastSender, e) => { deferral.Complete(); };
            
        ToastNotificationManager.CreateToastNotifier().Show(toast);
        args.SkipSystemErrorToast = true;
    }

    private XmlDocument GetErrorToastXml(Exception jobError, PrintWorkflowJobIssueKind issueKind,
        PrintWorkflowPrinterJob printerJob, PrintWorkflowConfiguration workflowConfig )
    {
        var errorToastXml = new XmlDocument();
        // Generate Toast Xml based on error information from Exception and PrintWorkflowPrinterJob.
        return errorToastXml;
    }
}

Time-out voor IPP-communicatie instellen

In dit voorbeeld ziet u hoe u de time-out voor IPP-communicatie instelt.

public sealed class PrintSupportExtensionBackGroundTask : IBackgroundTask
{
    public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
    private PrintSupportExtensionSession session;

    public void Run(IBackgroundTaskInstance taskInstance)
    {
        taskInstance.Canceled += OnTaskInstanceCanceled;
        TaskInstanceDeferral = taskInstance.GetDeferral();

        if (taskInstance.TriggerDetails is PrintSupportExtensionTriggerDetails extensionDetails)
        {
            session = extensionDetails.Session;
            session.PrintTicketValidationRequested += OnSessionPrintTicketValidationRequested;
            session.PrintDeviceCapabilitiesChanged += OnSessionPrintDeviceCapabilitiesChanged;
            session.CommunicationErrorDetected += OnCommunicationErrorDetected;

            // Make sure to register all the event handlers before PrintSupportExtensionSession.Start is called.
            session.Start();
        }
    }

    private void OnTaskInstanceCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
    {
        session = null;
        TaskInstanceDeferral.Complete();
    }
    
    private void OnSessionPrintDeviceCapabilitiesChanged(PrintSupportExtensionSession sender, PrintSupportPrintDeviceCapabilitiesChangedEventArgs args)
    {
        // Using deferral to exclude the background process from being suspended while PSA updates the printer PDC and other configurations.
        using (args.GetDeferral())
        {
            if (args.CommunicationConfiguration.CanModifyTimeouts)
                {
                    this.UpdateAttributeTimeouts(args.CommunicationConfiguration, sender.Printer);
                    this.UpdateJobTimeouts(args.CommunicationConfiguration, sender.Printer);
                }
                // Do other operations, such as Updating PDC, PDR, and so on here.
        }
    }

    void UpdateAttributeTimeouts(PrintSupportIppCommunicationConfiguration config, IppPrintDevice device)
    {
        IppPrinterCommunicationKind communicationKind = config.CommunicationKind;
        PrintSupportIppCommunicationTimeouts currentTimeouts = config.IppAttributeTimeouts;

        // Adjust attribute timeouts based on the printer
        switch (communicationKind)
        {
            case IppPrinterCommunicationKind.Network:
                currentTimeouts.ConnectTimeout = TimeSpan.FromSeconds(10);
                currentTimeouts.SendTimeout = TimeSpan.FromSeconds(10);
                currentTimeouts.ReceiveTimeout = TimeSpan.FromSeconds(10);
                break;
            case IppPrinterCommunicationKind.UniversalPrint:
                // adjust timeout for universal printer
                break;
        }
        
    }

    void UpdateJobTimeouts(
        PrintSupportIppCommunicationConfiguration config, IppPrintDevice device)
    {
        IppPrinterCommunicationKind communicationKind = config.CommunicationKind;
        PrintSupportIppCommunicationTimeouts currentTimeouts = config.IppJobTimeouts;
        // Adjust job timeouts based on the printer and communication type
        switch (communicationKind)
        {
            case IppPrinterCommunicationKind.Network:
                currentTimeouts.ConnectTimeout = TimeSpan.FromSeconds(30);
                currentTimeouts.SendTimeout = TimeSpan.FromSeconds(30);
                currentTimeouts.ReceiveTimeout = TimeSpan.FromSeconds(30);
                break;
            case IppPrinterCommunicationKind.UniversalPrint:
                // adjust timeout for universal printer
                break;
        }
    }
}

Afhandelen van IPP-communicatiefouten

In dit voorbeeld laten we zien hoe u kunt omgaan met IPP-communicatiefouten.

public sealed class PrintSupportExtensionBackGroundTask : IBackgroundTask
{
    public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
    private PrintSupportExtensionSession session;
    public void Run(IBackgroundTaskInstance taskInstance)
    {
        taskInstance.Canceled += OnTaskInstanceCanceled;
        TaskInstanceDeferral = taskInstance.GetDeferral();

        if (taskInstance.TriggerDetails is PrintSupportExtensionTriggerDetails extensionDetails)
        {
            session = extensionDetails.Session;
            session.PrintTicketValidationRequested += OnSessionPrintTicketValidationRequested;
            session.PrintDeviceCapabilitiesChanged += OnSessionPrintDeviceCapabilitiesChanged;
            session.CommunicationErrorDetected += OnCommunicationErrorDetected ;

            // Make sure to register all the event handlers before PrintSupportExtensionSession.Start is called.
            session.Start();
        }
    }

    private void OnTaskInstanceCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
    {
        session = null;
        TaskInstanceDeferral.Complete();
    }

    private void OnCommunicationErrorDetected(PrintSupportExtensionSession sender, PrintSupportCommunicationErrorDetectedEventArgs args)
    {
        // Using deferral to exclude the background process from being suspended while PSA updates the timeouts.
        using (args.GetDeferral())
        {

            if (args.ErrorKind == IppCommunicationErrorKind.Timeout)
            {
                PrintSupportIppCommunicationConfiguration ippConfig = args.CommunicationConfiguration;
                IppPrintDevice device = sender.Printer;
                // Update timeout based on the communication error
            }
        }
    }  
}

Afdrukken naar IPP-uitfaxprinter in PSA

In dit voorbeeld ziet u hoe u een IPPFaxOut-printer gebruikt om af te drukken binnen een PSA.

public sealed class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{
    public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
    private PrintWorkflowJobBackgroundSession session;

    public void Run(IBackgroundTaskInstance taskInstance)
    {
        TaskInstanceDeferral = taskInstance.GetDeferral();

        if (taskInstance.TriggerDetails is PrintWorkflowJobTriggerDetails jobDetails)
        {
            session = jobDetails.PrintWorkflowJobSession;
            session.JobStarting += OnJobStarting;
            session.PdlModificationRequested += OnPdlModificationRequested;
            session.JobIssueDetected += OnJobIssueDetected;

            // Make sure to register all the event handlers before PrintWorkflowJobBackgroundSession.Start is called.
            session.Start();
        }
    }

    private async void OnPdlModificationRequested(PrintWorkflowJobBackgroundSession sender, PrintWorkflowPdlModificationRequestedEventArgs args)
    {
        using (args.GetDeferral())
        {
            IppPrintDevice printer = args.PrinterJob.Printer;
            IInputStream xpsContent = args.SourceContent.GetInputStream();
            WorkflowPrintTicket printTicket = args.PrinterJob.GetJobPrintTicket();

            string documentFormat = this.GetPrinterDocumentFormat(printer);
            PrintWorkflowPdlTargetStream targetStream = args.CreateJobOnPrinter(documentFormat);
            IInputStream xpsSourceContent = xpsContent;
            if (printer.IsIPPFaxOutPrinter)
            {                    
                // Add cover page to XPS source document   
                xpsSourceContent = this.AddCoverPageToXpsContent(xpsContent);
            }
            
            PrintWorkflowPdlConverter pdlConverter;
            switch (documentFormat.ToLowerInvariant())
            {
                case "image/pwg-raster":
                    pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToPwgr);
                    break;
                case "application/pclm":
                    pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToPclm);
                    break;
                case "application/pdf":
                    pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToPdf);
                    break;
                case "image/tiff":
                    pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToTiff);
                    break;
                default:
                    // This should not happen, aborting workflow if PSA does not identify the supported PDLs
                    args.Configuration.AbortPrintFlow(PrintWorkflowJobAbortReason.JobFailed);
                    return;
                }
                // Use pdlConverter to convert the source XPS stream to printer's document format and send it to the printer using targetStream.
                await pdlConverter.ConvertPdlAsync(printTicket, xpsSourceContent, targetStream.GetOutputStream());

                targetStream.CompleteStreamSubmission(PrintWorkflowSubmittedStatus.Succeeded);
            }
        }

    private IInputStream AddCoverPageToXpsContent(IInputStream xpsStream)
    {
        var coverPageXps = new InMemoryRandomAccessStream();
        // Add cover page to XPS content and write to coverPageXps stream
        return coverPageXps;
    }
}

Fax-gebruikersinterface uitschakelen voor telefoonnummer van PSA

Met de ondersteuning van de IPP-faxprinter toont dit voorbeeld een gebruikersinterface voor het aanvragen van de gebruiker om het faxnummer in te voeren bij het afdrukken naar de faxprinter. Maar de PSA wil mogelijk zijn eigen gebruikersinterface weergeven met meer informatie en opties. Omdat het verwarrend is voor de gebruiker als er twee UI's voor fax zijn, illustreert dit voorbeeld een optie voor een PSA om de gebruikersinterface van het systeem uit te schakelen wanneer ze hun faxgebruikersinterface willen weergeven.

In het volgende voorbeeld ziet u het API-gebruik.

public sealed class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{

    private void OnJobStarting(PrintWorkflowJobBackgroundSession sender, PrintWorkflowJobStartingEventArgs args)
    {
        using (args.GetDeferral())
        {
            // If the job is printing to an Ipp fax printer,
            // check whether PSA has a custom UI and disable system UI for getting the fax number.
            if (args.IsIPPFaxOutPrinter)
            {
                if (this.HasCustomUIForFax(args.Printer))
                {
                    args.SkipSystemFaxUI = true;
                }
            }
        }
    }

    bool HasCustomUIForFax(IppPrintDevice device)
    {
        bool hasCustomUIForFax = false;
        // Check if the PSA does custom UI for the given fax printer.
        return hasCustomUIForFax;
    }  
}

Opmerkingen

Voorbeelden in dit artikel zijn gebouwd op basis van de voorbeelden van de PSA v1- en v2-API's in de Print-handleiding voor het ontwerpen van apps met de veronderstelling dat de ontwikkelaar bekend is met de PSA API-werkstroom.

Dit artikel bevat de extensies voor de bestaande openbare printondersteuningsapplicatie-API die wordt beschreven in de ontwerphandleiding voor printondersteuningsapplicaties en Windows.Graphics.Printing.PrintSupport naamruimte. Met de PSA-API kunnen printerfabrikanten UWP-apps ontwikkelen die de afdrukervaring van Windows-gebruikers kunnen verbeteren terwijl ze de ingebouwde Microsoft IPP Class Driver gebruiken, zonder dat er een aangepast stuurprogramma hoeft te worden ontwikkeld.

Afdrukonderdelen communiceren met de PSA-app met behulp van een PSA-brokerproces.

DisableIppCompressionForJob

einde van het onderhoudsplan voor printerstuurprogramma's van derden in Windows

IsIppCompressionEnabled

IsIPPFaxOutPrinter

IppPrintDevice

ProbleemMetOpdrachtGedetecteerd

PrintSupportIppCommunicationConfiguration

PrintSupportPrintDeviceCapabilitiesChangedEventArgs

PrintWorkflowJobBackgroundSession

PrintWorkflowJobIssueDetectedEventArgs

PrintWorkflowJobStartingEventArgs

PrintWorkflowPdlConversionType

SkipSystemErrorToast

Windows.Graphics.Printing.PrintSupport