概要

 横書きフォントの一覧を印刷します。
 Windows 10 Version 1703以降の場合、高DPI環境で綺麗に表示されます。
 以下に印刷により作成されたPDFファイルを表示結果を示します。

fonts.pdf

テスト環境

コンパイラ

Visual C++ 2013 Express 32/64bit

プログラムソースの概要

_tWinMain関数

 Windowsから最初に_tWinMain関数が呼び出されます。
 GetDC APIによりディスクトップのハンドルを取得しhdcに保存します。
 LOGONT構造体に検索条件を設定してEnumFontFamiliesEx APIを呼び出します。
 コールバック関数EnumFontFamProcがフォント1個に対して1回呼び出されますので、EnumFontFamProc関数側で可変長の配列であるvector fontsにフォント名等を格納します。
 print2font関数でフォントの一覧を印刷します。

EnumFontFamProc関数

 フォントが見つかるたびに呼び出されるので引数よりフォントの情報を可変長の配列であるvector fontsに格納します。文字列については_tcsdupにより動的にメモリを確保して保存しています。なお縦書きフォントについてはフォント名の最初の文字@が見つかった場合は配列に保存しないようにして対応しています。

print2font

 以下の様な印刷のコモンダイアログボックスを表示してプリンタの選択をしてフォントの一覧を印刷します。

 PRINTDLG構造体を初期化してPrintDlg APIを呼び出します。なおページ数についてはわからないので1ページと仮定しています。このAPIが正常に終了するとTRUEを返します。
 PrintDlg APIで取得されたデバイスコンテキストを使用してStartDoc APIを呼び出します。印刷の開始とDOCINFO構造体により文章名を設定しています。
 GetDeviceCaps APIでLOGPIXELSXを指定してプリンタの解像度を取得し10㎜当たりのピクセル数を計算しfhに代入します。
 GetDeviceCaps APIでVERTRESを指定してプリンタの縦方向の印刷可能領域のピクセル数を取得します。
 GetDeviceCaps APIでLOGPIXELSXを指定して印刷領域の余白20㎜当たりのピクセル数を計算しmargeに代入します。
 CreateFont APIによりフォント名と文字高さ10㎜に相当するピクセル数を指定してフォントを作成します。なお最初の呼び出し時には元のフォントのハンドルを保存しておきます。
 SelectObj APIにより現在のフォントを作成されたフォントに変更します。
 TextOut APIにより見つかったフォントの通し番号とフォント名を印刷します。
 CreateFont APIによりフォント名と文字高さ3.5㎜に相当するピクセル数を指定してフォントを作成します。
 SelectObj APIにより現在のフォントを作成されたフォントに変更します。
 TextOut APIによりフォントの言語とフォントのタイプを印刷します。
 なお、ページをはみ出す場合はEndPage APIにより今のページを終了させStartPageにより新しいページの開始を指定します。
 全部のフォントを印刷したらEndDoc APIにより印刷ジョブが終了したことを指定します。

プログラムソース

// 印刷コモンダイアログボックスを使用してフォントの一覧を印刷する。
// Win32/64 Unicode/マルチバイト

#include <windows.h>
#include <vector>
#include <tchar.h>

using namespace std;

struct FONT_INFO{
	TCHAR* elfFullName;
	TCHAR* elfStyle;
	TCHAR* elfScript;
	DWORD FontType;
};

vector<FONT_INFO*> fonts;

//	横書きフォントの列挙
int CALLBACK EnumFontFamProc(const LOGFONT * lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam);
//	フォントの印刷
void print2font(void);

#ifndef _DPI_AWARENESS_CONTEXTS_
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
#endif
typedef HRESULT(_stdcall* SetThreadDpiAwarenessContextFunc)(DPI_AWARENESS_CONTEXT);

HMODULE hModUser32 = 0;
SetThreadDpiAwarenessContextFunc ThreadAwareFunc = 0;


#ifndef _DPI_AWARENESS_CONTEXTS_

typedef enum _DPI_AWARENESS {
	DPI_AWARENESS_INVALID = -1,
	DPI_AWARENESS_UNAWARE = 0,
	DPI_AWARENESS_SYSTEM_AWARE = 1,
	DPI_AWARENESS_PER_MONITOR_AWARE = 2
} DPI_AWARENESS;

#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4)

#endif


int win10ver2(void);
int WIN10VER;

int WINAPI _tWinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, TCHAR* lpsCmdLine, int nCmdShow){
	LOGFONT lf;
	WIN10VER = win10ver2();
	hModUser32 = LoadLibrary(L"User32.dll");
	if (hModUser32){
		ThreadAwareFunc = (SetThreadDpiAwarenessContextFunc)GetProcAddress(hModUser32, "SetThreadDpiAwarenessContext");
		if (ThreadAwareFunc){
			if (1703 <= WIN10VER)
				(*ThreadAwareFunc)(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
		}
	}
	HDC hdc = GetDC(0);
	lf.lfFaceName[0] = _T('¥0'); // 全てのフォント名
	lf.lfPitchAndFamily = DEFAULT_PITCH;
	lf.lfCharSet = SHIFTJIS_CHARSET;
	EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC)EnumFontFamProc, (LONG_PTR)&lf, 0);
	ReleaseDC(0, hdc);
	print2font();
	for (UINT n = 0; n < fonts.size(); n++){
		free(fonts[n]->elfFullName);
		free(fonts[n]->elfScript);
		free(fonts[n]->elfStyle);
		delete fonts[n];
	}
	fonts.clear();
	if (hModUser32)
		FreeLibrary(hModUser32);
	return 0;
}

int CALLBACK EnumFontFamProc(const LOGFONT * lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam){
	ENUMLOGFONTEX *lpelfe = (ENUMLOGFONTEX  *)lpelf;
	if (lpelfe->elfFullName[0] != _T('@')){
		FONT_INFO* fip = new FONT_INFO;
		fip->elfFullName = _tcsdup(lpelfe->elfFullName);
		fip->elfScript = _tcsdup(lpelfe->elfScript);
		fip->elfStyle = _tcsdup(lpelfe->elfStyle);
		fip->FontType = FontType;
		fonts.push_back(fip);
	}
	return 1;
}

void print2font(void){
	PRINTDLG pd;
	DOCINFO di;

	memset(&pd, 0, sizeof(PRINTDLG));
	pd.lStructSize = sizeof(PRINTDLG);
	pd.hwndOwner = NULL;
	pd.hDevMode = NULL;
	pd.hDevNames = NULL;
	// 	pd.Flags = デバイスコンテキストを返す 「選択した部分」ラジオボタンを使用不可にします 「ファイルへ出力」チェックボックスを隠します。
	pd.Flags = PD_RETURNDC |
		PD_NOPAGENUMS | PD_NOSELECTION | PD_HIDEPRINTTOFILE;
	pd.nCopies = 1;		//	印刷部数1
	pd.nFromPage = 1;	//	スタートページ1
	pd.nToPage = 1;		//	最後のページ1
	pd.nMinPage = 1;	//	ページ範囲の最小値1
	pd.nMaxPage = 1;	//	ページエディットコントロールの最大値1
	memset(&di, 0, sizeof(DOCINFO));
	di.cbSize = sizeof(DOCINFO);
	di.lpszDocName = TEXT("fonts");
	UINT n;
	if (PrintDlg(&pd) == TRUE) {	//	ダイアログ表示
		StartDoc(pd.hDC, &di);


		int fh = int(10 * double(GetDeviceCaps(pd.hDC, LOGPIXELSX)) / 25.4);	//10ミリの文字幅を計算(ピクセル)

		// 印刷可能領域
		int pheight = GetDeviceCaps(pd.hDC, VERTRES) - fh;
		int marge = int(20 * double(GetDeviceCaps(pd.hDC, LOGPIXELSX)) / 25.4);	//20ミリの余白を計算(ピクセル)
		int y = marge;
		StartPage(pd.hDC);
		HFONT hOldFont = 0;
		for (n = 0; fonts.size() > n; n++){
#ifdef UNICODE
			HFONT hfont = CreateFont(fh, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fonts[n]->elfFullName);
#else
			HFONT hfont = CreateFont(fh, 0, 0, 0, 0, 0, 0, 0, SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fonts[n]->elfFullName);
#endif
			if (hOldFont == 0)
				hOldFont = (HFONT)SelectObject(pd.hDC, hfont);
			else
				SelectObject(pd.hDC, hfont);
			if (pheight - marge < y){	//	改ページ
				StartPage(pd.hDC);
				EndPage(pd.hDC);
				y = marge;
			}
			TCHAR* ft = _TEXT("");
			switch (fonts[n]->FontType){
			case DEVICE_FONTTYPE:
				ft = _TEXT("デバイスフォント");
				break;
			case RASTER_FONTTYPE:
				ft = _TEXT("ラスターフォント");
				break;
			case TRUETYPE_FONTTYPE:
				ft = _TEXT("TrueTypeフォント");
				break;
			}
			TCHAR buf[64];
			_stprintf_s(buf, sizeof(buf) / sizeof(buf[0]), TEXT("%03d %s"), n, fonts[n]->elfFullName);
			TextOut(pd.hDC, marge, y, buf, _tcslen(buf));
			SIZE size;
			GetTextExtentPoint32(pd.hDC, buf, _tcslen(buf), &size);
			int fh2 = int(3.5 * double(GetDeviceCaps(pd.hDC, LOGPIXELSX)) / 25.4);	//3.5ミリの文字幅を計算(ピクセル)

#ifdef UNICODE
			HFONT hfont2 = CreateFont(fh2, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fonts[n]->elfFullName);
#else
			HFONT hfont2 = CreateFont(fh2, 0, 0, 0, 0, 0, 0, 0, SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fonts[n]->elfFullName);
#endif
			SelectObject(pd.hDC, hfont2);
			_stprintf_s(buf, sizeof(buf) / sizeof(buf[0]), TEXT("%s %s"), fonts[n]->elfScript, ft);
			TextOut(pd.hDC, marge + size.cx + fh2, y + fh - fh2, buf, _tcslen(buf));
			SelectObject(pd.hDC, hOldFont);
			DeleteObject(hfont);
			DeleteObject(hfont2);
			y += fh;
		}
		EndPage(pd.hDC);
		EndDoc(pd.hDC);
		DeleteDC(pd.hDC);
	}
}


//	DLL内の関数へのポインタ型を定義
typedef void (WINAPI *RtlGetVersion_FUNC)(OSVERSIONINFOEXW*);

int win10ver2(void){
	int ver = 0;
	HMODULE hMod;
	OSVERSIONINFOEXW osw;
	hMod = LoadLibrary(TEXT("ntdll.dll"));
	RtlGetVersion_FUNC func;
	if (hMod){
		func = (RtlGetVersion_FUNC)GetProcAddress(hMod, "RtlGetVersion");
		if (func == 0){
			FreeLibrary(hMod);
			return FALSE;
		}
		ZeroMemory(&osw, sizeof(osw));
		osw.dwOSVersionInfoSize = sizeof(osw);
		func(&osw);
		FreeLibrary(hMod);
		if (osw.dwMajorVersion == 10){
			switch (osw.dwBuildNumber){
			case 10240: ver = 1507; break;
			case 10586: ver = 1511; break;
			case 14393: ver = 1607; break;
			case 15063: ver = 1703; break;
			case 16299: ver = 1709; break;
			case 17134: ver = 1803; break;
			case 17763: ver = 1809; break;
			default: ver = 1809; break;
			}
			return ver;
		}
	}
	return -1;
}

ソースファイルと実行ファイルのダウンロード

ダウンロード enumfont2.zip(54.4kByte)
ZIPファイルに含まれるファイル
enumfont2.cpp
enumfont2.exe