Partager via


Guide de conception de l’application de support d’impression v1 et v2

Cet article fournit des conseils et des exemples pour les fabricants oem d’imprimante et les IHV pour développer une application de support d’impression (PSA) qui peut améliorer l’expérience d’impression d’un utilisateur Windows de plusieurs façons.

Important

À compter de la version du Kit de développement logiciel (SDK) Windows 11 (22000.1), les applications de support d’impression (PSA) sont la méthode recommandée pour développer des applications UWP pour les imprimantes. Pour développer une application de support d’impression pour votre appareil d’impression, téléchargez et installez le Kit de développement logiciel (SDK) Windows 11 pour la version de Windows que vous ciblez.

Important

Cet article contient des sections qui décrivent les fonctionnalités PSA disponibles à partir de Windows 11, version 22H2. Ces sections contiennent une note indiquant qu’elle s’applique à cette version.

Pour plus d’informations, consultez les articles suivants :

Sujet Description
Guide de conception v3 API pour les applications de support d’impression Fournit des conseils et des exemples pour les oem d’imprimante et les IHD qui implémentent une application de support d’impression v3 (PSA) pour leur appareil.
Guide de conception v4 API pour les applications de support d’impression Fournit des conseils et des exemples pour les oem d’imprimante et les IHD qui implémentent une application de support d’impression v4 (PSA) pour leur appareil.
Spécification du manifeste MSIX pour l’imprimante virtuelle de prise en charge de l’impression Donne des conseils et des exemples de manifeste MSIX pour les fabricants d’imprimantes et les fournisseurs de matériel qui implémentent une imprimante virtuelle avec support d’impression.
Association d’applications de support d’impression Fournit des conseils et des exemples pour associer une application de support d’impression (PSA) à une imprimante.

Certaines fonctionnalités d’imprimante ne sont pas présentées dans les boîtes de dialogue d’impression affichées par Windows, car elles sont des fonctionnalités spéciales qui ont besoin d’aide d’une application fabricant pour être configurées correctement. Elles peuvent également être des fonctionnalités qui ne sont pas fournies dans les fonctionnalités par défaut de l’imprimante.

Les fonctionnalités spécifiques à l’imprimante peuvent être regroupées d’une manière qui permet à l’utilisateur de choisir facilement une option et d’approuver que toutes les fonctionnalités impliquées dans ce scénario sont automatiquement définies sur les valeurs correctes. Par exemple, il peut s’agir d’un choix entre l’économiseur d’encre, l’économiseur de papier et les modes de qualité les plus élevés qui peuvent manipuler automatiquement différentes fonctionnalités d’impression en fonction d’une sélection de l’utilisateur. Windows ne peut pas les regrouper automatiquement, car cela nécessite de comprendre toutes les fonctionnalités personnalisées de chaque modèle d’imprimante.

Cette nécessité d’afficher les préférences d’impression personnalisées est traitée par cette API avec un contrat d’extension UWP facultatif qui peut être activé par l’utilisateur à partir de toutes les boîtes de dialogue d’impression Windows et de boîtes de dialogue d’impression personnalisées qui utilisent l’API fournie par Windows. Les fabricants sont en mesure de personnaliser leur interface utilisateur afin de fournir la meilleure expérience d’impression pour l’imprimante spécifique que l’utilisateur possède.

Un autre domaine où les fabricants d’imprimantes peuvent améliorer et différencier est la qualité de l’impression. Les fabricants peuvent améliorer la qualité de l’impression après le rendu en optimisant le contenu de l’imprimante spécifique. Ils peuvent également présenter un aperçu haute fidélité qui représente mieux la sortie finale, car il peut prendre en compte les fonctionnalités spécifiques de l’imprimante.

application de support d’impression chronologie d’impression

Terminologie

Terme Définition
Antigène prostatique spécifique (PSA) Application de prise en charge d’impression. Application UWP qui utilise l’API décrite dans cet article.
MPD Boîte de dialogue d’impression moderne. Cela s’affiche à l’utilisateur lorsqu’une application imprime à l’aide de l’API Windows.Graphics.Printing.
CPD Boîte de dialogue d’impression commun. Cela s’affiche à l’utilisateur lorsque l’application imprime à l’aide de l’API Win32. Les applications qui doivent afficher l’aperçu avant impression ne déclenchent pas cette boîte de dialogue et implémentent une version de boîte de dialogue elles-mêmes. Les applications Office sont un exemple de premier choix.
IPP Protocole d’impression Internet. Utilisé à partir d’un appareil client pour interagir avec l’imprimante pour récupérer et définir les préférences d’impression et envoyer le document à imprimer.
Imprimante associée au support d’impression. Imprimante liée à PSA.
Imprimante IPP Imprimante prenant en charge le protocole IPP.
Autres paramètres Lien qui ouvre l’interface utilisateur de l’application fournie par le partenaire dans MPD. Par défaut, il ouvre l’interface utilisateur des préférences d’impression intégrées lorsqu’aucun PSA n’est installé.
Interface utilisateur préférences de l’imprimante Boîte de dialogue utilisée pour définir les options d’imprimante par défaut appliquées au moment de l’impression. Par exemple : orientation, taille du papier, couleur, impression sur les deux côtés, et ainsi de suite.
PDL Langue de description de la page. Format dans lequel un document est envoyé à l’imprimante.
Imprimante PSA associée Imprimante IPP physique associée à une application PSA.
PrintDeviceCapabilities Format de document XML pour la définition des fonctionnalités d’imprimante. Pour plus d’informations, veuillez consulter la section Technologies de ticket d’impression et de capacités d’impression.
PrintTicket Collection de différentes fonctionnalités liées à l’impression et de leurs valeurs utilisées pour capturer l’intention de l’utilisateur pour un travail d’impression donné.
PrintSupportExtension Tâche de fond PSA responsable de la fourniture des capacités d’extension de contrainte de l’imprimante.

Ces exemples font référence à un espace de noms printsupport, qui est défini comme suit :

    xmlns:printsupport="http://schemas.microsoft.com/appx/manifest/printsupport/windows10"

Lorsqu’un utilisateur est sur le point d’imprimer un document, il souhaite souvent définir certaines préférences pour l’imprimer. Par exemple, ils peuvent choisir d’imprimer un document en orientation paysage. Ils peuvent également tirer parti d’une fonctionnalité personnalisée prise en charge par leur imprimante. Windows fournit l’interface utilisateur par défaut pour afficher les préférences personnalisées, mais l’utilisateur peut ne pas les comprendre, car il n’existe aucune icône ou description appropriée. Windows peut également utiliser le mauvais contrôle d’interface utilisateur pour les présenter. Une telle fonctionnalité personnalisée est mieux présentée par une application qui comprend complètement la fonctionnalité. Il s’agit de la motivation de l’offre d’une API qui permet aux fabricants d’imprimantes de créer des applications adaptées aux différents modèles d’imprimante qu’ils fabriquent.

Un nouveau contrat d’extension UAP est créé avec une nouvelle catégorie nommée windows.printSupportSettingsUI. Les applications activées avec ce contrat reçoivent un nouvel ActivationKind appelé PrintSupportSettingsUI. Ce contrat ne nécessite aucune nouvelle fonctionnalité.

<Extensions>
    <printsupport:Extension Category="windows.printSupportSettingsUI" 
        EntryPoint="PsaSample.PsaSettingsUISample"/>
</Extensions>

Ce contrat est appelé lorsque l’utilisateur sélectionne Autres paramètres dans MPD ou Préférences dans CPD. Ce contrat peut également être invoqué à partir de Préférences d’impression dans l’application Paramètres. Lorsque le contrat est activé, l’application reçoit un objet PrintSupportSettingsUISession qui peut être utilisé pour obtenir les objets PrintTicket et PrintDevice actuels. L’objet PrintDevice peut être utilisé pour communiquer avec l’imprimante pour recevoir des attributs d’imprimante et de travail. L’application peut ensuite afficher l’interface utilisateur avec les options appropriées de l’imprimante à l’utilisateur. Lorsque l’utilisateur effectue les choix et sélectionne OK, l’application peut ensuite modifier le ticket d’impression, le valider, puis renvoyer à l’aide de PrintSupportPrintTicketTarget objet. Si l’utilisateur choisit d’annuler la fenêtre préférences, les modifications doivent être ignorées et l’application doit se fermer en terminant le report pris à partir de l’objet PrintSupportSettingsUISession.

L’application de support d’impression est censée gérer plusieurs activations simultanées pour différents travaux d’impression. Par conséquent, une telle application doit prendre en charge plusieurs instances à l’aide des SupportsMultipleInstances élément dans le fichier package.appxmanifest. L’échec de cette opération peut entraîner des situations où la confirmation des préférences d’un travail d’impression peut fermer d’autres fenêtres de préférences qui peuvent être ouvertes. L’utilisateur est tenu d’ouvrir à nouveau ces fenêtres de préférences.

Le diagramme de séquence suivant représente le concept de manipulation du ticket d’impression de l’interface utilisateur des paramètres :

diagramme de séquence diagramme de séquence de la manipulation du PrintTicket dans l’interface utilisateur des paramètres

Modification de PrintTicket dans l’interface utilisateur des paramètres

Exemple de code C# pour l’activation de l’interface utilisateur des paramètres lorsqu’elle est lancée à partir d’une boîte de dialogue d’impression (MPD/CPD ou boîte de dialogue d’impression personnalisée) ou à partir des paramètres système :

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 pour la 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>

Exemple de code C# pour afficher l’interface utilisateur et modifier 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();
        }
    }
}

Obtenir des attributs d’imprimante à partir de l’appareil d’imprimante

Réponse WireShark d’une imprimante IPP à une requête get-printer-attributes :

réponse Wireshark d’une imprimante IPP à une requête d’obtention des attributs de l’imprimante

Exemple de code C# pour obtenir des noms d’encre et des niveaux d’encre à partir de l’imprimante :

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

Définition des attributs d’imprimante sur l’imprimante

Exemple de code C# pour définir des attributs d’imprimante :

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

Extension des contraintes d’imprimante

L’application de support d’impression prend en charge la validation PrintTicket personnalisée et la définition du printTicket par défaut. Cette section décrit comment nous prenons en charge ces fonctionnalités.

Pour prendre en charge les contraintes d’extension d’imprimante, un nouveau type de tâche en arrière-plan, PrintSupportExtension, a été implémenté. Le Package.appxmanifest a une entrée d’extensibilité pour l’extension de support d’impression, comme indiqué ici :

<Extensions>
    <printsupport:Extension Category="windows.printSupportExtension" 
        EntryPoint="PsaBackgroundTasks.PrintSupportExtension"/>
</Extensions>

Ce service peut s’exécuter à tout moment dans un travail d’impression pour l’imprimante IPP associée. Lorsque l’extension de support d’impression est activée via la fonction IBackgroundTaskInstance, une instance d’IBackgroundTaskInstance est donnée à PrintSupportExtension pour fournir l’accès à la classe runtime PrintSupportExtensionTriggerDetails, qui fournit en interne PrintSupportExtensionSession en tant que propriété. La classe de fond PrintSupportExtension peut ensuite utiliser l'objet de session pour s'inscrire à des événements afin de fournir des fonctionnalités personnalisées.

  1. event Windows.Foundation.TypedEventHandler<PrintSupportExtensionSession, PrintSupportPrintTicketValidationRequestedEventArgs>; PrintTicketValidationRequested;

    Si l’extension Print Support fournit son propre mécanisme de validation du PrintTicket, elle peut s’inscrire à cet événement. Chaque fois qu’un PrintTicket doit être validé, le système d’impression déclenche cet événement. PrintSupportExtension obtiendra alors le PrintTicket actuel qui doit être validé dans les EventArgs. La PrintSupportExtension classe d’arrière-plan peut ensuite vérifier la PrintTicket pour sa validité et la modifier pour résoudre d'éventuels conflits. La classe d’arrière-plan PrintSupportExtension doit ensuite définir le résultat de la validation à l’aide de la fonction SetPrintTicketResult pour indiquer si le PrintTicket a été résolu, a des conflits ou n’est pas valide. Cet événement peut être déclenché à tout moment pendant la durée de vie d’un travail d’impression. Si la classe PrintSupportExtension ne s’inscrit pas à cet événement, le système d’impression effectue sa propre validation du printTicket.

  2. event Windows.Foundation.TypedEventHandler<PrintSupportExtensionSession, PrintSupportPrintDeviceCapabilitiesChangedEventArgs>; PrintDeviceCapabilitiesChanged;

    L’événement est déclenché après que le système d’impression a mis à jour le cache des PrintDeviceCapabilities of de l’imprimante IPP associée. Lorsque cet événement est déclenché, la classe d’arrière-plan PrintSupportExtension peut inspecter les PrintDeviceCapabilities modifiés et les modifier.

Validation personnalisée du ticket d’impression

Exemple de code C# pour fournir un service de validation de 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);
    }
}

Mise à jour de 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);
    }
}

Amélioration de la qualité de l’impression

Une fois que l’utilisateur s’est engagé à imprimer en appuyant sur le bouton Imprimer dans la boîte de dialogue Imprimer, le document à imprimer est envoyé à la pile d’impression à partir de l’application qui imprime. Ce document subit ensuite une transformation (rendu au format PDL) pour le rendre adapté à l’imprimante cible. Windows détermine la transformation à choisir en fonction des attributs interrogés à partir de l’imprimante. Le document transformé est ensuite envoyé à l’imprimante. Bien que cela fonctionne bien pour la plupart des imprimantes, il existe des cas où la qualité de l’impression peut être améliorée en permettant à une application partenaire de participer à la transformation. Pour faciliter cette opération, l’API de flux de travail d’impression actuelle est étendue pour inclure des appels à l’application à des points supplémentaires de la pile d’impression. Cette API prend en charge deux nouveaux événements auxquels l’application PSA peut s’inscrire. Il s’agit des seuls points d’entrée dans la surface de l’API PSA :

  1. JobStarting

    • Cet événement est déclenché lorsqu’un travail d’impression est démarré par n’importe quelle application. Lorsque l’événement est déclenché, une application de support d’impression peut choisir d’ignorer le rendu système en appelant SetSkipSystemRendering sur PrintWorkflowJobStartingEventArgs. Si l'option de sauter le rendu système est sélectionnée, le système d'impression ne convertira pas le document XPS au format PDL requis par l'imprimante. Au lieu de cela, le XPS généré par l’application d’impression sera directement donné au PSA qui est ensuite responsable de la conversion de XPS au format PDL.
  2. PdlModificationRequested

    • Cet événement est déclenché lorsque Windows démarre la conversion du flux XPS au format PDL indiqué par l’imprimante. La classe Runtime PrintWorkflowPdlModificationRequestedEventArgs est fournie comme argument pour cet événement. Cette classe d’événements fournit des objets source et cible PDL pour la lecture et l’écriture du contenu du travail d’impression. Si l’application détermine qu’elle a besoin d’une entrée utilisateur, elle peut lancer l’interface utilisateur à l’aide de PrintWorkflowUILauncher à partir d’EventArgs. Cette API utilise le modèle Tester-Doer. PrintWorkflowUILauncher ne pourra pas appeler l’interface utilisateur si la fonction IsUILaunchEnabled retourne false. Cette fonction retourne false si la session PSA fonctionne en mode silencieux (mode autonome ou mode kiosque). L’application de support avant impression ne doit pas essayer de lancer l’interface utilisateur si la fonction retourne false.

    Un OutputStream est disponible dans le cadre de PrintWorkflowPdlTargetStream retourné par la fonction GetStreamTargetAsync. Le contenu écrit dans outputStream cible est transmis à l’imprimante en tant que contenu de document.

Diagramme de séquence pour l’événement de modification PDL :

diagramme de séquence pour l’événement de modification P D L du flux source

L’application de premier plan PSA est lancée lorsque la tâche en arrière-plan PSA demande de lancer l’interface utilisateur. L’application PSA peut utiliser le contrat en premier plan pour obtenir l’entrée de l’utilisateur et/ou pour afficher un aperçu de l’impression à l’utilisateur.

Un nouveau type de tâche en arrière-plan printSupportWorkflow a été défini. Package.appxmanifest a l’entrée d’extensibilité suivante pour le contrat PrintSupportWorkflow :

<Extensions>
    <printsupport:Extension Category="windows.printSupportWorkflow" 
        EntryPoint="PsaBackgroundTasks.PrintSupportWorkflowSample"/>
</Extensions>

Lors de l’activation du contrat, PrintWorkflowJobTriggerDetails est donné en tant que IBackgroundTaskInstance->TriggerDetails. PrintWorkflowJobTriggerDetails fournit internement PrintWorkflowJobBackgroundSession en tant que partie de ses propriétés. L’application peut utiliser PrintWorkflowJobBackgroundSession pour s’inscrire aux événements liés aux différents points d’injection dans le flux de travail du travail d’impression. Une fois l'enregistrement de l'événement terminé, l'application doit appeler PrintWorkflowJobBackgroundSession::Start pour que le système d'impression puisse commencer à déclencher des événements liés à différents points d'injection.

Un nouveau ActivationKind appelé printSupportJobUI est défini. Cela ne nécessite pas de nouvelle fonctionnalité.

<Extensions>
    <printsupport:Extension Category="windows.printSupportJobUI" 
        EntryPoint="PsaSample.PrintSupportJobUISample"/>
</Extensions>

C’est un contrat d’interface utilisateur qui peut être lancé à partir du contrat de fond de workflow d’assistance à l’impression, ou lorsque l’utilisateur sélectionne une notification d’erreur de travail d’impression. Lors de l’activation, PrintWorkflowJobActivatedEventArgs est fourni, qui a un objet PrintWorkflowJobUISession. À l’aide de PrintWorkflowJobUISession, l’application de premier plan doit s’inscrire à l’événement PdlDataAvailable si elle souhaite accéder aux données PDL. Si l’application de premier plan souhaite afficher des messages d’erreur personnalisés pour toutes les erreurs qui peuvent se produire pendant le travail, elle doit s’inscrire à l’événement JobNotification. Une fois les événements inscrits, l’application doit appeler la fonction PrintWorkflowJobUISession ::Start function pour que le système d’impression commence à déclencher des événements.

Saut du rendu système

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

Événement de modification PDL

Diagramme de séquence pour l’événement de modification PDL :

diagramme de séquence pour l’événement de modification P D L du flux d’entrée

Exemple de code C# pour le moniteur de support d'impression : lecture et écriture du contenu du travail d’impression.

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

Lancement de l'interface utilisateur depuis l'arrière-plan du flux de travail

Exemple de code en C# pour le lancement de l’interface utilisateur du travail d’impression depuis le contrat d’événement de modification PDL de l’application PSA :

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

Activation de l’interface utilisateur du travail d’impression pour l’événement PDLDataAvailable

Diagramme de séquence pour l’activation de l’interface utilisateur du travail d’impression pour l’événement PdlDataAvailable :

diagramme de séquence diagramme de séquence pour l’activation de l’interface utilisateur de la tâche d’impression pour l’événement de disponibilité des données PDL

Exemple de code en C# pour le contrat d’activation de l’interface utilisateur du travail d’impression de l’application 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);
            }
        }
    }
}

Obtenir les attributs de travail de l’imprimante

Exemple de code C# pour obtenir des attributs de travail pour un travail d’impression :

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

Définir des attributs de travail d’imprimante

Exemple de code C#, en commençant à partir de la section Obtenir les attributs des tâches d'impression ci-dessus, illustrant la définition des attributs de tâche :

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

Certaines imprimantes IPP ne permettent pas d'obtenir ou de définir les attributs de tâche après la création de la tâche. Pour ces imprimantes, PrintJob a la propriété JobId définie sur « 0 » et GetJobAttributes/SetJobAttributes échoue immédiatement avec une exception.

Fournir un accès au système de stockage pour le contenu PDL

Certains formats PDL tels que PDF ont besoin d’un flux complet pour démarrer le traitement. Pour cette raison, une nouvelle méthode nommée GetContentFileAsync est fournie sur la classe PrintWorkflowPdlSourceContent qui retourne une StorageFile du contenu source.

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

Conversion PDL de XPS en PDF

Exemple de code C# montrant la conversion PDL de XPS en 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();
}

Événement de notification de travail

Diagramme de séquence pour l’événement de notification de travail :

diagramme de séquence pour l’événement de notification de travail

Exemple de code C#, en continuant à partir de l’activation de l’UI du flux de travail pour la section d’événements PDLDataAvailable mentionnée ci-dessus, pour afficher l’erreur dans la notification de travail :

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

Créer un travail avec des attributs de travail initiaux

Actuellement, certaines imprimantes IPP ne prennent pas en charge l’opération de définition d'attribut. La fonction CreateJobOnPrinterWithAttributes et la fonction CreateJobOnPrinterWithAttributesBuffer sur PrintWorkflowPdlDataAvailableEventArgs sont fournies pour atténuer ce problème. À l’aide de ces API, un développeur PSA peut fournir des attributs de travail transmis à l’imprimante lors de la création d’un travail sur l’imprimante.

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

Traitement séquentiel XPS

Exemple de code C++/Winrt pour traiter séquentiellement le XPS avant que l’impression ne soit terminée.

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

Localisation du nom d’affichage et intégration de l’API de transfert de PDL

Important

Cette section décrit les fonctionnalités PSA disponibles à partir de Windows 11, version 22H2.

Dans ce scénario, l’application PSA personnalise les Capacités de l’appareil d’impression (PDC) et fournit des Ressources de l’appareil d’impression (PDR) pour la localisation des chaînes.

Le PSA définit également les types de contenu API Passthrough PDL pris en charge (formats PDL). Si le PSA ne s’abonne pas à l’événement ou n’appelle pas explicitement SetSupportedPdlPassthroughContentTypes, le mode PDL Passthrough est désactivé pour les imprimantes associées à cette application 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);
    }
}

Prise en charge des fonctionnalités au niveau de la page et attributs d’opération

Important

Cette section décrit les fonctionnalités PSA disponibles à partir de Windows 11, version 22H2.

Les scénarios de prise en charge des fonctionnalités au niveau de la page et les attributs d’opération sont regroupés, car ils sont traités en apportant des modifications au même endroit dans l’exemple de code.

  • Support des fonctionnalités au niveau de la page : Dans ce scénario, l’application PSA spécifie l’attribut au niveau de la page, qui ne doit pas être remplacé par un attribut IPP analysé à partir du PrintTicket.

  • Collecte distincte pour les attributs d’opération pris en charge (impression de PIN) : Dans ce scénario, l’application PSA spécifie des attributs d’opération IPP personnalisés (par exemple, code confidentiel).

Le code source d’exemple C# suivant montre les modifications nécessaires pour les scénarios Support des fonctionnalités au niveau de la page et Collection séparée pour les attributs d’opération.

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

Amélioration de la boîte de dialogue d’impression avec PSA

Important

Cette section décrit les fonctionnalités PSA disponibles à partir de Windows 11, version 22H2.

Dans ce scénario, l’utilisation de la boîte de dialogue d’impression avec l’intégration de PSA active les actions suivantes :

  • Recevoir un rappel lorsque la sélection est modifiée dans le MPD vers l’imprimante associée à la PSA.

  • Afficher une AdaptiveCard avec une action de openUrl.

  • Afficher les fonctionnalités et paramètres personnalisés dans la boîte de dialogue Imprimer

  • Modifier le PrintTicket, ce qui modifie la sélection des options de fonctionnalité affichées dans la boîte de dialogue d’impression

  • Obtenir les informations Windows.ApplicationModel.AppInfo de l’application d’impression, ouvrir la boîte de dialogue d’impression.

L’exemple C# suivant illustre ces améliorations de boîte de dialogue d’impression :

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

Conversion PDL avec des indicateurs de traitement basé sur l’hôte

Important

Cette section décrit les fonctionnalités PSA disponibles à partir de Windows 11, version 22H2.

L’API de conversion PDL actuelle, PrintWorkflowPdlConverter.ConvertPdlAsync, effectue le traitement basé sur l’hôte par défaut. Cela signifie que l’ordinateur hôte/impression effectue la rotation, l’ordre des pages, et ainsi de suite, afin que l’imprimante n’ait pas besoin d’effectuer ces opérations. Cependant, les fournisseurs de périphériques d’impression (IHV) peuvent souhaiter une conversion PDL sans traitement basé sur l’hôte, car leur imprimante peut le faire mieux. La fonction ConvertPdlAsync prend des indicateurs de traitement basés sur l’hôte pour répondre à cette exigence. La PSA peut ignorer tout traitement basé sur l’hôte ou une opération de traitement basé sur l’hôte particulière à l’aide de cet indicateur.

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
}

Définir la stratégie de mise à jour des fonctionnalités de l’appareil d’impression (PDC)

Important

Cette section décrit les fonctionnalités PSA disponibles à partir de Windows 11, version 22H2.

Les fournisseurs de périphériques d’impression (IHV) peuvent avoir des exigences différentes concernant le moment où les Capacités de Périphérique d’Impression (PDC) doivent être mises à jour. Pour répondre à ces exigences, PrintSupportPrintDeviceCapabilitiesUpdatePolicy peut définir une politique de mise à jour pour les PDC. PSA peut définir la stratégie de mise à jour du contrôleur de domaine principal en fonction de l’heure ou du nombre de travaux d’impression à l’aide de cette API.

Définir la stratégie de mise à jour du PDC en fonction du nombre de tâches

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

Définir la stratégie de mise à jour du PDC en fonction du 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);      
    }
}

Conseils généraux sur la conception de l’application de support d’impression (PSA)

Lors de la conception d’une application de prise en charge d’impression, il est important d’inclure ces aspects dans la conception :

  • Les contrats de premier plan et d’arrière-plan doivent être marqués comme prenant en charge plusieurs instances, par exemple, SupportsMultipleInstance doivent être présents dans le manifeste du package. Cela permet de s’assurer que la durée de vie des contrats peut être gérée de manière fiable pour plusieurs travaux simultanés.

  • Traitez le lancement de l’interface utilisateur pour la modification PDL comme une étape facultative. Faites un meilleur effort pour terminer le travail d’impression correctement même si le lancement de l’interface utilisateur n’a pas été autorisé. Les travaux d’impression ne doivent être abandonnés que s’il n’existe aucun moyen de les terminer correctement sans entrée utilisateur lors de la modification PDL. Envisagez d’envoyer le fichier PDL non modifié dans de tels cas.

  • Lors du lancement de l’interface utilisateur pour la modification de PDL, appeler IsUILaunchEnabled avant d’appeler LaunchAndCompleteUIAsync. Cela permet de s’assurer que les scénarios qui ne peuvent pas afficher l’interface utilisateur à l’heure actuelle continuent à s’imprimer correctement. Ces scénarios pourraient être sur un appareil sans écran ou sur un appareil actuellement en mode kiosque ou ne pas déranger.

plan de fin de maintenance pour les pilotes d’imprimante tiers sur Windows

spécification IPP (Internet Printing Protocol)

Association d’applications de support d’impression

Windows.Devices.Printers

Windows.Graphics.Printing.PrintSupport

Windows.Graphics.Printing.Workflow