Partager via


Guide de conception de l’API Application de support d’impression v3

Cet article fournit des conseils et des exemples pour les oem d’imprimante et les IHV qui implémentent une application de support d’impression v3 (PSA) pour leur appareil.

Terminologie

Terme Définition
Antigène prostatique spécifique (PSA) Application de prise en charge d’impression. Application UWP qui utilise l’API dans ce document.
IPP Protocole d’impression Internet. Utilisé à partir d’un appareil client pour interagir avec l’imprimante pour récupérer et définir les préférences d’impression et envoyer le document à imprimer.
Imprimante associée au support d’impression. Imprimante IPP physique liée à PSA.
Imprimante IPP Imprimante qui prend en charge le protocole IPP.
PDL Langue de description de la page. Format dans lequel un document est envoyé à l’imprimante.
Imprimante PSA associée Imprimante IPP physique associée à une application PSA.
Capacités de l'appareil d'impression Format de document XML pour la définition des fonctionnalités d’imprimante.
PrintSupportExtension Tâche de fond PSA responsable de la fourniture des capacités d’extension de contrainte de l’imprimante.

Cet article contient les extensions v3 de l’API publique existante de l’application de support d’impression décrite dans le guide de conception de l’application de support d’impression et dans l’espace de noms Windows.Graphics.Printing.PrintSupport. L’API PSA permet aux fabricants d’imprimantes de développer des applications de support matériel qui peuvent améliorer l’expérience d’impression d’un utilisateur Windows lors de l’utilisation du pilote de classe IPP Microsoft sans avoir à développer un pilote personnalisé. Les composants d’impression communiquent avec l’application PSA via un processus de courtage PSA.

Pour plus d’informations, consultez les articles suivants :

Sujet Description
Guide de Conception de l’Application de Support d’Impression Fournit des conseils et des exemples pour les oem d’imprimante et les IHD qui implémentent une application de support d’impression (PSA) pour leur appareil.
Guide de conception v4 API pour les applications de support d’impression Fournit des conseils et des exemples pour les oem d’imprimante et les IHD qui implémentent une application de support d’impression v4 (PSA) pour leur appareil.
Spécification du manifeste MSIX pour l’imprimante virtuelle de prise en charge de l’impression Fournit des directives et des exemples sur le manifeste MSIX pour les OEM d'imprimantes et les IHV qui implémentent une imprimante virtuelle Print Support.
Association d’applications de support d’impression Fournit des conseils et des exemples pour associer une application de support d’impression (PSA) à une imprimante.

Les extensions importantes de l’API sont les suivantes :

  • Compression IPP : L’API PSA v3 ajoute une fonctionnalité pour améliorer l’impression IPP en intégrant une fonctionnalité de compression IPP dans une tâche d’impression pour les imprimantes IPP qui supportent cette fonctionnalité. Certaines PSA peuvent avoir une compression personnalisée, ce qui signifie que la tâche IPP subit une double compression affectant les performances. Pour atténuer ce problème, l’API PSA v3 introduit une propriété IsIppCompressionEnabled et une fonction DisableIppCompressionForJob (pour désactiver la compression du travail actuel si nécessaire) dans la classe d’exécution PrintWorkflowJobStartingEventArgs (API PSA v1).

  • Gestion des erreurs de tâche IPP et notification d’erreur : L’API PSA v3 introduit un événement JobIssueDetected dans la classe d’exécution PrintWorkflowJobBackgroundSession (API PSA v1). L’événement est déclenché chaque fois que PSA détecte une erreur/avertissement dans le travail d’impression. PSA est ensuite responsable de l’affichage de la notification d’erreur à l’utilisateur. Lorsque PSA s’enregistre pour cet événement et définit la propriété SkipSystemErrorToast sur True dans PrintWorkflowJobIssueDetectedEventArgs, elle indique au système d’impression de ne pas afficher la notification du système d’impression Windows. L’API PSA v3 fournit également un mécanisme permettant à PSA de lancer l’interface utilisateur lorsque l’utilisateur interagit avec toast.

  • Délai d’attente personnalisé pour la communication IPP : L’API PSA v3 fournit une API permettant à une application de support d’impression de remplacer les délais d’attente IPP. En outre, la classe runtime PrintSupportIppCommunicationConfiguration est ajoutée à PrintSupportPrintDeviceCapabilitiesChangedEventArgs pour manipuler les délais d’expiration de communication IPP. En outre, l’API PSA v3 introduit un événement, qui est déclenché lorsqu’il existe une erreur avec la communication IPP. Cet événement a été introduit afin que les IHV puissent enquêter sur l’échec et ajuster les valeurs de délai d’attente en conséquence.

  • Support IPPFaxOut : L’API PSA v3 ajoute une fonctionnalité au système d’impression pour supporter les imprimantes IPPFaxOut. Pour prendre en charge Fax, PSA prend en charge un filtre de rendu pour convertir XPS en TIFF. Comme PSA peut manipuler le contenu XPS avant la conversion en TIFF, il fournit la valeur d’énumération XpsToTiff dans PrintWorkflowPdlConversionType afin que PSA puisse avoir accès à XPS au convertisseur TIFF. De plus, elle fournit la propriété IsIPPFaxOutPrinter à la classe d’exécution IppPrintDevice permettant à l’application de support d’impression de différencier entre l’imprimante standard et les imprimantes IPPFaxOut.

Désactivation de la compression IPP

La compression IPP est illustrée dans l’exemple de code suivant.

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

Gestion des erreurs de tâche IPP

Cet exemple démontre comment l’application de support d’impression peut s’enregistrer pour les erreurs de tâches, afficher des notifications d’erreur, et lancer l’interface utilisateur lorsque l’utilisateur active ces notifications.

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

Configuration du délai d’attente de communication IPP

Cet exemple montre comment définir le délai d’expiration de communication IPP.

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

Gestion des erreurs de communication IPP

Cet exemple montre comment gérer les erreurs de communication IPP.

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
            }
        }
    }  
}

Impression vers une imprimante IPPFaxOut dans l’application de support d’impression

Cet exemple démontre comment imprimer sur une imprimante IPPFaxOut dans une application de support d’impression.

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

Désactivation de l’interface utilisateur de télécopie pour le numéro de téléphone fourni par PSA

Avec la prise en charge de l’imprimante de télécopie IPP, cet exemple montre une interface utilisateur pour demander à l’utilisateur d’entrer le numéro de télécopie lors de l’impression sur l’imprimante de télécopie. Mais le PSA peut souhaiter afficher sa propre interface utilisateur avec plus d’informations et d’options. Étant donné qu’il est déroutant pour l’utilisateur s’il existe deux interfaces utilisateur pour la télécopie, cet exemple illustre une option permettant à un PSA de désactiver l’interface utilisateur système lorsqu’il souhaite afficher son interface utilisateur de télécopie.

L’exemple suivant illustre l’utilisation de l’API.

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

Remarques

Les exemples de cet article sont basés sur les exemples des API PSA v1 et v2 dans le guide de conception de l’application de support d’impression avec l’hypothèse que le développeur est familiarisé avec le flux de travail de l’API PSA.

Cet article contient les extensions de l’API publique existante de l’application de support d’impression décrite dans le guide de conception de l’application de support d’impression et dans l’espace de noms Windows.Graphics.Printing.PrintSupport. L’API PSA permet aux fabricants d’imprimantes de développer des applications UWP qui peuvent améliorer l’expérience d’impression des utilisateurs Windows lors de l’utilisation du pilote de classe IPP Microsoft, sans avoir besoin de développer un pilote personnalisé.

Les composants d’impression communiquent avec l’application PSA à travers un processus de courtier PSA.

DisableIppCompressionForJob

plan de fin de maintenance pour les pilotes d’imprimante tiers sur Windows

IsIppCompressionEnabled

IsIPPFaxOutPrinter

IppPrintDevice

ProblèmeDeTravailDétecté

PrintSupportIppCommunicationConfiguration

PrintSupportPrintDeviceCapabilitiesChangedEventArgs

PrintWorkflowJobBackgroundSession

PrintWorkflowJobIssueDetectedEventArgs

PrintWorkflowJobStartingEventArgs

PrintWorkflowPdlConversionType

SkipSystemErrorToast

Windows.Graphics.Printing.PrintSupport