|開発環境|Microsoft Visual C++ 2010 Express (SP1)| |実行環境|Microsoft Windows XP Home Edition (SP3)| |プロジェクトの種類|Win32 プロジェクト| |プロジェクト名|PrnTest| |アプリケーションの種類|Windows アプリケーション| |追加のオプション|空のプロジェクト| |文字セット|Unicode| 参考 -[[プリンタの設定>http://wisdom.sakura.ne.jp/system/winapi/common/common7.html]] -[[第297章 ネットワークプリンタを使う その1>http://www.kumei.ne.jp/c_lang/sdk3/sdk_297.htm]] -[[プリンタプログラミング (その 2)>http://www30020u.sakura.ne.jp/nohito/program/memo/lecture/printer-2.html]] -[[手づくりアプリの裏側 Win32>http://yuzublo.blog48.fc2.com/category4-2.html]] PrnTest.c #highlight(c){{ // Unicode文字セット #include <Windows.h> #include <tchar.h> #include <stdio.h> #include "resource.h" #define pxtolm(px,dpi) ((px) * 254 / (dpi)) // Pixel to LoMetric #define lmtopx(lm,dpi) ((lm) * (dpi) / 254) // LoMetric to Pixel #define LOGWRITE(fmt,var) LogWrite(TEXT(#var)TEXT("=[")fmt##TEXT("]\n"), var) // プリンタ能力 typedef struct { int nHorzRes; // 印刷可能領域の幅 (ピクセル単位) int nVertRes; // 印刷可能領域の高さ (ピクセル単位) int nPhysicalWidth; // 物理ページ全体の幅 (ピクセル単位) int nPhysicalHeight; // 物理ページ全体の高さ (ピクセル単位) int nPhysicalOffsetX; // 物理ページの左辺から印刷可能領域の左辺までの距離 (ピクセル単位) int nPhysicalOffsetY; // 物理ページの上辺から印刷可能領域の上辺までの距離 (ピクセル単位) int nDpiX; // 水平方向のピクセル数 (論理インチ当たり) int nDpiY; // 垂直方向のピクセル数 (論理インチ当たり) } PRNCAPS; // 関数プロトタイプ宣言 INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); void OnInitDialog(HWND hDlg); void OnPageSetup(HWND hDlg); void OnPrint(HWND hDlg); void TestPrint(HDC hdc); void OnDestroy(void); void TracePrnInfo(void); void GetPrnCaps(HDC hdc, PRNCAPS *ppc); int LogOpen(void); void LogClose(void); void LogWrite(LPCTSTR format, ...); int LogCopy(HWND hEdit); // 外部変数 HWND g_hEdit; HGLOBAL g_hDevMode = NULL; // デバイスモード構造体ハンドル HGLOBAL g_hDevNames = NULL; // デバイス名構造体ハンドル TCHAR g_szLog[MAX_PATH]; FILE *g_pLog = NULL; //============================================================================== int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, DialogProc); return 0; } //------------------------------------------------------------------------------ INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { INT_PTR iRet = TRUE; // メッセージを処理した switch (uMsg) { case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_PAGESETUP: OnPageSetup(hDlg); break; case IDC_PRINT: OnPrint(hDlg); break; } break; case WM_INITDIALOG: OnInitDialog(hDlg); iRet = TRUE; // SetFocusでフォーカスを設定した場合はFALSE break; case WM_CLOSE: EndDialog(hDlg, IDOK); break; case WM_DESTROY: OnDestroy(); break; default: iRet = FALSE; // メッセージを処理しなかった } return iRet; } //------------------------------------------------------------------------------ void OnInitDialog(HWND hDlg) { PRINTDLGEX pd; HRESULT hr; g_hEdit = GetDlgItem(hDlg, IDC_EDIT); // デフォルトプリンタの取得 ZeroMemory(&pd, sizeof pd); pd.lStructSize = sizeof pd; pd.hwndOwner = hDlg; pd.Flags = PD_RETURNDEFAULT | PD_NOPAGENUMS; pd.nStartPage = START_PAGE_GENERAL; hr = PrintDlgEx(&pd); if (FAILED(hr)) { return; } g_hDevMode = pd.hDevMode; g_hDevNames = pd.hDevNames; TracePrnInfo(); } /* PRINTDLG pd; BOOL br; ZeroMemory(&pd, sizeof pd); pd.lStructSize = sizeof pd; pd.Flags = PD_RETURNDEFAULT; br = PrintDlg(&pd); if (br == FALSE) { return; } */ //------------------------------------------------------------------------------ void OnPageSetup(HWND hDlg) { PAGESETUPDLG psd; BOOL br; // ページ設定ダイアログ ZeroMemory(&psd, sizeof psd); psd.lStructSize = sizeof psd; psd.hwndOwner = hDlg; psd.hDevMode = g_hDevMode; psd.hDevNames = g_hDevNames; psd.Flags = 0; br = PageSetupDlg(&psd); if (br == FALSE) { return; // キャンセル時、デバイス構造体ハンドルはそのまま } g_hDevMode = psd.hDevMode; g_hDevNames = psd.hDevNames; TracePrnInfo(); } /* PRINTDLG pd; BOOL br; ZeroMemory(&pd, sizeof pd); pd.lStructSize = sizeof pd; pd.hwndOwner = hDlg; pd.hDevMode = g_hDevMode; pd.hDevNames = g_hDevNames; pd.Flags = PD_PRINTSETUP; br = PrintDlg(&pd); if (br == FALSE) { return; // キャンセル時、デバイス構造体ハンドルはそのまま } */ //------------------------------------------------------------------------------ void OnPrint(HWND hDlg) { PRINTDLGEX pd; HRESULT hr; BOOL br; // 印刷ダイアログ ZeroMemory(&pd, sizeof pd); pd.lStructSize = sizeof pd; pd.hwndOwner = hDlg; pd.hDevMode = g_hDevMode; pd.hDevNames = g_hDevNames; pd.Flags = PD_NOPAGENUMS | PD_RETURNDC; pd.nStartPage = START_PAGE_GENERAL; hr = PrintDlgEx(&pd); if (FAILED(hr)) { return; } g_hDevMode = pd.hDevMode; g_hDevNames = pd.hDevNames; if (pd.dwResultAction != PD_RESULT_PRINT) { return; } // テスト印刷 TestPrint(pd.hDC); br = DeleteDC(pd.hDC); } //------------------------------------------------------------------------------ void TestPrint(HDC hdc) { PRNCAPS pc; DOCINFO di; HPEN hPen; HGDIOBJ hPenOld; RECT rcMargin; // 余白 RECT rc; BOOL br; int nr; // デバイス能力の取得 GetPrnCaps(hdc, &pc); // 最小余白 rcMargin.left = pc.nPhysicalOffsetX; rcMargin.top = pc.nPhysicalOffsetY; rcMargin.right = pc.nPhysicalWidth - pc.nHorzRes - pc.nPhysicalOffsetX; rcMargin.bottom = pc.nPhysicalHeight - pc.nVertRes - pc.nPhysicalOffsetY; // 余白10.0mmの枠 rcMargin.left = max(lmtopx(100, pc.nDpiX), rcMargin.left); rcMargin.top = max(lmtopx(100, pc.nDpiY), rcMargin.top); rcMargin.right = max(lmtopx(100, pc.nDpiX), rcMargin.right); rcMargin.bottom = max(lmtopx(100, pc.nDpiY), rcMargin.bottom); SetRect(&rc, rcMargin.left, rcMargin.top, pc.nPhysicalWidth - rcMargin.right, pc.nPhysicalHeight - rcMargin.bottom); OffsetRect(&rc, -pc.nPhysicalOffsetX, -pc.nPhysicalOffsetY); // 開始 ZeroMemory(&di, sizeof di); di.cbSize = sizeof di; di.lpszDocName = TEXT("test print"); nr = StartDoc(hdc, &di); nr = StartPage(hdc); // 幅0.3mmの黒いペン hPen = CreatePen(PS_INSIDEFRAME, lmtopx(3, pc.nDpiY), RGB(0x00,0x00,0x00)); hPenOld = SelectObject(hdc, hPen); br = Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom); SelectObject(hdc, hPenOld); br = DeleteObject(hPen); // 終了 nr = EndPage(hdc); nr = EndDoc(hdc); } //------------------------------------------------------------------------------ void OnDestroy(void) { HGLOBAL hr; hr = GlobalFree(g_hDevMode); hr = GlobalFree(g_hDevNames); } //------------------------------------------------------------------------------ void TracePrnInfo(void) { LPDEVNAMES pdn; LPDEVMODE pdm; HDC hdc; // 情報コンテキスト。デバイス準備不要。GDI出力不可 LPTSTR pszDriver; // ドライバ名 LPTSTR pszDevice; // デバイス名 LPTSTR pszPort; // 出力ポート名 PRNCAPS pc; int nWidth; int nHeight; BOOL br; // ログ開始 LogOpen(); // デバイス名構造体 pdn = (LPDEVNAMES)GlobalLock(g_hDevNames); pszDriver = _tcsdup((LPCTSTR)pdn + pdn->wDriverOffset); pszDevice = _tcsdup((LPCTSTR)pdn + pdn->wDeviceOffset); pszPort = _tcsdup((LPCTSTR)pdn + pdn->wOutputOffset); br = GlobalUnlock(g_hDevNames); LOGWRITE(TEXT("%s"), pszDriver); LOGWRITE(TEXT("%s"), pszDevice); LOGWRITE(TEXT("%s"), pszPort); // デバイスモード構造体 pdm = (LPDEVMODE)GlobalLock(g_hDevMode); hdc = CreateIC(pszDriver, pszDevice, pszPort, pdm); GlobalUnlock(g_hDevMode); GetPrnCaps(hdc, &pc); br = DeleteDC(hdc); LogWrite(TEXT("\n")); LOGWRITE(TEXT("%d px"), pc.nHorzRes); LOGWRITE(TEXT("%d px"), pc.nVertRes); LOGWRITE(TEXT("%d px"), pc.nPhysicalWidth); LOGWRITE(TEXT("%d px"), pc.nPhysicalHeight); LOGWRITE(TEXT("%d px"), pc.nPhysicalOffsetX); LOGWRITE(TEXT("%d px"), pc.nPhysicalOffsetY); LOGWRITE(TEXT("%d dpi"), pc.nDpiX); LOGWRITE(TEXT("%d dpi"), pc.nDpiY); // 計算 nWidth = pxtolm(pc.nPhysicalWidth, pc.nDpiX); nHeight = pxtolm(pc.nPhysicalHeight, pc.nDpiY); LogWrite(TEXT("\n")); LOGWRITE(TEXT("%d * 0.1mm"), nWidth); LOGWRITE(TEXT("%d * 0.1mm"), nHeight); // ログ終了・エディットコントロールに転記 LogClose(); LogCopy(g_hEdit); free(pszPort); free(pszDevice); free(pszDriver); } //------------------------------------------------------------------------------ void GetPrnCaps(HDC hdc, PRNCAPS *ppc) { ppc->nHorzRes = GetDeviceCaps(hdc, HORZRES); ppc->nVertRes = GetDeviceCaps(hdc, VERTRES); ppc->nPhysicalWidth = GetDeviceCaps(hdc, PHYSICALWIDTH); ppc->nPhysicalHeight = GetDeviceCaps(hdc, PHYSICALHEIGHT); ppc->nPhysicalOffsetX = GetDeviceCaps(hdc, PHYSICALOFFSETX); ppc->nPhysicalOffsetY = GetDeviceCaps(hdc, PHYSICALOFFSETY); ppc->nDpiX = GetDeviceCaps(hdc, LOGPIXELSX); ppc->nDpiY = GetDeviceCaps(hdc, LOGPIXELSY); } //============================================================================== int LogOpen(void) { TCHAR szPath[_MAX_PATH]; TCHAR szDrive[_MAX_DRIVE]; TCHAR szDir[_MAX_DIR]; TCHAR szFName[_MAX_FNAME]; TCHAR szExt[_MAX_EXT]; DWORD dw; errno_t er; // 実行ファイル名からログファイル名を作る dw = GetModuleFileName(NULL, szPath, _countof(szPath)); if (dw == 0) { return -1; } er = _tsplitpath_s(szPath, szDrive, _countof(szDrive), szDir, _countof(szDir), szFName, _countof(szFName), szExt, _countof(szExt)); if (er != 0) { return -1; } er = _tmakepath_s(g_szLog, _countof(g_szLog), szDrive, szDir, szFName, _T("log")); if (er != 0) { return -1; } // ログファイルのオープン er = _tfopen_s(&g_pLog, g_szLog, TEXT("wt,ccs=UNICODE")); if (er != 0) { return -1; } return 0; } //------------------------------------------------------------------------------ void LogClose(void) { // ログファイルのクローズ fclose(g_pLog); } //------------------------------------------------------------------------------ void LogWrite(LPCTSTR format, ...) { va_list arg_ptr; int ir; va_start(arg_ptr, format); ir = _vftprintf_s(g_pLog, format, arg_ptr); va_end(arg_ptr); } //------------------------------------------------------------------------------ int LogCopy(HWND hEdit) { HANDLE hFile; HANDLE hMap; LPBYTE pBaseAddr; BOOL br; // ログファイルのメモリマップ割当 hFile = CreateFile(g_szLog, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) { return -1; } hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (hMap == NULL) { return -1; } pBaseAddr = (LPBYTE)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); if (pBaseAddr == NULL) { return -1; } // コピー br = SetWindowText(hEdit, (LPCTSTR)(pBaseAddr + 2)); // BOM(ff fe)読み飛ばし PostMessage(hEdit, EM_SETSEL, 0, 0); // Sendはダメみたい // ログファイルのメモリマップ解除 br = UnmapViewOfFile(pBaseAddr); br = CloseHandle(hMap); br = CloseHandle(hFile); return 0; } }} resource.h #highlight(c){{ #define IDD_DIALOG 100 #define IDC_EDIT 1000 #define IDC_PAGESETUP 1001 #define IDC_PRINT 1002 }} PrnTest.rc #highlight(c){{ // resource script #include <windows.h> #include "resource.h" IDD_DIALOG DIALOGEX 100, 100, 300, 240 STYLE WS_POPUPWINDOW | WS_MINIMIZEBOX EXSTYLE WS_EX_APPWINDOW CAPTION "PrnTest" FONT 9, "MS Pゴシック" BEGIN EDITTEXT IDC_EDIT,4,4,200,200, ES_MULTILINE | ES_WANTRETURN | ES_AUTOVSCROLL | WS_VSCROLL PUSHBUTTON "ページ設定(&U)",IDC_PAGESETUP,208,4,64,16 PUSHBUTTON "印刷(&P)",IDC_PRINT,208,28,64,16 END }} 出力 pszDriver=[winspool] pszDevice=[Canon iP2700 series] pszPort=[USB001] pc.nHorzRes=[4800 px] pc.nVertRes=[6826 px] pc.nPhysicalWidth=[4960 px] pc.nPhysicalHeight=[7015 px] pc.nPhysicalOffsetX=[80 px] pc.nPhysicalOffsetY=[70 px] pc.nDpiX=[600 dpi] pc.nDpiY=[600 dpi] nWidth=[2099 * 0.1mm] nHeight=[2969 * 0.1mm]