プリンタの設定


印刷ダイアログ

Win32 API を用いれば、名前から、プリンタのデバイスコンテキストのハンドルを得られますが
使用可能なプリンタの名前を列挙し、これを用いるのは面倒な作業です
列挙したプリンタの中から、ユーザーにどのプリンタを用いるのかを選択させるとなると
専用のダイアログなどを生成する必要があり、これだけでも作業は複雑です

そこで、プリンタのデバイスコンテキストを得るには、一般的にコモンダイアログを用います
印刷ダイアログを作成するには PrintDlg() 関数を用います

BOOL PrintDlg(LPPRINTDLG lppd);

lppd には、初期化情報を格納した PRINTDLG 構造体へのポインタを指定します
ユーザーが OK ボタンを押せば 0 以外、そうでなければ 0 が返ります

PRINTDLG 構造体は次のように定義されています
typedef struct tagPD {  // pd 
    DWORD     lStructSize; 
    HWND      hwndOwner; 
    HANDLE    hDevMode; 
    HANDLE    hDevNames; 
    HDC       hDC; 
    DWORD     Flags; 
    WORD      nFromPage; 
    WORD      nToPage; 
    WORD      nMinPage; 
    WORD      nMaxPage; 
    WORD      nCopies; 
    HINSTANCE hInstance; 
    DWORD     lCustData; 
    LPPRINTHOOKPROC lpfnPrintHook; 
    LPSETUPHOOKPROC lpfnSetupHook; 
    LPCTSTR    lpPrintTemplateName; 
    LPCTSTR    lpSetupTemplateName; 
    HANDLE    hPrintTemplate; 
    HANDLE    hSetupTemplate; 
} PRINTDLG;
lStructSize には、この構造体のサイズを指定します
hwndOwner には、ダイアログボックスの親ウィンドウを指定します

hDevMode には、DEVMODE 構造体を格納するメモリオブジェクトを指定します
この値は、関数を呼び出す時はダイアログの初期化情報として用いられ
ユーザーが設定を終了した後は、ダイアログで設定された情報が格納されています
DEVMODE のメモリオブジェクトの生成には GlobalAlloc() 関数を用いてください
このメンバに NULL を指定すれば、PrintDlg() 関数がてメモリを割り当ててくれます

hDevName には、DEVNAMES 構造体を格納するメモリオブジェクトを指定します
DEVNAMES 構造体については、すぐ後で説明いたします
このメンバは初期化に用いられ、ダイアログが閉じられれば設定情報が格納されています

hDC には、プリンタのデバイスコンテキスト、または情報コンテキストが格納されます
Flags メンバで PD_RETURNDC が設定されていればデバイスコンテキストが
PD_RETURNIC が設定されていれば、情報コンテキストが格納されます

Flags はダイアログの初期化フラグを指定します
このメンバには、以下の定数の組み合わせを指定することができます

定数解説
PD_ALLPAGES 「すべて」ボタンが選択された
PD_COLLATE 入力時に「部単位で印刷」チェックボックスがセットされる
PrintDlg() 関数が戻った後では、ユーザーが「部単位で印刷」を選択したが
プリンタドライバが部単位の印刷をサポートしていないことを表す
PD_DISABLEPRINTTOFILE 「ファイルへ出力」チェックボックスを無効にする1
PD_ENABLEPRINTHOOK lpfnHook で指定されたフック関数を有効にする
PD_ENABLEPRINTTEMPLATE hInstance が lpPrintTemplateName メンバで指定された
ダイアログテンプレートを含むリソースのインスタンスであることを示す
PD_ENABLEPRINTTEMPLATEHANDLE hPrintTemplate メンバがロード済みのダイアログボックステンプレートを含む
メモリブロックを指していることを表す
このフラグが指定されている場合、lpPrintTemplateName は無視される
PD_ENABLESETUPHOOK lpfnSetupHook で指定されたフック関数を有効にする
PD_ENABLESETUPTEMPLATE hInstance および lpSetupTemplateName で指定された
ダイアログボックステンプレートを使用することを示す
PD_ENABLESETUPTEMPLATEHANDLE hSetupTemplate メンバがロード済みのダイアログボックステンプレートを含む
メモリブロックを指していることを表す
このフラグが指定されている場合、lpSetupTemplateName は無視される
PD_HIDEPRINTTOFILE 「ファイルへ出力」チェックボックスを隠す
PD_NONETWORKBUTTON 「ネットワーク」ボタンを無効にする
PD_NOPAGENUMS 「ページ設定」ボタンと関連する編集コントロールを無効にする
PD_NOSELECTION 「選択した部分」ボタンを無効にする
PD_NOWARNING デフォルトプリンタがない場合に、警告を表示しない
PD_PAGENUMS 「ページ設定」ボタンが選択された状態であることを示す
PD_PRINTSETUP 「印刷」ダイアログボックスではなく
「プリンタの設定」ダイアログボックスを表示する
PD_PRINTTOFILE 「ファイルへ出力」チェックボックスがチェック状態であることを示す
PD_RETURNDC hDC にデバイスコンテキストを格納することを表す
PD_RETURNDEFAULT ダイアログを表示せず、システム設定のデフォルトプリンタで初期化する
DEVMODE と DEVNAMES 構造体は NULL でなければならない
PD_RETURNIC hDC に情報コンテキストを格納することを表す
PD_SELECTION 「選択した部分」ボタンが選択されていることを示す
PD_SHOWHELP 「ヘルプ」ボタンを表示する
この値が設定される場合、親ウィンドウを持たなければなりません
PD_USEDEVMODECOPIES PD_USEDEVMODECOPIESANDCOLLATE と同じ
PD_USEDEVMODECOPIESANDCOLLATE プリンタドライバが複数部印刷をサポートしていない場合
「部数」編集コントロールを無効にする
部単位印刷をサポートしていない場合は
「部単位で印刷」チェックボックスを無効にする

nFromPage は開始ページ、nToPage は終了ページ番号を指定します
ダイアログ表示時は初期化に用いられ、設定後はその値が格納されます

nMinPage は、開始、終了ページの各編集コントロールで指定された
ページ範囲に対する最小値、nMaxPage は最大値です

nCopies は、hDevMode が NULL の場合「部数」編集コントロールに対する初期値です
ダイアログが閉じられると、このメンバには実際の印刷部数が格納されます
プリンタが複数部印刷をサポートしていなくても、1以上の値を設定することができ
この場合は、アプリケーションが要求された部数を印刷しなければなりません

hInstance には、ダイアログテンプレートを格納するモジュールのインスタンスハンドルを指定します
lCustData はフック関数に渡す追加情報を指定します
lpfnPrintHook は「印刷」ダイアログボックスのフック関数へのポインタを
lpfnSetupHook は「プリンタの設定」ダイアログボックスのフック関数のポインタを指定します

lpPrintTemplateName には、「印刷」ダイアログボックステンプレートの名前を
lpSetputTemplateName には、「プリンタの設定」ダイアログボックステンプレートの名前を指定します

hPrintTemplate は、デフォルトの「印刷」ダイアログボックステンプレートの代わりに用いる
ロード済みのダイアログボックステンプレートを格納するメモリオブジェクトを、
hSetuptTemplate は、「プリンタの設定」ダイアログボックステンプレートの代わりに用いる
ロード済みのダイアログボックステンプレートを格納するメモリオブジェクトを指定します

プリンタの名前は hDevMode メモリオブジェクトをロックしてポインタを取得すれば
DEVMODE 構造体から得ることができますが
デバイスドライバのファイル名や出力ポート名を取得したい場合は hDevNames メンバの
DEVNAMES 構造体を用いて文字列を取得します
typedef struct tagDEVNAMES { // dvnm 
    WORD wDriverOffset; 
    WORD wDeviceOffset; 
    WORD wOutputOffset; 
    WORD wDefault; 
} DEVNAMES;
この構造体は、面白いことに文字列型のメンバを含んでいません
実は、構造体のメンバは文字列の位置を表す情報を格納しています
実際の文字列は、構造体の先頭アドレスからメンバ値を加算した位置に存在します

wDriverOffset は、デバイスドライバのファイル名を表す文字列へのオフセットアドレス
wDeviceOffset は、デバイスの名前を表す文字列へのオフセットアドレス
wOutputOffset は、出力ポートのデバイス名をあらわす文字列へのオフセットアドレスです

wDefault は、DEVNAMES 構造体の文字列がデフォルトのプリンターかどうかを表します
DN_DEFAULTPRN が指定されていれば、デフォルトプリンタが選択されています
特定のプリンタが選択されていれば、フラグは使われません
これ以外のフラグは、ダイアログプロシージャ内部で用いる予約されたフラグです
#include <windows.h>
#define TITLE TEXT("Kitty on your lap")

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	HDC hdc;
	PAINTSTRUCT ps;
	BCHAR *strName;
	static PRINTDLG pd;

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		pd.lStructSize = sizeof (PRINTDLG);
		pd.hwndOwner = hWnd;
		pd.Flags = PD_RETURNDC;
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hWnd , &ps);
		if (pd.hDevMode) {
			strName = (BCHAR *)GlobalLock(pd.hDevMode);
			TextOut(hdc , 0 , 0 , strName , lstrlen(strName));
			GlobalUnlock(pd.hDevMode);
		}
		EndPaint(hWnd , &ps);
		return 0;
	case WM_RBUTTONUP:
		PrintDlg(&pd);
		InvalidateRect(hWnd , NULL , TRUE);
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow ) {
	HWND hwnd;
	MSG msg;
	WNDCLASS winc;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return -1;

	hwnd = CreateWindow(
			TEXT("KITTY") , TITLE ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL , hInstance , NULL
	);

	if (hwnd == NULL) return -1;

	while(GetMessage(&msg , NULL , 0 , 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}


プログラムを起動して、クライアント領域を右クリックすると
上の図のような印刷ダイアログボックスが表示されます
このダイアログで設定した DEVMODE 構造体の設定情報を用いて
PRINTDLG 構造体の hDC メンバを用いれば、選択したプリンタに印刷することも可能です


ページ設定

印刷ダイアログではなく、用紙サイズや余白のサイズなどを設定する
ページ設定ダイアログボックスを表示するには PageSetupDlg() を使います

BOOL PageSetupDlg(LPPAGESETUPDLG lppsd);

lppsd には、初期化情報を格納した PAGESETUPDLG 構造体へのポインタを指定します
ユーザーが OK ボタンを押せば 0 以外、そうでなければ 0 が返ります

PAGESETUPDLG 構造体は次のように定義されています
typedef struct tagPSD {  // psd 
    DWORD           lStructSize; 
    HWND            hwndOwner; 
    HGLOBAL         hDevMode; 
    HGLOBAL         hDevNames; 
    DWORD           Flags; 
    POINT           ptPaperSize; 
    RECT            rtMinMargin; 
    RECT            rtMargin; 
    HINSTANCE       hInstance; 
    LPARAM          lCustData; 
    LPPAGESETUPHOOK lpfnPageSetupHook; 
    LPPAGEPAINTHOOK lpfnPagePaintHook; 
    LPCTSTR         lpPageSetupTemplateName; 
    HGLOBAL         hPageSetupTemplate; 
} PAGESETUPDLG, * LPPAGESETUPDLG;
lStructSize には、この構造体のサイズを指定します
hwndOwner は、ダイアログボックスの親ウィンドウのハンドルを指定します

hDevMode は、DEVMODE 構造体を格納するメモリオブジェクトを、
hDevName には、DEVNAMES 構造体を格納するメモリオブジェクトを指定します
これらのメンバは、PRINTDLG 構造体と同じです

Flags には、ダイアログの初期化情報を示す定数を指定します
このメンバには、以下の定数の組み合わせを指定することができます

定数解説
PSD_DEFAULTMINMARGINS デフォルトの最小余白値を使用する
PSD_DISABLEMARGINS 余白を無効にする
PSD_DISABLEORIENTATION 印刷の向きを無効にする
PSD_DISABLEPAGEPAINTING ページ設定プレビューを無効にする
PSD_DISABLEPAPER 用紙の設定を無効にする
PSD_DISABLEPRINTER 「プリンタ」ボタンを無効にする
PSD_ENABLEPAGEPAINTHOOK lpfnPagePaintHook で指定されたフック関数を有効にする
PSD_ENABLEPAGESETUPHOOK lpfnPageSetupHook で指定されたフック関数を有効にする
PSD_ENABLEPAGESETUPTEMPLATE hInstance と lpPageSetupTemplateName で指定された
ダイアログボックステンプレートを用いて作成する
PSD_ENABLEPAGESETUPTEMPLATEHANDLE lPageSetupTemplate がロード済みの
ダイアログボックステンプレートを格納する
データブロックを指すことを示す
PSD_INHUNDREDTHSOFMILLIMETERS 1/100 ミリメートルを測定単位とする
PSD_INTHOUSANDTHSOFINCHES 1/1000 インチを測定単位とする
PSD_INWININIINTLMEASURE 実装されない
PSD_MARGINS 初期余白値を rMargin メンバの値に設定する
PSD_MINMARGINS 最小余白値を rMinMargin メンバの値に設定する
PSD_NONETWORKBUTTON 「ネットワーク」ボタンを隠して無効にする
PSD_NOWARNING エラーメッセージを表示しない
PSD_RETURNDEFAULT 「ページ設定」ダイアログボックスを表示せず
デフォルトプリンタに関する情報を取得する
PSD_SHOWHELP 「ヘルプ」ボタンを表示する
この場合、ダイアログは親ウィンドウを持たなければならない

ptPaperSize は、プリンタページの幅と高さが入る POINT 構造体です
rtMinMargin は、上下左右の最小余白値を指定するための RECT 構造体です
PSD_MINMARGINS を設定する場合、このメンバに値を指定します

rtMargin には、上下左右の余白値が格納される RECT 構造体です
ダイアログはこの値で初期化され、閉じた時に設定された情報が格納されます

hInstance は、ダイアログボックステンプレートを用いる場合に
ダイアログボックステンプレートを格納するモジュールのインスタンスハンドルを指定します

lCustData はフック関数に渡す追加情報を指定します
lpfnPageSetupHook は、「ページ設定」ダイアログのフック関数へのポインタを、
lpfnPagePaintHook は、プレビューの描画処理を行うフック関数へのポインタを指定します

lpPageSetupTemplateName は、使用するダイアログボックステンプレートの名前を指定します
lpPageSetupTemplate は、ダイアログボックステンプレートがロード済みの場合に
ダイアログボックステンプレートを格納するメモリオブジェクトを指定します
#include <windows.h>
#define TITLE TEXT("Kitty on your lap")

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rect;
	static TCHAR strText[1024] = "";
	static PAGESETUPDLG psd;

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		psd.lStructSize = sizeof (PAGESETUPDLG);
		psd.hwndOwner = hWnd;
		psd.Flags = PSD_INTHOUSANDTHSOFINCHES;
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hWnd , &ps);
		GetClientRect(hWnd , &rect);
		DrawText(hdc , strText , -1 , &rect , DT_LEFT);
		EndPaint(hWnd , &ps);
		return 0;
	case WM_RBUTTONUP:
		PageSetupDlg(&psd);
		wsprintf(strText , TEXT("width=%d\nheight=%d\nMargin=%d,%d,%d,%d") ,
			psd.ptPaperSize.x , psd.ptPaperSize.y ,
			psd.rtMargin.left , psd.rtMargin.top ,
			psd.rtMargin.right , psd.rtMargin.bottom);
		InvalidateRect(hWnd , NULL , TRUE);
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow ) {
	HWND hwnd;
	MSG msg;
	WNDCLASS winc;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return -1;

	hwnd = CreateWindow(
			TEXT("KITTY") , TITLE ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL , hInstance , NULL
	);

	if (hwnd == NULL) return -1;

	while(GetMessage(&msg , NULL , 0 , 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}


このプログラムを実行して、ウィンドウのクライアント領域を右クリックすれば
上の図のようなページ設定ダイアログボックスが出現します
それぞれの項目を設定して OK ボタンを押せば、ページサイズと余白のサイズが
1/1000 インチ単位でウィンドウのクライアント領域に表示されます


PrintDlg()

BOOL PrintDlg(LPPRINTDLG lppd);

印刷ダイアログボックスを表示します

lppd - 初期化情報を格納した PRINTDLG 構造体へのポインタを指定します

戻り値 - ユーザーが OK ボタンを押せば 0 以外、そうでなければ 0

PageSetupDlg()

BOOL PageSetupDlg(LPPAGESETUPDLG lppsd);

ページ設定ダイアログボックスを表示します

lppsd - 初期化情報を格納した PAGESETUPDLG 構造体へのポインタを指定します

戻り値 - ユーザーが OK ボタンを押せば 0 以外、そうでなければ 0



前のページへ戻る次のページへ