|
#include <windows.h> |
|
#include <stdio.h> |
|
#include <stdarg.h> |
|
#include <wchar.h> |
|
|
|
#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])) |
|
|
|
|
|
|
|
|
|
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]; |
|
}; |
|
|
|
|
|
typedef BOOL WINAPI SetConsoleFont_t( |
|
HANDLE hOutput, |
|
DWORD dwFontIndex); |
|
|
|
|
|
typedef DWORD WINAPI GetNumberOfConsoleFonts_t(); |
|
|
|
|
|
typedef BOOL WINAPI GetCurrentConsoleFont_t( |
|
HANDLE hOutput, |
|
BOOL bMaximumWindow, |
|
AGENT_CONSOLE_FONT_INFO *lpConsoleCurrentFont); |
|
|
|
|
|
typedef COORD WINAPI GetConsoleFontSize_t( |
|
HANDLE hConsoleOutput, |
|
DWORD nFont); |
|
|
|
|
|
typedef BOOL WINAPI GetCurrentConsoleFontEx_t( |
|
HANDLE hConsoleOutput, |
|
BOOL bMaximumWindow, |
|
AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx); |
|
|
|
|
|
typedef BOOL WINAPI SetCurrentConsoleFontEx_t( |
|
HANDLE hConsoleOutput, |
|
BOOL bMaximumWindow, |
|
AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx); |
|
|
|
#define GET_MODULE_PROC(mod, funcName) \ |
|
m_##funcName = reinterpret_cast<funcName##_t*>((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<std::pair<DWORD, COORD> > readFontTable( |
|
XPFontAPI &api, HANDLE conout, DWORD maxCount) { |
|
std::vector<std::pair<DWORD, COORD> > 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<std::pair<DWORD, COORD> > 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<unsigned>(first), static_cast<unsigned>(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<unsigned>(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<unsigned>(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; |
|
} |
|
|