印刷ジョブをレンダリングする

重要

プリンターデバイス開発におけるWindows 10および11での印刷体験をカスタマイズするために、MicrosoftのIPPインボックスクラスドライバーとPrint Support Apps (PSA)の使用を推奨します。

詳細については、プリントサポートアプリデザインガイド.

印刷ジョブは、作成時にレンダリングされるか、EMF レコードとしてスプール ファイルに書き込まれます。 EMF レコードの場合、EMF 印刷プロセッサ (localspl.dll) がレコードを再生するときにレンダリングが行われます。 レンダリングは、CreateDC から開始する、ユーザー モード GDI 描画関数の一連の呼び出しで構成されます。 CreateDC の呼び出しは、グラフィックス レンダリング エンジン (GRE、カーネル モード GDI とも呼ばれます) とプリンター グラフィックス DLL を含むアクションのチェーンにつながる一連のアプリケーション呼び出しの最初に行われます。

次の図は、CreateDC が呼び出された後のカーネル モード GDI とプリンター グラフィックス DLL の間の相互作用を示しています。

diagram illustrating the interaction between kernel-mode gdi and the printer graphics dll after createdc is called.

  1. アプリケーションが CreateDC 関数を呼び出してプリンター デバイス コンテキストを作成すると、GDI は適切なプリンター グラフィックス DLL が読み込まれているかどうかを確認します。 読み込まれていない場合、GDI は DLL を読み込み、その DLL の DrvEnableDriver 関数を呼び出します。 ドライバーが再読み込みされない限り、関数は再度呼び出されません。

  2. 次に、GDI はプリンター グラフィックス DLL の DrvEnablePDEV 関数を呼び出します。これにより、ドライバーは物理デバイス インスタンスを作成し、デバイスの特性を返すことができます。 GDI は、返された情報を使用して、デバイス インスタンスの内部説明を作成します。

  3. GDI は、グラフィックス DLL の DrvCompletePDEV 関数を呼び出して、デバイス インスタンスに GDI ハンドルを提供します。 グラフィックス DLL は、このハンドルを、GDI 描画エンジンによって提供される Eng プレフィックス付きコールバックの一部への入力として使用する必要があります (「GDI サポート サービス」を参照)。

  4. GDI は、デバイス インスタンス ハンドルを受け取った後、グラフィックス DLL の DrvEnableSurface 関数を呼び出します。これにより、描画用のサーフェスが設定され、物理デバイス インスタンスに関連付けられます。

  5. ドライバーは、EngCreateBitmap を呼び出すことによって、デバイス インスタンスの描画サーフェスを作成できます。 または、描画サーフェスがデバイスで管理されている場合、ドライバーは EngCreateDeviceSurface を呼び出すことができます。

  6. EngCreateBitmap が物理ページ全体を格納するのに十分な大きさのビットマップを提供できない場合、ドライバーがページ バンディングをサポートしていれば、EngMarkBandingSurface を呼び出して、バンディングが使用されることを GDI に通知できます。

  7. 最後に、EngAssociateSurface を呼び出して、GDI が作成されたサーフェスを指定されたデバイス インスタンスに関連付けることができるようにし、この特定のサーフェスに描画するときに呼び出す必要があるドライバー提供のグラフィックス DDI 描画関数 (存在する場合) を GDI に通知する必要があります。

この時点で、描画サーフェスが作成され、レンダリングを開始できます。 GDI が呼び出す関数は、バンディングが有効かどうかによって異なります。

バンディングが使用されている

バンディングが使用されている場合、レンダリングされるドキュメントごとに、GDI はプリンター グラフィックス DLL の次の関数を呼び出します。

DrvStartDoc

物理ページごと

DrvStartPage

DrvStartBanding

物理ページ上の各バンディング パスごと

DrvQueryPerBandInfo

レンダリング操作

DrvNextBand // このバンドのラスター データを送信し、次のバンドで再利用するサーフェスをクリアします

DrvEndDoc

バンディングが使用されていない

バンディングが使用されていない場合、レンダリングされるドキュメントごとに、GDI はプリンター グラフィックス DLL の次の関数を呼び出します。

DrvStartDoc

物理ページごと

DrvStartPage

レンダリング操作

DrvSendPage // ページのラスター データを送信します

DrvEndDoc

DrvQueryPerBandInfo を除き、これらの関数は、プリンター グラフィックス DLL が (EngWritePrinter を呼び出すことによって) プリンター ハードウェアに制御シーケンスを送信し、ドキュメント、ページ、またはバンドの処理を初期化または完了するために必要な内部操作を実行することを目的としています。

プリンター グラフィックス DLL は、次のように (EngWritePrinter を呼び出すことによって) 適切な時間にレンダリングされた画像 (つまり、描画サーフェスの内容) をプリンターに送信する役割を担います。

  • GDI 管理またはデバイス管理のビットマップ サーフェスの場合

    描画サーフェスは、GDI 提供またはドライバー提供のビットマップです。 プリンター グラフィックス DLL は、描画関数をフックする場合があります (「Surface ネゴシエーション」を参照)。 ページ バンディングが使用されている場合、DrvNextBand 関数は描画サーフェスの内容を送信する必要があります。 バンディングが使用されていない場合、 DrvSendPage 関数は描画サーフェスの内容を送信する必要があります。

  • デバイス管理のベクター サーフェスの場合

    描画サーフェスはデバイス内にあります。 プリンター グラフィックス DLL は、すべての描画関数をフックし (「Surface ネゴシエーション」を参照)、これらの関数は、レンダリング操作中にプリンターに画像データを送信します。 ページのバンディングは使用されません。

プリンター グラフィックス DLL によって提供されるグラフィックス DDI 関数の実行にかかる時間が 5 秒を超える場合は、少なくとも 5 秒ごとに EngCheckAbort を呼び出して印刷ジョブを終了する必要があるかどうかを確認するコードを含める必要があります。

GDI は、DrvEndDoc を呼び出して、ドキュメントが完全にレンダリングされたことを示した後、DrvDisableSurface を呼び出します。 DrvEnableSurfaceEngCreateBitmap を呼び出した場合、DrvDisableSurfaceEngDeleteSurface を呼び出す必要があります。

GDI は、アプリケーションが DeleteDC を呼び出すときに、プリンター グラフィックス DLL の DrvDisablePDEV 関数を呼び出します。

アプリケーションがドキュメントの印刷中に ResetDC 関数を呼び出す場合、GDI は新しいデバイス コンテキストを作成し、この新しいコンテキストに対してプリンター グラフィックス DLL の DrvEnablePDEV 関数を呼び出します。 次に GDI は DrvResetPDEV 関数を呼び出して、グラフィックス DLL が古いコンテキストからの情報で新しいコンテキストを更新できるようにします。 次に、 古いコンテキストに対して DrvDisableSurfaceDrvDisablePDEV が呼び出され、その後、新しいコンテキストに対して DrvEnableSurface が呼び出されます。 最後に、GDI は DrvStartDoc を呼び出し、レンダリングは新しいページで再開します。

GDI は、プリンター グラフィックス DLL をアンロードする前に DrvDisableDriver を呼び出します。

プリンター ハードウェアが GDI 描画関数でサポートされていない描画操作をサポートしている場合、プリンター グラフィックス DLL は DrvDrawEscape 関数を提供できます。

GDI 関数では使用できない描画操作または描画以外の操作をサポートする必要がある場合、プリンター グラフィックス DLL は DrvEscape 関数を提供できます。 たとえば、Microsoft PostScript プリンター ドライバーは、エスケープを使用して PostScript 挿入ポイントをサポートします。 または、アプリケーションで FAX マシンの電話番号を取得する必要がある場合があります。 DrvEscape 関数は、DrvDrawEscape 関数でサポートされる操作を示す場合にも使用されます。