Guida alla progettazione dell'app di supporto di stampa v1 e v2
Questo articolo fornisce indicazioni ed esempi per gli OEM e gli IHV della stampante per sviluppare un'app di supporto per la stampa (PSA) che può migliorare l'esperienza di stampa di un utente Windows in diversi modi.
Importante
A partire dalla versione di Windows 11 SDK (22000.1), Print Support Apps (PSA) sono il metodo consigliato per lo sviluppo di app UWP per stampanti. Per sviluppare un'app di supporto di stampa per il dispositivo di stampa, scaricare e installare Windows 11 SDK per la versione di Windows di destinazione.
Importante
Questo articolo contiene sezioni che descrivono le funzionalità di PSA disponibili a partire da Windows 11, versione 22H2. Tali sezioni contengono una nota che indica che si applica a tale versione.
Per altre informazioni, vedere gli articoli seguenti:
Argomento | Descrizione |
---|---|
guida alla progettazione dell'API app di supporto alla stampa v3 | Fornisce indicazioni ed esempi per gli OEM e gli IHV delle stampanti che implementano un'app di supporto stampa v3 (PSA) per il loro dispositivo. |
Guida alla progettazione dell'API v4 dell'App di supporto stampa | Fornisce indicazioni ed esempi per gli OEM e gli IHV delle stampanti che implementano un'app di supporto di stampa v4 (PSA) per il loro dispositivo. |
Specifica del Manifesto MSIX per il Supporto di Stampa della Stampante Virtuale | Fornisce linee guida e esempi sul manifesto MSIX per i produttori OEM e i fornitori di hardware indipendenti (IHV) che stanno implementando una stampante virtuale per il supporto di stampa. |
l'associazione dell'app di supporto di stampa | Fornisce indicazioni ed esempi per l'associazione di un'app di supporto di stampa (PSA) a una stampante. |
Alcune funzionalità della stampante non vengono presentate nelle finestre di dialogo di stampa visualizzate da Windows perché sono funzionalità speciali che richiedono assistenza da un'app produttore per essere configurate correttamente. Possono anche essere funzionalità che non sono disponibili nelle funzionalità predefinite della stampante.
Le funzionalità specifiche della stampante possono essere raggruppate in modo da consentire all'utente di scegliere facilmente un'opzione e considerare attendibile che tutte le funzionalità coinvolte in tale scenario vengano impostate automaticamente sui valori corretti. Un esempio di questo potrebbe essere una scelta tra risparmio inchiostro, risparmio carta e modalità di alta qualità, che possono modificare automaticamente le varie funzionalità di stampa basate sulla selezione dell'utente. Windows non è in grado di raggrupparli automaticamente perché richiede la comprensione di tutte le funzionalità personalizzate di ogni modello di stampante.
Questa necessità di visualizzare le preferenze di stampa personalizzate è indirizzata da questa API con un contratto di estensione UWP facoltativo che può essere attivato dall'utente da tutte le finestre di dialogo di stampa di Windows e finestre di dialogo di stampa personalizzate che usano l'API fornita da Windows. I produttori sono in grado di personalizzare l'interfaccia utente per offrire la migliore esperienza di stampa per la stampante specifica di proprietà dell'utente.
Un'altra area in cui i produttori di stampanti possono migliorare e distinguere è la qualità della stampa. I produttori possono migliorare la qualità di stampa dopo il rendering ottimizzando il contenuto per la stampante specifica. Possono anche presentare un'anteprima ad alta fedeltà che rappresenta meglio l'output finale in quanto potrebbe prendere in considerazione funzionalità specifiche della stampante.
della sequenza temporale di stampa dell'app di supporto per la stampa
Terminologia
Termine | Definizione |
---|---|
PSA | Applicazione di supporto per la stampa. Un'app UWP che usa l'API descritta in questo articolo. |
MPD | Finestra di dialogo moderna per la stampa. Viene visualizzato all'utente quando un'app sta stampando tramite l'API Windows.Graphics.Printing. |
Formazione Professionale Continua | Finestra di dialogo di stampa predefinita. Questo viene visualizzato all'utente quando l'app esegue la stampa usando l'API Win32. Le app che devono mostrare l'anteprima di stampa non attivano questa finestra di dialogo e implementano autonomamente una versione del dialogo. Le app di Office sono un esempio principale di questo. |
IPP | Protocollo di stampa Internet. Utilizzato da un dispositivo client per interagire con la stampante per recuperare e impostare le preferenze di stampa e inviare il documento da stampare. |
Supporto stampa stampante associata | Stampante collegata a PSA. |
Stampante IPP | Stampante che supporta il protocollo IPP. |
Altre impostazioni | Collegamento che apre l'interfaccia utente dell'app fornita dal partner in MPD. Per impostazione predefinita, si apre l'interfaccia utente delle preferenze di stampa integrate quando non è installato alcun PSA. |
Interfaccia utente preferenze stampante | Finestra di dialogo utilizzata per impostare le opzioni predefinite della stampante applicate in fase di stampa. Ad esempio: orientamento, formato carta, colore, stampa su entrambi i lati e così via. |
PDL | Linguaggio di descrizione delle pagine. Formato in cui un documento viene inviato alla stampante. |
Stampante associata PSA | Stampante IPP fisica associata a un'applicazione PSA. |
Capacità del dispositivo di stampa | Formato documento XML per la definizione delle funzionalità della stampante. Per ulteriori informazioni, vedere Print Ticket and Print Capabilities Technologies. |
PrintTicket | Raccolta di varie funzionalità correlate alla stampa e i relativi valori usati per acquisire la finalità dell'utente per un determinato processo di stampa. |
PrintSupportExtension | Attività in background PSA responsabile della fornitura di funzionalità di estensione dei vincoli della stampante. |
Spazio dei nomi del supporto di stampa
Questi esempi fanno riferimento a uno spazio dei nomi printsupport, definito come:
xmlns:printsupport="http://schemas.microsoft.com/appx/manifest/printsupport/windows10"
Interfaccia utente delle impostazioni di assistenza alla stampa
Quando un utente sta per stampare un documento, spesso desidera impostare alcune preferenze con cui stamparlo. Ad esempio, possono scegliere di stampare un documento con orientamento orizzontale. Possono anche sfruttare una funzionalità personalizzata supportata dalla stampante. Windows fornisce l'interfaccia utente predefinita per visualizzare le preferenze personalizzate, ma l'utente potrebbe non comprenderle perché non ci sono icone o descrizioni appropriate. Windows potrebbe utilizzare anche il controllo dell'interfaccia utente sbagliato per mostrarlo. Una funzionalità personalizzata di questo tipo è meglio supportata da un'app che comprende completamente questa. Questa è la motivazione alla base dell'offerta di un'API che consente ai produttori di stampanti di creare app personalizzate per i vari modelli di stampante che creano.
Viene creato un nuovo contratto di estensione UAP con una nuova categoria denominata windows.printSupportSettingsUI. Le app attivate con questo contratto ricevono un nuovo ActivationKind denominato PrintSupportSettingsUI. Questo contratto non richiede alcuna nuova funzionalità.
<Extensions>
<printsupport:Extension Category="windows.printSupportSettingsUI"
EntryPoint="PsaSample.PsaSettingsUISample"/>
</Extensions>
Questo contratto viene richiamato quando l'utente seleziona Altre impostazioni in MPD o Preferenze in CPD. Questo contratto può essere richiamato anche da Preferenze di stampa nell'app Impostazioni. Quando il contratto viene attivato, l'app riceve un oggetto PrintSupportSettingsUISession
L'app di supporto per la stampa deve gestire più attivazioni simultanee per lavori di stampa diversi, quindi questa app deve supportare più istanze usando l'elemento SupportaPiùIstanze nel file package.appxmanifest. In caso contrario, potrebbero verificarsi situazioni in cui confermare le preferenze di un lavoro di stampa potrebbe chiudere altre finestre di preferenze che potrebbero essere aperte. L'utente deve aprire nuovamente le finestre delle preferenze.
Il diagramma di sequenza seguente rappresenta il concetto di manipolazione dei ticket di stampa dell'interfaccia utente di impostazioni.
Modifica di PrintTicket nell'interfaccia utente delle impostazioni
Codice di esempio C# per l'attivazione dell'interfaccia utente delle impostazioni quando viene lanciata sia da una qualsiasi finestra di dialogo di stampa (MPD/CPD o finestra di dialogo di stampa personalizzata) sia dalle impostazioni di sistema.
namespace PsaSampleApp
{
sealed partial class App : Application
{
Deferral settingsDeferral;
protected override void OnActivated(IActivatedEventArgs args)
{
if (args.Kind == ActivationKind.PrintSupportSettingsUI)
{
// Get the activation arguments
var settingsEventArgs = args as PrintSupportSettingsActivatedEventArgs;
PrintSupportSettingsUISession settingsSession = settingsEventArgs.Session;
// Take deferral
this.settingsDeferral = settingsEventArgs.GetDeferral();
// Create root frame
var rootFrame = new Frame();
// Choose the page to be shown based upon where the application is being launched from
switch (settingsSession.LaunchKind)
{
case SettingsLaunchKind.UserDefaultPrintTicket:
{
// Show settings page when launched for default printer settings
rootFrame.Navigate(typeof(DefaultSettingsView), settingsSession);
}
break;
case SettingsLaunchKind.JobPrintTicket:
{
// Show settings page when launched from printing app
rootFrame.Navigate(typeof(JobSettingsView), settingsSession);
}
break;
}
Window.Current.Content = rootFrame;
}
}
internal void ExitSettings()
{
settingsDeferral.Complete();
}
}
}
XAML per classe DefaultSettingsView:
<Page
x:Class="PsaSampleApp.DefaultSettingsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PsaSampleApp"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Vertical" Margin="30,50,0,0">
<ComboBox x:Name="OrientationOptions" ItemsSource="{x:Bind OrientationFeatureOptions}" SelectedItem="{x:Bind SelectedOrientationOption, Mode=TwoWay}" DisplayMemberPath="DisplayName" HorizontalAlignment="Left" Height="Auto" Width="Auto" VerticalAlignment="Top"/>
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Button x:Name="Ok" Content="Ok" HorizontalAlignment="Left" Margin="50,0,0,0" VerticalAlignment="Top" Click="OkClicked"/>
<Button x:Name="Cancel" Content="Cancel" HorizontalAlignment="Left" Margin="20,0,0,0" VerticalAlignment="Top" Click="CancelClicked"/>
</StackPanel>
</Grid>
</Page>
Codice di esempio C# per visualizzare l'interfaccia utente e modificare PrintTicket:
namespace PsaSampleApp
{
/// <summary>
/// Class for showing print settings to the user and allow user to modify it
/// </summary>
public sealed partial class DefaultSettingsView: Page
{
private IppPrintDevice printer;
private PrintSupportSettingsUISession uiSession;
private WorkflowPrintTicket printTicket;
private App application;
// Bound to XAML combo box
public ObservableCollection<PrintTicketOption> OrientationFeatureOptions { get; } = new ObservableCollection<PrintTicketOption>();
public PrintTicketOption SelectedOrientationOption { get; set; }
public SettingsView()
{
this.InitializeComponent();
this.application = Application.Current as App;
this.orientationFeatureOptions = new ObservableCollection<PrintTicketOption>();
}
internal void OnNavigatedTo(NavigationEventArgs e)
{
this.uiSession = = e.Parameter as PrintSupportSettingsUISession;
this.printer = session.SessionInfo.Printer;
this.printTicket = session.SessionPrintTicket;
PrintTicketCapabilities printTicketCapabilities = this.printTicket.GetCapabilities();
// Read orientation feature from PrintTicket capabilities
PrintTicketFeature feature = printTicketCapabilities.PageOrientationFeature;
// Populate XAML combo box with orientation feature options
this.PopulateOrientationOptionComboBox(feature.Options);
PrintTicketOption printTicketOrientationOption = printTicket.PageOrientationFeature.GetSelectedOption();
// Update orientation option in XAML combo box
this.SelectedOrientationOption = this.orientationFeatureOptions.Single((option)=> (option.Name == printTicketOrientationOption.Name && option.XmlNamespace == printTicketOrientationOption.XmlNamespace));
}
private async void OkClicked(object sender, RoutedEventArgs e)
{
// Disable Ok button while the print ticket is being submitted
this.Ok.IsEnabled = false;
// Set selected orientation option in the PrintTicket and submit it
PrintTicketFeature orientationFeature = this.printTicket.PageOrientationFeature;
orientationFeature.SetSelectedOption(this.SelectedOrientationOption);
// Validate and submit PrintTicket
WorkflowPrintTicketValidationResult result = await printTicket.ValidateAsync();
if (result.Validated)
{
// PrintTicket validated successfully – submit and exit
this.uiSession.UpdatePrintTicket(printTicket);
this.application.ExitSettings();
}
else
{
this.Ok.IsEnabled = true;
// PrintTicket is not valid – show error
this.ShowInvalidPrintTicketError(result.ExtendedError);
}
}
private void CancelClicked(object sender, RoutedEventArgs e)
{
this.application.ExitSettings();
}
}
}
Ottenere gli attributi della stampante dal dispositivo stampante
Risposta Wireshark da una stampante IPP a una query "get-printer-attributes":
Codice di esempio C# per ottenere nomi di inchiostri e livelli di inchiostro dalla stampante.
namespace PsaSampleApp
{
/// <summary>
/// Class for showing print settings to the user
/// </summary>
public sealed partial class SettingsView : Page
{
IList<string> inkNames;
IList<int> inkLevels;
private async void GetPrinterAttributes()
{
// Read ink names and levels, along with loaded media-sizes
var attributes = new List<string>();
attributes.Add("marker-names");
attributes.Add("marker-levels");
attributes.Add("media-col-ready");
IDictionary<string, IppAttributeValue> printerAttributes = this.printer.GetPrinterAttributes(attributes);
IppAttributeValue inkNamesValue = printerAttributes["marker-names"];
CheckValueType(inkNamesValue, IppAttributeValueKind.Keyword);
this.inkNames = inkNamesValue.GetKeywordArray();
IppAttributeValue inkLevelsValue = printerAttributes["marker-levels"];
CheckValueType(inkLevelsValue, IppAttributeValueKind.Integer);
this.inkLevels = inkLevelsValue.GetIntegerArray();
// Read loaded print media sizes
IppAttributeValue mediaReadyCollectionsValue = printerAttributes["media-col-ready"];
foreach (var mediaReadyCollection in mediaReadyCollectionsValue.GetCollectionArray())
{
IppAttributeValue mediaSizeCollection;
if (mediaReadyCollection.TryGetValue("media-size", out mediaSizeCollection))
{
var xDimensionValue = mediaSizeCollection.GetCollectionArray().First()["x-dimension"];
var yDimensionValue = mediaSizeCollection.GetCollectionArray().First()["y-dimension"];
CheckValueType(xDimensionValue, IppAttributeValueKind.Integer);
CheckValueType(yDimensionValue, IppAttributeValueKind.Integer);
int xDimension = xDimensionValue.GetIntegerArray().First();
int yDimension = yDimensionValue.GetIntegerArray().First();
this.AddMediaSize(xDimension, yDimension);
}
}
}
private void CheckValueType(IppAttributeValue value, IppAttributeValueKind expectedKind)
{
if (value.Kind != expectedKind)
{
throw new Exception(string.Format("Non conformant type found: {0}, expected: {1}", value.Kind, expectedKind));
}
}
}
}
Impostazione degli attributi della stampante sulla stampante
Codice di esempio C# per l'impostazione degli attributi della stampante:
int defaultResolutionX = 1200;
int defaultResolutionY = 1200;
string pdlFormat = "image/pwg-raster";
private async void SetPrinterAttributes()
{
var attributes = new Dictionary<string, IppAttributeValue>();
attributes.Add("document-format-default", IppAttributeValue.CreateKeyword(this.pdlFormat));
var resolution = new IppResolution(this.defaultResolutionX, this.defaultResolutionY, IppResolutionUnit.DotsPerInch);
attributes.Add("printer-resolution-default", IppAttributeValue.CreateResolution(resolution));
var result = this.printer.SetPrinterAttributes(attributes);
if (!result.Succeeded)
{
foreach (var attributeError in result.AttributeErrors)
{
var attributeName = attributeError.Key;
switch (attributeError.Value.Reason)
{
case IppAttributeErrorReason.AttributeValuesNotSupported:
var values = attributeError.Value.GetUnsupportedValues().First();
this.LogUnSupportedValues(attributeName, values);
break;
case IppAttributeErrorReason.AttributeNotSettable:
this.LogAttributeNotSettable(attributeName);
break;
case IppAttributeErrorReason.AttributeNotSupported:
this.LogAttributeNotSupported(attributeName);
break;
case IppAttributeErrorReason.RequestEntityTooLarge:
this.LogAttributeNotEntityTooLarge(attributeName);
break;
case IppAttributeErrorReason. ConflictingAttributes:
this.LogConflictingAttributes(attributeName);
break;
}
}
}
}
Estensione dei vincoli della stampante
L'app Print Support supporta la convalida personalizzata di PrintTicket e definisce il PrintTicket predefinito. Questa sezione descrive come vengono supportate queste funzionalità.
Per supportare i vincoli di estensione della stampante, è stato implementato un nuovo tipo di attività in background PrintSupportExtension. Il file Package.appxmanifest include una voce di estensione per l'Estensione di Supporto alla Stampa, come illustrato di seguito:
<Extensions>
<printsupport:Extension Category="windows.printSupportExtension"
EntryPoint="PsaBackgroundTasks.PrintSupportExtension"/>
</Extensions>
Questo servizio può essere eseguito in qualsiasi momento in un processo di stampa per la stampante IPP associata. Quando la Print Support Extension viene attivata tramite la funzione IBackgroundTaskInstance, un'istanza di IBackgroundTaskInstance viene assegnata a PrintSupportExtension per fornire l'accesso alla classe runtime PrintSupportExtensionTriggerDetails, che fornisce, internamente, PrintSupportExtensionSession come proprietà. La classe di sfondo PrintSupportExtension può quindi utilizzare l'oggetto sessione per registrarsi agli eventi ai quali desidera fornire funzionalità personalizzate.
event Windows.Foundation.TypedEventHandler<PrintSupportExtensionSession, PrintSupportPrintTicketValidationRequestedEventArgs>; PrintTicketValidationRequested;
Se l'estensione supporto di stampa fornisce un proprio meccanismo di convalida PrintTicket, può registrarsi per questo evento. Ogni volta che è necessario convalidare un PrintTicket, il sistema di stampa genera questo evento. PrintSupportExtension otterrà quindi il PrintTicket corrente che deve essere convalidato all'interno di EventArgs. La classe in background PrintSupportExtension può quindi controllare la validità del PrintTicket e modificarlo per risolvere eventuali conflitti. La PrintSupportExtension classe in background deve quindi impostare il risultato per la convalida usando la funzione SetPrintTicketResult per indicare se l'PrintTicket è stato risolto, ha conflitti o non è valido. Questo evento può essere generato in qualsiasi momento durante la durata di un processo di stampa. Se la classe PrintSupportExtension non si registra per questo evento, il sistema di stampa esegue la propria convalida del PrintTicket.
event Windows.Foundation.TypedEventHandler<PrintSupportExtensionSession, PrintSupportPrintDeviceCapabilitiesChangedEventArgs>; PrintDeviceCapabilitiesChanged;
L'evento viene generato dopo che il sistema di stampa aggiorna la cache PrintDeviceCapabilities di stampante IPP associata. Quando viene generato questo evento, la classe di sfondo PrintSupportExtension può esaminare il PrintDeviceCapabilities modificato e modificarlo.
Convalida personalizzata del biglietto di stampa
Codice di esempio C# per fornire servizio di convalida PrintTicket:
public void Run(IBackgroundTaskInstance taskInstance)
{
// Take task deferral
this.taskDeferral = taskInstance.GetDeferral();
// Associate a cancellation handler with the background task
taskInstance.Canceled += OnTaskCanceled;
var psaTriggerDetails = taskInstance.TriggerDetails as PrintSupportExtensionTriggerDetails;
var serviceSession = psaTriggerDetails.Session as PrintSupportExtensionSession;
this.ippPrintDevice = serviceSession.Printer;
serviceSession.PrintTicketValidationRequested += this.OnPrintTicketValidationRequested;
serviceSession.PrinterDeviceCapabilitiesChanged += this.OnPdcChanged;
serviceSession.Start();
}
private void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
// Complete the deferral
this.taskDeferral.Complete();
}
private void OnPrintTicketValidationRequested(PrintSupportExtensionSession session, PrintSupportPrintTicketValidationRequestedEventArgs args)
{
using (args.GetDeferral())
{
// Get PrintTicket that needs needs to be validated and resolved
var printTicket = args.PrintTicket;
// Validate and resolve PrintTicket
WorkflowPrintTicketValidationStatus validationStatus = this.ValidateAndResolvePrintTicket(printTicket);
args.SetPrintTicketValidationStatus(validationStatus);
}
}
Aggiornamento di PrintDeviceCapabilities
private void OnPdcChanged(PrintSupportExtensionSession session, PrintSupportPrintDeviceCapabilitiesChangedEventArgs args)
{
using (args.GetDeferral())
{
var pdc = args.GetCurrentPrintDeviceCapabilities();
// Check current PDC and make changes according to printer device capabilities
XmlDocument newPdc = this.CheckAndUpdatePrintDeviceCapabilities(pdc);
args.UpdatePrintDeviceCapabilities(newPdc);
}
}
Miglioramento della qualità di stampa
Dopo che l'utente si è impegnato a stampare premendo il pulsante di stampa nella finestra di dialogo di stampa, il documento da stampare viene inviato allo stack di stampa dall'app che sta stampando. Questo documento viene quindi sottoposto a trasformazione (rendering in PDL) per renderlo adatto alla stampante di destinazione. Windows determinerà la trasformazione da scegliere in base agli attributi ottenuti tramite query dalla stampante. Il documento trasformato viene quindi inviato alla stampante. Sebbene questo funzioni bene per la maggior parte delle stampanti, esistono casi in cui la qualità della stampa potrebbe essere migliorata consentendo a un'app partner di partecipare alla trasformazione. Per semplificare questa operazione, l'API corrente del flusso di lavoro di stampa viene estesa per includere le chiamate all'applicazione in ulteriori punti dello stack di stampa. Questa API supporta due nuovi eventi per cui l'app PSA può registrarsi. Questi sono gli unici punti di ingresso nella superficie dell'API PSA:
inizioLavoro
- Questo evento viene generato quando un processo di stampa viene avviato da qualsiasi applicazione. Quando viene generato l'evento, un'app di supporto di stampa può scegliere di saltare il rendering del sistema chiamando SetSkipSystemRendering su PrintWorkflowJobStartingEventArgs. Se si seleziona di saltare il rendering del sistema, il sistema di stampa non convertirà il documento XPS nel formato PDL richiesto dalla stampante. Al contrario, l'XPS generato dall'applicazione di stampa verrà assegnato direttamente al PSA che è quindi responsabile della conversione di XPS in formato PDL.
PdlModificaRichiesta
- Questo evento viene generato quando Windows avvia la conversione del flusso XPS nel formato PDL indicato dalla stampante. La classe di runtime PrintWorkflowPdlModificationRequestedEventArgs viene fornita come argomento per questo evento. Questa classe di eventi fornisce oggetti PDL di origine e destinazione per la lettura e la scrittura del contenuto del processo di stampa. Se l'app determina che è necessario l'input dell'utente, può lanciare l'interfaccia utente usando PrintWorkflowUILauncher da EventArgs. Questa API usa il modello di Tester-Doer. PrintWorkflowUILauncher non sarà in grado di richiamare l'interfaccia utente se la funzione IsUILaunchEnabled restituisce false. Questa funzione restituisce false se la sessione PSA è in esecuzione in modalità silenziosa (modalità headless o modalità chiosco). L'app di supporto per la stampa non deve provare ad avviare l'interfaccia utente se la funzione restituisce false.
Un OutputStream è disponibile come parte di PrintWorkflowPdlTargetStream restituito dalla funzione GetStreamTargetAsync . Il contenuto scritto nella destinazione OutputStream viene passato alla stampante come contenuto del documento.
Diagramma di sequenza per l'evento di modifica del PDL.
L'applicazione PSA in primo piano viene avviata quando il task in background PSA richiede l'avvio dell'interfaccia utente. Il PSA può usare il contratto in primo piano per ottenere l'input dell'utente e/o per visualizzare un'anteprima di stampa all'utente.
Attività in background di supporto al flusso di lavoro per la stampa
È stato definito un nuovo tipo di attività in background printSupportWorkflow. Il file Package.appxmanifest ha la seguente voce di estendibilità per il contratto PrintSupportWorkflow:
<Extensions>
<printsupport:Extension Category="windows.printSupportWorkflow"
EntryPoint="PsaBackgroundTasks.PrintSupportWorkflowSample"/>
</Extensions>
All'attivazione del contratto, PrintWorkflowJobTriggerDetails è dato come IBackgroundTaskInstance->TriggerDetails. PrintWorkflowJobTriggerDetails fornisce internamente PrintWorkflowJobBackgroundSession come parte delle relative proprietà. L'app può usare PrintWorkflowJobBackgroundSession per registrarsi per gli eventi correlati a vari punti di inserimento nel flusso di lavoro del processo di stampa. Al termine della registrazione dell'evento, l'app deve chiamare PrintWorkflowJobBackgroundSession::Start affinché il sistema di stampa inizi a generare eventi correlati a vari punti di iniezione.
Interfaccia utente del flusso di lavoro di stampa
Viene definita una nuova
<Extensions>
<printsupport:Extension Category="windows.printSupportJobUI"
EntryPoint="PsaSample.PrintSupportJobUISample"/>
</Extensions>
Si tratta di un contratto dell'interfaccia utente che può essere avviato dal contratto in background Print Support Workflow o quando l'utente seleziona un avviso popup di errore del processo di stampa. All'attivazione, viene fornito PrintWorkflowJobActivatedEventArgs, che contiene un oggetto PrintWorkflowJobUISession. Usando PrintWorkflowJobUISession, l'applicazione in primo piano deve registrarsi per l'evento PdlDataAvailable se vuole accedere ai dati PDL. Se l'applicazione in primo piano desidera visualizzare messaggi di errore personalizzati per eventuali errori che potrebbero verificarsi durante l'attività, deve registrarsi per l'evento JobNotification. Dopo la registrazione degli eventi, l'applicazione deve chiamare la funzione PrintWorkflowJobUISession::Start affinché il sistema di stampa inizi a generare eventi.
Saltare il rendering del sistema
namespace PsaBackground
{
class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{
BackgroundTaskDeferral taskDeferral;
public void Run(IBackgroundTaskInstance taskInstance)
{
// Take Task Deferral
taskDeferral = taskInstance.GetDeferral();
var jobTriggerDetails = taskInstance.TriggerDetails as PrintWorkflowJobTriggerDetails;
var workflowBackgroundSession = jobTriggerDetails.PrintWorkflowJobSession as PrintWorkflowJobBackgroundSession;
// Register for events
workflowBackgroundSession.JobStarting += this.OnJobStarting;
workflowBackgroundSession.PdlModificationRequested += this.OnPdlModificationRequested;
// Start Firing events
workflowBackgroundSession.Start();
}
private void OnJobStarting(PrintWorkflowJobBackgroundSession session, PrintWorkflowJobStartingEventArgs args)
{
using (args.GetDeferral())
{
// Call SetSkipSystemRendering to skip conversion for XPS to PDL, so that PSA can directly manipulate the XPS file.
args.SetSkipSystemRendering();
}
}
}
}
Evento di modifica PDL
Diagramma di sequenza per l'evento di modifica PDL.
Codice di esempio C# per Print Support Job Monitor lettura e scrittura del contenuto del processo di stampa:
private void OnPdlModificationRequested(PrintWorkflowJobBackgroundSession session, PrintWorkflowPdlModificationRequestedEventArgs args)
{
using (args.GetDeferral())
{
IInputStream pdlContent = args.SourceContent.GetInputStream();
// Specify the Content type of stream that will be written to target that is passed to printer accordingly.
PrintWorkflowPdlTargetStream streamTarget = args.CreateJobOnPrinter(args.SourceStream.ContentType);
IOutputStream outputStream = streamTarget.GetOutputStream();
using (var inputReader = new Windows.Storage.Streams.DataReader(pdlContent))
{
inputReader.InputStreamOptions = InputStreamOptions.Partial;
using (var outputWriter = new Windows.Storage.Streams.DataWriter(outputStream))
{
// Write the updated Print stream from input stream to the output stream
uint chunkSizeInBytes = 256 * 1024; // 256K chunks
uint lastAllocSize = 0;
byte[] contentData = new byte[chunkSize];
while(this.ReadChunk(inputReader, ref contentData))
{
// Make any changes required to the input data
// ...
// Write out the modified content
outputWriter.WriteBytes(contentData);
await outputWriter.StoreAsync();
}
}
}
streamTarget.CompleteStreamSubmission(PrintWorkflowSubmittedStatus.Succeeded);
this.taskDeferral.Complete();
}
}
}
Avvio dell'interfaccia utente dallo sfondo del flusso di lavoro
Codice di esempio C# per avviare l'interfaccia utente del processo di supporto stampa dall'evento di richiesta modifica del contratto PSA PDL:
private async void OnPdlModificationRequested(PrintWorkflowJobBackgroundSession session, PrintWorkflowPdlModificationRequestedEventArgs args)
{
IInputStream pdlContent = args.SourceContent.GetInputStream();
WorkflowPrintTicket printTicket = args.PrinterJob.GetJobPrintTicket();
bool uiRequired = this.IsUIRequired(pdlContent, printTicket);
if (!uiRequired)
{
// Specify the Content type of content that will be written to target that is passed to printer accordingly.
PrintWorkflowPdlTargetStream streamTarget = args.CreateJobOnPrinter (args.SourceStream.ContentType);
// Process content directly if UI is not required
this.ProcessContent(pdlContent, streamTarget);
}
else if (args.UILauncher.IsUILaunchEnabled())
{
// LaunchAndCompleteUIAsync will launch the UI and wait for it to complete before returning
PrintWorkflowUICompletionStatus status = await args.UILauncher.LaunchAndCompleteUIAsync();
if (status == PrintWorkflowUICompletionStatus.Completed)
{
PrintWorkflowPdlTargetStream streamTarget = args.CreateJobOnPrinter(args.SourceStream.ContentType);
this.ProcessContent(pdlContent, streamTarget);
}
else
{
if (status == PrintWorkflowUICompletionStatus.UserCanceled)
{
// Log user cancellation and cleanup here.
this.taskDeferral.Complete();
}
else
{
// UI launch failed, abort print job.
args.Configuration.AbortPrintFlow(PrintWorkflowAbortReason.JobFailed);
this.taskDeferral.Complete();
}
}
}
else
{
// PSA requires to show UI, but launching UI is not supported at this point because of user selection.
args.Configuration.AbortPrintFlow(PrintWorkflowAbortReason.JobFailed);
this.taskDeferral.Complete();
}
}
Attivazione dell'interfaccia utente del processo di workflow per l'evento PDLDataAvailable
Diagramma di sequenza per l'attivazione dell'interfaccia utente del processo di stampa per l'evento PdlDataAvailable:
Codice di esempio C# per il contratto di attivazione dell'interfaccia utente del processo PSA:
namespace PsaSampleApp
{
sealed partial class App : Application
{
protected override void OnActivated(IActivatedEventArgs args)
{
if (args.Kind == ActivationKind.PrintSupportJobUI)
{
var rootFrame = new Frame();
rootFrame.Navigate(typeof(JobUIPage));
Window.Current.Content = rootFrame;
var jobUI = rootFrame.Content as JobUIPage;
// Get the activation arguments
var workflowJobUIEventArgs = args as PrintWorkflowJobActivatedEventArgs;
PrintWorkflowJobUISession session = workflowJobUIEventArgs.Session;
session.PdlDataAvailable += jobUI.OnPdlDataAvailable;
session.JobNotification += jobUI.OnJobNotification;
// Start firing events
session.Start();
}
}
}
}
namespace PsaSampleApp
{
public sealed partial class JobUIPage : Page
{
public JobUIPage()
{
this.InitializeComponent();
}
public string WorkflowHeadingLabel;
public void OnPdlDataAvailable(PrintWorkflowJobUISession session, PrintWorkflowPdlDataAvailableEventArgs args)
{
using (args.GetDeferral())
{
string jobTitle = args.Configuration.JobTitle;
string sourceApplicationName = args.Configuration.SourceAppDisplayName;
string printerName = args.Printer.PrinterName;
this.WorkflowHeadingLabel = string.Format(this.formatHeading, jobTitle, sourceApplicationName, printerName);
// Get pdl stream and content type
IInputStream pdlContent = args.SourceContent.GetInputStream();
string contentType = args.SourceContent.ContentType;
this.ShowPrintPreview(pdlContent, contentType);
}
}
}
}
Ottenere gli attributi del processo di stampa
Codice di esempio C# per ottenere le caratteristiche del lavoro di stampa:
namespace PsaBackground
{
class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{
private async void OnPdlModificationRequested(PrintWorkflowJobBackgroundSession session,
PrintWorkflowPdlModificationRequestedEventArgs args)
{
using (args.GetDeferral())
{
string colorMode = this.GetJobColorMode(args.PrinterJob);
if (colorMode != "monochrome")
{
this.SetJobColorModeToMonochrome(args.PrinterJob);
}
}
}
private string GetJobColorMode(PrintWorkflowPrinterJob printerJob)
{
var attributes = new List<string>();
attributes.Add("print-color-mode");
// Gets the IPP attributes from the current print job
IDictionary<string, IppAttributeValue> printerAttributes = printerJob.GetJobAttributes(attributes);
var colorModeValue = printerAttributes["print-color-mode"];
this.CheckValueType(colorModeValue, IppAttributeValueKind.Keyword);
return colorModeValue.GetKeywordArray().First();
}
}
}
Impostare gli attributi del lavoro di stampa
Codice di esempio C#, continuando dalla sezione Ottenere gli attributi del processo della stampante precedente, illustrando l'impostazione degli attributi del processo:
private async void SetJobColorModeToMonochrome(PrintWorkflowPrinterJob printerJob)
{
var attributes = new Dictionary<string, IppAttributeValue>();
attributes.Add("print-color-mode", IppAttributeValue.CreateKeyword("monochrome"));
var result = PrinterJob.SetJobAttributes(attributes);
if (!result.Succeeded)
{
this.LogSetAttributeError(result.AttributeErrors);
}
}
Alcune stampanti IPP non supportano l'acquisizione/impostazione degli attributi del processo dopo la creazione del processo. Per tali stampanti, PrintJob dispone della proprietà JobId impostata su "0" e GetJobAttributes/SetJobAttributes fallirà immediatamente con un'eccezione.
Consentire l'accesso ai file di archiviazione per i contenuti PDL
Alcuni formati PDL, ad esempio PDF, necessitano di un flusso completo per iniziare l'elaborazione. Per questo motivo, viene fornito un nuovo metodo denominato GetContentFileAsync nella classe PrintWorkflowPdlSourceContent che restituisce un StorageFile del contenuto di origine.
public sealed partial class JobUIPage : Page
{
public async void OnPdlDataAvailable(PrintWorkflowJobUISession session, PrintWorkflowPdlDataAvailableEventArgs args)
{
using (args.GetDeferral())
{
if (String.Equals(args.SourceContent.ContentType, "application/pdf", StringComparison.OrdinalIgnoreCase))
{
// Wait for all PDL data to be available
StorageFile sourceFile == await args.SourceContent.GetContentFileAsync();
IRandomAccessStream sourceStream = await sourceFile.OpenReadAsync();
PdfDocument pdfDocument = await PdfDocument.LoadFromStreamAsync(sourceStream);
for (uint i = 0; i < pdfDocument.PageCount; i++)
{
PdfPage page = pdfDocument.GetPage(i);
var pageImage = new InMemoryRandomAccessStream();
await page.RenderToStreamAsync(pageImage);
this.AddImageToPreviewImageList(pageImage);
}
}
}
}
}
Conversione PDL di XPS in PDF
Codice di esempio C# che mostra la conversione PDL di XPS in PDF:
private async void OnPdlModificationRequested(PrintWorkflowJobBackgroundSession session, PrintWorkflowPdlModificationRequestedEventArgs args)
{
using (args.GetDeferral())
{
if (String.Equals(args.SourceContent.ContentType, "application/oxps", StringComparison.OrdinalIgnoreCase))
{
var xpsContent = args.SourceContent.GetInputStream();
var printTicket = args.PrinterJob.GetJobPrintTicket();
PrintWorkflowPdlTargetStream streamTarget = args.CreateJobOnPrinter("application/pdf");
// Modify XPS stream here to make the needed changes
// for example adding a watermark
PrintWorkflowPdlConverter pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToPdf);
await pdlConverter.ConvertPdlAsync(printTicket, xpsContent, streamTarget.GetOutputStream());
streamTarget.CompleteStreamSubmission(PrintWorkflowSubmittedStatus.Succeeded);
}
else
{
// We except source content to be XPS in this case, abort the session if it is not XPS.
args.Configuration.AbortPrintFlow(PrintWorkflowAbortReason.JobFailed);
}
}
this.taskDeferral.Complete();
}
Evento di notifica di lavoro
Diagramma di sequenza per l'evento di notifica del processo:
Codice di esempio C#, continuando dall'attivazione dell'interfaccia utente del flusso di lavoro per la sezione evento PDLDataAvailable sopra, per visualizzare un errore nella notifica del lavoro:
public sealed partial class JobUIPage : Page
{
public void OnJobNotification(PrintWorkflowJobUISession session, PrintWorkflowJobNotificationEventArgs args)
{
using (args.GetDeferral())
{
PrintWorkflowPrinterJobStatus jobStatus = args.PrintJob.GetJobStatus();
switch (jobStatus)
{
case PrintWorkflowPrinterJobStatus::Error:
// Show print job error to the user
Frame->Navigate(JobErrorPage::typeid, this);
break;
case PrintWorkflowPrinterJobStatus::Abort:
// Show message that print job has been aborted.
Frame->Navigate(JobAbortPage::typeid, this);
break;
case PrintWorkflowPrinterJobStatus::Completed:
// Show job successfully completed message to the user.
Frame->Navigate(JobCompletedPage::typeid, this);
break;
}
}
}
}
Creare un lavoro con attributi iniziali del lavoro
Attualmente, alcune stampanti IPP non supportano l'operazione di impostazione dell'attributo. La funzione CreateJobOnPrinterWithAttributes e la funzione CreateJobOnPrinterWithAttributesBuffer su PrintWorkflowPdlDataAvailableEventArgs sono fornite per mitigare questo problema. Usando queste API, uno sviluppatore di PSA può fornire attributi di lavoro che vengono passati alla stampante quando il lavoro viene creato sulla stampante.
public sealed partial class JobUIPage : Page
{
public async void OnPdlDataAvailable(PrintWorkflowJobUISession session, PrintWorkflowPdlDataAvailableEventArgs args)
{
var attributes = new Dictionary<string, IppAttributeValue>();
attributes.Add("print-color-mode", IppAttributeValue.CreateKeyword("monochrome"));
// Create job on printer with initial job attributes
PrintWorkflowPdlTargetStream streamTarget = args.CreateJobOnPrinterWithAttributes(attributes, "application/pdf");
// Write data to target stream
}
}
Elaborazione sequenziale XPS
Esempio di codice C++/Winrt per l'elaborazione sequenziale di XPS prima che lo spooling sia completato.
namespace winrt
{
struct WorkflowReceiver : public winrt::implements<WorkflowReceiver, IPrintWorkflowXpsReceiver2>
{
STDMETHODIMP SetDocumentSequencePrintTicket(_In_ IStream* documentSequencePrintTicket) noexcept override
{
// process document sequence print ticket
return S_OK;
}
STDMETHODIMP SetDocumentSequenceUri(PCWSTR documentSequenceUri) noexcept override
{
// process document sequence URI
}
STDMETHODIMP AddDocumentData(UINT32 documentId, _In_ IStream* documentPrintTicket,
PCWSTR documentUri) noexcept override
{
// process document URI and print ticket
return S_OK;
}
STDMETHODIMP AddPage(UINT32 documentId, UINT32 pageId,
_In_ IXpsOMPageReference* pageReference, PCWSTR pageUri) noexcept override
{
// process XPS page
return S_OK;
}
STDMETHODIMP Close() noexcept override
{
// XPS processing finished
return S_OK;
}
STDMETHODIMP Failed(HRESULT XpsError) noexcept override
{
// XPS processing failed, log error and exit
return S_OK;
}
};
void PsaBackgroundTask::OnPdlModificationRequested(PrintWorkflowJobBackgroundSession session,
PrintWorkflowPdlModificationRequestedEventArgs args)
{
auto contentType = args.SourceContent().ContentType();
if (contentType == L"application/oxps")
{
auto xpsContent = args.SourceContent().GetInputStream();
PrintWorkflowObjectModelSourceFileContent xpsContentObjectModel(xpsContent);
com_ptr<IPrintWorkflowObjectModelSourceFileContentNative> xpsContentObjectModelNative;
check_hresult(winrt::get_unknown(xpsContentObjectModel)->QueryInterface(
IID_PPV_ARGS(xpsContentObjectModelNative.put())));
auto xpsreceiver = make_self<WorkflowReceiver>();
check_hresult(xpsContentObjectModelNative->StartXpsOMGeneration(xpsreceiver.get()));
}
}
}
Localizzazione dei nomi visualizzati e integrazione dell'API pass-through PDL
Importante
Questa sezione descrive le funzionalità di PSA disponibili a partire da Windows 11 versione 22H2.
In questo scenario, PSA personalizza le funzionalità del dispositivo di stampa (PDC) e fornisce le risorse del dispositivo di stampa (PDR) per la localizzazione delle stringhe.
Il PSA definisce anche i tipi di contenuto supportati dell'API pass-through PDL (formati PDL). Se il PSA non sottoscrive l'evento o non chiama SetSupportedPdlPassthroughContentTypes in modo esplicito, il pass-through PDL è disabilitato per le stampanti associate a questa app PSA.
// Event handler called every time PrintSystem updates PDC or BindPrinter is called
private void OnPdcChanged(PrintSupportExtensionSession session, PrintSupportPrintDeviceCapabilitiesChangedEventArgs args)
{
using (args.GetDeferral())
{
XmlDocument pdc = args.GetCurrentPrintDeviceCapabilities();
XmlDocument pdr = args.GetCurrentPrintDeviceResources();
// Check current PDC and make changes according to printer device capabilities
XmlDocument newPdc = this.CheckAndUpdatePrintDeviceCapabilities(pdc);
// Get updated printer devices resources, corresponding to the new PDC
XmlDocument newPdr = this.GetPrintDeviceResourcesInfo(newPdc, pdr, args.ResourceLanguage);
// Update supported PDL formats
args.SetSupportedPdlPassthroughContentTypes(GetSupportedPdlContentTypes());
args.UpdatePrintDeviceCapabilities(newPdc);
args.UpdatePrintDeviceResources(newPdr);
}
}
Supporto delle funzionalità a livello di pagina e attributi dell'operazione
Importante
Questa sezione descrive le funzionalità di PSA disponibili a partire da Windows 11 versione 22H2.
Gli scenari di supporto delle funzionalità a livello di pagina e degli attributi dell'operazione vengono raggruppati perché vengono risolti apportando modifiche nella stessa posizione nel codice di esempio.
supporto delle funzionalità a livello pagina: In questo scenario, l'applicazione PSA specifica l'attributo a livello pagina, che non deve essere sostituito da un attributo IPP derivato dal PrintTicket.
Raccolta separata per il supporto degli attributi operativi (stampa PIN): In questo scenario, l'applicazione PSA specifica attributi operativi IPP personalizzati (ad esempio, PIN).
Il codice di esempio C# seguente illustra le modifiche necessarie per gli scenari di supporto delle funzionalità a livello di pagina
private void OnPdlModificationRequested(PrintWorkflowJobBackgroundSession session, PrintWorkflowPdlModificationRequestedEventArgs args)
{
using (args.GetDeferral())
{
IInputStream pdlContent = args.SourceContent.GetInputStream();
// Custom job attributes to add to the printJob
IDictionary<string, IppAttributeValue> jobAttributes = LocalStorageUtil.GetCustomIppJobAttributes();
// Custom operation attributes to add to printJob
IDictionary<string, IppAttributeValue> operationAttributes = LocalStorageUtil.GetCustomIppOperationAttributes();
// PSA has an option to select preferred PDL format
string documentFormat = GetDocumentFormat(args.PrinterJob.Printer);
// Create PrintJob with specified PDL and custom attributes
PrintWorkflowPdlTargetStream targetStream = args.CreateJobOnPrinterWithAttributes(jobAttributes, documentFormat , operationAttributes,
PrintWorkflowAttributesMergePolicy .DoNotMergeWithPrintTicket /*jobAttributesMergePolicy*/, PrintWorkflowAttributesMergePolicy.MergePreferPsaOnConflict /*operationAttributesMergePolicy*/);
// Adding a watermark to the output(targetStream) if source payload type is XPS
this.ModifyPayloadIfNeeded(targetStream, args, documentFormat, deferral);
// Marking the stream submission as Succeeded.
targetStream.CompleteStreamSubmission(PrintWorkflowSubmittedStatus.Succeeded);
this.taskDeferral.Complete();
}
}
Miglioramento del dialogo di stampa con PSA
Importante
Questa sezione descrive le funzionalità di PSA disponibili a partire da Windows 11 versione 22H2.
In questo scenario, l'uso della finestra di dialogo di stampa con l'integrazione PSA abilita le azioni seguenti:
Ricevi un callback quando la selezione viene modificata nel MPD alla stampante associata a PSA
Mostra una scheda adattiva con il supporto per azione openUrl.
Mostra caratteristiche e parametri personalizzati nella finestra di dialogo di stampa
Modificare PrintTicket, modificando così la selezione per le opzioni di funzionalità visualizzate nella finestra di dialogo di stampa
Accedere al Windows.ApplicationModel.AppInfo dell'app di stampa, con l'apertura della finestra di dialogo di stampa
L'esempio C# seguente illustra i miglioramenti apportati alla finestra di dialogo di stampa:
public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
public void Run(IBackgroundTaskInstance taskInstance)
{
// Take task deferral
TaskInstanceDeferral = taskInstance.GetDeferral();
// Associate a cancellation handler with the background task
taskInstance.Canceled += OnTaskCanceled;
if (taskInstance.TriggerDetails is PrintSupportExtensionTriggerDetails extensionDetails)
{
PrintSupportExtensionSession session = extensionDetails.Session;
session.PrintTicketValidationRequested += OnSessionPrintTicketValidationRequested;
session.PrintDeviceCapabilitiesChanged += OnSessionPrintDeviceCapabilitiesChanged;
session.PrinterSelected += this.OnPrinterSelected;
}
}
private void OnTaskInstanceCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
TaskInstanceDeferral.Complete();
}
// Event handler called when the PSA Associated printer is selected in Print Dialog
private void OnPrinterSelected(PrintSupportExtensionSession session, PrintSupportPrinterSelectedEventArgs args)
{
using (args.GetDeferral())
{
// Show adaptive card in the Print Dialog (generated based on Printer and Printing App)
args.SetAdaptiveCard (GetCustomAdaptiveCard(session.Printer, args.SourceAppInfo));
// Request to show Features and Parameters in the Print Dialog if not shown already
const string xmlNamespace = "\"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords\"";
var additionalFeatures= new List<PrintSupportPrintTicketElement> { new PrintSupportPrintTicketElement { LocalName = "PageMediaType", NamespaceUri = xmlNamespace } };
var additionalParameters = new List<PrintSupportPrintTicketElement> { new PrintSupportPrintTicketElement { LocalName = "JobCopiesAllDocuments", NamespaceUri = xmlNamespace } };
if ((featuresToShow.Count + parametersToShow.Count) <= args.AllowedCustomFeaturesAndParametersCount)
{
args.SetAdditionalFeatures(additionalFeatures);
args.SetAdditionalParameter(additionalParameters);
}
else
{
// Cannot show that many additional features and parameters, consider reducing the number
// of additional features and parameters by selecting only the most important ones
}
}
}
// Create simple AdaptiveCard to show in MPD
public IAdaptiveCard GetCustomAdaptiveCard(IppPrintDevice ippPrinter, AppInfo appInfo)
{
return AdaptiveCardBuilder.CreateAdaptiveCardFromJson($@"
{{""body"": [
{{
""type"": ""TextBlock"",
""text"": ""Hello {appInfo.DisplayInfo.DisplayName} from {ippPrinter.PrinterName}!""
}}
],
""$schema"": ""http://adaptivecards.io/schemas/adaptive-card.json"",
""type"": ""AdaptiveCard"",
""version"": ""1.0""
}}");
}
Conversione PDL con flag basati su host per l'elaborazione
Importante
Questa sezione descrive le funzionalità di PSA disponibili a partire da Windows 11 versione 22H2.
L'attuale API di conversione PDL, PrintWorkflowPdlConverter.ConvertPdlAsync, esegue l'elaborazione basata su host di default. Ciò significa che il computer host/stampa esegue la rotazione, l'ordine di pagina e così via, affinché la stampante non debba eseguire queste operazioni. Tuttavia, i produttori di stampanti (IHV) possono richiedere la conversione PDL senza l'elaborazione basata su host, poiché la stampante è in grado di farlo meglio. La funzione ConvertPdlAsync accetta flag di elaborazione basati sull'host per soddisfare questo requisito. Il PSA può ignorare tutte le operazioni di elaborazione basate su host o una specifica operazione di elaborazione basata su host utilizzando questo flag.
class HostBaseProcessingRequirements
{
public bool CopiesNeedsHostBasedProcessing = false;
public bool PageOrderingNeedsHostBasedProcessing = false;
public bool PageRotationNeedsHostBasedProcessing = false;
public bool BlankPageInsertionNeedsHostBasedProcessing = false;
}
private async void OnPdlModificationRequested(PrintWorkflowJobBackgroundSession sender, PrintWorkflowPdlModificationRequestedEventArgs args)
{
using (args.GetDeferral())
{
var targetStream = args.CreateJobOnPrinter("application/pdf");
var pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToPdf);
var hostBasedRequirements = this.ReadHostBasedProcessingRequirements(args.PrinterJob.Printer);
PdlConversionHostBasedProcessingOperations hostBasedProcessing = PdlConversionHostBasedProcessingOperations.None;
if (hostBasedRequirements.CopiesNeedsHostBasedProcessing)
{
hostBasedProcessing |= PdlConversionHostBasedProcessingOperations.Copies;
}
if (hostBasedRequirements.PageOrderingNeedsHostBasedProcessing)
{
hostBasedProcessing |= PdlConversionHostBasedProcessingOperations.PageOrdering;
}
if (hostBasedRequirements.PageRotationNeedsHostBasedProcessing)
{
hostBasedProcessing |= PdlConversionHostBasedProcessingOperations.PageRotation;
}
if (hostBasedRequirements.BlankPageInsertionNeedsHostBasedProcessing)
{
hostBasedProcessing |= PdlConversionHostBasedProcessingOperations.BlankPageInsertion;
}
await pdlConverter.ConvertPdlAsync(args.PrinterJob.GetJobPrintTicket(), args.SourceContent.GetInputStream(), targetStream.GetOutputStream(), hostBasedProcessing);
}
}
private HostBaseProcessingRequirements ReadHostBasedProcessingRequirements(IppPrintDevice printDevice)
{
// Read Host based processing requirements for the printer
}
Impostare i criteri di aggiornamento PDC (Print Device Capabilities)
Importante
Questa sezione descrive le funzionalità di PSA disponibili a partire da Windows 11 versione 22H2.
Gli IHV della stampante possono avere requisiti diversi su quando le funzionalità del dispositivo di stampa (PDC) devono essere aggiornate. Per soddisfare questi requisiti, PrintSupportPrintDeviceCapabilitiesUpdatePolicy può definire una politica di aggiornamento per il PDC. PSA può impostare i criteri di aggiornamento PDC in base all'ora o al numero di processi di stampa usando questa API.
Impostare la politica di aggiornamento PDC in base al numero di attività
// Event handler called every time PrintSystem updates PDC
private void OnPdcChanged(PrintSupportExtensionSession session, PrintSupportPrintDeviceCapabilitiesChangedEventArgs args)
{
using (args.GetDeferral())
{
// Set update policy to update the PDC on bind printer of every print job.
var updatePolicy = PrintSupportPrintDeviceCapabilitiesUpdatePolicy.CreatePrintJobRefresh(1);
args.SetPrintDeviceCapabilitiesUpdatePolicy(updatePolicy);
}
}
Impostare la politica di aggiornamento PDC in base al timeout
// Event handler called every time PrintSystem updates PDC
private void OnPdcChanged(PrintSupportExtensionSession session, PrintSupportPrintDeviceCapabilitiesChangedEventArgs args)
{
using (args.GetDeferral())
{
// Set update policy to update the PDC on bind printer of every print job.
var updatePolicy = PrintSupportPrintDeviceCapabilitiesUpdatePolicy.CreatePrintJobRefresh(1);
args.SetPrintDeviceCapabilitiesUpdatePolicy(updatePolicy);
}
}
Linee guida generali per la progettazione dell'app di supporto per la stampa (PSA)
Quando si progetta un'app di supporto per la stampa, è importante includere questi aspetti nella progettazione:
Sia i contratti in primo piano che quelli in background devono essere contrassegnati come supportano più istanze; ad esempio, SupportsMultipleInstance devono essere presenti nel manifesto del pacchetto. Ciò consente di garantire che la durata dei contratti possa essere gestita in modo affidabile per più processi simultanei.
Considerare l'avvio dell'interfaccia utente per la modifica PDL come passaggio facoltativo. Fare del proprio meglio per completare il lavoro di stampa con successo anche se l'avvio dell'interfaccia utente non era consentito. I processi di stampa devono essere interrotti solo se non è possibile completarli correttamente senza l'input dell'utente durante la modifica PDL. Prendere in considerazione l'invio del PDL non modificato in questi casi.
Quando si avvia l'interfaccia utente per la modifica di PDL, è necessario chiamare IsUILaunchEnabled prima di chiamare LaunchAndCompleteUIAsync. Ciò consente di assicurarsi che gli scenari che non possono mostrare l'interfaccia utente al momento corrente continuano a essere stampati correttamente. Questi scenari potrebbero essere su un dispositivo headless o su un dispositivo attualmente in modalità kiosk o in modalità non disturbare.
Articoli correlati
Piano di fine supporto per i driver di stampante per terze parti su Windows
specifica del protocollo di stampa Internet (IPP)
l'associazione dell'app di supporto per la stampa