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. |
Aplicação de suporte de impressão v3 API
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.
Artigos relacionados
Fim do plano de manutenção para drivers de impressora de terceiros no Windows
PrintSupportIppCommunicationConfiguration
PrintSupportPrintDeviceCapabilitiesChangedEventArgs
PrintWorkflowJobBackgroundSession
PrintWorkflowJobIssueDetectedEventArgs
PrintWorkflowJobStartingEventArgs