Partilhar via


Guia de design da API do Aplicativo de Suporte de Impressão v3

Este artigo fornece orientações e exemplos para OEMs de impressoras e IHVs que estão implementando um aplicativo de suporte de impressão v3 (PSA) para seus dispositivos.

Terminologia

Prazo Definição
PSA Aplicação de Suporte de Impressão. Aplicativo UWP que usa a API neste documento.
IPP Protocolo de impressão pela Internet. Usado a partir de um dispositivo cliente para interagir com a impressora para recuperar e definir preferências de impressão e para enviar o documento a ser impresso.
Impressora associada ao suporte de impressão Impressora IPP física vinculada à PSA.
Impressora IPP Impressora que suporta o protocolo IPP.
PDL Linguagem de descrição da página. O formato em que um documento é enviado para a impressora.
Impressora PSA associada Impressora IPP física associada a uma aplicação PSA.
CapacidadesDoDispositivoDeImpressão Formato de documento XML para definir os recursos da impressora.
PrintSupportExtension Tarefa em segundo plano da PSA responsável por oferecer capacidades de extensão das restrições de impressora.

Este artigo contém as extensões v3 para a API pública existente do Aplicativo de Suporte de Impressão descrita no guia de design do aplicativo de suporte de impressão e Namespace de Windows.Graphics.Printing.PrintSupport . A API PSA permite que os fabricantes de impressoras desenvolvam aplicativos de suporte de hardware que podem aprimorar a experiência de impressão de um utilizador do Windows ao usar o driver de classe IPP nativo da Microsoft sem a necessidade de desenvolver um driver personalizado. Os componentes de impressão comunicam-se com a aplicação PSA através de um processo de broker PSA.

Para obter mais informações, consulte os seguintes artigos:

Tópico Descrição
Guia de design do aplicativo de suporte de impressão Fornece orientações e exemplos para OEMs e IHVs de impressoras que estão implementando um aplicativo de suporte de impressão (PSA) para seus dispositivos.
Guia de design da API da aplicação de suporte a impressão v4 Fornece orientação e exemplos para OEMs de impressoras e IHVs que estão implementando um aplicativo de suporte de impressão v4 (PSA) para seus dispositivos.
Especificação de manifesto MSIX para impressora virtual para suporte a impressão Fornece orientação sobre o manifesto MSIX e exemplos para OEMs e IHVs de impressoras que estão a implementar uma Impressora Virtual de Suporte de Impressão.
Associação do aplicativo de suporte de impressão Fornece orientações e exemplos para associar uma aplicação de suporte de impressão (PSA) a uma impressora.

As extensões significativas para a API são as seguintes:

  • Compressão IPP - A API PSA v3 adiciona uma funcionalidade para melhorar a impressão IPP através da adição de um recurso de compressão IPP num trabalho de impressão para impressoras IPP que suportam essa funcionalidade. Alguns PSA podem ter compactação personalizada, o que significa que o trabalho IPP tem compressão dupla que afeta o desempenho. Para atenuar isso, a API PSA v3 introduz uma propriedade IsIppCompressionEnabled e uma função DisableIppCompressionForJob (para desabilitar a compactação para o trabalho atual, se necessário) na classe de tempo de execução PrintWorkflowJobStartingEventArgs (PSA v1 API).

  • IPP Job Error handling and Error Toast - PSA v3 API introduz um evento JobIssueDetected na classe em tempo de execução PrintWorkflowJobBackgroundSession (PSA v1 API). O evento é gerado sempre que o PSA deteta um erro/aviso no trabalho de impressão. O PSA é então responsável por mostrar a notificação de erro ao utilizador. Quando o PSA se registra para esse evento e define propriedade SkipSystemErrorToast como true em PrintWorkflowJobIssueDetectedEventArgs , ele informa ao sistema de impressão para não mostrar o sistema de impressão do sistema do Windows. A API do PSA v3 também fornece um mecanismo para o PSA iniciar a interface do utilizador quando o utilizador interage com a notificação.

  • Tempos limite de comunicação IPP personalizados - A API PSA v3 fornece uma API com a qual um PSA pode substituir os tempos limite de IPP. Além disso, a classe de tempo de execução PrintSupportIppCommunicationConfiguration é adicionada a PrintSupportPrintDeviceCapabilitiesChangedEventArgs para manipular os tempos limite de comunicação IPP. Além disso, a API PSA v3 introduz um evento, que é gerado quando há um erro com a comunicação IPP. O evento foi introduzido para que a IHV pudesse investigar a falha e ajustar os valores de tempo limite de acordo.

  • Suporte IPPFaxOut - PSA v3 API adiciona um recurso ao sistema de impressão para suportar impressoras IPPFaxOut. Para suportar Fax, o PSA suporta um filtro de renderização para converter XPS em Tiff. Como o PSA pode manipular o conteúdo XPS antes de converter para TIFF, ele fornece o valor de enum XpsToTiff em PrintWorkflowPdlConversionType para que o PSA possa ter acesso ao conversor XPS para TIFF. Além disso, fornece a propriedade IsIPPFaxOutPrinter à classe de execução IppPrintDevice para que a PSA possa diferenciar entre a impressora padrão e as impressoras IPPFaxOut.

Desativando a compactação IPP

A compactação IPP é mostrada no exemplo de código a seguir.

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

Tratamento de erros de trabalho IPP

Este exemplo demonstra como a aplicação PSA pode registar erros de trabalho, mostrar notificações pop-up para erros de trabalho e iniciar a interface do utilizador quando o utilizador ativa essas notificações.

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

Configuração do tempo limite de comunicação IPP

Este exemplo demonstra como definir o tempo limite de comunicação 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;
        }
    }
}

Tratamento de erros de comunicação IPP

Este exemplo demonstra como manipular erros de comunicação 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
            }
        }
    }  
}

Impressão em impressora IPP para envio de fax em PSA

Este exemplo demonstra como imprimir numa impressora IPPFaxOut num 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;
    }
}

Desativar a interface de fax para o número de telefone da PSA

Com o suporte da impressora de fax IPP, este exemplo mostra uma interface do usuário para solicitar que o usuário insira o número de fax ao imprimir na impressora de fax. Mas o PSA pode querer mostrar sua própria interface do usuário com mais informações e opções. Como é confuso para o utilizador se houver duas interfaces de fax, este exemplo ilustra uma opção para um PSA desativar a interface do sistema quando quiser mostrar a sua interface de fax.

O exemplo a seguir demonstra o uso da 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;
    }  
}

Comentários

Os exemplos neste artigo são criados com base nos exemplos das APIs PSA v1 e v2 no guia de design do aplicativo de suporte do Print com a suposição de que o desenvolvedor está familiarizado com o fluxo de trabalho da API PSA.

Este artigo contém as extensões para a API de aplicativo de suporte de impressão pública existente descrita no guia de design do aplicativo de suporte de impressão e Windows.Graphics.Printing.PrintSupport Namespace. A API PSA permite que os fabricantes de impressoras desenvolvam aplicativos UWP que podem aprimorar uma experiência de impressão dos usuários do Windows ao usar o Microsoft IPP Class Driver da caixa de entrada, sem a necessidade de desenvolver um driver personalizado.

Os componentes de impressão estão a comunicar-se com a aplicação PSA por meio de um processo de agente PSA.

DisableIppCompressionForJob

Fim do plano de manutenção para drivers de impressora de terceiros no Windows

IsIppCompressionEnabled

IsIPPFaxOutPrinter

IppPrintDevice

ProblemaDeTrabalhoDetectado

PrintSupportIppCommunicationConfiguration

PrintSupportPrintDeviceCapabilitiesChangedEventArgs

PrintWorkflowJobBackgroundSession

PrintWorkflowJobIssueDetectedEventArgs

PrintWorkflowJobStartingEventArgs

PrintWorkflowPdlConversionType

SkipSystemErrorToast

Windows.Graphics.Printing.PrintSupport