メニューのリソース・スクリプトです。// printer01.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "ページ設定(&U)...", IDM_SETPAGE MENUITEM "印刷(&P)...", IDM_PRINT MENUITEM SEPARATOR MENUITEM "終了(&X)", IDM_END END END
いつもと同じですが、テスト印刷の部分を独立した関数にしてみました(MyPrint関数)。// printer01.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); BOOL MyPrint(HWND); BOOL MyPageSet(HWND); char szClassName[] = "printer01"; //ウィンドウクラス 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; }
親ウィンドウのプロシージャです。メニューからIDM_PRINTが選択されたらMyPrint関数を、IDM_SETPAGEが 選択されたらMyPageSet関数を呼びます。//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_PRINT: MyPrint(hWnd); break; case IDM_SETPAGE: MyPageSet(hWnd); break; } 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; }
印刷を実行する関数です。第297章では、親ウィンドウのプロシージャに直接書いていましたが 独立した関数にしてみました。中身は全く同じです。BOOL MyPrint(HWND hWnd) { int i; HPEN hPen; PRINTDLG pd; DOCINFO di; TEXTMETRIC tm; char *szStrOrg = "This is a test print--Line(%02d)"; char szStr[128]; char *szLine = "******************************"; 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_ALLPAGES | 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); } return TRUE; }
ページ設定をする関数です。前章の解説と合わせて読んでみてください。BOOL MyPageSet(HWND hWnd) { PAGESETUPDLG psd; char szPrnName[256]; HGLOBAL hMem; DEVMODE *pdev = NULL; PRINTER_DEFAULTS pdef; HANDLE hPrn; DWORD dwNeeded, dwSize; PRINTER_INFO_2 *pprn_info; memset(&psd, 0, sizeof(PAGESETUPDLG)); psd.lStructSize = sizeof(PAGESETUPDLG); psd.hwndOwner = hWnd; psd.Flags = PSD_DISABLEMARGINS; if (PageSetupDlg(&psd)) { //デバイス名の取得 pdev = (DEVMODE *)GlobalLock(psd.hDevMode); if (pdev == NULL) { MessageBox(hWnd, "GlobalLock Error", "Error", MB_OK); return FALSE; } strcpy(szPrnName, (char *)(pdev->dmDeviceName)); //PRINTER_ALL_ACCESS権でプリンタオープン memset(&pdef, 0, sizeof(PRINTER_DEFAULTS)); pdef.DesiredAccess = PRINTER_ALL_ACCESS; if (OpenPrinter(szPrnName, &hPrn, &pdef) == 0) MessageBox(hWnd, "OpenPrinter Error", "Error", MB_OK); //1回目はわざとに失敗して必要バイト数を取得 GetPrinter(hPrn, 2, 0, 0, &dwNeeded); dwSize = dwNeeded; hMem = GlobalAlloc(GHND, dwSize); if (hMem == NULL) { MessageBox(hWnd, "GlobalAlloc Error", "Error", MB_OK); ClosePrinter(hPrn); return FALSE; } pprn_info = (PRINTER_INFO_2 *)GlobalLock(hMem); if (pprn_info == NULL) { MessageBox(hWnd, "GlobalLock Error", "Error", MB_OK); GlobalFree(hMem); ClosePrinter(hPrn); return FALSE; } //PRINTER_INFO_2構造体にプリンタ情報を取得 if (GetPrinter(hPrn, 2, (LPBYTE)pprn_info, dwSize, &dwNeeded) == 0) { MessageBox(hWnd, "GetPrinter Error", "Error", MB_OK); GlobalUnlock(hMem); GlobalFree(hMem); ClosePrinter(hPrn); return FALSE; } //現在のプリンタ情報のうちユーザー入力されたものに変更 pprn_info->pDevMode->dmFields = DM_ORIENTATION | DM_PAPERSIZE | DM_PAPERLENGTH | DM_PAPERWIDTH | DM_DEFAULTSOURCE | DM_PRINTQUALITY | DM_COLOR | DM_DUPLEX; pprn_info->pDevMode->dmOrientation = pdev->dmOrientation; pprn_info->pDevMode->dmPaperSize = pdev->dmPaperSize; pprn_info->pDevMode->dmPaperLength = pdev->dmPaperLength; pprn_info->pDevMode->dmPaperWidth = pdev->dmPaperWidth; pprn_info->pDevMode->dmDefaultSource = pdev->dmDefaultSource; pprn_info->pDevMode->dmPrintQuality = pdev->dmPrintQuality; pprn_info->pDevMode->dmColor = pdev->dmColor; //デバイス依存部分のアップデート if (DocumentProperties(hWnd, hPrn, szPrnName, (PDEVMODE)pprn_info->pDevMode, (PDEVMODE)pprn_info->pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER) < 0) { MessageBox(hWnd, "DocumentProperties Error", "Error", MB_OK); GlobalUnlock(hMem); GlobalFree(hMem); ClosePrinter(hPrn); return FALSE; } //プリンタ情報のセット if (SetPrinter(hPrn, 2, (LPBYTE)pprn_info, 0) == 0) { MessageBox(hWnd, "SetPrinter Error", "Error", MB_OK); return FALSE; } if (GlobalUnlock(hMem) == 0) { if (GetLastError() != NO_ERROR) { MessageBox(hWnd, "GlobalUnlock Error", "Error", MB_OK); return FALSE; } } if (GlobalFree(hMem) != NULL) MessageBox(hWnd, "GlobalFree Error", "Error", MB_OK); GlobalUnlock(psd.hDevMode); if (GlobalFree(psd.hDevMode) != NULL) MessageBox(hWnd, "Error", "Error", MB_OK); ClosePrinter(hPrn); return TRUE; } return FALSE; }
さて、このプログラムはうまく動作したでしょうか。筆者の環境ではA,B,CのコンピュータがLANでつながっており B,CにはPRN-B, PRN-Cというローカルプリンターが接続されています。これらのプリンタは、共有設定が されており、どのコンピュータからも印刷ができるようになっています。 A, B, Cのコンピュータからこのプログラムを実行してPRN-B, PRN-Cのプリンタでの印刷は問題なくできました。 ところが、AのプリンタからPRN-Cのプリンタのページ設定をする時のみ、非常に時間がかかります。(ハングアップしたのでは ないかと思うほど時間がかかります)。 ネットワークの設定とか、プリンタドライバがきちんとインストールされていないとか、何か環境に問題があるのかも しれませんが、現在の所原因不明です。
Update 19/Jan/2001 By Y.Kumei