#include #include #include #include #include "../src/shared/OsModule.h" #include "../src/shared/StringUtil.h" #include "TestUtil.cc" #include "../src/shared/StringUtil.cc" #define COUNT_OF(x) (sizeof(x) / sizeof((x)[0])) // Some of these types and functions are missing from the MinGW headers. // Others are undocumented. struct AGENT_CONSOLE_FONT_INFO { DWORD nFont; COORD dwFontSize; }; struct AGENT_CONSOLE_FONT_INFOEX { ULONG cbSize; DWORD nFont; COORD dwFontSize; UINT FontFamily; UINT FontWeight; WCHAR FaceName[LF_FACESIZE]; }; // undocumented XP API typedef BOOL WINAPI SetConsoleFont_t( HANDLE hOutput, DWORD dwFontIndex); // undocumented XP API typedef DWORD WINAPI GetNumberOfConsoleFonts_t(); // XP and up typedef BOOL WINAPI GetCurrentConsoleFont_t( HANDLE hOutput, BOOL bMaximumWindow, AGENT_CONSOLE_FONT_INFO *lpConsoleCurrentFont); // XP and up typedef COORD WINAPI GetConsoleFontSize_t( HANDLE hConsoleOutput, DWORD nFont); // Vista and up typedef BOOL WINAPI GetCurrentConsoleFontEx_t( HANDLE hConsoleOutput, BOOL bMaximumWindow, AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx); // Vista and up typedef BOOL WINAPI SetCurrentConsoleFontEx_t( HANDLE hConsoleOutput, BOOL bMaximumWindow, AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx); #define GET_MODULE_PROC(mod, funcName) \ m_##funcName = reinterpret_cast((mod).proc(#funcName)); \ #define DEFINE_ACCESSOR(funcName) \ funcName##_t &funcName() const { \ ASSERT(valid()); \ return *m_##funcName; \ } class XPFontAPI { public: XPFontAPI() : m_kernel32(L"kernel32.dll") { GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFont); GET_MODULE_PROC(m_kernel32, GetConsoleFontSize); } bool valid() const { return m_GetCurrentConsoleFont != NULL && m_GetConsoleFontSize != NULL; } DEFINE_ACCESSOR(GetCurrentConsoleFont) DEFINE_ACCESSOR(GetConsoleFontSize) private: OsModule m_kernel32; GetCurrentConsoleFont_t *m_GetCurrentConsoleFont; GetConsoleFontSize_t *m_GetConsoleFontSize; }; class UndocumentedXPFontAPI : public XPFontAPI { public: UndocumentedXPFontAPI() : m_kernel32(L"kernel32.dll") { GET_MODULE_PROC(m_kernel32, SetConsoleFont); GET_MODULE_PROC(m_kernel32, GetNumberOfConsoleFonts); } bool valid() const { return this->XPFontAPI::valid() && m_SetConsoleFont != NULL && m_GetNumberOfConsoleFonts != NULL; } DEFINE_ACCESSOR(SetConsoleFont) DEFINE_ACCESSOR(GetNumberOfConsoleFonts) private: OsModule m_kernel32; SetConsoleFont_t *m_SetConsoleFont; GetNumberOfConsoleFonts_t *m_GetNumberOfConsoleFonts; }; class VistaFontAPI : public XPFontAPI { public: VistaFontAPI() : m_kernel32(L"kernel32.dll") { GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFontEx); GET_MODULE_PROC(m_kernel32, SetCurrentConsoleFontEx); } bool valid() const { return this->XPFontAPI::valid() && m_GetCurrentConsoleFontEx != NULL && m_SetCurrentConsoleFontEx != NULL; } DEFINE_ACCESSOR(GetCurrentConsoleFontEx) DEFINE_ACCESSOR(SetCurrentConsoleFontEx) private: OsModule m_kernel32; GetCurrentConsoleFontEx_t *m_GetCurrentConsoleFontEx; SetCurrentConsoleFontEx_t *m_SetCurrentConsoleFontEx; }; static std::vector > readFontTable( XPFontAPI &api, HANDLE conout, DWORD maxCount) { std::vector > ret; for (DWORD i = 0; i < maxCount; ++i) { COORD size = api.GetConsoleFontSize()(conout, i); if (size.X == 0 && size.Y == 0) { break; } ret.push_back(std::make_pair(i, size)); } return ret; } static void dumpFontTable(HANDLE conout) { const int kMaxCount = 1000; XPFontAPI api; if (!api.valid()) { printf("dumpFontTable: cannot dump font table -- missing APIs\n"); return; } std::vector > table = readFontTable(api, conout, kMaxCount); std::string line; char tmp[128]; size_t first = 0; while (first < table.size()) { size_t last = std::min(table.size() - 1, first + 10 - 1); winpty_snprintf(tmp, "%02u-%02u:", static_cast(first), static_cast(last)); line = tmp; for (size_t i = first; i <= last; ++i) { if (i % 10 == 5) { line += " - "; } winpty_snprintf(tmp, " %2dx%-2d", table[i].second.X, table[i].second.Y); line += tmp; } printf("%s\n", line.c_str()); first = last + 1; } if (table.size() == kMaxCount) { printf("... stopped reading at %d fonts ...\n", kMaxCount); } } static std::string stringToCodePoints(const std::wstring &str) { std::string ret = "("; for (size_t i = 0; i < str.size(); ++i) { char tmp[32]; winpty_snprintf(tmp, "%X", str[i]); if (ret.size() > 1) { ret.push_back(' '); } ret += tmp; } ret.push_back(')'); return ret; } static void dumpFontInfoEx( const AGENT_CONSOLE_FONT_INFOEX &infoex) { std::wstring faceName(infoex.FaceName, winpty_wcsnlen(infoex.FaceName, COUNT_OF(infoex.FaceName))); cprintf(L"nFont=%u dwFontSize=(%d,%d) " "FontFamily=0x%x FontWeight=%u FaceName=%ls %hs\n", static_cast(infoex.nFont), infoex.dwFontSize.X, infoex.dwFontSize.Y, infoex.FontFamily, infoex.FontWeight, faceName.c_str(), stringToCodePoints(faceName).c_str()); } static void dumpVistaFont(VistaFontAPI &api, HANDLE conout, BOOL maxWindow) { AGENT_CONSOLE_FONT_INFOEX infoex = {0}; infoex.cbSize = sizeof(infoex); if (!api.GetCurrentConsoleFontEx()(conout, maxWindow, &infoex)) { printf("GetCurrentConsoleFontEx call failed\n"); return; } dumpFontInfoEx(infoex); } static void dumpXPFont(XPFontAPI &api, HANDLE conout, BOOL maxWindow) { AGENT_CONSOLE_FONT_INFO info = {0}; if (!api.GetCurrentConsoleFont()(conout, maxWindow, &info)) { printf("GetCurrentConsoleFont call failed\n"); return; } printf("nFont=%u dwFontSize=(%d,%d)\n", static_cast(info.nFont), info.dwFontSize.X, info.dwFontSize.Y); } static void dumpFontAndTable(HANDLE conout) { VistaFontAPI vista; if (vista.valid()) { printf("maxWnd=0: "); dumpVistaFont(vista, conout, FALSE); printf("maxWnd=1: "); dumpVistaFont(vista, conout, TRUE); dumpFontTable(conout); return; } UndocumentedXPFontAPI xp; if (xp.valid()) { printf("maxWnd=0: "); dumpXPFont(xp, conout, FALSE); printf("maxWnd=1: "); dumpXPFont(xp, conout, TRUE); dumpFontTable(conout); return; } printf("setSmallFont: neither Vista nor XP APIs detected -- giving up\n"); dumpFontTable(conout); } int main() { const HANDLE conout = openConout(); const COORD largest = GetLargestConsoleWindowSize(conout); printf("largestConsoleWindowSize=(%d,%d)\n", largest.X, largest.Y); dumpFontAndTable(conout); UndocumentedXPFontAPI xp; if (xp.valid()) { printf("GetNumberOfConsoleFonts returned %u\n", xp.GetNumberOfConsoleFonts()()); } else { printf("The GetNumberOfConsoleFonts API was missing\n"); } printf("CP=%u OutputCP=%u\n", GetConsoleCP(), GetConsoleOutputCP()); return 0; }