C++20とWin32 APIでフォントの名前を列挙するコードです。
フォント情報の列挙にはEnumFontFamiliesExW
関数を使用します。これはHDC
とLOGFONTW
構造体等を引数とするコールバック関数を受け取ります。HDC
に使用するスクリーンのHDC
はGetDC
関数で取得してReleaseDC
関数で解放しますが、ReleaseDC
関数はHDC
の他にGetDC
関数に与えたウィンドウハンドルを必要とします。std::unique_ptr
の特殊化による対応が思いつかなかったため、"HDCForRelease.hpp"
にHDCForRelease
クラスを作成しています。
また、再利用可能な関数を"Utility.hpp"
に定義しています。
HDCForRelease.hpp
// HDCForRelease.hpp // #define STRICT // #include <Windows.h> #include <utility> #include <tuple> class HDCForRelease { private: HDC hdc; HWND hwnd; public: constexpr HDCForRelease() noexcept : hdc(), hwnd() { } constexpr HDCForRelease(HDCForRelease&) = delete; constexpr HDCForRelease(HDCForRelease&& x) noexcept : hdc(x.hdc), hwnd(x.hwnd) { x.hdc = nullptr; x.hwnd = nullptr; } constexpr HDCForRelease(HWND hwnd, HDC hdc) noexcept : hdc(hdc), hwnd(hwnd) { } constexpr HDCForRelease(std::tuple<HWND, HDC>& x) noexcept : hdc(std::get<HDC>(x)), hwnd(std::get<HWND>(x)) { } ~HDCForRelease() { reset(); } constexpr HDC get_hdc() const noexcept { return hdc; } constexpr HWND get_hwnd() const noexcept { return hwnd; } constexpr std::tuple<HDC, HWND> get_tuple() const noexcept { return std::make_tuple(hdc, hwnd); } constexpr operator HDC() const noexcept { return hdc; } constexpr std::tuple<HDC, HWND> release() noexcept { std::tuple<HDC, HWND> data{ hdc, hwnd }; hdc = nullptr; hwnd = nullptr; return data; } void reset() noexcept { reset(nullptr, nullptr); } void reset(HWND hwnd, HDC hdc) noexcept { ::ReleaseDC(hwnd, hdc); this->hdc = hdc; this->hwnd = hwnd; } constexpr void swap(HDCForRelease& x) noexcept { std::swap(x.hdc, this->hdc); std::swap(x.hwnd, this->hwnd); } constexpr operator bool() const noexcept { return hdc != nullptr; } HDCForRelease& operator=(HDCForRelease&) noexcept = delete; constexpr HDCForRelease& operator=(HDCForRelease&& x) noexcept { hdc = x.hdc; hwnd = x.hwnd; x.hdc = nullptr; x.hwnd = nullptr; return *this; } HDCForRelease& operator=(nullptr_t) noexcept { reset(); return *this; } public: static HDCForRelease GetDC(HWND hwnd) noexcept { return HDCForRelease(hwnd, ::GetDC(hwnd)); } static HDCForRelease GetWindowDC(HWND hwnd) noexcept { return HDCForRelease(hwnd, ::GetWindowDC(hwnd)); } };
Utility.hpp
// Utility.hpp #include <algorithm> #include <iterator> #include <iostream> #include <set> #include <string> #include <vector> #include <ranges> using namespace std; vector<LOGFONTW> GetFontFamiliesEx( HDC hdc, BYTE filterCharSet, LPCWSTR filterFaceName) { LOGFONTW lf{}; lf.lfCharSet = filterCharSet; if (filterFaceName != nullptr) { if (lstrlenW(filterFaceName) > LF_FACESIZE) throw invalid_argument(nullptr); lstrcpyW(lf.lfFaceName, filterFaceName); } vector<LOGFONTW> logFonts; ::EnumFontFamiliesEx(hdc, &lf, [](const LOGFONTW* plf, const TEXTMETRIC*, DWORD, LPARAM lParam) { auto& logFonts = *reinterpret_cast<vector<LOGFONTW>*>(lParam); logFonts.push_back(*plf); return 1; }, reinterpret_cast<LPARAM>(&logFonts), 0); return move(logFonts); } template <ranges::range LOGFONTW_RANGE> requires same_as<ranges::range_value_t<LOGFONTW_RANGE>, LOGFONTW> set<wstring> GetFaceNameSetFromLOGFONTWRange(LOGFONTW_RANGE& logFonts) { set<wstring> faceNames; for (const LOGFONTW& lf : logFonts) faceNames.emplace(lf.lfFaceName); return move(faceNames); }
すべてのフォント名を列挙する
#define STRICT #define NOMINMAX #include <Windows.h> #include "HDCForRelease.hpp" #include "Utility.hpp" int main() { auto hdcScreen = HDCForRelease::GetDC(nullptr); auto logFonts = GetFontFamiliesEx(hdcScreen, DEFAULT_CHARSET, nullptr); auto faceNames = GetFaceNameSetFromLOGFONTWRange(logFonts); wcout.imbue(locale("Japanese", locale::ctype)); for (const auto& faceName : faceNames) { wcout << faceName << endl; } }
固定幅フォントの名前を列挙する
#define STRICT #define NOMINMAX #include <Windows.h> #include "HDCForRelease.hpp" #include "Utility.hpp" int main() { auto hdcScreen = HDCForRelease::GetDC(nullptr); auto logFonts = GetFontFamiliesEx(hdcScreen, DEFAULT_CHARSET, nullptr); auto fixedPicthLogFonts = logFonts | views::filter([](const LOGFONT& lf) { return (lf.lfPitchAndFamily & FIXED_PITCH) != 0; }); auto faceNames = GetFaceNameSetFromLOGFONTWRange(fixedPicthLogFonts); wcout.imbue(locale("Japanese", locale::ctype)); for (const auto& faceName : faceNames) { wcout << faceName << endl; } }