Nyomtatási támogatási alkalmazás v1 és v2 tervezési útmutatója

Ez a cikk útmutatást és példákat nyújt a nyomtató oem-jeihez és IHV-jeihez egy nyomtatástámogatási alkalmazás (PSA) fejlesztéséhez, amely többféleképpen is javíthatja a Windows-felhasználók nyomtatási élményét.

A Windows 11 SDK (22000.1) kiadásától kezdve a Nyomtatótámogatási alkalmazások (PSA) a nyomtatókhoz készült UWP-alkalmazások fejlesztésének ajánlott módja. Nyomtatástámogatási alkalmazás nyomtatóeszközhöz való fejlesztéséhez töltse le és telepítse a Windows 11 SDK-t a megcélzott Windows-verzióhoz.

Ez a cikk olyan szakaszokat tartalmaz, amelyek a Windows 11 22H2-es verziójában elérhető PSA-funkciókat ismertetik. Ezek a szakaszok tartalmaznak egy megjegyzést, amely jelzi, hogy az adott verzióra vonatkozik.

További információkért lásd a következő cikkeket:

Téma Leírás
Print Support App v3 API tervezési útmutatója Útmutatást és példákat nyújt azokhoz a nyomtató-oemekhez és IHV-khez, amelyek egy v3-ás nyomtatótámogatási alkalmazást (PSA) implementálnak az eszközükhöz.
Print Support App v4 API tervezési útmutatója Útmutatást és példákat kínál azokhoz a nyomtató-oemekhez és IHV-khez, amelyek v4-alapú nyomtatótámogatási alkalmazást (PSA) implementálnak az eszközükhöz.
MSIX nyomtatástámogatási virtuális nyomtató manifeszt specifikációja MSIX-jegyzékbeli útmutatást és példákat biztosít a nyomtató oem-jeihez és a nyomtatótámogatási virtuális nyomtatót implementáló IHV-khez.
Nyomtatási támogató alkalmazás társítása Útmutatást és példákat kínál a nyomtatótámogatási alkalmazás (PSA) nyomtatóval való társításához.

Egyes nyomtatófunkciók nem jelennek meg a Windows által megjelenített nyomtatási párbeszédpaneleken, mivel ezek olyan speciális funkciók, amelyekhez egy gyártói alkalmazás segítségére van szükség a megfelelő konfiguráláshoz. Lehetnek olyan funkciók is, amelyek nem érhetők el a nyomtató alapértelmezett képességeiben.

A nyomtatóspecifikus funkciók csoportosíthatók oly módon, hogy a felhasználó egyszerűen válasszon egy lehetőséget, és bízik abban, hogy az adott forgatókönyvben részt vevő összes funkció automatikusan a megfelelő értékekre van állítva. Ilyen lehet például a tintakímélő, a papírkímélő és a legjobb minőségű mód, amely a felhasználó egyetlen választása alapján automatikusan módosíthatja a különböző nyomtatási funkciókat. A Windows nem tudja automatikusan csoportosítani őket, mivel ehhez minden nyomtatómodell egyéni funkcióinak megértése szükséges.

Az egyéni nyomtatási beállítások megjelenítésének szükségességét ez az API egy opcionális UWP-bővítményszerződéssel kezeli, amelyet a felhasználó aktiválhat a Windows által biztosított API-t használó összes windowsos nyomtatási párbeszédpanelen és egyéni nyomtatási párbeszédpanelen. A gyártók úgy alakíthatják felhasználói felületüket, hogy a felhasználó által birtokolt nyomtatóhoz a legjobb nyomtatási élményt nyújtsák.

Egy másik terület, ahol a nyomtatógyártók javíthatják és megkülönböztethetik a nyomtatási minőséget. A gyártók a renderelés után javíthatják a nyomtatási minőséget az adott nyomtató tartalmának optimalizálásával. Emellett olyan nagy megbízhatóságú előnézetet is megjeleníthetnek, amely jobban megfelel a végső kimenetnek, mivel figyelembe veheti a nyomtatóspecifikus funkciókat.

nyomtatási támogatási alkalmazás nyomtatási idővonala

Terminológia

Kifejezés Definíció
PSA Nyomtassa ki a támogatási alkalmazást. A cikkben ismertetett API-t használó UWP-alkalmazás.
MPD Modern nyomtatási párbeszédablak. Ez akkor jelenik meg a felhasználó számára, ha egy alkalmazás a Windows.Graphics.Printing API használatával nyomtat.
Folyamatos Szakmai Fejlődés Szokásos nyomtatási párbeszédablak. Ez akkor jelenik meg a felhasználó számára, ha az alkalmazás a Win32 API használatával nyomtat. A nyomtatási kép megjelenítéséhez szükséges alkalmazások nem aktiválják ezt a párbeszédpanelt, és maguk implementálják a párbeszédpanel egy verzióját. Erre kiváló példa az Office-alkalmazások.
IPP (Internetes Nyomtatási Protokoll) Internet Printing Protocol. Az ügyféleszközről a nyomtatóval való interakcióra szolgál a nyomtatási beállítások lekéréséhez és beállításához, valamint a nyomtatandó dokumentum elküldéséhez.
Nyomtatótámogatáshoz társított nyomtató PSA-hoz társított nyomtató.
IPP-nyomtató Az IPP protokollt támogató nyomtató.
További beállítások A partner által biztosított alkalmazás felhasználói felületét megnyitó hivatkozás az MPD-ben. A beépített nyomtatási beállítások felhasználói felületének megnyitása alapértelmezés szerint, ha nincs telepítve a PSA.
Nyomtatóbeállítások felhasználói felülete A nyomtatáskor alkalmazott alapértelmezett nyomtatóbeállítások beállításához használt párbeszédpanel. Például: tájolás, papírméret, szín, nyomtatás mindkét oldalon, és így tovább.
PDL Oldal leírásának nyelve. Az a formátum, amelyben a dokumentumot elküldi a nyomtatónak.
Társított PSA-nyomtató PSA-alkalmazáshoz társított fizikai IPP-nyomtató.
Nyomtatóeszköz Funkcionalitások XML-dokumentumformátum a nyomtató képességeinek meghatározásához. További információkért lásd: Nyomtatási jegy és nyomtatási képességek technológiái.
PrintTicket A különböző nyomtatással kapcsolatos funkciók és azok értékeinek gyűjteménye, amelyek a felhasználó adott nyomtatási feladathoz való szándékának rögzítésére szolgálnak.
Nyomtatástámogatási Kiterjesztés PSA háttérfeladat, amely a nyomtatók korlátozásainak kiterjesztéséhez szükséges képességek biztosításáért felelős.

Ezek a minták egy printsupport névtérre hivatkoznak, amely a következőképpen van definiálva:

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

Amikor egy felhasználó éppen nyomtatni készül egy dokumentumot, gyakran meg szeretne adni bizonyos beállításokat a nyomtatáshoz. Választhatják például, hogy egy dokumentumot fekvő tájolásban nyomtatnak. A nyomtató által támogatott egyéni funkciókat is kihasználhatják. A Windows alapértelmezett felhasználói felületet biztosít az egyéni beállítások megjelenítéséhez, de előfordulhat, hogy a felhasználó nem érti őket, mivel nincsenek megfelelő ikonok vagy leírások. Előfordulhat, hogy a Windows nem a megfelelő felhasználói felületi vezérlőt használja a bemutatóhoz. Az ilyen egyéni funkciókat legjobban egy olyan alkalmazás mutatja be, amely teljesen megérti a funkciót. Ez az a motiváció, amely egy OLYAN API-t kínál, amely lehetővé teszi a nyomtatógyártók számára, hogy az általuk létrehozott különböző nyomtatómodellek alapján hozzanak létre alkalmazásokat.

Új UAP-bővítményszerződés jön létre a windows.printSupportSettingsUI nevű új kategóriával. Az ezzel a szerződéssel aktivált alkalmazások egy új, PrintSupportSettingsUI nevű ActivationKindet kapnak. Ez a szerződés nem igényel új képességet.

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

Ez a szerződés akkor lesz meghívva, ha a felhasználó kiválasztja További beállítások MPD-ben vagy Beállítások a CPD-ben. Ez a szerződés a Beállítások alkalmazás Nyomtatási beállítások is meghívható. A szerződés aktiválása után az alkalmazás kap egy PrintSupportSettingsUISession objektumot, amely az aktuális PrintTicket és PrintDevice objektum lekérésére használható. A PrintDevice objektum használható a nyomtatóval való kommunikációhoz nyomtató- és feladatattribútumok fogadásához. Az alkalmazás ezután megjelenítheti a felhasználói felületet a nyomtató megfelelő beállításaival a felhasználó számára. Amikor a felhasználó kiválasztja a döntéseket, és kiválasztja OK, az alkalmazás módosíthatja a nyomtatási jegyet, érvényesítheti, majd visszaküldheti PrintSupportPrintTicketTarget objektum használatával. Ha a felhasználó úgy dönt, hogy megszakítja a beállítások ablakát, a módosításokat el kell vetni, és az alkalmazásnak ki kell lépnie a PrintSupportSettingsUISession objektumból vett halasztás végrehajtásával.

A nyomtatótámogatási alkalmazásnak várhatóan több egyidejű aktiválást kell kezelnie a különböző nyomtatási feladatokhoz, ezért egy ilyen alkalmazásnak több példányt kell támogatnia a package.appxmanifest fájl SupportsMultipleInstances elemével. Ennek elmulasztása olyan helyzetekhez vezethet, amikor egy nyomtatási feladat beállításainak megerősítése bezárhat más, esetleg megnyitott beállítások ablakait. A felhasználónak újra meg kell nyitnia ezeket a beállítások ablakait.

A következő szekvenciadiagram a Beállítások felhasználói felület nyomtatási jegykezelésének fogalmát mutatja be:

a beállítások sorrendi diagramja U I nyomtatási jegy kezelése

A PrintTicket módosítása a beállítások felhasználói felületén

C# mintakód a Beállítások felhasználói felület aktiválásához bármely nyomtatási párbeszédpanelről (MPD/CPD vagy egyéni nyomtatási párbeszédpanel) vagy a rendszerbeállításokból:

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 DefaultSettingsView osztályhoz:

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

C# mintakód a felhasználói felület megjelenítéséhez és a PrintTicket módosításához:

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

Nyomtatóattribútumok lekérése a nyomtatóeszközről

WireShark-válasz egy IPP-nyomtatóról egy get-printer-attributes lekérdezésre:

wireshark válasz egy I P P nyomtatótól a nyomtatóattribútumok lekérdezésére

C# mintakód a tintanevek és a tintaszintek nyomtatóról való lekéréséhez:

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

Nyomtatóattribútumok beállítása a nyomtatón

C# mintakód nyomtatóattribútumok beállításához:

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

Nyomtatókorlátozások kiterjesztése

A nyomtatástámogatási alkalmazás támogatja az egyéni PrintTicket-ellenőrzést, és meghatározza az alapértelmezett PrintTicket-et. Ez a szakasz ismerteti, hogyan támogatjuk ezeket a funkciókat.

A nyomtatóbővítményekre vonatkozó korlátozások támogatásához egy új háttérfeladat-típus, a PrintSupportExtension lett implementálva. A Package.appxmanifest bővíthetőségi bejegyzéssel rendelkezik a Nyomtatási támogatás bővítményhez az itt látható módon:

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

Ez a szolgáltatás a társított IPP-nyomtató nyomtatási feladatának bármely pontján futtatható. Mivel a Nyomtatási támogatás bővítmény az IBackgroundTaskInstancefüggvényen keresztül aktiválódik, az IBackgroundTaskInstance egy példányát a PrintSupportExtension kapja, hogy hozzáférést biztosítson a PrintSupportExtensionTriggerDetails futtatókörnyezeti osztályhoz, amely belsőleg biztosítja a PrintSupportExtensionSession tulajdonságot. A PrintSupportExtension háttérosztály ezután a munkamenet-objektummal regisztrálhat azokra az eseményekre, amelyekhez egyéni funkciókat kíván nyújtani.

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

    Ha a Nyomtatási támogatás bővítmény saját PrintTicket érvényesítési mechanizmust biztosít, regisztrálhat az eseményre. Amikor egy PrintTicket ellenőrizni szükséges, a nyomtatási rendszer kezdeményezi ezt az eseményt. PrintSupportExtension ekkor lekéri az aktuális PrintTicket-t, amelyet az EventArgsben érvényesíteni kell. A PrintSupportExtension háttérosztály ezután ellenőrizheti a PrintTicket érvényességét, és módosíthatja az ütközések feloldásához. A PrintSupportExtension háttérosztálynak ezután a SetPrintTicketResult függvénnyel kell beállítania az ellenőrzés eredményét annak jelzésére, hogy a PrintTicket fel lett-e oldva, vannak-e konfliktusok, vagy érvénytelen-e. Ez az esemény bármikor előhozható egy nyomtatási feladat élettartama alatt. Ha a PrintSupportExtension osztály nem regisztrál erre az eseményre, a nyomtatórendszer elvégzi a PrintTicket saját ellenőrzését.

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

    Az esemény azután következik be, hogy a nyomtatórendszer frissíti az adott IPP-nyomtatóhoz tartozó gyorsítótárazott PrintDeviceCapabilities-t. Az esemény felmerülésekor a PrintSupportExtension háttérosztály megvizsgálhatja a módosított PrintDeviceCapabilities és módosíthatja azt.

Nyomtatási jegy egyéni érvényesítése

C# mintakód PrintTicket érvényesítési szolgáltatás biztosításához:

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

A PrintDeviceCapabilities frissítése

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

A nyomtatási minőség javítása

Miután a felhasználó a nyomtatási párbeszédpanel nyomtatási gombjának lenyomásával véglegesítette a nyomtatást, a nyomtatni kívánt dokumentumot a nyomtatandó alkalmazásból küldi el a nyomtatási verembe. Ez a dokumentum ezután átalakításon megy keresztül (PDL-vé alakítva), hogy alkalmassá tegye a célnyomtató számára. A Windows a nyomtatóról lekérdezett attribútumok alapján határozza meg, hogy milyen átalakítást válasszon. Ezután a rendszer elküldi az átalakított dokumentumot a nyomtatónak. Bár ez a legtöbb nyomtató esetében jól működik, vannak olyan esetek, amikor a nyomtatás minősége javítható azáltal, hogy lehetővé teszi egy partneralkalmazás számára, hogy részt vegyen az átalakításban. Ennek megkönnyítése érdekében az aktuális nyomtatási munkafolyamat API-t kiterjesztettük, hogy az a nyomtatási folyamat további pontjain az alkalmazáshoz is hívásokat intézzen. Ez az API két új eseményt támogat, amelyekre a PSA-alkalmazás regisztrálhat. Ezek az egyetlen belépési pontok a PSA API felületére:

  1. Munkaindítás

    • Ez az esemény akkor jön létre, ha egy nyomtatási feladatot bármely alkalmazás elindít. Az esemény bekövetkezésekor a Nyomtatási Támogató Alkalmazás dönthet úgy, hogy kihagyja a rendszer szerinti megjelenítést, ha meghívja a SetSkipSystemRendering a PrintWorkflowJobStartingEventArgs. Ha kihagyja a rendszermegjelenítést, a nyomtatási rendszer nem konvertálja az XPS-dokumentumot a nyomtató által igényelt PDL formátumba. Ehelyett a nyomtatóalkalmazás által létrehozott XPS közvetlenül a PSA-nak lesz átadva, amely az XPS PDL formátummá alakításáért felelős.
  2. PdlMódosításKérve

    • Ez az esemény akkor jelentkezik, amikor a Windows elindítja az XPS-stream konvertálását a nyomtató által megadott PDL-formátumra. A Runtime osztály PrintWorkflowPdlModificationRequestedEventArgs argumentumként van megadva az eseményhez. Ez az eseményosztály PDL-forrás- és célobjektumokat biztosít a nyomtatási feladat tartalmának olvasásához és írásához. Ha az alkalmazás megállapítja, hogy felhasználói bemenetre van szüksége, elindíthatja a felhasználói felületet PrintWorkflowUILauncher, az EventArgsből. Ez az API a Tester-Doer mintát használja. A PrintWorkflowUILauncher nem tudja meghívni a felhasználói felületet, ha a függvény IsUILaunchEnabled hamis értéket ad vissza. Ez a függvény hamis értéket ad vissza, ha a PSA-munkamenet csendes módban (fej nélküli vagy kioszk módban) fut. Ha a függvény hamis eredményt ad vissza, a nyomtatási támogatási alkalmazás nem próbálja meg elindítani a felhasználói felületet.

    A OutputStream PrintWorkflowPdlTargetStream részeként érhető el, amelyet a GetStreamTargetAsyncfüggvény ad vissza. A cél outputstreambe írt tartalmat a rendszer dokumentumtartalomként továbbítja a nyomtatónak.

A PDL-módosítási esemény szekvenciadiagramja:

a forrásstream P D L módosítási eseményének szekvenciadiagramja

A PSA előtéralkalmazás akkor indul el, amikor a PSA háttérfeladata a felhasználói felület elindítását kéri. A PSA az előtérszerződés használatával lekérheti a felhasználói bemenetet, és/vagy megjeleníthet egy nyomtatási előnézetet a felhasználó számára.

Definiált egy új printSupportWorkflow háttérfeladattípust. A Package.appxmanifest a következő kiterjesztési bejegyzéssel rendelkezik a PrintSupportWorkflow kontraktushoz:

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

A szerződés aktiválásakor a PrintWorkflowJobTriggerDetails a IBackgroundTaskInstance>TriggerDetailsadattal adódik meg. A PrintWorkflowJobTriggerDetails belsőleg biztosítja a PrintWorkflowJobBackgroundSession-ot a tulajdonságai részeként. Az alkalmazás PrintWorkflowJobBackgroundSession használatával regisztrálhat a nyomtatási feladat munkafolyamatának különböző injektálási pontjaihoz kapcsolódó eseményekre. Az eseményregisztráció befejezése után az alkalmazásnak meg kell hívnia PrintWorkflowJobBackgroundSession::Start a nyomtatórendszer számára, hogy elindítsa a különböző injektálási pontokhoz kapcsolódó eseményeket.

Egy új nevezték meg ActivationKind, amit PrintSupportJobUI néven határoztak meg. Ehhez nincs szükség új képességre.

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

Ez egy felhasználói felületi szerződés, amely elindítható a nyomtatási támogatási munkafolyamat háttérszerződéséből, vagy ha a felhasználó kiválaszt egy nyomtatási feladattal kapcsolatos hiba bejelentést. Aktiváláskor a PrintWorkflowJobActivatedEventArgs kerül biztosításra, amely egy PrintWorkflowJobUISession objektumot tartalmaz. A PrintWorkflowJobUISessionhasználatával az előtéralkalmazásnak regisztrálnia kell az PdlDataAvailable eseményre, ha hozzá szeretne férni a PDL-adatokhoz. Ha az előtéralkalmazás egyéni hibaüzeneteket szeretne megjeleníteni a feladat során esetlegesen előforduló hibákról, regisztrálnia kell a JobNotification eseményre. Az események regisztrálása után az alkalmazásnak meghívnia kell a PrintWorkflowJobUISession::Start függvényt annak érdekében, hogy a nyomtatási rendszer elindítsa az eseményeket.

Rendszermegjelenítés kihagyása

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

PDL-módosítási esemény

A PDL-módosítási esemény szekvenciadiagramja:

a bemeneti stream P D L módosítási eseményének szekvenciadiagramja

C# mintakód a nyomtatási támogatás feladatfigyelője nyomtatási feladat tartalmának olvasásához és írásához:

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

Felhasználói felület indítása a munkafolyamat hátteréből

C# mintakód a nyomtatási támogatási feladat felhasználói felületének psa PDL-módosítással kért eseményszerződésből való elindításához:

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

Munkafolyamat-feladat felhasználói felületének aktiválása PDLDataAvailable eseményhez

Folyamatábra a nyomtatási feladat felhasználói felületének aktiválásához a PdlDataAvailable eseményhez:

A nyomtatási feladat U I aktiválásának folyamatábraja a P D L-adatok rendelkezésre álló eseményéhez

C# mintakód a PSA-feladat felhasználói felületének aktiválási szerződéséhez:

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

Nyomtatófeladat-attribútumok lekérése

C# mintakód egy nyomtatási feladat feladatattribútumainak lekéréséhez:

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

Nyomtatófeladat-attribútumok beállítása

C# mintakód, a fenti Nyomtatófeladat-attribútumok lekérése szakaszból folytatva, a feladatattribútumok beállításának bemutatásával:

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

Egyes IPP-nyomtatók nem támogatják a feladatattribútumok lekérését/beállítását a feladat létrehozása után. Ezen nyomtatók esetében PrintJobJobId tulajdonsága "0" értékre van állítva, és GetJobAttributes/SetJobAttributes kivétellel azonnal sikertelen lesz.

Tárolófájl-hozzáférés biztosítása a PDL-tartalomhoz

Egyes PDL-formátumokhoz, például a PDF-hez, teljes adatfolyamra van szükség a feldolgozás megkezdéséhez. Ezért a GetContentFileAsync nevű új metódus a PrintWorkflowPdlSourceContent osztályban található, amely a forrástartalom StorageFile ad vissza.

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

XPS PDL-konvertálása PDF-fájlra

C# mintakód, amely az XPS PDF-fájllá alakítását mutatja be:

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

Feladatértesítési esemény

Feladatértesítési esemény szekvenciadiagramja:

a feladatértesítési esemény sorszámdiagramja

C#-mintakód, amely az fenti PDLDataAvailable eseményszakasz munkafolyamat-feladat felhasználói felületének aktiválása után a feladatértesítés hibájának megjelenítését mutatja be:

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

Feladat létrehozása kezdeti feladatattribútumokkal

Egyes IPP-nyomtatók jelenleg nem támogatják a set-attribute műveletet. A probléma megoldásához a CreateJobOnPrinterWithAttributes függvény és a CreateJobOnPrinterWithAttributesBuffer függvény biztosítva van a PrintWorkflowPdlDataAvailableEventArgs-en. Ezen API-k használatával a PSA-fejlesztő olyan feladatattribútumokat biztosíthat, amelyeket a nyomtatón végzett feladat létrehozásakor a rendszer átad a nyomtatónak.

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

Szekvenciális XPS-feldolgozás

C++/Winrt mintakód az XPS sorrendben történő feldolgozásához a nyomtatás befejezése előtt.

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

Megjelenítendő név honosítása és PDL passthrough API-integráció

Fontos

Ez a szakasz a Windows 11 22H2-es verziójától kezdve elérhető PSA-funkciókat ismerteti.

Ebben a forgatókönyvben a PSA testre szabja a Nyomtató Eszköz Képességeket (PDC), és biztosítja a Nyomtató Eszköz Erőforrásokat (PDR) a karakterláncok lokalizálásához.

A PSA a támogatott PDL átengedési API-tartalomtípusokat (PDL-formátumokat) is beállítja. Ha a PSA nem iratkozott fel az eseményre, vagy nem hívja meg SetSupportedPdlPassthroughContentTypes explicit módon, a PSA-alkalmazáshoz társított nyomtatók esetében a PDL-átengedés le van tiltva.

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

Lapszintű szolgáltatástámogatási és műveleti attribútumok

Fontos

Ez a szakasz a Windows 11 22H2-es verziójától kezdve elérhető PSA-funkciókat ismerteti.

Az oldalszintű funkciók támogatási és műveleti attribútumai azért vannak csoportosítva, mert a mintakódban ugyanazon a helyen végzett módosításokkal foglalkoznak.

  • Lapszintű funkció támogatása: Ebben a forgatókönyvben a PSA-alkalmazás megadja az oldalszintű attribútumot, amelyet nem szabad felülírni a PrintTicketből elemezett IPP-attribútummal.

  • Különálló gyűjtemény a műveletattribútumok támogatásához (PIN-nyomtatás): Ebben az esetben a PSA-alkalmazás egyéni IPP-műveleti attribútumokat (például PIN-kódot) határoz meg.

Az alábbi C# mintakód a lapszintű funkció támogatásához, valamint a műveleti attribútumok külön gyűjteményéhez szükséges módosításokat mutatja be a és a forgatókönyvekhez.

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

A nyomtatási párbeszédpanel továbbfejlesztése a PSA-val

Fontos

Ez a szakasz a Windows 11 22H2-es verziójától kezdve elérhető PSA-funkciókat ismerteti.

Ebben a forgatókönyvben a PSA-integrációval rendelkező nyomtatási párbeszédpanel használata a következő műveleteket teszi lehetővé:

  • Kapjon visszahívást, amikor az MPD-ben a kijelölés a PSA-hoz társított nyomtatóra módosul.

  • Egy AdaptiveCard megjelenítése egy openUrl művelet támogatásával

  • Egyéni funkciók és paraméterek megjelenítése a nyomtatási párbeszédpanelen

  • Módosítsa a PrintTicketet, és ezzel módosítsa a nyomtatási párbeszédpanelen megjelenő funkcióbeállítások kiválasztását

  • Kérje le a Windows.ApplicationModel.AppInfo a nyomtatási párbeszédpanel megnyitásával

A következő C#-minta az alábbi nyomtatási párbeszédpanel-fejlesztéseket szemlélteti:

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

PDL-átalakítás házigépalapú feldolgozási flagekkel

Fontos

Ez a szakasz a Windows 11 22H2-es verziójától kezdve elérhető PSA-funkciókat ismerteti.

Az aktuális PDL konverziós API, PrintWorkflowPdlConverter.ConvertPdlAsync, alapértelmezés szerint gazdagépalapú feldolgozást hajt végre. Ez azt jelenti, hogy a gazdagép/nyomtatási számítógép elvégzi a forgatást, az oldalsorrendet, stb., hogy a nyomtatónak ne kelljen elvégeznie ezeket a műveleteket. Előfordulhat azonban, hogy a nyomtató IHV-k gazdagépalapú feldolgozás nélkül szeretnének PDL-átalakítást végezni, mivel a nyomtatójuk ezt jobban tudja elvégezni. A ConvertPdlAsync függvény gazdagépalapú feldolgozási jelzőket használ a követelmény kezeléséhez. A PSA ezzel a jelzővel kihagyhatja az összes host alapú feldolgozást vagy egy adott host alapú feldolgozási műveletet.

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
}

Nyomtatási eszköz képességeinek (PDC) frissítési szabályzatának beállítása

Fontos

Ez a szakasz a Windows 11 22H2-es verziójától kezdve elérhető PSA-funkciókat ismerteti.

A nyomtató IHV-jeinek eltérő követelményei lehetnek a nyomtatóeszköz képességeinek (PDC) frissítésére. A követelmények teljesítéséhez PrintSupportPrintDeviceCapabilitiesUpdatePolicy beállíthat egy frissítési szabályzatot a PDC-hez. A PSA beállíthatja az PDC frissítési szabályzatát az idő vagy az API használatával végzett nyomtatási feladatok száma alapján.

A PDC frissítési szabályzatának beállítása a feladatok száma alapján

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

PDC-frissítési szabályzat beállítása TimeOut-időkorlát alapján

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

Általános nyomtatási támogatási alkalmazás (PSA) tervezési útmutatója

Nyomtatástámogatási alkalmazás tervezésekor fontos, hogy ezeket a szempontokat is belefoglalja a tervezésbe:

  • Az előtér- és háttérszerződéseket egyaránt úgy kell megjelölni, mint amelyek több példányt támogatnak; például a SupportsMultipleInstance jelen kell lennie a csomagjegyzékben. Ez biztosítja, hogy a szerződések élettartama megbízhatóan kezelhető legyen több egyidejű feladat esetében.

  • A PDL-módosításhoz szükséges felhasználói felület indítása nem kötelező lépés. A nyomtatási feladat sikeres végrehajtásához akkor is érdemes mindent megtesz, ha a felhasználói felület elindítása nem engedélyezett. A nyomtatási feladatokat csak akkor szabad megszakítani, ha a PDL módosítása során felhasználói bevitel nélkül nem lehet sikeresen végrehajtani őket. Ilyen esetekben fontolja meg, hogy a PDL-t módosítás nélkül küldje el.

  • A felhasználói felület PDL-módosításhoz való indításakor hívja meg IsUILaunchEnabled, mielőtt meghívja LaunchAndCompleteUIAsync. Ennek célja annak biztosítása, hogy azok a forgatókönyvek, amelyek jelenleg nem tudják megjeleníteni a felhasználói felületet, továbbra is megfelelően legyenek nyomtatva. Ezek a forgatókönyvek lehetnek olyan eszközön, amely jelenleg kioszk módban vagy "ne zavarjanak" módban van, esetleg egy kijelző nélküli eszközön.

Külső nyomtatóillesztők karbantartási tervének megszűnése Windows

Internet Printing Protocol (IPP) specifikációja

Nyomtatási támogató alkalmazás társítása

Windows.Devices.Printers

Windows.Graphics.Printing.PrintSupport

Windows.Graphics.Printing.Workflow