レガシー Windows API(概要)について

ここで紹介しているAPIは、Windows95、Windows NT3.5時代のAPI群であり、最新のAPIは含まれていないことに注しして欲しい。なお、当時の解説書は現在よりもより詳細に解説しているため、参考になるはずである。

  • レイアウトを変換する際、崩れているページがあります。
  • 概要およびSampleコードはありますが、APIの解説はありません。

ご要望があれば旧版のWin32 API(HELP形式)をお譲りします。問い合わせフォームより申し込みください。

Windows API 印刷と印刷スプーラの概要

Microsoft(R) Windows(TM) では、 レーザー プリンタやベクタ プロッタ、 ラスタ プリンタ、 ファックスなどさまざまなデバイスにアプリケーションが印刷できるようにするための関数のセットを用意しています。この関数の大きな特徴の1つに、 デバイスに依存しないサポートがあります。特定のプリンタやプロッタに出力を描画するとき、 アプリケーションは、 デバイス固有コマンドを発行せずに、 グラフィック デバイス インターフェイス (GDI) の高レベル関数を呼び出すことができます。たとえば、 ビットマップ イメージを印刷するには、 ビットマップの座標と転送元と転送先のデバイス コンテキストを識別するハンドルを指定して、 BitBlt関数を呼び出します。BitBlt関数は、 プリンタ デバイス ドライバによって、 低レベルのデバイス コマンドに変換されます。「デバイス ドライバ」とは、 Windowsデバイス ドライバ インターフェイス (DDI) をサポートするダイナミック リンク ライブラリ(DLL)です。デバイス ドライバは、 グラフィック エンジンからのDDI関数呼び出しを処理するとき、 低レベルのデバイス コマンドを生成します。「グラフィック エンジン」とは、 印刷プロセッサの出力をデバイス ドライバ関数の呼び出しに変換するWindows DLLです。プリンタは、 低レベルのデバイス コマンドを処理して、 イメージを印刷します。デバイス コマンドの構文、 個数、 種類は、 デバイスによって異なります。

次に示すトピックでは、 印刷について説明しています。

  • デフォルトの印刷インターフェイス
  • プリンタ デバイス コンテキスト
  • プリンタ エスケープ
  • 表示と出力のWYSIWYG
  • .BMPファイルのオープンと表示
  • [Print]ダイアログ ボックスの表示とプリンタ デバイス コンテキストの取得
  • 印刷の準備
  • ドキュメントの印刷
  • 印刷と印刷スプーラの関数
  • 印刷と印刷スプーラの構造体

デフォルトの印刷インターフェイス

Win32 APIの印刷インターフェイスは、 GDIやデバイス ドライバのほかに、 プリンタに送られる前の出力を処理するいくつかの要素で構成されています。この構成要素には、 印刷スプーラ、 印刷プロセッサ、 グラフィック エンジン、 モニタがあります。

印刷スプーラ

印刷インターフェイスの最も重要な構成要素は印刷スプーラです。「印刷スプーラ」とは、 印刷処理を管理するWindows実行可能ファイルです。印刷処理には、 適切なプリンタ ドライバの位置の取得、 そのドライバのロード、 高レベル関数呼び出しからジャーナル レコードへの変換、 ジャーナル レコードのディスク上の印刷ジョブとしての格納などがあります。

スプーラは起動時にロードされ、 オペレーティング システムがシャット ダウンするまで動作し続けます。Windowsプリント マネージャは、 ユーザーやシステム管理者がスプーラにアクセスしたりスプーラを設定するためのグラフィック インターフェイスです。しかし、 プリント マネージャが存在しなかったり終了していても、 スプーラは動作し続けます。

印刷するには、 プリンタ デバイス コンテキスト (DC) を作成します。アプリケーションがプリンタDCを作成すると、 スプーラは、 必要なプリンタ ドライバの特定やロードなど、 必要な作業を実行します。また、 スプーラは、 印刷ジョブの記録に使われるデータ型を判断します。サポートされているデータ型には、 ジャーナル レコード、 ASCIIテキスト、 PostScriptがあります。「印刷ジョブ」とは、 (サポートされているデータ型のいずれかで) 内部的に格納されるドキュメントで、 出力ページを含みます。印刷ジョブは、 複数のページで構成される場合もあります。たとえば、 封筒1つとA4用紙3枚で構成されます。印刷ジョブは、 StartDocEndDocの2つの関数で囲みます。

印刷ジョブのデフォルトのデータ型はジャーナル レコードです。「ジャーナル レコード」とは、 テキスト出力コマンドやラスタ グラフィック コマンドなどを格納するのに使われる小さなデータ構造体です。アプリケーションがStartDoc関数を呼び出すと、 スプーラは、 ジャーナル ファイルとデータ ファイルを作成し、 ジャーナル ファイルにジャーナル レコードを格納し始めます。アプリケーションがGDI描画関数を1つ呼び出すごとに、 新しいジャーナル レコードが1つ以上作成され、 ジャーナル ファイルに格納されます。ジャーナル ファイルとデータ ファイルは、 オペレーティング システム ディレクトリに作成されます。スプーラは、 ジャーナル ファイルにジャーナル レコードを格納し、 用紙の種類や印刷ジョブのデータ型、 出力先プリンタなどをデータ ファイルに記録します。ジョブが正常に印刷されると、 スプーラはこの2つのファイルを削除します。

印刷プロセッサ

スプーラは、 現在の印刷ジョブと出力先プリンタを監視して、 ジョブを印刷する時期を判断します。スプーラは、 ジョブを印刷すべきだと判断すると、 印刷プロセッサを呼び出します。「印刷プロセッサ」とは、 ジャーナル レコードを読み取ってDDI呼び出しに変換するWindows DLLです。

グラフィック エンジン

グラフィック エンジンは、 印刷プロセッサの出力をデバイス ドライバ関数呼び出しに変換します。デバイス ドライバは、 この呼び出しを処理して、 デバイスが処理できる低レベル デバイス コマンドに変換します。

モニタ

デバイス ドライバがジャーナル ファイル全体を低レベル デバイス コマンドに変換すると、 変換されたコマンドのファイルがスプーラに渡されます。スプーラは、 この低レベル コマンドをモニタに送ります。「モニタ」とは、 ネットワークやパラレル ポート、 シリアル ポートなどを通じてデバイスに低レベル デバイス コマンドを渡すWindows DLLです。

プリンタ デバイス コンテキスト

ウィンドウのクライアント領域に描画するにはディスプレイDCが必要なのと同様に、 プリンタに出力を送るには特別なプリンタDCが必要です。プリンタDCは、 ディスプレイDCと同様に、 グラフィック オブジェクトのセットとそれに関連する属性、 出力に影響するグラフィック モードを定義する内部的なデータ構造体です。グラフィック オブジェクトには、 ペン (線描画用)、 ブラシ (ペイントと塗りつぶし用)、 フォント (テキスト出力用) などがあります。

しかし、 プリンタDCは、 ディスプレイDCとは異なり、 ウィンドウ マネージャが所有するものではなく、 GetDC関数で取得することはできません。代わりに、 アプリケーションは、 CreateDC関数かPrintDlg関数を呼び出さなければなりません。アプリケーションは、 CreateDC関数を呼び出すとき、 ドライバ名とポート名を指定しなければなりません。このデータは、 オペレーティング システムの初期化ファイル (.INI) に格納されています。プリンタに関するデータを取得するには、 EnumPrinters関数を使います。

アプリケーションがPRINTDLG構造体のFlagsメンバにPD_RETURNDC定数を設定してPrintDlg関数を呼び出すと、 Windowsは、 ユーザーが選択したプリンタのデバイス コンテキストを識別するハンドルを自動的に返します。この作業を行うコード例については、 [Print]ダイアログ ボックスの表示とプリンタ デバイス コンテキストの取得を参照してください。

プリンタ エスケープ

16ビット版のWindowsでは、 プリンタ エスケープという特別な関数を64個サポートしており、 アプリケーションはプリンタ エスケープを使ってデバイスの特殊機能にアクセスしていました。プリンタ エスケープを呼び出すには、 64個の定義済み定数のいずれかを第2引数に指定してEscape関数を呼び出します。たとえば、 PostScriptプリンタに印刷する場合、 パスと呼ばれるPostScriptグラフィック オブジェクトを描画するには、 BEGIN_PATH定数とEND_PATH定数を指定してEscape関数を呼び出します。Win32 APIでは、 GDIが改良されたため、 このようなエスケープの多くは使われなくなりました。たとえば、 Win32バージョンのGDIは、 任意のデバイスにパスを描画できるパス関数の完全なセットをサポートしています。このため、 以前のプリンタ エスケープの代わりに新しい関数が使われます。

以前の64個のプリンタ エスケープのうち、 Win32 APIでは10個だけがサポートされています。しかし、 Win32 API用に開発されたアプリケーションは、 この10個のうちQUERYESCSUPPORTPASSTHROUGHの2つしか呼び出さないでください。ほかは、 16ビット版のWindows用に作成されたアプリケーションとの互換性を保つためのものです。

サポートされている10個のエスケープを次に示します。

  • ABORTDOC
  • ENDDOC
  • GETPHYSPAGESIZE
  • GETPRINTINGOFFSET
  • GETSCALINGFACTOR
  • NEWFRAME
  • NEXTBAND
  • PASSTHROUGH
  • QUERYESCSUPPORT
  • SETABORTPROC

Win32 APIでは、 以前のEscape関数のほかに、 新しい拡張エスケープ関数ExtEscapeもサポートしています。アプリケーションは、 この関数を使って、 GDIからは直接利用できない特定のデバイスの機能にアクセスできます。

表示と出力のWYSIWYG

通常、 アプリケーションは、 WYSIWYG (“What You See Is What You Get”) 出力をサポートしようとします。WYSIWYGとは、 アプリケーションのウィンドウに10ポイントのHelvetica Boldフォントで描画されたテキストを印刷しても同様に見えることです。完全なWYSIWYG出力の実現は事実上不可能であり、 ほとんどの場合は望ましくない結果になります。この問題の原因の一部は、 ビデオとプリンタの技術の違いにあります。一般に、 画面上の1ピクセルは、 レーザー プリンタの1ドットよりも大きくなっています。また、 視距離も異なります。通常、 コンピュータの画面は50センチメートルほど離れて見ますが、 印刷した紙は30センチメートルの距離から見ます。

画面と印刷ページの読みやすさの違いを補償するため、 Windowsは、 常にピクセル数で指定される論理インチという単位をサポートしています。ビデオ ディスプレイの場合、 大きな視距離と低解像度を補償するため、 論理インチは必ず物理インチよりも大きくなっています。プリンタの場合、 論理インチは常に物理インチと同じです。

テキスト描画時にWYSIWYGを実現するには、 仮想フォント (論理フォント) の書体名とポイント サイズを指定してCreateFont関数を呼び出し、 ディスプレイDCかプリンタDCを指定してSelectObject関数を呼び出してください。アプリケーションがSelectObject関数を呼び出すと、 Windowsは、 指定された論理フォントに最も近い物理フォントを選択します。Windowsは、 ディスプレイ フォントを選択するとき、 実際のポイント サイズよりも大きい物理フォントを選択します。しかし、 ユーザーから見ると、 この方が正しい高さに近いように見えます。Windowsは、 プリンタのフォントを選択するとき、 要求されたポイント サイズどおりの物理フォントを選択します。フォントとテキスト出力について、 詳しくはフォントとテキストの概要を参照してください。

ビットマップ グラフィックを描画するときにWYSIWYGを実現するには、 画面と印刷ページの幅と高さを論理インチ単位で取得してください。この値を使って、 水平と垂直のスケール係数を決定すれば、 ビットマップ イメージをプリンタに描画しても同じ比率を保つことができます。ビットマップとビットマップ出力について、 詳しくはビットマップの概要を参照してください。

印刷関数の使用

ここでは、 テキストとグラフィックを印刷するコード例を示します。このコードは、 .BMPファイルに格納されている16色のビットマップ イメージをユーザーがオープンして表示できるアプリケーションの一部です。

このアプリケーションでは、 ビットマップ イメージを表示するほかに、 プリンタを設定して、 イメージとイメージを含むファイルの位置を示すテキスト文字列を印刷できます。アプリケーションは、 テキストをページのいちばん上に印刷し、 イメージをページの中央に印刷します。

.BMPファイルのオープンと表示

このサンプル アプリケーションでは、 ユーザーは、 ビットマップ イメージを含む.BMPファイルをオープンし、 そのイメージをアプリケーションのクライアント領域に表示できます。ユーザーは、 アプリケーションが表示した[Open]ダイアログ ボックスで、 オープンするファイルを選択できます。([Open]ダイアログ ボックスについて、 詳しくはコモン ダイアログ ボックス ライブラリの概要を参照してください)。

ユーザーがファイルを選択してダイアログ ボックスをクローズすると、 ファイル名とパス名がOPENFILENAME構造体に設定されます。アプリケーションは、 このデータを使って適切なファイルをオープンし、 ビットマップのヘッダーとデータを取得します。次の例は、 このデータを取得するのに必要なコードを示しています。

/* Retrieve a handle identifying the file. */
hfbm = CreateFile(ofn.lpstrFile, GENERIC_READ,
	  FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES) NULL,
	  OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, (HANDLE) NULL);

/* Retrieve the BITMAPFILEHEADER structure. */
ReadFile(hfbm, &bmfh, sizeof(BITMAPFILEHEADER), &dwRead, (LPOVERLAPPED)NULL);

/* Retrieve the BITMAPFILEHEADER structure. */
ReadFile(hfbm, &bmih, sizeof(BITMAPINFOHEADER), &dwRead, (LPOVERLAPPED)NULL);

/* Allocate memory for the BITMAPINFO structure. */
hmem1 = GlobalAlloc(GHND, sizeof(BITMAPINFOHEADER) + ((1<bmiHeader.biSize = bmih.biSize;
lpbmi->bmiHeader.biWidth = bmih.biWidth;
lpbmi->bmiHeader.biHeight = bmih.biHeight;
lpbmi->bmiHeader.biPlanes = bmih.biPlanes;
lpbmi->bmiHeader.biBitCount = bmih.biBitCount;
lpbmi->bmiHeader.biCompression = bmih.biCompression;
lpbmi->bmiHeader.biSizeImage = bmih.biSizeImage;
lpbmi->bmiHeader.biXPelsPerMeter = bmih.biXPelsPerMeter;
lpbmi->bmiHeader.biYPelsPerMeter = bmih.biYPelsPerMeter;
lpbmi->bmiHeader.biClrUsed = bmih.biClrUsed;
lpbmi->bmiHeader.biClrImportant = bmih.biClrImportant;

/*
* Retrieve the color table.
* 1 << bmih.biBitCount == 2 ^ bmih.biBitCount
*/
ReadFile(hfbm, lpbmi->bmiColors, ((1 << bmih.biBitCount) * sizeof(RGBQUAD)), 
		 &dwRead, (LPOVERLAPPED) NULL);

/*
* Allocate memory for the required number of
* bytes.
*/
hmem2 = GlobalAlloc(GHND, (bmfh.bfSize - bmfh.bfOffBits));
lpvBits = GlobalLock(hmem2);

/* Retrieve the bitmap data. */
ReadFile(hfbm, lpvBits, (bmfh.bfSize - bmfh.bfOffBits), 
		 &dwRead, (LPOVERLAPPED) NULL);

/*
* Create a bitmap from the data stored in the
* .BMP file.
*/
hbm = CreateDIBitmap(hdc, &bmih, CBM_INIT, lpvBits, 
					 lpbmi, DIB_RGB_COLORS);

/*
* Unlock the global memory objects and
* close the .BMP file.
*/
GlobalUnlock(hmem1);
GlobalUnlock(hmem2);
CloseHandle(hfbm);

/* Set the fDisplayBitmap flag. */
if (hbm)
	fDisplayBitmap = TRUE;
else
	TextOut(hdc, 100, 100, "LoadBitmap Failed", 17);

/* Paint the window (and draw the bitmap). */
GetClientRect(hwnd, &rect);
InvalidateRect(hwnd, &rect, TRUE);
UpdateWindow(hwnd);

ビットマップ データを取得したら、 そのビットマップ イメージをアプリケーションのクライアント領域内に描画できます。次の例は、 ビットマップの描画に必要なコードを示したものです。

case WM_PAINT:
	BeginPaint(hwnd, &ps);

	if (fDisplayBitmap)
	{
		hdcMem = CreateCompatibleDC(hdc);
		SelectObject(hdcMem, hbm);
		GetObject(hbm, sizeof(BITMAP), (LPSTR) &bm);
		BitBlt(hdc, 0, 0, bmih.biWidth, bmih.biHeight,
			hdcMem, 0, 0, SRCCOPY);
		DeleteDC(hdcMem);
	}

	EndPaint(hwnd, &ps);

	break;
			

[Print]ダイアログ ボックスの表示とプリンタ デバイス コンテキストの取得

印刷の最初の段階では、 プリンタを設定し、 プリンタ デバイス コンテキストを取得します。このサンプル アプリケーションでは、 [File]メニューに、 [Print][Print Setup]の2つのオプションがあります。ユーザーは、 このオプションを選択してプリンタを設定できます。ユーザーが[Print Setup]オプションを選択すると、 [Print Setup]ダイアログ ボックスが表示され、 ユーザーは、 プリンタや用紙の向き、 用紙のサイズなどを選択できます。ユーザーが[Print]オプションを選択すると、 [Print]ダイアログ ボックスが表示され、 ユーザーは、 印刷範囲、 印刷品質、 部数などを設定できます。また、 ユーザーは、 [Setup]プッシュ ボタンを選択して[Print Setup]ダイアログ ボックスを表示できます。

[Print]ダイアログ ボックスや[Print Setup]ダイアログ ボックスを表示するには、 PRINTDLG構造体のメンバを初期化してPrintDlg関数を呼び出します ([Print Setup]ダイアログ ボックスの表示について、 詳しくはコモン ダイアログ ボックス ライブラリの概要を参照してください)。PRINTDLGFlagsメンバにPD_RETURNDCを設定すれば、 PrintDlg関数は、 ユーザーが指定したデータを取得するほかに、 プリンタ デバイス コンテキストも取得します。次のコード例は、 この作業を示しています。

/* Initialize the PRINTDLG members. */
pd.lStructSize = sizeof(PRINTDLG);
pd.hDevMode = (HANDLE) NULL;
pd.hDevNames = (HANDLE) NULL;
pd.Flags = PD_RETURNDC;
pd.hwndOwner = hwnd;
pd.hDC = (HDC) NULL;
pd.nFromPage = 1;
pd.nToPage = 1;
pd.nMinPage = 0;
pd.nMaxPage = 0;
pd.nCopies = 1;
pd.hInstance = (HANDLE) NULL;
pd.lCustData = 0L;
pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL;
pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL;
pd.lpPrintTemplateName = (LPSTR) NULL;
pd.lpSetupTemplateName = (LPSTR) NULL;
pd.hPrintTemplate = (HANDLE) NULL;
pd.hSetupTemplate = (HANDLE) NULL;

/* Display the PRINT dialog box. */
PrintDlg(&pd);
		

印刷の準備

次に示すコード例は、 RASTERCAPSフラグを指定してGetDeviceCaps関数を呼び出すことによって、 選択されているプリンタがビットマップを印刷できるか調べます。この関数の戻り値を調べることによって、 ドキュメントを印刷するか、 デバイスがラスタ出力をサポートしていないことをユーザーに知らせるかを決定します。

/*
* Examine the raster capabilities of the device
* identified by pd.hDC to verify that it supports
* the BitBlt function.
*/
if (!(GetDeviceCaps(pd.hDC, RASTERCAPS) & RC_BITBLT))
{
	DeleteDC(pd.hDC);
	MessageBox(hwnd, "Printer cannot display bitmaps.", "Device Error", MB_OK);
	break;
}

サンプル アプリケーションは、 選択されているプリンタがビットマップの印刷をサポートしていることを調べた後、 次に示す作業を実行します。

1. アプリケーションの印刷中止プロシージャが印刷を続行させるかどうかを判断するのに使うブール値フラグを設定します。

2. アプリケーションの印刷ジョブ中止関数を登録します。

3. モードレスの[Cancel]ダイアログ ボックスを表示します。

4. ダイアログ ボックスが表示されている間、 アプリケーションのウィンドウを使用不能にします。

/*
* Set the flag used by the AbortPrintJob
* dialog procedure.
*/
bPrint = TRUE;

/*
* Register the application's AbortProc
* function with GDI.
*/
SetAbortProc(pd.hDC, AbortProc);

/* Display the modeless Cancel dialog box. */
hdlgCancel = CreateDialog(hinst, (LPTSTR) "AbortDlg", 
	hwnd, (DLGPROC) AbortPrintJob);

/* Disable the application's window. */
EnableWindow(hwnd, FALSE);

アプリケーションが中止プロシージャをWindowsに登録すると、 GDIは、 印刷処理中にそのプロシージャを何度も呼び出して、 ジョブを取り消すかどうか判断します。現在のバージョンのWin32 APIでは、 GDIは、 ジョブ全体がスプールされるまで約2秒おきにこのプロシージャを呼び出します。

ユーザーがジョブの取り消しを選択すると、 GDIは、 スプーラに、 対応するジャーナル ファイルを印刷キューから削除してプリンタをデフォルト状態に戻すように指示します。

中止プロシージャ

印刷をサポートするWindows用アプリケーションは、 ユーザーが印刷ジョブを取り消せるようにするための中止プロシージャとモードレス ダイアログを用意しなければなりません。このサンプル アプリケーションの中止プロシージャには、 モードレス ダイアログ ボックスのメッセージを取得するメッセージ ループがあります。

このプロシージャは、 アプリケーションのモジュール定義ファイルでエクスポートしなければなりません。

[Cancel]ダイアログ ボックス

通常、 [Cancel]ダイアログ ボックスには、 ユーザーが印刷ジョブを取り消すためのプッシュ ボタンが1つあります。次に示す[Cancel]ダイアログ ボックスのテンプレートは、 アプリケーションのリソース ファイルの一部です。

AbortDlg DIALOG LOADONCALL MOVEABLE DISCARDABLE 33, 32, 160, 70
CAPTION "Sample Printing App"
STYLE WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_VISIBLE> |WS_POPUP | WS_SYSMENU

BEGIN
CONTROL "Now Printing: ", IDD_TEXT, "static",SS_CENTER | WS_CHILD, 0, 10, 160, 8
CONTROL "", IDD_FILE, "static",SS_CENTER | WS_CHILD, 0, 25, 160, 8
CONTROL "Cancel", IDD_CANCEL, "button",BS_DEFPUSHBUTTON | WS_TABSTOP | WS_CHILD
60, 45, 45, 15
END

次に示すコード例は、 サンプル アプリケーションのダイアログ ボックス プロシージャです。

LRESULT CALLBACK AbortPrintJob(
	HWND	hwndDlg,		/* window handle of dialog box */
	LPARAM	lParam)		/* message-specific information */
{
	switch (message) 
	{
		case WM_INITDIALOG: /* message: initialize dialog box */
			/* Initialize the static text control. */
			SetDlgItemText(hwndDlg, IDD_FILE, ofn.lpstrFile);
			return TRUE;
	
		case WM_COMMAND:	/* message: received a command */
			/* User pressed "Cancel" button--stop print job. */
			MessageBox(hwndDlg, "Incoming", "WM_COMMAND", MB_OK);
			bPrint = FALSE;
			return TRUE;

		default:
			return FALSE;	/* didn't process a message */
	}

	UNREFERENCED_PARAMETER(lParam);
	UNREFERENCED_PARAMETER(wParam);
	UNREFERENCED_PARAMETER(message);
}

ドキュメントの印刷

アプリケーションは、 必要な変数を初期化して中止プロシージャを登録し、 モードレスの[Cancel]ダイアログ ボックスを表示したら、 StartDoc関数を呼び出して印刷ジョブを開始できます。

アプリケーションは、 印刷ジョブを開始したら、 StartPage関数とEndPage関数の呼び出しの間に適切なGDI関数を呼び出すことによって、 ドキュメントの各ページを定義します。最後のページを定義し終わったら、 EndDoc関数を呼び出して、 ドキュメントをクローズし、 印刷ジョブを終了します。

次の例は、 テキスト文字列とビットマップ イメージの印刷に必要なコードを示しています。ページのいちばん上の中央のテキストは、 ビットマップ イメージを含むファイルのパスとファイル名を示しています。ページの中央のビットマップ イメージは、 アプリケーションのクライアント領域にイメージを描画したときと同じ比率になるように描画されます。

/*
* Initialize the members of a DOCINFO
* structure.
*/
di.cbSize = sizeof(DOCINFO);
di.lpszDocName = "Bitmap Printing Test";
di.lpszOutput = (LPTSTR) NULL;

/*
* Begin a print job by calling the StartDoc
* function.
*/
nError = StartDoc(pd.hDC, &di);

if (nError == SP_ERROR) {
	errhandler("StartDoc", hwnd);
	goto Error;
}

/*
* Inform the driver that the application is
* about to begin sending data.
*/
nError = StartPage(pd.hDC);

if (nError <= 0) {
	errhandler("StartPage", hwnd);
	goto Error;
}

/*
* Retrieve the number of pixels-per-logical-inch
* in the horizontal and vertical directions
* for the display upon which the bitmap
* was created.
*/
fLogPelsX1 = (float) GetDeviceCaps(hdc, LOGPIXELSX);
fLogPelsY1 = (float) GetDeviceCaps(hdc, LOGPIXELSY);

/*
* Retrieve the number of pixels-per-logical-inch
* in the horizontal and vertical directions
* for the printer upon which the bitmap
* will be printed.
*/
fLogPelsX2 = (float) GetDeviceCaps(pd.hDC, LOGPIXELSX);
fLogPelsY2 = (float) GetDeviceCaps(pd.hDC, LOGPIXELSY);

/*
* Determine the scaling factors required to
* print the bitmap and retain its original
* proportions.
*/
if (fLogPelsX1 > fLogPelsX2)
	fScaleX = (fLogPelsX1 / fLogPelsX2);
else
	fScaleX = (fLogPelsX2 / fLogPelsX1);

if (fLogPelsY1 > fLogPelsY2)
	fScaleY = (fLogPelsY1 / fLogPelsY2);
else
	fScaleY = (fLogPelsY2 / fLogPelsY1);

/*
* Compute the coordinate of the upper left
* corner of the centered bitmap.
*/
cWidthPels = GetDeviceCaps(pd.hDC, HORZRES);
xLeft = ((cWidthPels / 2) -
		 ((int) (((float) bmih.biWidth) * fScaleX)) / 2);
cHeightPels = GetDeviceCaps(pd.hDC, VERTRES);
yTop = ((cHeightPels / 2) -
		((int) (((float) bmih.biHeight) * fScaleY)) / 2);

/*
* Create a memory DC that is compatible with
* the printer and select the bitmap (which
* the user requested) into this DC.
*/
hdcMem = CreateCompatibleDC(pd.hDC);

if (!SelectObject(hdcMem, hbm))
	errhandler("SelectObject Failed", hwnd);

/*
* Use the StretchBlt function to scale the
* bitmap and maintain its original proportions
* (that is, if the bitmap was square when it
* appeared in the application's client area,
* it should also appear square on the page).
*/
if (!StretchBlt(pd.hDC, xLeft, yTop,
	(int) ((float) bmih.biWidth * fScaleX),
	(int) ((float) bmih.biHeight * fScaleY),
	hdcMem, 0, 0,
	bmih.biWidth, bmih.biHeight, SRCCOPY))

	errhandler("StretchBlt Failed", hwnd);

/* Delete the memory DC. */
DeleteDC(hdcMem);

/*
* Retrieve the width of the string that
* specifies the full path and filename for the
* file that contains the bitmap.
*/
GetTextExtentPoint32(pd.hDC, ofn.lpstrFile,
	ofn.nFileExtension + 3, &szMetric);

/*
* Compute the starting point for the
* text-output operation. The string will
* be centered horizontally and positioned
* three-lines down from the top of the page.
*/
xLeft = ((cWidthPels / 2) - (szMetric.cx / 2));
yTop = (szMetric.cy * 3);

/*
* Print the path and filename for the bitmap,
* centered at the top of the page.
*/
TextOut(pd.hDC, xLeft, yTop, ofn.lpstrFile,
		ofn.nFileExtension + 3);

/*
* Determine whether the user has pressed
* the Cancel button in the AbortPrintJob
* dialog box; if the button has been pressed,
* call the AbortDoc function. Otherwise, inform
* the spooler that the page is complete.
*/
nError = EndPage(pd.hDC);

if (nError <= 0) {
	errhandler("EndPage", hwnd);
	goto Error;
}

/* Inform the driver that the document has ended. */
nError = EndDoc(pd.hDC);

if (nError <= 0) {
	errhandler("EndDoc", hwnd);
}

Error:
/* Enable the application's window. */
EnableWindow(hwnd, TRUE);

/* Remove the AbortPrintJob dialog box. */
DestroyWindow(hdlgCancel);

/* Delete the printer DC. */
DeleteDC(pd.hDC);

通常、 画面上のピクセルの寸法はプリンタのドットの寸法とは異なるため、 WYSIWYG出力を実現するには、 ビットマップ イメージをスケール変更しなければなりません。WYSIWYGを実現するには、 まず、 水平と垂直のスケール係数を取得し、 ビットマップ関数のStretchBltに渡す幅と高さの値にこの係数を適用します。このサンプル アプリケーションでは、 2つのデバイスの水平と垂直の論理ピクセル数を取得して、 このスケール係数を計算しています。スケール係数を計算したら、 その値を使ってビットマップの幅と高さを調整します。

ビットマップをページの中央に置くため、 まず、 スケール変更したビットマップの幅と高さを計算します (イメージの元の比率を保つため、 ビットマップをスケール変更します)。この値を2で割って、 ページの幅や高さの半分からその値を引くと、 ビットマップの左上隅の座標になります。

テキストをページのいちばん上に置くため、 GetTextExtentPoint32関数を呼び出して、 パス名とファイル名を示す文字列の幅と高さを取得します。それから、 高さの値を使ってページのいちばん上から3行目に文字列を置き、 幅の値を使ってページの中央に文字列を置きます。

次の図は、 ファイルWINLOGO.BMPにあるビットマップ化されたイメージを出力したときに表示されるページを表しています。また、 この図は、 テキストを配置するために使う変数と、 ビットマップを配置したりスケーリングするために使う変数を示しています。

 

印刷と印刷スプーラの関数

印刷に関する関数を次に示します。

関数

  • AbortDoc
  • DeviceCapabilities
  • EndDoc
  • EndPage
  • Escape
  • ExtEscape
  • SetAbortProc
  • StartDoc
  • StartPage

印刷スプーラのアクセスに使われる関数を次に示します。

  • AbortPrinter
  • AbortProc
  • AddForm
  • AddJob
  • AddMonitor
  • AddPort
  • AddPrinter
  • AddPrinterDriver
  • AddPrintProcessor
  • AddPrintProvidor
  • AdvancedDocumentProperties
  • ClosePrinter
  • ConfigurePort
  • ConnectToPrinterDlg
  • DeleteForm
  • DeleteMonitor
  • DeletePort
  • DeletePrinter
  • DeletePrinterConnection
  • DeletePrinterDriver
  • DeletePrintProcessor
  • DeletePrintProvidor
  • DocumentProperties
  • EndDocPrinter
  • EndPagePrinter
  • EnumForms
  • EnumJobs
  • EnumMonitors
  • EnumPorts
  • EnumPrinterDrivers
  • EnumPrinters
  • EnumPrintProcessorDataTypes
  • EnumPrintProcessors
  • FindClosePrinterChangeNotification
  • FindFirstPrinterChangeNotification
  • FindNextPrinterChangeNotification
  • GetForm
  • GetJob
  • GetPrinter
  • GetPrinterData
  • GetPrinterDriver
  • GetPrinterDriverDirectory
  • GetPrintProcessorDirectory
  • OpenPrinter
  • PrinterMessageBox
  • PrinterProperties
  • ReadPrinter
  • ScheduleJob
  • SetForm
  • SetJob
  • SetPrinter
  • SetPrinterData
  • StartDocPrinter
  • StartPagePrinter
  • WaitForPrinterChange
  • WritePrinter

メッセージ

  • WM_SPOOLERSTATUS

▲ページトップに戻る

【本を読んでもよくらからない】 … 個別指導でわかりやすくお教えします