印刷サポート アプリケーション v3 API 設計ガイド
この記事では、デバイスの v3 印刷サポート アプリ (PSA) を実装しているプリンター OEM および IHV のガイダンスと例を示します。
用語
用語 | 定義 |
---|---|
PS4 | 印刷サポート アプリケーション。 このドキュメントの API を使用する UWP アプリ。 |
IPP | インターネット印刷プロトコル。 クライアント デバイスからプリンターを操作して印刷設定を取得および設定し、印刷するドキュメントを送信するために使用します。 |
印刷サポートが関連付けられているプリンター | PSA にリンクされている物理 IPP プリンター。 |
IPP プリンター | IPP プロトコルをサポートするプリンター。 |
PDL | ページの説明言語。 文書がプリンターに送信される形式。 |
関連付けされた PSA プリンター | PSA アプリケーションに関連付けられている物理 IPP プリンター。 |
印刷デバイスの機能 | プリンター機能を定義するための XML ドキュメント形式。 |
プリントサポートエクステンション | プリンター制約拡張機能の提供を担当する PSA バックグラウンド タスク。 |
印刷サポート アプリケーション v3 API
この記事には、「印刷サポート アプリの設計ガイド」および「Windows.Graphics.Printing.PrintSupport 名前空間の
詳細については、次の記事を参照してください。
トピック | 説明 |
---|---|
印刷サポート アプリの設計ガイド | デバイスの印刷サポート アプリ (PSA) を実装しているプリンター OEM および IHV のガイダンスと例を示します。 |
印刷サポート アプリ v4 API 設計ガイド | デバイスの v4 印刷サポート アプリ (PSA) を実装しているプリンター OEM および IHV のガイダンスと例を示します。 |
"印刷サポート仮想プリンタ用MSIXマニフェスト仕様" | 印刷サポート仮想プリンターを実装しているプリンター OEM および IHV の MSIX マニフェスト ガイダンスと例を提供します。 |
印刷サポート アプリの関連付け | 印刷サポート アプリ (PSA) をプリンターに関連付けるガイダンスと例を示します。 |
API の重要な拡張機能は次のとおりです。
IPP 圧縮 -PSA v3 API は、この機能をサポートする IPP プリンターの印刷ジョブに IPP 圧縮機能を追加することで、IPP 印刷を強化する機能を追加します。 一部のPSAはカスタム圧縮を持つ可能性があり、これはIPPジョブがパフォーマンスに影響を与える二重圧縮を有することを意味する。 これを軽減するために、PSA v3 API では、
(PSA v1 API) ランタイム クラスに、IsIppCompressionEnabledPrintWorkflowJobStartingEventArgs プロパティと 関数 (必要に応じて現在のジョブの圧縮を無効にする) が導入されています。DisableIppCompressionForJob IPP ジョブ エラー処理とエラー トースト - PSA v3 API では、PrintWorkflowJobBackgroundSession (PSA v1 API) ランタイム クラスに JobIssueDetected イベントが導入されています。 このイベントは、印刷ジョブでPSAがエラー/警告を検出するたびに発生します。 PSAは、その後、エラー トーストをユーザーに表示する役割を担います。 PSA がこのイベントに登録し、
の SkipSystemErrorToast プロパティを で Windows 印刷システムトーストを表示しないように印刷システムに指示します。 また、PSA v3 API は、ユーザーがトーストを操作するときに、PSA が UI を起動するためのメカニズムも提供します。で true に設定すると、PrintWorkflowJobIssueDetectedEventArgs カスタム IPP 通信タイムアウト - PS v3 API は、PSA が IPP タイムアウトをオーバーライドできる API を提供します。 さらに、PrintSupportIppCommunicationConfiguration ランタイム クラスが、IPP 通信タイムアウトを操作するための PrintSupportPrintDeviceCapabilitiesChangedEventArgs に追加されます。 さらに、PSA v3 API では、IPP 通信でエラーが発生したときに発生するイベントが導入されます。 IHV が障害を調査し、それに応じてタイムアウト値を調整できるように、イベントが導入されました。
サポート IPPFaxOut - PSA v3 API は、IPPFaxOut プリンターをサポートする機能を印刷システムに追加します。 FAX をサポートするために、PSA は XPS を Tiff に変換するレンダリング フィルターをサポートしています。 TIFF に変換する前に XPS コンテンツを操作する場合があるため、PrintWorkflowPdlConversionType で XpsToTiff 列挙値を提供し、XPS から TIFF へのコンバーターにアクセスできるようにします。 さらに、PSA が標準プリンターと IPPFaxOut プリンターを区別できるように、ISIPPFaxOutPrinter プロパティを IPpPrintDevice ランタイム クラスに提供します。
IPP 圧縮の無効化
IPP 圧縮を次のコード サンプルに示します。
public sealed class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{
public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
private PrintWorkflowJobBackgroundSession session;
public void Run(IBackgroundTaskInstance taskInstance)
{
TaskInstanceDeferral = taskInstance.GetDeferral();
if (taskInstance.TriggerDetails is PrintWorkflowJobTriggerDetails jobDetails)
{
session = jobDetails.PrintWorkflowJobSession;
session.JobStarting += OnJobStarting;
session.PdlModificationRequested += OnPdlModificationRequested;
session.JobIssueDetected += OnJobIssueDetected;
// Make sure to register all the event handlers before PrintWorkflowJobBackgroundSession.Start is called.
session.Start();
}
}
private void OnJobStarting(PrintWorkflowJobBackgroundSession sender, PrintWorkflowJobStartingEventArgs args)
{
using (args.GetDeferral())
{
// Skip system rendering.
args.SetSkipSystemRendering();
// If Ipp compression is enabled by the system, check to see if PSA does custom compression for the printer
// and disable system compression if required.
if (args.IsIppCompressionEnabled)
{
if (this.HasCustomCompression(args.Printer))
{
args.DisableIppCompressionForJob();
}
}
}
}
bool HasCustomCompression(IppPrintDevice device)
{
bool hasCustomCompression = false;
// Check if the PSA does custom compression for the printer
return hasCustomCompression;
}
}
IPP ジョブエラー処理
このサンプルでは、PSA アプリでジョブ エラーを登録し、ジョブ エラーのトーストを表示し、ユーザーがトーストをアクティブ化したときに UI を起動する方法を示します。
public sealed class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{
public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
private PrintWorkflowJobBackgroundSession session;
public void Run(IBackgroundTaskInstance taskInstance)
{
TaskInstanceDeferral = taskInstance.GetDeferral();
if (taskInstance.TriggerDetails is PrintWorkflowJobTriggerDetails jobDetails)
{
session = jobDetails.PrintWorkflowJobSession;
session.JobStarting += OnJobStarting;
session.PdlModificationRequested += OnPdlModificationRequested;
session.JobIssueDetected += OnJobIssueDetected;
// Make sure to register all the event handlers before PrintWorkflowJobBackgroundSession.Start is called.
session.Start();
}
}
private void OnJobIssueDetected (PrintWorkflowJobBackgroundSession sender, PrintWorkflowJobIssueDetectedEventArgs args)
{
// Using a deferral to exclude the background process from being suspended while PSA displays UI.
Deferral deferral = args.GetDeferral();
var toast = new ToastNotification(GetErrorToastXml(args.ExtendedError,
args.JobIssueKind, args.PrinterJob, args.Configuration));
toast.Activated += async (toastSender, e) =>
{
// PSA UI application
PrintWorkflowUICompletionStatus uiStatus = await args.UILauncher.LaunchAndCompleteUIAsync();
// Complete deferral
deferral.Complete();
};
toast.Dismissed += async (toastSender, e) => { deferral.Complete(); };
toast.Failed += async (toastSender, e) => { deferral.Complete(); };
ToastNotificationManager.CreateToastNotifier().Show(toast);
args.SkipSystemErrorToast = true;
}
private XmlDocument GetErrorToastXml(Exception jobError, PrintWorkflowJobIssueKind issueKind,
PrintWorkflowPrinterJob printerJob, PrintWorkflowConfiguration workflowConfig )
{
var errorToastXml = new XmlDocument();
// Generate Toast Xml based on error information from Exception and PrintWorkflowPrinterJob.
return errorToastXml;
}
}
IPP 通信タイムアウトの設定
このサンプルでは、IPP 通信タイムアウトを設定する方法を示します。
public sealed class PrintSupportExtensionBackGroundTask : IBackgroundTask
{
public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
private PrintSupportExtensionSession session;
public void Run(IBackgroundTaskInstance taskInstance)
{
taskInstance.Canceled += OnTaskInstanceCanceled;
TaskInstanceDeferral = taskInstance.GetDeferral();
if (taskInstance.TriggerDetails is PrintSupportExtensionTriggerDetails extensionDetails)
{
session = extensionDetails.Session;
session.PrintTicketValidationRequested += OnSessionPrintTicketValidationRequested;
session.PrintDeviceCapabilitiesChanged += OnSessionPrintDeviceCapabilitiesChanged;
session.CommunicationErrorDetected += OnCommunicationErrorDetected;
// Make sure to register all the event handlers before PrintSupportExtensionSession.Start is called.
session.Start();
}
}
private void OnTaskInstanceCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
session = null;
TaskInstanceDeferral.Complete();
}
private void OnSessionPrintDeviceCapabilitiesChanged(PrintSupportExtensionSession sender, PrintSupportPrintDeviceCapabilitiesChangedEventArgs args)
{
// Using deferral to exclude the background process from being suspended while PSA updates the printer PDC and other configurations.
using (args.GetDeferral())
{
if (args.CommunicationConfiguration.CanModifyTimeouts)
{
this.UpdateAttributeTimeouts(args.CommunicationConfiguration, sender.Printer);
this.UpdateJobTimeouts(args.CommunicationConfiguration, sender.Printer);
}
// Do other operations, such as Updating PDC, PDR, and so on here.
}
}
void UpdateAttributeTimeouts(PrintSupportIppCommunicationConfiguration config, IppPrintDevice device)
{
IppPrinterCommunicationKind communicationKind = config.CommunicationKind;
PrintSupportIppCommunicationTimeouts currentTimeouts = config.IppAttributeTimeouts;
// Adjust attribute timeouts based on the printer
switch (communicationKind)
{
case IppPrinterCommunicationKind.Network:
currentTimeouts.ConnectTimeout = TimeSpan.FromSeconds(10);
currentTimeouts.SendTimeout = TimeSpan.FromSeconds(10);
currentTimeouts.ReceiveTimeout = TimeSpan.FromSeconds(10);
break;
case IppPrinterCommunicationKind.UniversalPrint:
// adjust timeout for universal printer
break;
}
}
void UpdateJobTimeouts(
PrintSupportIppCommunicationConfiguration config, IppPrintDevice device)
{
IppPrinterCommunicationKind communicationKind = config.CommunicationKind;
PrintSupportIppCommunicationTimeouts currentTimeouts = config.IppJobTimeouts;
// Adjust job timeouts based on the printer and communication type
switch (communicationKind)
{
case IppPrinterCommunicationKind.Network:
currentTimeouts.ConnectTimeout = TimeSpan.FromSeconds(30);
currentTimeouts.SendTimeout = TimeSpan.FromSeconds(30);
currentTimeouts.ReceiveTimeout = TimeSpan.FromSeconds(30);
break;
case IppPrinterCommunicationKind.UniversalPrint:
// adjust timeout for universal printer
break;
}
}
}
IPP 通信エラーの処理
このサンプルでは、IPP 通信エラーを処理する方法を示します。
public sealed class PrintSupportExtensionBackGroundTask : IBackgroundTask
{
public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
private PrintSupportExtensionSession session;
public void Run(IBackgroundTaskInstance taskInstance)
{
taskInstance.Canceled += OnTaskInstanceCanceled;
TaskInstanceDeferral = taskInstance.GetDeferral();
if (taskInstance.TriggerDetails is PrintSupportExtensionTriggerDetails extensionDetails)
{
session = extensionDetails.Session;
session.PrintTicketValidationRequested += OnSessionPrintTicketValidationRequested;
session.PrintDeviceCapabilitiesChanged += OnSessionPrintDeviceCapabilitiesChanged;
session.CommunicationErrorDetected += OnCommunicationErrorDetected ;
// Make sure to register all the event handlers before PrintSupportExtensionSession.Start is called.
session.Start();
}
}
private void OnTaskInstanceCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
session = null;
TaskInstanceDeferral.Complete();
}
private void OnCommunicationErrorDetected(PrintSupportExtensionSession sender, PrintSupportCommunicationErrorDetectedEventArgs args)
{
// Using deferral to exclude the background process from being suspended while PSA updates the timeouts.
using (args.GetDeferral())
{
if (args.ErrorKind == IppCommunicationErrorKind.Timeout)
{
PrintSupportIppCommunicationConfiguration ippConfig = args.CommunicationConfiguration;
IppPrintDevice device = sender.Printer;
// Update timeout based on the communication error
}
}
}
}
PSA で IPP FAX 出力プリンターに印刷する
このサンプルでは、PSA の IPPFaxOut プリンターに印刷する方法を示します。
public sealed class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{
public BackgroundTaskDeferral TaskInstanceDeferral { get; set; }
private PrintWorkflowJobBackgroundSession session;
public void Run(IBackgroundTaskInstance taskInstance)
{
TaskInstanceDeferral = taskInstance.GetDeferral();
if (taskInstance.TriggerDetails is PrintWorkflowJobTriggerDetails jobDetails)
{
session = jobDetails.PrintWorkflowJobSession;
session.JobStarting += OnJobStarting;
session.PdlModificationRequested += OnPdlModificationRequested;
session.JobIssueDetected += OnJobIssueDetected;
// Make sure to register all the event handlers before PrintWorkflowJobBackgroundSession.Start is called.
session.Start();
}
}
private async void OnPdlModificationRequested(PrintWorkflowJobBackgroundSession sender, PrintWorkflowPdlModificationRequestedEventArgs args)
{
using (args.GetDeferral())
{
IppPrintDevice printer = args.PrinterJob.Printer;
IInputStream xpsContent = args.SourceContent.GetInputStream();
WorkflowPrintTicket printTicket = args.PrinterJob.GetJobPrintTicket();
string documentFormat = this.GetPrinterDocumentFormat(printer);
PrintWorkflowPdlTargetStream targetStream = args.CreateJobOnPrinter(documentFormat);
IInputStream xpsSourceContent = xpsContent;
if (printer.IsIPPFaxOutPrinter)
{
// Add cover page to XPS source document
xpsSourceContent = this.AddCoverPageToXpsContent(xpsContent);
}
PrintWorkflowPdlConverter pdlConverter;
switch (documentFormat.ToLowerInvariant())
{
case "image/pwg-raster":
pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToPwgr);
break;
case "application/pclm":
pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToPclm);
break;
case "application/pdf":
pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToPdf);
break;
case "image/tiff":
pdlConverter = args.GetPdlConverter(PrintWorkflowPdlConversionType.XpsToTiff);
break;
default:
// This should not happen, aborting workflow if PSA does not identify the supported PDLs
args.Configuration.AbortPrintFlow(PrintWorkflowJobAbortReason.JobFailed);
return;
}
// Use pdlConverter to convert the source XPS stream to printer's document format and send it to the printer using targetStream.
await pdlConverter.ConvertPdlAsync(printTicket, xpsSourceContent, targetStream.GetOutputStream());
targetStream.CompleteStreamSubmission(PrintWorkflowSubmittedStatus.Succeeded);
}
}
private IInputStream AddCoverPageToXpsContent(IInputStream xpsStream)
{
var coverPageXps = new InMemoryRandomAccessStream();
// Add cover page to XPS content and write to coverPageXps stream
return coverPageXps;
}
}
PSAで電話番号のFAX UIを無効にする
IPP FAX プリンターのサポートにより、このサンプルでは、FAX プリンターに印刷するときにユーザーに FAX 番号の入力を要求する UI を示します。 しかし、PSAは、より多くの情報とオプションを持つ独自のUIを表示したいかもしれません。 ユーザーが混乱する可能性があるため、FAX 用の UI が2つ存在する場合、このサンプルでは、FAX 用 UI を表示する際にシステム UI を無効にするオプションを示しています。
次の例では、API の使用方法を示します。
public sealed class PrintSupportWorkflowBackgroundTask : IBackgroundTask
{
private void OnJobStarting(PrintWorkflowJobBackgroundSession sender, PrintWorkflowJobStartingEventArgs args)
{
using (args.GetDeferral())
{
// If the job is printing to an Ipp fax printer,
// check whether PSA has a custom UI and disable system UI for getting the fax number.
if (args.IsIPPFaxOutPrinter)
{
if (this.HasCustomUIForFax(args.Printer))
{
args.SkipSystemFaxUI = true;
}
}
}
}
bool HasCustomUIForFax(IppPrintDevice device)
{
bool hasCustomUIForFax = false;
// Check if the PSA does custom UI for the given fax printer.
return hasCustomUIForFax;
}
}
Remarks
この記事のサンプルは、Print サポート アプリ設計ガイドのPSA v1 および v2 API のサンプルに基づいて構築されています。これは、開発者がPSA API ワークフローに精通していることを前提に されています。
この記事には、「印刷サポート アプリの設計ガイド」および「Windows.Graphics.Printing.PrintSupport 名前空間
印刷コンポーネントは、PSA ブローカー プロセスを通じて、PSA アプリと通信しています。
関連記事
Windows でのサード パーティ製プリンター ドライバーのサービス終了プラン
PrintSupportIppCommunicationConfiguration
PrintSupportPrintDeviceCapabilitiesChangedEventArgs
PrintWorkflowJobBackgroundSession
PrintWorkflowJobIssueDetectedEventArgs
PrintWorkflowJobStartingEventArgs