第297章 ネットワークプリンタを使う その1


パソコンの環境もいろいろ変化してきました。個人でLANを組んで プリンタをネットワーク・プリンタとして利用している人も少なくないでしょう。 さて、今まで解説してきた方法ではうまく印刷されないことも多々見られるようになってきました。

第77章からの方法ではwin.iniに記載のないコンピュータでは 無効です。また、第136章からの方法はEnumPrinters関数を使っていますが、 いろいろ問題が生じます。不思議なことにEnumPrinters関数はコンソール・アプリケーションで使う場合と SDKのプログラムの中で使う場合で結果が異なることもあります。また、ここの章ではPRINTER_INFO_5 構造体を使っていますが、これはNT/2000ではサポートされていません。

今回は、Windows95/98, NT/2000でも、ローカル・プリンタでもネットワーク・プリンタでも印刷できる ようにしてみます。



一番簡単な方法はPrintDlg関数を用いて、プリンタのデバイスコンテキストハンドルを取得することです。

BOOL PrintDlg( LPPRINTDLG lppd );

この関数を実行すると「印刷ダイアログ」ボックスが現れます。 ユーザーが「印刷」ボタンを押すと関数はTRUEを返します。

lppdは、PRINTDLG構造体へのポインタを指定します。 この構造体は、次のように定義されています。

typedef struct tagPD { DWORD lStructSize; HWND hwndOwner; HGLOBAL hDevMode; HGLOBAL hDevNames; HDC hDC; DWORD Flags; WORD nFromPage; WORD nToPage; WORD nMinPage; WORD nMaxPage; WORD nCopies; HINSTANCE hInstance; LPARAM lCustData; LPPRINTHOOKPROC lpfnPrintHook; LPSETUPHOOKPROC lpfnSetupHook; LPCTSTR lpPrintTemplateName; LPCTSTR lpSetupTemplateName; HGLOBAL hPrintTemplate; HGLOBAL hSetupTemplate; } PRINTDLG, *LPPRINTDLG;

lStructSizeには、この構造体のサイズを指定します。

hwndOwnerには、ダイアログボックスを所有しているウィンドウのハンドルを 指定します。オーナーがない場合はNULLでもかまいません。

hDevModeには、DEVMODE構造体を含んでいるグローバルメモリオブジェクトのハンドルを 指定します。NULLを指定しない場合は、自分でDEVMODE構造体をメモリブロックにアロケートして そのメンバを初期化しなくてはなりません。

hDevNamesには、DEVNAMES構造体を含んだグローバルメモリオブジェクトのハンドルを 指定します。NULLを指定しないときは、自分でメモリブロックをアロケートして、構造体の メンバを初期化しなくてはなりません。

hDCには、デバイスコンテキストまたは、インフォーメーションコンテキストのハンドルが格納されます。 どちらが格納されるかはFlagsメンバの値によります。この値がPD_RETURNDCならば前者が、PD_RETURNICなら 後者が格納されます。どちらも指定しないとこの値は不定です。両方指定するとPD_RETURNDCが優先されます。

Flagsには、印刷ダイアログボックスを初期化するために使われるビットフラグのセットを指定します。次の組み合わせ で指定します。

PD_ALLPAGES「すべて」ラジオボタンが選択された状態となります。
PD_PAGENUMSとPD_SELECTIONフラグが指定されていないことを示すプレースホルダとして使われます。
PD_COLLATEこのフラグがセットされると「部単位で印刷」チェックボックスが選択されます。
このフラグがセットされているとPrintDlg関数が戻ってきたときに、アプリケーションは複数コピーの 「部単位で印刷」をシミュレートしなくてはなりません。
PD_DISABLEPRINTTOFILE「ファイルへ出力」のチェックボックスを使用不可にします。
PD_ENABLEPRINTHOOKlpfnPrintHookメンバで指定されたフックプロシージャを使用可能にします。
これは、印刷ダイアログボックスのプロシージャをフック可能にします。
PD_ENABLEPRINTTEMPLATEデフォルトの印刷ダイアログテンプレートに代わってhInstanceと lpPrintTemplateNameで指定されたテンプレートが使われます。
PD_ENABLEPRINTTEMPLATEHANDLEhPrintTemplateがダイアログボックステンプレートの データブロックのハンドルであることを示します。
このテンプレートは印刷ダイアログボックスの デフォルトのテンプレートに置き換わります。
システムはlpPrintTemplateNameを無視します。
PD_ENABLESETUPHOOKlpfnSetupHookメンバに指定されたフックプロシージャが使用可能となります。
PD_ENABLESETUPTEMPLATEhInstance と lpSetupTemplateName メンバで指定されたテンプレートが 印刷セットアップダイアログボックスのテンプレートにとってかわります。
PD_ENABLESETUPTEMPLATEHANDLEhSetupTemplateメンバがダイアログボックスのテンプレートの データブロックを示すことを表します。
システムはlpSetupTemplateNameメンバを無視します。
PD_HIDEPRINTTOFILE「ファイルへ出力」チェックボックスを隠します。
PD_NONETWORKBUTTON「ネットワーク」ボタンを隠します。
PD_NOPAGENUMS「ページ」ラジオボタンとそのエディットコントロールを使用不可にします。
PD_NOSELECTION「選択した部分」ラジオボタンを使用不可にします。
PD_NOWARNINGデフォルトプリンタがないときに現れる警告メッセージを出さないようにします。
PD_PAGENUMS「ページ指定」ラジオボタンが選択されます。
PrintDlg関数が戻ってきたときに、nFromPageとnTopPageメンバにユーザの指定したページが格納されます。
PD_PRINTSETUP印刷セットアップダイアログボックスが現れます。
PD_PRINTTOFILE「ファイルへ出力」チェックボックスが選択されます。
このフラグがセットされていると、PrintDlg関数が戻ってきたときに、"FILE:"という文字列を含んだ、DEVNAMES構造体の wOutputOffsetメンバにオフセットが指定されます。
PD_RETURNDCユーザーがダイアログボックスで選択した機械のデバイスコンテキストがhDCメンバに返されます。
PD_RETURNDEFAULTダイアログボックスは表示されません。hDevNameやhDevModeメンバに デフォルトプリンタに初期化されたDEVMODE構造体や、DEVNAMES構造体のハンドルがセットされます。
PD_RETURNIChDCにインフォーメーションコンテキストのハンドルが返されます。
PD_SELECTION「選択した部分」チェックボックスが選択されます。
もし、PD_PAGENUMSもPD_SELECTIONもセットされなければ、「すべて」ラジオボタンが選択されます。
PD_SHOWHELPヘルプボタンが表示されます。
PD_USEDEVMODECOPIESPD_USEDEVMODECOPIESANDCOLLATEと同じです。
PD_USEDEVMODECOPIESANDCOLLATEアプリケーションが複数コピーと「部単位で印刷」をサポートするかどうかを 指定します。
もし、このフラグがセットされると複数コピーと「部単位で印刷」はサポートされません。この場合nCopiesメンバは1になります。 もし、このフラグがセットされているとアプリケーションは「部単位で印刷」に反応しなくてはいけません。

nFromPage には、スタートページの初期値をセットします。PrintDlg関数が戻ってきたときに、nFromPageには ユーザーが指定したスタートページの値がセットされます。

nToPageには、最後のページの初期値を指定します。PrintDlg関数が戻ってきたときにユーザーが指定した 最後のページが格納されます。

nMinPageには、ページ範囲の最小値を指定します。これとnMaxPageが等しいときは「ページ指定」ラジオボタンと 始まりと終わりのページを入力するエディットコントロールが使用不可です。

nMaxPageには、ページエディットコントロールの最大値を指定します。

nCopiesには、印刷部数の初期値を指定します。PrintDlg関数が戻ってきたときには、印刷すべき部数が格納されます。

hInstanceには、もしPD_ENABLEPRINTTEMPLATE または、PD_ENABLESETUPTEMPLATE フラグがセットされている場合は、 アプリケーションまたはモジュールのインスタンスハンドルを指定します。

lCustDataには、フック関数に渡すアプリケーション定義のデータを指定します。フックプロシージャでは WM_INITDIALOGメッセージが来たときのlParamで受け取ることができます。

lpfnPrintHookには、フックプロシージャのポインタを指定します。PD_ENABLEPRINTHOOKフラグがセットされていないと 無視されます。

lpfnSetupHookには、フックプロシージャのポインタを指定します。PD_ENABLESETUPHOOKフラグがセットされていないと 無視されます。

lpPrintTemplateNameには、ダイアログボックステンプレートの名前を指定します。PD_ENABLEPRINTTEMPLATE フラグが セットされていないと無視されます。

lpSetupTemplateNameには、ダイアログボックステンプレートの名前を指定します。PD_ENABLESETUPTEMPLATE フラグが セットされていないと無視されます。

hPrintTemplateには、もし、PD_ENABLEPRINTTEMPLATEHANDLE がセットされているときは、 ダイアログボックステンプレートのメモリオブジェクトのハンドルを指定します。

hSetupTemplateには、もしPD_ENABLESETUPTEMPLATEHANDLEがセットされているときは、 ダイアログボックステンプレートのメモリオブジェクトのハンドルを指定します。

ま、結局PRINTDLG構造体に必要なものをセットしてPrintDlg関数を呼べばよい、ということです。 今回は、単に印刷ができるということが主眼なので、非常に簡単なプログラムを作ってみました。

メニューから「印刷」を選択すると左の図のようなダイアログボックスが表示されます。 今回はページ指定や部数は指定できません。表示されているプリンタは2台とも ネットワークプリンタですが、もちろんローカルプリンタも選択できます。



// printer00.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END MENUITEM "印刷(&P)...", IDM_PRINT END END

メニューのリソース・スクリプトです。

// printer00.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); char szClassName[] = "printer00"; //ウィンドウクラス HINSTANCE hInst; DWORD dwFlags; int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; hInst = hCurInst; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst;//インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるプリンタ", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }

いつもと同じです。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id, i; HPEN hPen; PRINTDLG pd; DOCINFO di; TEXTMETRIC tm; char *szStrOrg = "This is a test print--Line(%02d)"; char szStr[128]; char *szLine = "******************************"; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_PRINT: memset(&pd, 0, sizeof(PRINTDLG)); pd.lStructSize = sizeof(PRINTDLG); pd.hwndOwner = hWnd; pd.hDevMode = NULL; pd.hDevNames = NULL; pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION | PD_HIDEPRINTTOFILE; pd.nCopies = 1; pd.nFromPage = 1; pd.nToPage = 1; pd.nMinPage = 1; pd.nMaxPage = 1; memset(&di, 0, sizeof(DOCINFO)); di.cbSize = sizeof(DOCINFO); di.lpszDocName = "TEST PRINT"; if (PrintDlg(&pd)==TRUE) { StartDoc(pd.hDC, &di); StartPage(pd.hDC); GetTextMetrics(pd.hDC, &tm); for (i = 1; i <= 20; i += 2) { wsprintf(szStr, szStrOrg, i); TextOut(pd.hDC, 100, tm.tmHeight * i, szStr, strlen(szStr)); TextOut(pd.hDC, 100, tm.tmHeight * (i + 1), szLine, strlen(szLine)); } hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0)); SelectObject(pd.hDC, hPen); MoveToEx(pd.hDC, 100, tm.tmHeight, NULL); LineTo(pd.hDC, tm.tmAveCharWidth * strlen(szLine) + 100, tm.tmHeight); LineTo(pd.hDC, tm.tmAveCharWidth * strlen(szLine) + 100, tm.tmHeight * 21); LineTo(pd.hDC, 100, tm.tmHeight * 21); LineTo(pd.hDC, 100, tm.tmHeight); EndPage(pd.hDC); EndDoc(pd.hDC); DeleteObject(hPen); DeleteDC(pd.hDC); } } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

親ウィンドウのプロシージャです。

メニューから「印刷」が選択されるとPRINTDLG構造体に必要事項をセットして PrintDlg関数を呼びだしてプリンタのデバイスコンテキストハンドルを取得しています。 デバイスコンテキストハンドルさえ取得できれば、あとは今までと同じです。



左の図は実際に印刷したものです。



プリンタのデフォルトのフォントによっては左の図のように印刷されることもあります。




[SDK第3部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 05/Jan/2001 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。