// 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 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