Guia de design da API do Aplicativo de Suporte de Impressão v3
Este artigo fornece diretrizes e exemplos para OEMs de impressora e IHVs que estão implementando um PSA (Aplicativo de Suporte à Impressão) v3 para seu dispositivo.
Terminologia
Prazo | Definição |
---|---|
PSA | Aplicativo de Suporte a Impressão. Aplicativo UWP que usa a API neste documento. |
IPP | Protocolo de Impressão da Internet. Usado em um dispositivo cliente para interagir com a impressora para recuperar e definir preferências de impressão e enviar o documento para ser impresso. |
Impressora associada ao suporte de impressão | Impressora IPP física vinculada ao PSA. |
Impressora IPP | Impressora que dá suporte ao protocolo IPP. |
PDL | Idioma de descrição da página. O formato no qual um documento é enviado para a impressora. |
Impressora PSA associada | Impressora IPP física associada a um aplicativo PSA. |
CapacidadesDoDispositivoDeImpressão | Formato de documento XML para definir recursos de impressora. |
PrintSupportExtension | Tarefa em segundo plano do PSA responsável por fornecer recursos de extensão de restrição de impressora. |
API do aplicativo de suporte de impressão v3
Este artigo contém as extensões v3 para a API pública do Aplicativo de Suporte à Impressão existente descrita no guia de design do aplicativo de suporte de impressão e Windows.Graphics.Printing.PrintSupport Namespace. A API de PSA permite que os fabricantes de impressoras desenvolvam aplicativos de Suporte a Hardware que podem aprimorar a experiência de impressão de um usuário do Windows ao usar o Driver de Classe IPP da Microsoft do Sistema de Impressão integrada sem precisar desenvolver um driver personalizado. Os componentes de impressão se comunicam com o aplicativo PSA através de um processo intermediário do PSA.
Para obter mais informações, consulte os seguintes artigos:
Tópico | Descrição |
---|---|
Guia de design do aplicativo de Suporte à Impressão | Fornece diretrizes e exemplos para OEMs de impressora e IHVs que estão implementando um PSA (aplicativo de suporte à impressão) para seu dispositivo. |
Guia de design da API do Aplicativo de Suporte à Impressão v4 | Fornece diretrizes e exemplos para OEMs de impressora e IHVs que estão implementando um PSA (Aplicativo de Suporte à Impressão) v4 para seu dispositivo. |
Especificação de manifesto MSIX para impressora virtual com suporte de impressão | Fornece orientação e exemplos de manifesto MSIX para OEMs e IHVs de impressora que estão implementando um aplicativo de suporte à impressão. |
Associação de aplicativos de suporte à impressão | Fornece diretrizes e exemplos para associar um PSA (aplicativo de suporte à impressão) a uma impressora. |
As extensões significativas para a API são as seguintes:
Compressão IPP - A API de PSA v3 adiciona um recurso para melhorar a impressão IPP, oferecendo compactação em trabalhos de impressão para impressoras IPP que suportam essa função. Alguns PSAs podem ter compactação personalizada, o que faz com que o trabalho IPP sofra uma compactação dupla, afetando o performance. Para atenuar isso, a API PSA v3 apresenta 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 (API PSA v1).
Tratamento de Erro de Trabalho do IPP e Error Toast - A PSA v3 API introduz um evento JobIssueDetected na classe de runtime PrintWorkflowJobBackgroundSession (PSA v1 API). O evento é gerado sempre que o PSA detecta um erro/aviso no trabalho de impressão. O PSA torna-se responsável por mostrar a notificação de erro ao usuário. Quando o PSA registra-se para este evento e define a propriedade SkipSystemErrorToast como verdadeira em PrintWorkflowJobIssueDetectedEventArgs, ele instrui o sistema de impressão a não mostrar o alerta do sistema de impressão do Windows. A API de PSA v3 também fornece um mecanismo para o PSA iniciar a interface do usuário quando o usuário interage com o sistema.
Tempos de espera de comunicação IPP personalizados – A API de PSA v3 fornece uma interface pela qual um PSA pode substituir os tempos de espera do IPP. Além disso, a classe de runtime PrintSupportIppCommunicationConfiguration é adicionada a PrintSupportPrintDeviceCapabilitiesChangedEventArgs para manipular os tempos limite de comunicação do IPP. Além disso, a API psa v3 apresenta um evento, que é gerado quando há um erro com a comunicação do IPP. O evento foi introduzido para que o IHV pudesse investigar a falha e ajustar os valores de tempo limite adequadamente.
Suporte a IPPFaxOut - A API de PSA v3 adiciona um recurso ao sistema de impressão para dar suporte a impressoras IPPFaxOut. Para dar suporte a Fax, o PSA dá suporte a um filtro de renderização para converter XPS em Tiff. Como o PSA pode manipular o conteúdo XPS antes de converter em TIFF, ele fornece o valor de enumeração XpsToTiff em PrintWorkflowPdlConversionType para que o PSA possa ter acesso ao conversor XPS para TIFF. Além disso, ele fornece a propriedade IsIPPFaxOutPrinter à classe de runtime IppPrintDevice para que o PSA possa diferenciar entre as impressoras IPPFaxOut e impressoras IPPFaxOut padrão.
Desabilitando a compactação do 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 erro de trabalho IPP
Este exemplo demonstra como o aplicativo de PSA pode registrar erros de trabalho, mostrar notificações para esses erros e iniciar a interface do usuário quando o usuário ativar as 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;
}
}
Configurando o tempo limite de comunicação do IPP
Este exemplo demonstra como definir o tempo limite de comunicação do 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;
}
}
}
Lidando com erros de comunicação do IPP
Este exemplo demonstra como lidar com erros de comunicação do 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 de saída de fax IPP no PSA
Este exemplo demonstra como imprimir em uma impressora IPPFaxOut em um 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;
}
}
Desabilitar a interface de fax para o número de telefone do 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 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 usuário se houver duas interfaces de usuário para fax, este exemplo ilustra uma opção para um PSA desabilitar a interface de usuário do sistema quando quiser mostrar sua interface de usuário 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;
}
}
Observações
Os exemplos neste artigo são baseados nos exemplos das APIs de PSA v1 e v2 no Guia de design do aplicativo de Suporte de Impressão com a suposição de que o desenvolvedor está familiarizado com o fluxo de trabalho da API de PSA.
Este artigo contém as extensões da API de Aplicativo de Suporte à Impressão pública existente descrita no guia de design do Aplicativo de Suporte à Impressão e Windows.Graphics.Printing.PrintSupport Namespace. A API de PSA permite que os fabricantes de impressoras desenvolvam aplicativos de UWP que podem aprimorar a experiência de impressão dos usuários do Windows ao usar o Driver de Classe IPP da Microsoft do Sistema de Impressão integrada sem a necessidade de desenvolver um driver personalizado.
Os componentes de impressão se comunicam com o app PSA por meio de um processo intermediário do PSA.
Artigos relacionados
Fim do plano de manutenção para drivers de impressora de terceiros no Windows
PrintSupportIppCommunicationConfiguration
PrintSupportPrintDeviceCapabilitiesChangedEventArgs
PrintWorkflowJobBackgroundSession
PrintWorkflowJobIssueDetectedEventArgs
PrintWorkflowJobStartingEventArgs