印刷サポート アプリ v1 および v2 の設計ガイド
この記事では、Windows ユーザーの印刷エクスペリエンスをいくつかの方法で強化できる印刷サポート アプリ (PSA) を開発するための、プリンター OEM と IHV のガイダンスと例を示します。
重要
Windows 11 SDK (22000.1) のリリース以降、プリンター用の UWP アプリを開発するための推奨される方法は、印刷サポート アプリ (PSA) です。 印刷デバイス用の印刷サポート アプリを開発するには、対象の Windows バージョン用の Windows 11 SDK をダウンロードしてインストールします。
重要
この記事には、Windows 11 バージョン 22H2 以降で使用できる PSA 機能について説明するセクションが含まれています。 これらのセクションには、そのバージョンに適用されることを示すメモが含まれています。
詳細については、次の記事を参照してください。
トピック | 説明 |
---|---|
印刷サポート アプリ v3 API 設計ガイド | デバイスの v3 印刷サポート アプリ (PSA) を実装しているプリンター OEM および IHV のガイダンスと例を示します。 |
印刷サポート アプリ v4 API 設計ガイド | デバイスの v4 印刷サポート アプリ (PSA) を実装しているプリンター OEM および IHV のガイダンスと例を示します。 |
印刷サポート仮想プリンターのための MSIX マニフェスト仕様 | 印刷サポート仮想プリンターを実装しているプリンター OEM および IHV の MSIX マニフェスト ガイダンスと例を提供します。 |
印刷サポート アプリの関連付け | 印刷サポート アプリ (PSA) をプリンターに関連付けるガイダンスと例を示します。 |
一部のプリンター機能は、製造元アプリのヘルプを正しく構成する必要がある特別な機能であるため、Windows によって表示される印刷ダイアログには表示されません。 プリンターの既定の機能では提供されない機能である場合もあります。
プリンター固有の機能は、ユーザーがオプションを選択し、そのシナリオに関連するすべての機能が自動的に正しい値に設定されることを信頼できるようにする方法でグループ化できます。 たとえば、インクセーバー、用紙セーバー、最高品質のモードのいずれかを選択できます。これは、ユーザーからの 1 つの選択に基づいてさまざまな印刷機能を自動的に操作できます。 Windows では、すべてのプリンター モデルのすべてのカスタム機能を理解する必要がある場合、それらを自動的にグループ化することはできません。
このカスタム印刷設定を表示する必要性は、この API によって対処されます。オプションの UWP 拡張コントラクトを使用して、Windows から提供されるすべての Windows 印刷ダイアログと、Windows で提供される API を使用するカスタム印刷ダイアログからユーザーがアクティブ化できます。 製造元は、ユーザーが所有する特定のプリンターに最適な印刷エクスペリエンスを提供するように UI を調整できます。
プリンターメーカーが改善し、差別化できるもう1つの領域は、印刷品質です。 製造元は、特定のプリンターのコンテンツを最適化することで、レンダリング後の印刷品質を向上させることができます。 また、プリンター固有の機能を考慮に入れる可能性があるため、最終的な出力をより適切に表す忠実度の高いプレビューを提供することもできます。
用語
用語 | 定義 |
---|---|
PS4 | 印刷サポート アプリケーション。 この記事で説明する API を使用する UWP アプリ。 |
MPD | モダンプリント ダイアログ。 これは、アプリが Windows.Graphics.Printing API を使用して印刷しているときにユーザーに表示されます。 |
CPD | 一般的な印刷ダイアログ。 これは、アプリが Win32 API を使用して印刷するときにユーザーに表示されます。 印刷プレビューを表示する必要があるアプリは、このダイアログをトリガーせず、ダイアログ自体のバージョンを実装します。 Office アプリは、この主要な例です。 |
IPP | インターネット印刷プロトコル。 クライアント デバイスからプリンターを操作して印刷設定を取得および設定し、印刷するドキュメントを送信するために使用します。 |
印刷サポートが関連付けられているプリンター | PSA にリンクされているプリンター。 |
IPP プリンター | IPP プロトコルをサポートするプリンター。 |
その他の設定 | パートナーが提供するアプリ UI を MPD で開くリンク。 既定では、PSA がインストールされていない場合に、組み込みの印刷設定 UI を開きます。 |
プリンターの基本設定 UI | 印刷時に適用される既定のプリンター オプションを設定するために使用されるダイアログ。 たとえば、向き、用紙サイズ、色、両面印刷などです。 |
PDL | ページの説明言語。 文書がプリンターに送信される形式。 |
関連付けされた PSA プリンター | PSA アプリケーションに関連付けられている物理 IPP プリンター。 |
印刷デバイスの機能 | プリンター機能を定義するための XML ドキュメント形式。 詳細については、「印刷チケットと印刷機能のテクノロジ」を参照してください。 |
PrintTicket | 特定の印刷ジョブに対するユーザーの意図をキャプチャするために使用される、さまざまな印刷関連機能とその値のコレクション。 |
PrintSupportExtension | プリンター制約拡張機能の提供を担当する PSA バックグラウンド タスク。 |
印刷サポート名前空間
これらのサンプルは、printsupport 名前空間を参照します。これは次のように定義されています。
xmlns:printsupport="http://schemas.microsoft.com/appx/manifest/printsupport/windows10"
印刷サポート設定のインターフェース
ユーザーが文書を印刷しようとしている場合、多くの場合、印刷に使用する設定を設定する必要があります。 たとえば、文書を横向きで印刷することを選択できます。 また、プリンターでサポートされているカスタム機能を利用することもできます。 Windows にはカスタム設定を表示する既定の UI が用意されていますが、適切なアイコンや説明がないため、ユーザーはそれらを理解できない場合があります。 Windows では、間違った UI コントロールを使用して表示している可能性もあります。 このようなカスタム機能は、その機能を完全に理解するアプリによって最適に提示されます。 これは、プリンターの製造元が作成するさまざまなプリンター モデルに合わせて調整されたアプリを作成できる API を提供する背後にある動機です。
windows.printSupportSettingsUI という名前の新しいカテゴリを使用して、新しい UAP 拡張コントラクトが作成されます。 このコントラクトでアクティブ化されたアプリは、PrintSupportSettingsUI という新しい ActivationKind を受け取ります。 このコントラクトには、新しい機能は必要ありません。
<Extensions>
<printsupport:Extension Category="windows.printSupportSettingsUI"
EntryPoint="PsaSample.PsaSettingsUISample"/>
</Extensions>
このコントラクトは、ユーザーが MPD で [その他の設定]
印刷サポート アプリは、異なる印刷ジョブに対して複数の同時アクティブ化を処理することが想定されているため、このようなアプリでは、package.appxmanifest ファイル内の SupportsMultipleInstances 要素を使用して複数のインスタンスをサポートする必要があります。 これを行わないと、ある印刷ジョブの環境設定を確認すると、開いている可能性のある他の環境設定ウィンドウが閉じる可能性があります。 ユーザーは、これらの環境設定ウィンドウをもう一度開く必要があります。
次のシーケンス図は、設定 UI の印刷チケット操作の概念を表しています。
チケット操作を印刷する
設定 UI での PrintTicket の変更
任意の印刷ダイアログ (MPD/CPD またはカスタム印刷ダイアログ) またはシステム設定から起動したときに設定 UI をアクティブ化するための C# サンプル コード:
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();
}
}
}
DefaultSettingsView クラスの XAML:
<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>
UI を表示して PrintTicket を変更するための C# サンプル コード:
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();
}
}
}
プリンター デバイスからプリンター属性を取得する
IPP プリンターから get-printer-attributes クエリへの WireShark 応答:
I P P プリンターからのプリンター属性取得クエリへのWiresharkの応答
プリンターからインク名とインク レベルを取得するための C# サンプル コード:
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));
}
}
}
}
プリンターでのプリンター属性の設定
プリンター属性を設定するための C# サンプル コード:
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;
}
}
}
}
プリンター制約の拡張
印刷サポート アプリでは、カスタム PrintTicket 検証と既定の PrintTicket の定義がサポートされています。 このセクションでは、これらの機能をサポートする方法について説明します。
プリンター拡張機能の制約をサポートするために、新しいバックグラウンド タスクの種類である PrintSupportExtension が実装されました。 Package.appxmanifest には、次に示すように、印刷サポート拡張機能の機能拡張エントリがあります。
<Extensions>
<printsupport:Extension Category="windows.printSupportExtension"
EntryPoint="PsaBackgroundTasks.PrintSupportExtension"/>
</Extensions>
このサービスは、関連付けられている IPP プリンターの印刷ジョブ内の任意の時点で実行できます。 IBackgroundTaskInstance
event Windows.Foundation.TypedEventHandler<PrintSupportExtensionSession, PrintSupportPrintTicketValidationRequestedEventArgs>; PrintTicketValidationRequested;
Print サポート拡張機能が独自の PrintTicket 検証メカニズムを提供する場合は、このイベントに登録できます。 PrintTicket を検証する必要があるときはいつでも、印刷システムではこのイベントが発生します。 PrintSupportExtension は、EventArgs 内で検証する必要がある現在の PrintTicket を取得します。 PrintSupportExtension バックグラウンド クラスは、PrintTicket の有効性を確認し、競合を解決するように変更できます。
PrintSupportExtension バックグラウンド クラスは、PrintTicket が解決されたか、競合しているか、無効であるかを示すために、SetPrintTicketResult 関数使用して検証の結果を設定する必要があります。 このイベントは、印刷ジョブの有効期間中にいつでも発生させることができます。 PrintSupportExtension クラスがこのイベントに登録されない場合、印刷システムは PrintTicket の独自の検証を実行します。 event Windows.Foundation.TypedEventHandler<PrintSupportExtensionSession, PrintSupportPrintDeviceCapabilitiesChangedEventArgs>; PrintDeviceCapabilitiesChanged;
印刷システムが、関連付けられている IPP プリンターのキャッシュされた PrintDeviceCapabilities を更新した後、このイベントが発生します。 このイベントが発生すると、PrintSupportExtension バックグラウンド クラスは、変更された PrintDeviceCapabilities を検査して変更できます。
印刷チケットのカスタム検証
C# サンプルコードは 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);
}
}
PrintDeviceCapabilities の更新
private void OnPdcChanged(PrintSupportExtensionSession session, PrintSupportPrintDeviceCapabilitiesChangedEventArgs args)
{
using (args.GetDeferral())
{
var pdc = args.GetCurrentPrintDeviceCapabilities();
// Check current PDC and make changes according to printer device capabilities
XmlDocument newPdc = this.CheckAndUpdatePrintDeviceCapabilities(pdc);
args.UpdatePrintDeviceCapabilities(newPdc);
}
}
印刷品質の向上
ユーザーが印刷ダイアログの印刷ボタンを押して印刷をコミットすると、印刷するドキュメントが印刷中のアプリから印刷スタックに送信されます。 このドキュメントでは、ターゲット プリンターに適した変換 (PDL へのレンダリング) が行われます。 Windows は、プリンターから照会された属性に基づいて、選択する変換を決定します。 その後、変換されたドキュメントがプリンターに送信されます。 これはほとんどのプリンターに適していますが、パートナー アプリが変換に参加できるようにすることで、印刷の品質が向上する可能性がある場合があります。 これを容易にするために、現在の印刷ワークフロー API が拡張され、印刷スタックから追加のポイントでアプリへの呼び出しが含まれます。 この API は、PSA アプリが登録できる 2 つの新しいイベントをサポートします。 PS API サーフェスへの唯一のエントリ ポイントは次のとおりです。
JobStarting
- このイベントは、任意のアプリケーションによって印刷ジョブが開始されたときに発生します。 イベントが発生すると、印刷サポートアプリは、PrintWorkflowJobStartingEventArgs上で SetSkipSystemRendering を呼び出すことにより、システムレンダリングをスキップすることを選択できます。 システムレンダリングのスキップを選択した場合、印刷システムは XPS ドキュメントをプリンターで必要な PDL 形式に変換しません。 代わりに、印刷アプリケーションによって生成された XPS は直接、XPS から PDL 形式への変換を担当する PSA に渡されます。
PdlModificationRequested
- このイベントは、Windows がプリンターによって示される PDL 形式への XPS ストリームの変換を開始するときに発生します。 PrintWorkflowPdlModificationRequestedEventArgs
ランタイム クラスは、このイベントの引数として提供されます。 このイベント クラスは、印刷ジョブの内容を読み書きするための PDL ソース オブジェクトとターゲット オブジェクトを提供します。 ユーザー入力が必要であるとアプリが判断した場合は、EventArgs から printWorkflowUILauncher 使用して UI を起動できます。 この API では、Tester-Doer パターンが使用されます。 関数 IsUILaunchEnabled が false を返した場合、PrintWorkflowUILauncher は UI を呼び出すことができません。 この関数は、PSA セッションがサイレント モード (ヘッドレス モードまたはキオスク モード) で実行されている場合に false を返します。 関数が false を返した場合、印刷サポート アプリは UI の起動を試みることはできません。
OutputStream は、関数 GetStreamTargetAsync によって返される PrintWorkflowPdlTargetStream の一部として使用できます。 ターゲット OutputStream に書き込まれたコンテンツは、ドキュメント コンテンツとしてプリンターに渡されます。
- このイベントは、Windows がプリンターによって示される PDL 形式への XPS ストリームの変換を開始するときに発生します。 PrintWorkflowPdlModificationRequestedEventArgs
PDL 変更イベントのシーケンス図:
ソース ストリーム P D L 変更イベント の
PSA フォアグラウンド アプリケーションは、PS バックグラウンド タスクが UI の起動を要求したときに起動されます。 PSA は、フォアグラウンド コントラクトを使用してユーザー入力を取得したり、プレビュー印刷プレビューをユーザーに表示したりできます。
印刷サポート ワークフローのバックグラウンド タスク
新しい printSupportWorkflow バックグラウンド タスクの種類が定義されました。 Package.appxmanifest には、PrintSupportWorkflow コントラクトの次の機能拡張エントリがあります。
<Extensions>
<printsupport:Extension Category="windows.printSupportWorkflow"
EntryPoint="PsaBackgroundTasks.PrintSupportWorkflowSample"/>
</Extensions>
コントラクトのアクティブ化時に、
印刷ワークフロー ジョブ UI
新しい ActivationKind である PrintSupportJobUI が定義されています。 これには新しい機能は必要ありません。
<Extensions>
<printsupport:Extension Category="windows.printSupportJobUI"
EntryPoint="PsaSample.PrintSupportJobUISample"/>
</Extensions>
これは、印刷サポート ワークフローのバックグラウンド コントラクトから、またはユーザーが印刷ジョブ エラー トーストを選択したときに起動できる UI コントラクトです。 アクティブ化時 PrintWorkflowJobActivatedEventArgs が提供され、PrintWorkflowJobUISession オブジェクトが含まれます。 PrintWorkflowJobUISessionを使用すると、PDL データにアクセスする場合は、フォアグラウンド アプリケーションが PdlDataAvailable イベントに登録する必要があります。 フォアグラウンド アプリケーションは、ジョブ中に発生する可能性があるエラーのカスタム エラー メッセージを表示する場合は、JobNotification イベントに登録する必要があります。 イベントが登録されると、アプリケーションは printWorkflowJobUISession::Start 関数
システムレンダリングのスキップ
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 変更イベント
PDL 変更イベントのシーケンス図:
のシーケンス図
印刷サポート ジョブ モニターの印刷ジョブ コンテンツの読み取りと書き込みの C# サンプル コード:
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();
}
}
}
ワークフローの背景から UI を起動する
PSPDL 変更要求イベント コントラクトから印刷サポート ジョブ UI を起動するための C# サンプル コード:
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();
}
}
PDLDataAvailable イベントのワークフロー ジョブ UI のアクティブ化
PdlDataAvailable イベント時の印刷ジョブ UI の起動のシーケンス図:
の印刷ジョブ U I アクティブ化のシーケンス図
PSAジョブUI活性化契約のC#サンプルコード:
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);
}
}
}
}
プリンター ジョブ属性を取得する
印刷ジョブのジョブ属性を取得するための C# サンプル コード:
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();
}
}
}
プリンター ジョブの属性を設定する
C# サンプル コード。前述の「プリンター ジョブ属性の取得」セクション 進み、ジョブ属性の設定を示します。
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);
}
}
一部の IPP プリンターは、ジョブの作成後にジョブ属性の取得/設定をサポートしていません。 これらのプリンターの場合、PrintJob には JobId プロパティが "0" に設定されており、GetJobAttributes/SetJobAttributes は例外ですぐに失敗します。
PDL コンテンツへのストレージ ファイル アクセスの提供
PDF などの一部の PDL 形式では、処理を開始するために完全なストリームを使用できる必要があります。 そのため、GetContentFileAsync
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 から PDF への PDL 変換
XPS から PDF への PDL 変換を示す C# サンプル コード:
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();
}
ジョブ通知イベント
ジョブ通知イベントのシーケンス図:
ジョブ通知イベント のための
上記の PDLDataAvailable イベント セクションのワークフロー ジョブ UI アクティブ化から続行して、ジョブ通知にエラーを表示する C# サンプル コード:
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;
}
}
}
}
初期ジョブ属性を使用してジョブを作成する
現在、一部の IPP プリンターでは set-attribute 操作がサポートされていません。 この問題を軽減するために、CreateJobOnPrinterWithAttributes 関数 と CreateJobOnPrinterWithAttributesBuffer 関数 PrintWorkflowPdlDataAvailableEventArgs が用意されています。 これらの API を使用して、PSA 開発者は、プリンターでジョブが作成されるときにプリンターに渡されるジョブ属性を提供できます。
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
}
}
シーケンシャル XPS 処理
スプールが完了する前に XPS を順次処理するための C++/Winrt サンプル コード。
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()));
}
}
}
表示名のローカライズと PDL パススルー API の統合
重要
このセクションでは、Windows 11 バージョン 22H2 以降で使用できるPSA機能について説明します。
このシナリオでは、PSA は印刷デバイス機能 (PDC) をカスタマイズし、文字列ローカライズ用の印刷デバイス リソース (PDR) を提供します。
サポートされている PDL パススルー API コンテンツの種類 (PDL 形式) も設定します。 PSA がイベントをサブスクライブしないか、明示的に SetSupportedPdlPassthroughContentTypes を呼び出さない場合、この PSA アプリに関連付けられたプリンターの PDL パススルーは無効になります。
// 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);
}
}
ページ レベル機能のサポートと操作属性
重要
このセクションでは、Windows 11 バージョン 22H2 以降で使用できるPSA機能について説明します。
ページ レベル機能のサポートと操作属性のシナリオは、サンプル コード内の同じ場所に変更を加えることで対処されるため、グループ化されます。
ページ レベル機能のサポート: このシナリオでは、PSA アプリケーションはページ レベル属性を指定します。これは、PrintTicket から解析された IPP 属性によってオーバーライドされるべきではありません。
操作属性のサポート (PIN 印刷) の個別のコレクション: このシナリオでは、PSA アプリケーションはカスタム IPP 操作属性 (PIN など) を指定します。
次の C# サンプル コードは、
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();
}
}
PSA による印刷ダイアログの拡張
重要
このセクションでは、Windows 11 バージョン 22H2 以降で使用できるPSA機能について説明します。
このシナリオでは、印刷ダイアログとPSA統合を使用すると、次のアクションが可能になります。
MPD で選択が変更されたときに、PSA に関連付けられているプリンターにコールバックを取得する
openUrl アクションをサポートする 1 つの AdaptiveCard を表示する
印刷ダイアログにカスタム機能とパラメーターを表示する
PrintTicket を変更し、印刷ダイアログに表示される機能オプションの選択を変更する
印刷アプリの Windows.ApplicationModel.AppInfo を取得し、印刷ダイアログを開きます
次の C# サンプルは、これらの印刷ダイアログの機能強化を示しています。
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 変換
重要
このセクションでは、Windows 11 バージョン 22H2 以降で使用できるPSA機能について説明します。
現在の PDL 変換 API PrintWorkflowPdlConverter.ConvertPdlAsyncは、既定でホスト ベースの処理を行います。 これは、プリンターがこれらの操作を実行する必要がないように、ホスト/印刷コンピューターが回転やページの順序などを実行することを意味します。 ただし、プリンターの IHV は、ホストベースの処理なしで PDL 変換を望むかもしれません。なぜなら、他の方法よりもプリンター自身がこれを効率的に行える可能性があるためです。 ConvertPdlAsync 関数は、この要件に対処するためにホスト ベースの処理フラグを受け取ります。 PSA は、このフラグを使用して、すべてのホストベースの処理または特定のホストベースの処理操作をスキップできます。
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
}
印刷デバイス機能 (PDC) 更新ポリシーの設定
重要
このセクションでは、Windows 11 バージョン 22H2 以降で使用できるPSA機能について説明します。
プリンターの IHV は、印刷デバイス機能 (PDC) を更新する必要がある場合に異なる要件があります。 これらの要件に対処するために、PrintSupportPrintDeviceCapabilitiesUpdatePolicy の更新ポリシーを PDC に設定できます。 この API を使用して、時間または印刷ジョブの数に基づいて PDC 更新ポリシーを設定できます。
ジョブの数に基づいて PDC 更新ポリシーを設定する
// 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);
}
}
TimeOut に基づいて PDC 更新ポリシーを設定する
// 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);
}
}
一般的な印刷サポート アプリ (PSA) の設計ガイダンス
印刷サポート アプリを設計するときは、次の点を設計に含める必要があります。
フォアグラウンド コントラクトとバックグラウンド コントラクトの両方が複数のインスタンスをサポートするようにマークする必要があります。たとえば、パッケージ マニフェストに supportsMultipleInstance
存在する必要があります。 これは、複数の同時ジョブに対してコントラクトの有効期間を確実に管理できるようにするためです。 PDL 変更の起動 UI を省略可能な手順として扱います。 UI の起動が許可されていない場合でも、印刷ジョブを正常に完了するように最善を尽くしてください。 印刷ジョブは、PDL の変更中にユーザー入力なしで正常に完了する方法がない場合にのみ中止する必要があります。 このような場合は、変更されていない PDL を送信することを検討してください。
PDL 変更用の UI を起動するときは、先に IsUILaunchEnabled を呼び出してから、LaunchAndCompleteUIAsyncを呼び出します。 これは、現在の時点で UI を表示できないシナリオが引き続き正しく印刷されるようにするためです。 これらのシナリオは、ヘッドレス デバイス、あるいは現在キオスク モードまたは応答不可モードになっているデバイスで考えられます。
関連記事
Windows でのサード パーティ製プリンター ドライバーのサービス終了プラン