Sdílet prostřednictvím


Průvodce návrhem aplikace podpory tisku v1 a v2

Tento článek obsahuje pokyny a příklady pro tiskárny OEM a IHV k vývoji aplikace pro podporu tisku (PSA), která může vylepšit tiskové prostředí uživatele Windows několika způsoby.

Důležitý

Počínaje vydáním sady Windows 11 SDK (22000.1) jsou aplikace pro podporu tisku (PSA) doporučenou metodou vývoje aplikací UWP pro tiskárny. Pokud chcete vyvíjet aplikaci podpory tisku pro tiskové zařízení, stáhněte a nainstalujte sadu Windows 11 SDK pro verzi Windows, na kterou cílíte.

Důležitý

Tento článek obsahuje části, které popisují funkce PSA, které jsou dostupné od Windows 11 verze 22H2. Tyto oddíly obsahují poznámku, která označuje, že se vztahuje na tuto verzi.

Další informace najdete v následujících článcích:

Námět Popis
průvodce návrhem rozhraní API pro podporu tisku v3 Poskytuje pokyny a příklady pro tiskárny OEM a IHV, které implementují aplikaci podpory tisku v3 (PSA) pro své zařízení.
průvodce návrhem rozhraní API podpory tisku v4 Poskytuje pokyny a příklady pro tiskárny OEM a IHV, které implementují aplikaci podpory tisku v4 (PSA) pro své zařízení.
Specifikace manifestu MSIX pro podporu tisku u virtuální tiskárny Poskytuje pokyny a příklady manifestu MSIX pro tiskárny OEM a IHV, které implementují virtuální tiskárnu s podporou tisku.
Podpora přidružení aplikace k tisku Obsahuje pokyny a příklady pro přidružení aplikace podpory tisku (PSA) k tiskárně.

Některé funkce tiskárny se nezobrazují v dialogových oknech tisku ve Windows, protože jsou to speciální funkce, které potřebují pomoct s konfigurací aplikace výrobce. Můžou se jednat také o funkce, které nejsou k dispozici ve výchozích funkcích tiskárny.

Funkce specifické pro tiskárnu je možné seskupit tak, aby uživatel snadno vybral možnost a důvěřoval tomu, že všechny funkce, které jsou součástí daného scénáře, jsou automaticky nastaveny na správné hodnoty. Příkladem může být volba mezi spořičem rukopisu, spořičem papíru a režimy nejvyšší kvality, které by mohly automaticky manipulovat s různými funkcemi tisku na základě jednoho výběru od uživatele. Systém Windows je nemůže automaticky seskupit, protože vyžaduje pochopení všech vlastních funkcí každého modelu tiskárny.

Tato potřeba k zobrazení vlastních předvoleb tisku je adresována tímto rozhraním API s volitelným kontraktem rozšíření UPW, který může uživatel aktivovat ze všech dialogových oken windows a vlastních dialogových oken tisku, které používají rozhraní API poskytované systémem Windows. Výrobci si můžou přizpůsobit uživatelské rozhraní tak, aby poskytovalo nejlepší možnosti tisku pro konkrétní tiskárnu, která vlastní uživatel.

Další oblastí, kde mohou výrobci tiskárny zlepšit a odlišit, je kvalita tisku. Výrobci mohou po vykreslení zlepšit kvalitu tisku optimalizací obsahu pro konkrétní tiskárnu. Můžou také prezentovat vysoce věrný náhled, který lépe představuje konečný výstup, protože by mohl vzít v úvahu specifické funkce tiskárny.

aplikace pro podporu tiskučasová osa tisku

Terminologie

Období Definice
PSA Aplikace podpory tisku. Aplikace pro UPW, která používá rozhraní API popsané v tomto článku.
MPD Moderní dialog tisku To se uživateli zobrazí, když aplikace tiská pomocí rozhraní API pro Windows.Graphics.Printing.
CPD Dialogové okno pro běžný tisk To se uživateli zobrazí při tisku aplikace pomocí rozhraní API Win32. Aplikace, které potřebují zobrazit náhled tisku, neaktivují tento dialog a implementují vlastní verzi dialogového okna. Příkladem tohoto příkladu jsou aplikace Office.
IPP Protokol pro tisk přes internet. Používá se z klientského zařízení k interakci s tiskárnou k načtení a nastavení předvoleb tisku a k odeslání dokumentu, který se má vytisknout.
Podpora tisku přidružená tiskárna Tiskárna propojena s PSA.
Tiskárna IPP Tiskárna, která podporuje protokol IPP.
Další nastavení Odkaz, který otevře uživatelské rozhraní aplikace poskytované partnerem v MPD. Ve výchozím nastavení se otevře integrované uživatelské rozhraní předvoleb tisku, když není nainstalovaný žádný PSA.
Uživatelské rozhraní Předvoleb tiskárny Dialogové okno slouží k nastavení výchozích možností tiskárny, které se použijí při tisku. Například: orientace, velikost papíru, barva, tisk na obě strany atd.
PDL Jazyk popisu stránky. Formát, ve kterém je dokument odeslán do tiskárny.
Přidružená tiskárna PSA Fyzická tiskárna IPP přidružená k aplikaci PSA.
Schopnosti tiskového zařízení Formát dokumentu XML pro definování možností tiskárny Další informace naleznete v tématu Technologie tiskových lístků a možností tisku.
PrintTicket Kolekce různých funkcí souvisejících s tiskem a jejich hodnot použitých k zachycení záměru uživatele pro danou tiskovou úlohu
RozšířeníPodporyTisku Úloha PSA na pozadí, která je zodpovědná za poskytování schopností rozšíření omezení tiskárny.

Tyto ukázky odkazují na printsupport oboru názvů, který je definován takto:

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

Když se uživatel chystá vytisknout dokument, často by chtěl nastavit určité předvolby, se kterými ho chcete vytisknout. Můžou se například rozhodnout vytisknout dokument v orientaci na šířku. Mohou také využít vlastní funkci, kterou tiskárna podporuje. Windows poskytuje výchozí uživatelské rozhraní pro zobrazení vlastních předvoleb, ale uživatel mu nemusí rozumět, protože neexistují žádné vhodné ikony nebo popisy. Systém Windows také může k jeho prezentaci používat nesprávný ovládací prvek uživatelského rozhraní. Takovou vlastní funkci nejlépe prezentuje aplikace, která tuto funkci plně rozumí. To je motivace nabídky rozhraní API, které umožňuje výrobcům tiskáren vytvářet aplikace přizpůsobené různým modelům tiskárny, které vytvářejí.

Vytvoří se nový kontrakt rozšíření UAP s novou kategorií s názvem windows.printSupportSettingsUI. Aplikace aktivované v rámci této smlouvy obdrží nový druh aktivace nazvaný PrintSupportSettingsUI. Tento kontrakt nevyžaduje žádnou novou funkci.

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

Tento kontrakt se vyvolá, když uživatel vybere Další nastavení v programu MPD nebo Předvolby v CPD. Tento kontrakt lze také vyvolat z Předvolby tisku v aplikaci Nastavení. Když je smlouva aktivována, aplikace obdrží objekt PrintSupportSettingsUISession, který lze použít k získání aktuálních objektů PrintTicket a PrintDevice. Objekt PrintDevice lze použít ke komunikaci s tiskárnou pro příjem atributů tiskárny a úlohy. Aplikace pak může uživateli zobrazit uživatelské rozhraní s příslušnými možnostmi tiskárny. Když uživatel provede volby a vybere OK, může aplikace upravit lístek tisku, ověřit ho a odeslat zpět pomocí PrintSupportPrintTicketTarget objektu. Pokud se uživatel rozhodne zrušit okno předvoleb, změny by se měly zahodit a aplikace by se měla ukončit dokončením odložení převzatého z objektu PrintSupportSettingsUISession.

Očekává se, že aplikace podpory tisku zpracuje více souběžných aktivací pro různé tiskové úlohy, takže taková aplikace musí podporovat více instancí pomocí SupportsMultipleInstances element v souboru package.appxmanifest. Pokud to neuděláte, může to vést k situacím, kdy potvrzení předvoleb jedné tiskové úlohy může zavřít jiná okna předvoleb, která mohou být otevřená. Uživatel musí znovu otevřít okna předvoleb.

Následující sekvenční diagram představuje koncept manipulace s lístky tisku uživatelského rozhraní nastavení:

sekvenční diagram nastavení uživatelského rozhraní pro manipulaci s tiskem lístků

Změna PrintTicketu v uživatelském rozhraní nastavení

Vzorový kód jazyka C# pro aktivaci uživatelského rozhraní nastavení při spuštění z libovolného dialogového okna tisku (MPD/CPD nebo vlastního dialogového okna tisku) nebo z nastavení systému:

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 pro třídu 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>

Vzorový kód jazyka C#, který zobrazuje uživatelské rozhraní a mění 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();
        }
    }
}

Získání atributů tiskárny ze zařízení tiskárny

Odpověď WireShark z tiskárny IPP na dotaz get-printer-attributes:

odpověď Wiresharku z I P P tiskárny v reakci na dotaz na získání atributů tiskárny

Vzorový kód jazyka C# pro získání názvů rukopisu a úrovní rukopisu z tiskárny:

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

Nastavení atributů tiskárny na tiskárně

Vzorový kód jazyka C#pro nastavení atributů tiskárny:

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

Rozšíření omezení tiskárny

Aplikace podpory tisku podporuje vlastní ověřování PrintTicket a definování výchozího printTicketu. Tato část popisuje, jak tyto funkce podporujeme.

Pro podporu omezení rozšíření tiskárny byl implementován nový typ úlohy na pozadí PrintSupportExtension. Package.appxmanifest má položku rozšiřitelnosti rozšíření podpory tisku, jak je znázorněno zde:

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

Tato služba může běžet v libovolném bodě tiskové úlohy pro přidruženou tiskárnu IPP. Jelikož je rozšíření podpory tisku aktivováno prostřednictvím funkce IBackgroundTaskInstance, je PrintSupportExtension předána instance IBackgroundTaskInstance, aby poskytla přístup k běhové třídě PrintSupportExtensionTriggerDetails, která interně poskytuje PrintSupportExtensionSession jako vlastnost. Třída pozadí PrintSupportExtension pak může použít objekt relace k registraci událostí, které chce poskytovat vlastní funkce.

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

    Pokud rozšíření podpory tisku poskytuje vlastní mechanismus ověřování PrintTicket, může se registrovat k této události. Kdykoli je potřeba ověřit PrintTicket, tiskový systém vyvolá tuto událost. PrintSupportExtension pak získá aktuální PrintTicket, který je třeba ověřit v rámci EventArgs. Třída PrintSupportExtension background pak může zkontrolovat validitu PrintTicket a upravit ji tak, aby vyřešila případné konflikty. Třída na pozadí PrintSupportExtension by pak měla nastavit výsledek pro validaci pomocí funkce SetPrintTicketResult, aby se určilo, zda byl PrintTicket vyřešen, má konflikty, nebo je neplatný. Tuto událost je možné vyvolat v kterémkoli okamžiku během životnosti tiskové úlohy. Pokud se třída PrintSupportExtension nezaregistruje pro tuto událost, tiskový systém uskuteční své samostatné ověření PrintTicket.

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

    Událost se vyvolá po té, co tiskový systém aktualizuje uložené PrintDeviceCapabilities přidružené IPP tiskárny. Při vyvolání této události může třída pozadí PrintSupportExtension zkontrolovat změněné PrintDeviceCapabilities a upravit je.

Vlastní ověření lístku tisku

Ukázkový kód v jazyce C# pro službu ověřování 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);
    }
}

Aktualizace tiskových schopností zařízení

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

Vylepšení kvality tisku

Jakmile uživatel potvrdí tisk stisknutím tlačítka tisku v dialogovém okně tisku, dokument, který se má vytisknout, se odešle do zásobníku tisku z aplikace, která tiskne. Tento dokument pak prochází transformací (vykreslováním do PDL), aby byl vhodný pro cílovou tiskárnu. Systém Windows určí, jakou transformaci zvolit na základě atributů dotazovaných z tiskárny. Transformovaný dokument se pak odešle do tiskárny. I když to funguje dobře u většiny tiskáren, existují případy, kdy je možné zlepšit kvalitu tisku tím, že partnerské aplikaci umožní účastnit se transformace. Pro usnadnění je aktuální rozhraní API pracovního postupu tisku rozšířeno tak, aby zahrnovalo volání aplikace v dalších bodech ze zásobníku tisku. Toto rozhraní API podporuje dvě nové události, ke kterým se aplikace PSA může zaregistrovat. Toto jsou jediné vstupní body na povrchu rozhraní PSA API:

  1. Spuštění práce

    • Tato událost je vyvolána při spuštění tiskové úlohy libovolnou aplikací. Při vyvolání události se může aplikace podpory tisku rozhodnout přeskočit systémové vykreslování tím, že zavolá SetSkipSystemRendering na PrintWorkflowJobStartingEventArgs. Pokud je vybráno přeskočení vykreslování systému, systém tisku nepřevedl dokument XPS na formát PDL vyžadovaný tiskárnou. Místo toho bude XPS vygenerované tiskovou aplikací předáno přímo PSA, které je pak zodpovědné za převod XPS do formátu PDL.
  2. PdlModificationRequested

    • Tato událost se vyvolá, když systém Windows spustí převod datového proudu XPS do formátu PDL označeného tiskárnou. Třída runtime PrintWorkflowPdlModificationRequestedEventArgs je k dispozici jako argument pro tuto událost. Tato třída událostí poskytuje zdrojové a cílové objekty PDL pro čtení a zápis obsahu tiskové úlohy. Pokud aplikace zjistí, že potřebuje uživatelský vstup, může spustit uživatelské rozhraní pomocí PrintWorkflowUILauncher z EventArgs. Toto rozhraní API používá vzor Tester-Doer. PrintWorkflowUILauncher nebude moct vyvolat uživatelské rozhraní, pokud funkce IsUILaunchEnabled vrátí hodnotu false. Tato funkce vrátí false, pokud je relace PSA spuštěná v tichém režimu (bezobslužný režim nebo kioskový režim). Aplikace podpory tisku by se neměla pokusit spustit uživatelské rozhraní, pokud funkce vrátí hodnotu false.

    OutputStream je k dispozici jako součást PrintWorkflowPdlTargetStream, která je vrácena funkcí GetStreamTargetAsync. Obsah napsaný do cílového výstupníhostreamu se předává tiskárně jako obsah dokumentu.

Sekvenční diagram události úpravy PDL:

sekvenční diagram události změny P D L zdrojového streamu

Aplikace PSA na popředí se spustí, když úloha PSA na pozadí vyžaduje spuštění uživatelského rozhraní. PSA může použít kontrakt popředí k získání uživatelského vstupu nebo k zobrazení náhledu tisku pro uživatele.

Byl definován nový typ úlohy na pozadí printSupportWorkflow. Package.appxmanifest má následující položku rozšiřitelnosti pro PrintSupportWorkflow kontrakt:

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

Při aktivaci kontraktu je PrintWorkflowJobTriggerDetails uveden jako IBackgroundTaskInstance->TriggerDetails. PrintWorkflowJobTriggerDetails interně poskytuje PrintWorkflowJobBackgroundSession jako jednu ze svých vlastností. Aplikace může použít PrintWorkflowJobBackgroundSession k registraci událostí souvisejících s různými body injektáže v pracovním postupu tiskové úlohy. Po dokončení registrace události musí aplikace volat PrintWorkflowJobBackgroundSession::Start, aby tiskový systém začal spouštět události související s různými vstřikovacími body.

Je definován nový ActivationKind s názvem PrintSupportJobUI. To nevyžaduje novou funkci.

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

Jedná se o smlouvu uživatelského rozhraní, kterou lze spustit buď z kontraktu na pozadí pracovního postupu podpory tisku, nebo když uživatel zvolí upozornění na chybu tiskové úlohy. Při aktivaci je k dispozici PrintWorkflowJobActivatedEventArgs, který má objekt PrintWorkflowJobUISession. Pomocí PrintWorkflowJobUISessionby se aplikace na popředí měla zaregistrovat pro událost PdlDataAvailable, pokud chce získat přístup k PDL datům. Pokud by aplikace na popředí chtěla zobrazit přizpůsobené chybové zprávy pro všechny chyby, ke kterým může dojít během úlohy, měla by se zaregistrovat k události JobNotification. Po registraci událostí by aplikace měla volat funkci PrintWorkflowJobUISession::Start, aby systém tisku začal spouštět události.

Přeskočení vykreslování systému

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

Událost změny PDL

Sekvenční diagram události úpravy PDL:

sekvenční diagram pro událost úpravy vstupního streamu P D L

Ukázkový kód jazyka C# pro Monitor tiskových úloh podpory, který čte a zapisuje obsah tiskové úlohy:

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

Spuštění uživatelského rozhraní z pozadí pracovního postupu

Ukázkový kód jazyka C# pro spuštění uživatelského rozhraní úlohy tiskové podpory na základě kontraktu události, při které je požadována úprava 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();
    }
}

Aktivace rozhraní úlohy workflow pro událost PDLDataAvailable

Sekvenční diagram pro aktivaci uživatelského rozhraní tiskové úlohy při události PdlDataAvailable:

sekvenční diagram pro aktivaci tiskové úlohy U I při události dostupnosti dat P D L

Ukázkový kód jazyka C# pro kontrakt aktivace uživatelského rozhraní úlohy 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);
            }
        }
    }
}

Získání atributů tiskové úlohy

Ukázkový kód jazyka C#pro získání atributů úlohy pro tiskovou úlohu:

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

Nastavení atributů úlohy tiskárny

Vzorový kód C#, navazující na část Získání atributů úlohy tiskárny výše, ukazuje nastavení atributů úlohy:

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

Po vytvoření úlohy některé tiskárny IPP nepodporují získávání nebo nastavování atributů. U těchto tiskáren má PrintJob vlastnost JobId nastavenou na 0 a GetJobAttributesSetJobAttributes selže okamžitě s výjimkou.

Poskytnutí přístupu k souborům úložiště pro obsah PDL

Některé formáty PDL, jako je PDF, potřebují kompletní datový proud, aby bylo možné začít zpracovávat. Z tohoto důvodu je k dispozici nová metoda s názvem GetContentFileAsync na PrintWorkflowPdlSourceContent třídy, která vrací StorageFile zdrojového obsahu.

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

Převod PDL XPS na PDF

Vzorový kód jazyka C# zobrazující převod PDL XPS do 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();
}

Oznámení o události práce

Sekvenční diagram události oznámení úlohy:

sekvenční diagram události oznámení úlohy

Ukázka kódu v jazyce C#, která pokračuje z aktivace uživatelského rozhraní úlohy ve workflow z části události PDLDataAvailable uvedené výše, aby se zobrazila chyba v notifikaci úlohy.

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

Vytvoření úlohy s počátečními atributy úlohy

Některé tiskárny IPP v současné době nepodporují operaci set-attribute. Funkce CreateJobOnPrinterWithAttributes a CreateJobOnPrinterWithAttributesBuffer na PrintWorkflowPdlDataAvailableEventArgs jsou k dispozici pro zmírnění tohoto problému. Pomocí těchto rozhraní API může vývojář PSA poskytnout atributy úloh, které se předávají tiskárně při vytváření úlohy na tiskárně.

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

Sekvenční zpracování XPS

Vzorový kód C++/Winrt pro zpracování XPS postupně před dokončením tisku.

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

Lokalizace zobrazovaného názvu a integrace PDL passthrough API

Důležitý

Tato část popisuje funkce PSA dostupné od Windows 11 verze 22H2.

V tomto scénáři PSA upravuje funkce tiskového zařízení (PDC) a poskytuje prostředky tiskového zařízení (PDR) pro lokalizaci řetězců.

PSA také stanovuje podporované typy obsahu rozhraní API pro přenos PDL (formáty PDL). Pokud se PSA k události nepřihlásí nebo nevolá SetSupportedPdlPassthroughContentTypes explicitně, pro tiskárny přidružené k této aplikaci PSA je passthrough PDL zakázaný.

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

Podpora funkcí na úrovni stránky a atributy operací

Důležitý

Tato část popisuje funkce PSA dostupné od Windows 11 verze 22H2.

Scénáře podpory funkcí na úrovni stránky a atributů operací jsou seskupené, protože jsou vyřešené provedením změn na stejném místě v ukázkovém kódu.

  • podpora funkce na úrovni stránky: V tomto scénáři aplikace PSA určuje atribut na úrovni stránky, který by neměl být přepsán atributem IPP parsovaným z PrintTicketu.

  • Samostatná kolekce pro podporu atributů operací (tisk PIN): V tomto scénáři aplikace PSA určuje vlastní atributy operace IPP (například PIN).

Následující ukázkový kód jazyka C# ukazuje požadované změny pro podporu funkcí na úrovni stránky a samostatnou kolekci atributů operací ve scénářích.

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

Vylepšení dialogového okna tisku pomocí PSA

Důležitý

Tato část popisuje funkce PSA dostupné od Windows 11 verze 22H2.

V tomto scénáři umožňuje použití dialogového okna tisku s integrací PSA následující akce:

  • Získejte zpětné volání při změně výběru v MPD na tiskárnu propojenou s PSA

  • Zobrazení jedné adaptivní karty s podporou akce openUrl

  • Zobrazení vlastních funkcí a parametrů v dialogovém okně tisk

  • Upravte printTicket, čímž změníte výběr možností funkcí zobrazených v dialogovém okně tisku.

  • Získejte Windows.ApplicationModel.AppInfo související s tiskovou aplikací otevřením dialogového okna tisku.

Následující ukázka jazyka C# znázorňuje tato vylepšení dialogového okna tisku:

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

Převod PDL s příznaky zpracování založenými na hostiteli

Důležitý

Tato část popisuje funkce PSA dostupné od Windows 11 verze 22H2.

Aktuální rozhraní API pro převod PDL PrintWorkflowPdlConverter.ConvertPdlAsyncve výchozím nastavení provádí zpracování na straně hostitele. To znamená, že hostitelský/tiskový počítač provádí rotaci, pořadí stránek atd., aby tiskárna nemusela tyto operace provádět. IHV tiskárny však mohou chtít převod PDL bez využití hostitele, protože jejich tiskárna to dokáže lépe. Funkce ConvertPdlAsync používá příznaky zpracování založené na hostiteli k řešení tohoto požadavku. Pomocí tohoto příznaku může PSA přeskočit veškeré zpracování založené na hostiteli nebo konkrétní operaci tohoto zpracování.

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
}

Nastavení zásad aktualizace funkcí tiskových zařízení (PDC)

Důležitý

Tato část popisuje funkce PSA dostupné od Windows 11 verze 22H2.

IHV tiskárny můžou mít různé požadavky, když je potřeba aktualizovat možnosti tiskového zařízení (PDC). Aby bylo možné splnit tyto požadavky, PrintSupportPrintDeviceCapabilitiesUpdatePolicy může nastavit zásady aktualizace pro funkce tisku. PSA může nastavit zásady pro aktualizaci PDC na základě času nebo počtu tiskových úloh pomocí tohoto rozhraní API.

Nastavení aktualizační zásady primárního řadiče domény (PDC) podle počtu úloh

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

Nastavení zásad aktualizace primárního řadiče domény na základě časového limitu

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

Obecné pokyny k návrhu aplikace podpory tisku (PSA)

Při navrhování aplikace podpory tisku je důležité zahrnout do návrhu tyto aspekty:

  • Kontrakty na popředí i na pozadí by měly být označeny jako podporující více instancí; například SupportsMultipleInstance by měly být přítomné v manifestu balíčku. To zajistí, aby životnost kontraktů byla spolehlivě spravována pro více souběžných úloh.

  • Zacházejte se spuštěním uživatelského rozhraní pro úpravy PDL jako s volitelným krokem. Snažte se dokončit tiskovou úlohu úspěšně i v případě, že spuštění uživatelského rozhraní nebylo povoleno. Tiskové úlohy by měly být přerušeny pouze v případě, že neexistuje způsob, jak je úspěšně dokončit bez vstupu uživatele během úprav PDL. Zvažte odeslání nemodifikovaného PDL v takových případech.

  • Při spouštění uživatelského rozhraní pro úpravu PDL nejprve zavolejte IsUILaunchEnabled, poté zavolejte LaunchAndCompleteUIAsync. Tím zajistíte, že scénáře, které nemůžou zobrazovat uživatelské rozhraní v aktuálním čase, budou nadále správně tisknout. Tyto scénáře můžou být na zařízení bez hlavy nebo na zařízení, které aktuálně je v režimu kiosku nebo v režimu nerušit.

Ukončení plánu údržby pro ovladače tiskáren třetích stran ve Windows

specifikace protokolu IPP (Internet Printing Protocol)

Asociace aplikace pro podporu tisku

Windows.Devices.Printers

Windows.Graphics.Printing.PrintSupport

Windows.Graphics.Printing.Workflow