Windows業務アプリの印刷とPDF出力 ── System.Drawing.Printing / WPF / 帳票ライブラリの使い分け
· 小村 豪 · CSharp, .NET, WinForms, WPF, 印刷, PDF, 帳票, Windows開発, 技術相談
Windows業務アプリの印刷は、「PrintDocumentで適当に描画すれば終わり」という話にはなりません。改ページが効かない、余白がずれる、プレビューと実際の出力が違う、PDFだけ欲しいのに印刷ダイアログが挟まる ── こうした問題は、たいてい印刷の仕組みそのものを誤解したまま実装を始めたことが原因です。
この記事では、WinFormsのSystem.Drawing.Printing、WPFのFlowDocument/FixedDocument、PDF出力ライブラリ、Excel/Word経由の帳票という4つの選択肢を、要件別にどう使い分けるかという観点で整理します。
1. まず結論
- 簡単な一覧や既存WinForms資産の延長なら
PrintDocumentで十分です。 改ページはPrintPageイベントをHasMorePagesがfalseになるまで繰り返し呼び出す仕組みで、これを忘れると2ページ目以降が出力されません。12 - 印刷のDPIは画面のDPIと別物です。
PageSettings.PrinterResolutionはプリンターの解像度を表し、余白はPageSettings.HardMarginX/HardMarginY(プリンターが物理的に持つ印字不可能領域)とMargins(アプリが指定する論理的な余白)の2段構えになっています。画面の座標をそのまま印刷に流用すると、この2つのDPI・座標系の違いでレイアウトがずれます。345 - WPFではWindows標準の印刷パスがGDI印刷パスとXPS印刷パスの2系統に分かれています。 WPFアプリケーションは本来XPS印刷パスを使い、XPSDrv非対応のプリンターに送る場合は自動的にGDI形式へ変換されます。67
- WPFの文書は「流し込み」の
FlowDocumentと「固定レイアウト」のFixedDocumentで設計思想が違います。FlowDocumentは可読性優先でウィンドウサイズや解像度に応じて再レイアウトされ、FixedDocumentは表示・印刷デバイスの忠実度を優先する構成です。89 - 用紙やトレイの指定はWPFの
PrintDialogとPrintTicket/PrintQueueで行います。 印刷前にPrintQueue.MergeAndValidatePrintTicketでプリンターの実際の能力に対して検証・マージするのが定石です。1011 - Microsoft Print to PDFは対話的な操作を前提にした印刷ドライバーです。 OSに標準搭載された印刷キューとドライバーパッケージという位置づけで、実行のたびに保存先を選ぶダイアログが挟まる構成が基本であり、無人バッチ処理には向きません。12
- サーバーやサービスからのOffice COM自動化は、Microsoftが公式に非サポート・非推奨としています。 Officeは対話的なデスクトップとユーザープロファイルを前提に設計されており、無人・非対話環境では不安定な動作やデッドロックを起こし得ます。13
- Windowsサービスはセッション0で動作するため、ダイアログを表示できず、ユーザーのセッションに紐づく既定プリンターにも依存できません。 印刷を伴う常駐処理を設計する際は、この境界を最初に意識してください。14
- 長期稼働でGDIオブジェクト(ハンドル)を解放し忘れると、プロセスあたりの上限に達してクラッシュします。 上限はレジストリの
GDIProcessHandleQuotaで調整可能な有限の値であり、無限に確保できるわけではありません。15
判断表 ── 要件 × 手段
| 要件 | 適した手段 | 理由 |
|---|---|---|
| 簡単な一覧・伝票を数枚印刷したい(WinForms) | PrintDocument |
標準クラスのみで完結し、既存のGDI+描画資産をそのまま流用できる |
| 罫線の多い帳票、複数用紙・複雑なレイアウト | 帳票ライブラリ、またはFixedDocumentでの固定レイアウト |
座標計算・改ページ制御・日本語組版を自前で書くコストが大きい |
| 大量バッチ印刷(夜間無人実行) | プログラム的なPrintDocument.Print()/XpsDocumentWriterへの直接送信 |
ダイアログを一切出さず完結させる必要があり、既定プリンター依存も避けたい |
| PDF保存だけでよい(印刷は使わない) | PDF生成ライブラリで直接PDFを作る | 印刷ダイアログや既定プリンター、スプーラーの状態に依存しない |
| プレビューが必須、社内の確認フローが重要 | PrintPreviewDialog(WinForms)、DocumentViewer(WPF) |
印刷前確認の標準UIがそのまま使える |
| 既存Excelテンプレートを流用したい | Open XML SDK等での直接生成、または限定的なCOM自動化 | 資産を再利用できるが、常駐サービスでのCOM自動化は避ける |
以下、各項目の詳細を見ていきます。
2. Windowsの印刷の仕組みを最低限だけ
Windowsの印刷アーキテクチャは、印刷スプーラーと各プリンター用のドライバーで構成されています。アプリケーションはデバイスに依存しない関数を呼ぶだけで、レーザープリンター、ベクタープロッター、ラスタープリンター、FAXなど多様な出力先に印刷ジョブを送れます。16
印刷パスは大きく2系統あります。
- GDI印刷パス。 Win32 GDIアプリケーションが印刷すると、GDIグラフィックスエンジンが描画命令をEMF(拡張メタファイル)としてスプールするか、プリンタードライバーと連携して印刷可能なイメージを直接レンダリングし、スプーラーへ送ります。従来のWinFormsアプリはこちらの経路を通ります。166
- XPS印刷パス。 XPS(XML Paper Specification)ベースのプリンタードライバー向けの経路で、WPFアプリケーションは本来こちらを使い、XPSドキュメントの形式でスプーラーに送ります。対象プリンターがXPSDrvドライバーでなければ、GDI形式に自動変換されてから送られます。67
なぜ画面の見た目と印刷結果がずれるのか。 一番よくある原因はDPIの取り違えです。画面のGraphicsは通常96 DPI前後で座標系が組まれていますが、プリンターのGraphicsはPageSettings.PrinterResolutionで決まる、多くの場合600 DPI前後のはるかに高い解像度で動きます。3 画面用に計算したピクセル座標をそのまま印刷用のGraphicsに渡すと、意図よりずっと小さく(あるいは高解像度設定によっては大きく)描画されます。印刷では常に「ハンドレスths・オブ・インチ」(1/100インチ)や実寸(ミリ・インチ)を基準に座標を組み立て、Graphicsの解像度に依存しない設計にするのが安全です。
もう一つ見落としやすいのが、プリンターが持つ物理的な印字不可能領域です。多くのプリンターは用紙の端から数ミリの範囲に印刷できません。この物理制約はPageSettings.HardMarginX/HardMarginYで取得でき、公式ドキュメントでも「プリンターが設定する物理的な余白を表す」と説明されています。4 アプリ側で指定する論理的な余白はPageSettings.Margins(既定は上下左右1インチ)ですが、これを0に設定しても、プリンターのハードマージンより内側には出力できません。5 「余白を0にしたのに端が切れる/思ったよりずれる」という不具合の多くは、このハードマージンの存在を意識していないことが原因です。
3. WinForms: System.Drawing.Printingの実務
WinFormsの印刷はPrintDocumentコンポーネントを中心に組み立てます。基本の流れは、PrintDocumentを作り、PrinterSettingsやDefaultPageSettingsを設定し、PrintPageイベントで実際の描画を行い、Print()メソッドで印刷を開始するというものです。1
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;
public sealed class ReportPrinter
{
// 印刷対象データ。1行1件の伝票明細を想定
private readonly IReadOnlyList<string> _lines;
private int _lineIndex;
public ReportPrinter(IReadOnlyList<string> lines) => _lines = lines;
public void Print(string printerName)
{
using var document = new PrintDocument();
document.DocumentName = "受注明細";
if (!string.IsNullOrEmpty(printerName))
{
document.PrinterSettings.PrinterName = printerName;
}
// 未知のプリンター名を指定した場合にここでfalseになる(オフライン検知には使えない)
if (!document.PrinterSettings.IsValid)
{
throw new InvalidOperationException(
$"指定したプリンターが見つかりません: {printerName}");
}
_lineIndex = 0;
document.PrintPage += Document_PrintPage;
document.Print();
}
private void Document_PrintPage(object? sender, PrintPageEventArgs e)
{
// MarginBoundsは論理的な余白(Margins)を反映した描画可能領域。
// PageBoundsは用紙全体で、ハードマージンより内側に描いても切れる
using var font = new Font("メイリオ", 10);
float lineHeight = font.GetHeight(e.Graphics);
float y = e.MarginBounds.Top;
while (_lineIndex < _lines.Count)
{
if (y + lineHeight > e.MarginBounds.Bottom)
{
// このページはここまで。続きがあるので次ページへ
e.HasMorePages = true;
return;
}
e.Graphics.DrawString(_lines[_lineIndex], font, Brushes.Black,
e.MarginBounds.Left, y);
y += lineHeight;
_lineIndex++;
}
// 全行を描き終えたので、これが最後のページ
e.HasMorePages = false;
}
}
「2ページ目が出ない」不具合の典型パターンは、HasMorePagesを明示的にfalseにし忘れる(既定値はfalse)か、逆に条件分岐の書き方を誤って常にfalseのまま抜けてしまうケースです。PrintPageイベントは、このプロパティがfalseになるまで繰り返し呼び出される仕組みであることを踏まえ、「まだ描くべき行が残っているか」を明示的に判定してから設定してください。12 ページごとに異なる設定(用紙サイズや向きなど)を反映したい場合は、PrintPageに加えてQueryPageSettingsイベントも活用できます。
「余白がずれる」不具合の典型パターンは、e.Graphics.VisibleClipBoundsやe.PageBoundsを基準に座標を組み立ててしまい、MarginBounds(論理余白を反映した領域)とHardMarginX/HardMarginY(プリンターの物理制約)を無視することです。4 特に、開発機のプリンターではハードマージンが小さくたまたま問題が出ず、納品先の別機種でハードマージンが大きく、罫線や項目が欠けて見える、という事故が起きやすいところです。複数機種での印刷検証は、開発時に見落とされがちな工程です。
プレビューを提供する場合はPrintPreviewDialogを使い、Documentプロパティに同じPrintDocumentを割り当てるだけで、PrintPageイベントのロジックをそのまま再利用できます。1 プリンター解像度に応じた出力を切り替えたい場合は、PrinterSettings.PrinterResolutionsから選択肢を取得し、PageSettings.PrinterResolutionに設定します。3
4. WPF: FlowDocument / FixedDocumentとPrintDialog
WPFでは、文書の性質によってFlowDocumentとFixedDocumentのどちらを軸にするかが変わります。
FlowDocument。 ウィンドウサイズやフォント設定など実行時の変数に応じて内容を動的に再レイアウトする、可読性優先の文書です。検索、ページング、表示モード変更などの機能を標準で持ちます。8FixedDocument。 アプリケーション側がレイアウトを完全に制御する、忠実度優先のWYSIWYG文書です。表示・印刷デバイスに対して高精度な再現性が必要な場合に向きます。9
流し込みで読みやすさを優先する社内向けレポートならFlowDocument、罫線位置や項目位置をピクセル単位で固定したい伝票・ラベルならFixedDocument、という判断が基本線です。
基本的な印刷はSystem.Windows.Controls.PrintDialogで行います。このクラスはSystem.Windows.Forms.PrintDialogとは別物で、WPF専用です。10
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
public static class FlowDocumentPrinter
{
public static void Print(FlowDocument document, string jobName)
{
var printDialog = new PrintDialog();
// ユーザーがOKを押した場合のみ印刷する
if (printDialog.ShowDialog() != true)
{
return;
}
// FlowDocumentは表示用と印刷用でページサイズの前提が異なるため、
// 印刷対象のページサイズ・余白をプリンターの印刷可能領域に合わせる
var paginator = ((IDocumentPaginatorSource)document).DocumentPaginator;
paginator.PageSize = new Size(
printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight);
printDialog.PrintDocument(paginator, jobName);
}
}
用紙サイズ・給紙トレイ・両面印刷などを細かく指定したい場合は、PrintQueueとPrintTicket/PrintCapabilitiesを使います。PrintTicketは印刷ジョブへの指示、PrintCapabilitiesはプリンターが実際にサポートする機能を表し、指定した設定はPrintQueue.MergeAndValidatePrintTicketでプリンター固有の妥当な値にマージ・検証してから使うのが定石です。711
using System.Linq;
using System.Printing;
public static class DuplexPrintTicketBuilder
{
public static PrintTicket BuildDuplexTicket(PrintQueue printQueue)
{
PrintCapabilities capabilities = printQueue.GetPrintCapabilities();
// 両面印刷(長辺綴じ)に対応しているプリンターかどうかを事前に確認する
bool supportsDuplex = capabilities.DuplexingCapability
.Contains(Duplexing.TwoSidedLongEdge);
var requestedTicket = new PrintTicket();
if (supportsDuplex)
{
requestedTicket.Duplexing = Duplexing.TwoSidedLongEdge;
}
// ユーザーの既定PrintTicketに対して、両面印刷の要求だけをマージする。
// 未対応の項目は妥当な値に自動的に置き換えられる
ValidationResult result = printQueue.MergeAndValidatePrintTicket(
printQueue.UserPrintTicket, requestedTicket);
return result.ValidatedPrintTicket;
}
}
固定レイアウトの帳票をFixedDocumentで組んでXPS印刷パスに直接送る場合は、XpsDocumentWriterのWrite/WriteAsyncメソッドでPrintQueueにジョブを追加します。対象がXPSDrv非対応のプリンターであれば、内部でGDI形式に自動変換されてから送られるため、呼び出し側で経路を意識する必要はありません。7
5. PDF出力の選択肢
「PDFで出したい」という要件は、実は次の3つのどれを指しているかで設計が変わります。
- 印刷の延長として、ユーザーが手動でPDF保存を選べればよい
- アプリ内から、印刷ダイアログを介してPDFを生成したい
- 印刷は一切せず、無人バッチでPDFファイルだけを大量生成したい
Microsoft Print to PDFは1と2向けの機能です。 Windows 10以降に標準搭載された、印刷キューとドライバーパッケージという位置づけの機能で、印刷対象アプリからは通常のプリンターの1つとして見えます。12 ただし実体は「印刷するたびに保存先ファイル名を尋ねる」という対話的な動作が前提の仕組みであり、公式にも印刷キューと当該ドライバーパッケージ自体を管理者がイメージから除去できる、という単位でしか制御手段が提供されていません。12 無人・大量のバッチ処理でファイルパスを固定して静かにPDFを吐き出す、という3の用途には設計上向いていません。3を実現したい場合は、印刷パイプラインを経由せず、PDFを直接生成するライブラリを使うのが素直です。
PDF生成ライブラリを選ぶときの比較観点は、特定の製品を推す前に、次の軸で自社の要件を整理しておくと選定がぶれません。
| 観点 | 確認すること |
|---|---|
| ライセンス | OSS(MIT/Apache系か、GPL/AGPL系か)か商用ライセンスか。自社アプリを社外に配布・販売する場合、ライブラリのライセンス条件(ソースコード開示義務の有無、再頒布条件、商用利用の可否)が自社の配布形態と矛盾しないかを必ず一次情報(ライセンス条文・提供元の公式サイト)で確認する |
| 日本語フォントの扱い | 日本語フォントのサブセット埋め込みに対応しているか、埋め込みなしでPDF側にフォントの実体を持たせられるか(閲覧環境にフォントがない場合に文字化けしないか)、縦書きや異体字(IVS)が必要な業務ならその対応状況 |
| 帳票向け機能 | テンプレートベースでの帳票定義に対応しているか、バーコード・2次元コードの生成、電子署名、PDF/A(長期保存規格)対応、既存の紙帳票のレイアウトをそのまま移植しやすいか |
| 依存関係・実行環境 | サーバー環境(GUIなしのWindows Server、コンテナー)でも動作するか、ネイティブライブラリへの依存があるか、.NET Core/.NET(非Framework)環境での動作実績 |
| パフォーマンス | 大量ページ・大量ジョブのバッチ生成時のメモリ使用量、並列生成時の挙動 |
ライセンス条件は製品やバージョンによって変わるため、必ず提供元の公式ドキュメントやライセンス条文そのものを確認してから採用判断をしてください。この記事では特定のライブラリ名や製品の推奨は行わず、比較の「観点」だけを示します。
6. Excel / Word経由の帳票という選択肢
すでにExcelテンプレートで運用している帳票がある場合、それをゼロから作り直すより、既存資産を活かす構成の方が現実的なことがあります。方式は大きく2つです。
- Open XML SDK等でxlsx/docxを直接生成・編集する。 Excel/Wordの実行ファイルを起動せず、ファイル形式(ZIP + XML)を直接読み書きするため、サーバー環境でも安定して動作します。テンプレートの罫線・書式をそのまま活かしつつ、値だけを差し込む構成と相性がよく、詳しくは「Excel帳票出力の作り方 - COM/Open XML/テンプレート」に整理しています。
- Excel COM Interopで実際にExcel.Applicationを操作する。 マクロや複雑な再計算を伴う既存Excelブックをそのまま使い回したい場合に選ばれますが、COM参照の解放漏れによりEXCEL.EXEプロセスが残り続ける問題が起きやすく、対策と判断基準は「C#のExcel操作でEXCEL.EXEが残る問題」で扱っています。
ここで重要なのは、サーバーサイドやWindowsサービスでのOffice COM自動化は、Microsoftが公式に「非推奨・非サポート」と明言していることです。Officeアプリケーションは対話的なデスクトップとログオン済みユーザーのプロファイルを前提に設計されており、無人・非対話環境で実行すると不安定な動作やデッドロックを起こし得るとされています。13 ライセンス上も、サーバー側の自動化でOffice機能をクライアントに提供する使い方は、通常のEULAでは想定されていません。13
したがって、帳票出力を常駐サービスやバッチジョブに組み込みたい場合は、たとえ既存のExcelテンプレートを流用するとしても、実行時に本当にExcel.exeを起動する構成(COM Interop)は避け、Open XML SDK等によるファイル直接生成に寄せるのが安全です。どうしてもCOM Interopが必要な場合は、対話的にログオンしたユーザーセッションで動く常駐アプリケーション(サービスではない)として構成する、という切り分けが現実的です。
7. 実務の落とし穴
Windowsサービス・セッション0からの印刷
印刷処理を常駐サービスに組み込みたいという相談は少なくありませんが、Windowsサービスはセッション0で動作します。セッション0は、Windows Vista以降サービスや対話的ユーザーと関わらないプロセス専用に予約されたセッションで、ユーザーの対話的セッションとは分離されています。14 この分離により、サービスはダイアログボックスを表示してもユーザーには見えず、ユーザーの入力を待つコード(印刷ダイアログの表示待ちなど)を書くとハングしたように見えます。14
さらに実務上の落とし穴になりやすいのが、ネットワークプリンターやユーザー個別にマップされたプリンターの見え方です。ユーザーがログオンして接続したネットワークプリンターは、そのユーザーの対話的セッションに紐づいて見えることが多く、別セッション(セッション0で動くサービスのプロセスコンテキスト)からは同じようには見えません。印刷を伴う常駐処理は、「どのアカウント・どのセッションから、どのプリンターが見えるか」を設計の最初に確認する必要があります。セッション分離の全体像は「Windowsのセッション分離をどう理解するか」に、サービスとしての実装・運用の基礎は「Windowsサービスの作り方と運用」に整理しています。
プリンター不在・オフライン時の挙動
PrinterSettings.PrinterNameに存在しないプリンター名を指定したり、既定プリンターが未設定の環境で実行したりすると、印刷を試みた時点で例外や失敗が起きます。PrinterSettings.IsValidで事前に検証してからにする、印刷失敗を想定した再試行・エラー通知の設計をしておく、という2点は最低限押さえておきたいところです。ネットワークプリンターが一時的にオフラインの場合、スプーラーにジョブは積まれても実際の出力は止まったままになることがあるため、印刷結果を「送信できた」で終わらせず、必要に応じてジョブの状態を確認する仕組みも検討してください。
既定プリンター依存の危険
PrinterSettings.PrinterNameを明示的に指定せず、常に「既定のプリンター」に頼る実装は、運用が長くなるほどリスクになります。ユーザーが別のプリンターを既定に変更する、ノートPCを別の場所に持ち出して既定プリンターが変わる、といった環境変化で意図しない出力先に送られてしまうためです。業務上重要な帳票は、設定ファイルやアプリ内の設定画面で印刷先プリンター名を明示的に保持し、既定プリンターの変化に引きずられない設計にしておくべきです。
長期稼働でのGDIハンドルリーク
Graphics、Font、Brush、PenなどのGDI/GDI+リソースをusingやDispose()で確実に解放しないコードを印刷処理の中に書くと、長期稼働後にGDIオブジェクトのハンドルが枯渇し、描画関連のAPI呼び出しが失敗し始めます。GDIオブジェクトのハンドルはプロセスごとに既定の上限があり、レジストリのGDIProcessHandleQuotaで256から65,536の範囲で調整できる、有限のリソースです。15 印刷を頻繁に行う常駐アプリケーションほど、この種のリークが本番環境でしか顕在化しない不具合になりがちです。ハンドルリークの調べ方・切り分け方は、産業用カメラの長期稼働クラッシュ事例を扱った「産業用カメラ長期稼働クラッシュ調査 - ハンドルリーク編」で具体的に解説しています。
関連記事
- Excel帳票出力の作り方 - COM/Open XML/テンプレート
- C#のExcel操作でEXCEL.EXEが残る問題 ── COM参照の解放パターンと置き換えの判断
- Windowsサービスの作り方と運用 ── タスクスケジューラとの使い分けからBackgroundServiceのサービス化まで
- Windowsのセッション分離をどう理解するか ── Session 0・RDP・複数ユーザー同時実行
- 産業用カメラ長期稼働クラッシュ調査 - ハンドルリーク編
関連する相談領域
合同会社小村ソフトでは、Windows業務アプリの印刷・帳票出力機能の設計、既存Excel資産を活かした帳票の作り直し、常駐サービスからの印刷・出力設計の技術相談を扱っています。
参考リンク
-
Microsoft Learn, PrintDocument Class.
PrintDocumentの役割(DocumentName・PrinterSettingsを設定しPrint()で印刷を開始する)と、WPFから印刷する場合はSystem.Printing名前空間を使うべきという案内について。 ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, PrintPageEventArgs.HasMorePages Property. 既定値が
falseであること、PrintPageイベントはこのプロパティがfalseになるまで繰り返し発生することについて。 ↩ ↩2 -
Microsoft Learn, PageSettings.PrinterResolution Property. ページの印刷解像度の既定値がプリンターの既定解像度であること、
PrinterSettings.PrinterResolutionsから選択可能な解像度一覧を取得できることについて。 ↩ ↩2 ↩3 -
Microsoft Learn, PageSettings.HardMarginX Property. ハードマージンがプリンターによって設定される物理的な余白を表すことについて。 ↩ ↩2 ↩3
-
Microsoft Learn, PageSettings.Margins Property. ページの余白の既定値が上下左右1インチであること、
PrintPageイベントでBoundsプロパティと組み合わせて印刷可能領域を計算できることについて。 ↩ ↩2 -
Microsoft Learn, Windows Print Path Overview. WindowsにGDI印刷パス(Win32アプリケーション由来)とXPS印刷パス(WPFアプリケーションまたはXPS Print API由来)の2つの主要な印刷パスが存在することについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Printing documents overview. WPFアプリケーションがXPS印刷パスを使うこと、
PrintDialogによる基本印刷、PrintTicket/PrintCapabilities/PrintQueue/XpsDocumentWriterによる高度な印刷、XPSDrv非対応プリンターへのGDI自動変換について。 ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, Flow Document Overview.
FlowDocumentがウィンドウサイズや解像度などの実行時変数に応じてコンテンツを再レイアウトする、可読性優先の文書であることについて。 ↩ ↩2 -
Microsoft Learn, FixedDocument Class.
FixedDocumentが表示・印刷デバイスへの忠実な再現を優先するWYSIWYG設計であり、FlowDocumentとは設計思想が異なることについて。 ↩ ↩2 -
Microsoft Learn, PrintDialog Class.
System.Windows.Controls.PrintDialogがPrintTicketとPrintQueueをユーザー入力に応じて構成するダイアログであること、System.Windows.Forms.PrintDialogとは別クラスであることについて。 ↩ ↩2 -
Microsoft Learn, How to: Validate and Merge PrintTickets.
PrintQueue.GetPrintCapabilitiesでプリンターの対応機能を確認し、MergeAndValidatePrintTicketで要求内容をプリンター固有の妥当なPrintTicketにマージ・検証する手順について。 ↩ ↩2 -
Microsoft Learn, RemoveMPDW. Microsoft Print to PDFが既定でインストールされるオプション機能であり、印刷キューとドライバーパッケージという単位で構成・削除されることについて。 ↩ ↩2 ↩3
-
Microsoft Support, Considerations for server-side Automation of Office. Microsoftが、ASP/ASP.NET/DCOM/NTサービスを含む無人・非対話のクライアントアプリケーションからのOffice自動化を推奨・サポートしていないこと、Officeが対話的デスクトップとユーザープロファイルを前提に設計されていることについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Service Changes for Windows Vista - Session 0 Isolation. Windows Vista以降、セッション0がサービスや対話的ユーザーに関連しないアプリケーション専用に予約され、サービスがダイアログボックスを直接表示できなくなったことについて。 ↩ ↩2 ↩3
-
Microsoft Learn, GDI Objects. GDIオブジェクトのハンドルがプロセスごとに既定の上限を持つこと、
GDIProcessHandleQuotaレジストリ値で256から65,536の範囲で上限を調整できることについて。 ↩ ↩2 -
Microsoft Learn, Introduction to printing. Windowsの印刷アーキテクチャがスプーラーとプリンタードライバーで構成されること、Win32 GDIアプリケーションの描画命令がEMFとしてスプールされる仕組みについて。 ↩ ↩2
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
Windowsアプリ 外注・受託開発を依頼する前に整理したいこと
Windowsアプリの外注・受託開発を依頼する前に、既存ソフト改修、装置連携、COM/ActiveX、配布・更新、保守の整理ポイントを解説します。
appsettings.jsonだけじゃない ── Windows業務アプリの構成管理実務(環境別設定・秘密情報・書き込み先)
Windows業務アプリの構成管理を、appsettings.jsonの階層化、IConfigurationとIOptions/IOptionsSnapshot/IOptionsMonitorの使い分け、環境別設定、書き込み可能な設定の置き場所、秘密情報の扱い、実行中の設定...
WinForms/WPFアプリにEntra ID認証を組み込む ── MSAL.NETとWAMブローカーの実務構成
WinForms/WPFデスクトップアプリにEntra ID(旧Azure AD)認証を組み込む手順を実務目線で整理します。パブリッククライアントの考え方、ROPC廃止の現状、アプリ登録、MSAL.NETのAcquireTokenSilentパターン、WAMブローカー、トー...
.NET Generic HostとBackgroundServiceをデスクトップアプリで使う理由
Windows ツールや常駐アプリで起動、定期処理、終了処理、ログ、設定、DIを整理するために、Generic HostとBackgroundServiceをどう使うかまとめます。
Windowsイベントログ・ETW入門 ── 業務アプリのログをOS標準の仕組みに乗せる
Windows業務アプリのログをファイルログだけで済ませていないでしょうか。イベントログとETWは、運用担当者やOS標準ツールから見える別レイヤーの記録です。3手段の使い分け、.NETからの書き込み方法、EventSourceによるETW計装、収集・調査の実務、ソース未登録...
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
UI スレッド / タイマーテーマ
WPF / WinForms、UI スレッド、async/await、タイマー設計を整理するトピックです。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
業務アプリの印刷・PDF出力機能の設計・実装はWindowsアプリ開発の相談範囲だからです。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- PrintDocumentとWPFの印刷、どちらで作るべきですか?
- 画面がWinFormsならPrintDocument、WPFならFlowDocument/FixedDocumentを使うのが素直です。技術を混在させる必要はなく、既存アプリの画面フレームワークに合わせるのが実務的な判断基準です。新規にWPFを選ぶなら、帳票が流し込み中心かレイアウト固定かでFlowDocumentとFixedDocumentのどちらを軸にするかを先に決めておくと迷いません。
- 帳票ライブラリは買うべきですか?
- 罫線の多い複雑な帳票、複数用紙サイズ対応、日本語フォントの埋め込みや縦書きなどを自前のGDI+/WPF描画で作り込むコストが大きい場合は、帳票ライブラリの導入コストの方が安くつくことが多いです。逆に、A4一覧表程度のシンプルな帳票であればPrintDocumentやFixedDocumentの自前実装で十分なことも多く、まずは要件の複雑さを見積もってから判断するのが安全です。
- PDFだけ作って印刷は使わない構成はありですか?
- 十分にありです。PDFはあくまで出力フォーマットの一つであり、印刷ダイアログや既定プリンターに依存しないPDFライブラリでの直接生成の方が、バッチ処理や自動化とは相性が良いことが多いです。Microsoft Print to PDFは対話的な操作を前提にしたドライバーであり、無人でのPDF生成には向きません。
- ラベルプリンターやレシートプリンターにも対応できますか?
- 対応可能ですが、汎用のPrintDocument/FixedDocumentの延長では対応しづらい場合があります。ラベルプリンターの多くは独自のコマンド言語やSDKを持ち、Windowsの標準印刷パスとは別経路で制御することも多いためです。まずは対象機種がWindowsの通常のプリンタードライバーとして振る舞うのか、専用SDK経由の制御が必要なのかを確認するところから始めてください。
著者プロフィール
記事の著者プロフィールページです。
小村 豪
合同会社小村ソフト 代表
Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。
公開リンク