Guía de diseño de la API v3 de la aplicación de soporte de impresión
En este artículo se proporcionan instrucciones y ejemplos para los OEM de impresora e IHD que implementan una aplicación de soporte de impresión v3 (PSA) para su dispositivo.
Terminología
Término | Definición |
---|---|
APE | Aplicación de soporte técnico de impresión. Aplicación para UWP que usa la API de este documento. |
IPP | Protocolo de impresión de Internet. Se usa desde un dispositivo cliente para interactuar con la impresora para recuperar y establecer preferencias de impresión y para enviar el documento que se va a imprimir. |
Impresora asociada a la compatibilidad con impresión | Impresora IPP física que está vinculada a PSA. |
Impresora IPP | Impresora que admite el protocolo IPP. |
PDL | Idioma de descripción de página. Formato en el que se envía un documento a la impresora. |
Impresora PSA asociada | Impresora IPP física asociada a una aplicación PSA. |
Capacidades del Dispositivo de Impresión | Formato de documento XML para definir funcionalidades de impresora. |
PrintSupportExtension | Tarea en segundo plano de PSA responsable de proporcionar funcionalidades de extensión de restricción de impresora. |
Aplicación de soporte de impresión v3 API
Este artículo contiene las extensiones v3 a la API pública existente de la aplicación de soporte técnico de impresión descrita en la guía de diseño de la aplicación de soporte de impresión y el espacio de nombres Windows.Graphics.Printing.PrintSupport. La API de PSA permite a los fabricantes de impresoras desarrollar aplicaciones de soporte técnico de hardware que pueden mejorar la experiencia de impresión de un usuario de Windows mientras se usa el controlador de clase IPP integrado de Microsoft, sin necesidad de desarrollar un controlador personalizado. Los componentes de impresión se comunican con la aplicación PSA a través de un proceso intermediario de PSA.
Para obtener más información, consulte los artículos siguientes:
Tema | Descripción |
---|---|
guía de diseño de aplicaciones de soporte de impresión | Proporciona orientación y ejemplos para los OEM de impresoras y los Proveedores de Hardware Independiente (IHVs) que implementan una aplicación de soporte de impresión (PSA) para su dispositivo. |
Guía de diseño de la API de la Aplicación de Soporte de Impresión v4 | Proporciona instrucciones y ejemplos para los OEM de impresora e IHD que implementan una aplicación de soporte de impresión v4 (PSA) para su dispositivo. |
Especificación del manifiesto MSIX para impresora virtual de soporte de impresión | Proporciona instrucciones y ejemplos de manifiestos MSIX para los OEM de impresoras e IHV que implementan una impresora virtual de soporte de impresión. |
Asociación de aplicaciones de soporte de impresión | Proporciona instrucciones y ejemplos para asociar una aplicación de soporte de impresión (PSA) con una impresora. |
Las extensiones significativas para la API son las siguientes:
Compresión IPP - La API PSA v3 agrega una función para mejorar la impresión IPP al incorporar compresión IPP en un trabajo de impresión para impresoras IPP que admiten esta característica. Algunas PSA pueden tener compresión personalizada, lo que significa que el trabajo IPP tiene una compresión doble que afecta el rendimiento. Para mitigar esto, la API de PSA v3 presenta una propiedad isIppCompressionEnabled y una función DisableIppCompressionForJob (para deshabilitar la compresión para el trabajo actual si es necesario) en la clase en tiempo de ejecución PrintWorkflowJobStartingEventArgs (API de PSA v1).
Control de errores de trabajos IPP y notificaciones del sistema de errores - La API PSA v3 presenta un evento JobIssueDetected en la clase en tiempo de ejecución PrintWorkflowJobBackgroundSession (API PSA v1). El evento se genera cada vez que PSA detecta un error o advertencia en el trabajo de impresión. La PSA se encarga de mostrar el mensaje de error al usuario. Cuando la PSA se registra para este evento y establece la propiedad SkipSystemErrorToast en true en PrintWorkflowJobIssueDetectedEventArgs, indica al sistema de impresión que no muestre la notificación del sistema de impresión de Windows. La API de PSA v3 también proporciona un mecanismo para que la PSA inicie la interfaz de usuario cuando el usuario interactúa con la notificación del sistema.
Tiempos de espera de comunicación IPP personalizados - La API PSA v3 proporciona una API con la que una PSA puede anular los tiempos de espera de IPP. Además, la clase en tiempo de ejecución PrintSupportIppCommunicationConfiguration se agrega a PrintSupportPrintDeviceCapabilitiesChangedEventArgs para manipular los tiempos de espera de comunicación IPP. Además, psa v3 API introduce un evento, que se genera cuando se produce un error con la comunicación IPP. El evento se introdujo para que IHV pudiera investigar el error y ajustar los valores de tiempo de espera según corresponda.
Compatibilidad con IPPFaxOut - La API PSA v3 añade una funcionalidad al sistema de impresión para admitir impresoras IPPFaxOut. Para admitir Fax, PSA admite un filtro de representación para convertir XPS a Tiff. Como PSA puede manipular el contenido XPS antes de convertir en TIFF, proporciona el valor de enumeración XpsToTiff en PrintWorkflowPdlConversionType para que PSA pueda tener acceso a XPS al convertidor TIFF. Además, proporciona la propiedad IsIPPFaxOutPrinter a la clase en tiempo de ejecución IppPrintDevice para que la PSA pueda diferenciar entre las impresoras estándar y las impresoras IPPFaxOut.
Deshabilitación de la compresión IPP
La compresión IPP se muestra en el ejemplo de código siguiente.
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;
}
}
Control de errores en trabajos IPP
En este ejemplo se muestra cómo la aplicación PSA puede registrarse para detectar errores de trabajo, mostrar notificaciones del sistema para errores de trabajo e iniciar la interfaz de usuario cuando el usuario activa las notificaciones del sistema.
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;
}
}
Establecimiento del tiempo de espera de comunicación de IPP
En este ejemplo se muestra cómo establecer el tiempo de espera de comunicación 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;
}
}
}
Gestión de errores de comunicación IPP
En este ejemplo se muestra cómo controlar los errores de comunicación 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
}
}
}
}
Impresión en impresoras de salida de fax IPP en PSA
En este ejemplo se muestra cómo imprimir en una impresora IPPFaxOut en una 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;
}
}
Deshabilitación de la interfaz de usuario de fax para el número de teléfono de PSA
Con el soporte de la impresora de fax IPP, este ejemplo muestra una interfaz de usuario para solicitar al usuario que escriba el número de fax al imprimir en la impresora fax. Pero es posible que el PSA quiera mostrar su propia interfaz de usuario con más información y opciones. Dado que resulta confuso para el usuario si hay dos interfaces de usuario para fax, este ejemplo muestra una opción para que un PSA deshabilite la interfaz de usuario del sistema cuando quiera mostrar su interfaz de usuario de fax.
En el ejemplo siguiente se muestra el uso de la 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;
}
}
Observaciones
Los ejemplos de este artículo se basan en las muestras de las API de PSA v1 y v2 en la guía de diseño de aplicaciones de soporte de impresión de con la suposición de que el desarrollador está familiarizado con el flujo de trabajo de la API de PSA.
Este artículo contiene las extensiones para la API pública existente de la aplicación de soporte técnico de impresión descrita en la guía de diseño de la aplicación de soporte de impresión y el espacio de nombres Windows.Graphics.Printing.PrintSupport. La API de PSA permite a los fabricantes de impresoras desarrollar aplicaciones UWP que pueden mejorar la experiencia de impresión de los usuarios de Windows mientras se usa el controlador de clase IPP de Microsoft integrado, sin necesidad de desarrollar un controlador personalizado.
Los componentes de impresión se comunican con la aplicación PSA a través de un proceso intermediario de PSA.
Artículos relacionados
Finalización del soporte de los controladores de impresoras de terceros en Windows
PrintSupportIppCommunicationConfiguration
PrintSupportPrintDeviceCapabilitiesChangedEventArgs
PrintWorkflowJobBackgroundSession
PrintWorkflowJobIssueDetectedEventArgs
PrintWorkflowJobStartingEventArgs