From ebefb91e8019c58a6534fda270c624af0bcbc506 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Sat, 4 Jun 2016 21:10:19 -0500 Subject: [PATCH] Update test programs for font/resizing work * Rename QueryFont.exe to GetFont.exe -- it's shorted. Make font table output shorter. Make the program work on XP. * Add IsNewConsole.exe * Add GetBufferInfo.exe * Clear the executable bit on some .cc files --- misc/GetBufferInfo.cc | 25 ++++ misc/GetFont.cc | 261 ++++++++++++++++++++++++++++++++++++++ misc/IsNewConsole.cc | 49 +++++++ misc/MoveConsoleWindow.cc | 0 misc/QueryFont.cc | 74 ----------- misc/SetBufferSize.cc | 0 misc/SetWindowRect.cc | 0 misc/TestUtil.cc | 9 ++ 8 files changed, 344 insertions(+), 74 deletions(-) create mode 100644 misc/GetBufferInfo.cc create mode 100644 misc/GetFont.cc create mode 100644 misc/IsNewConsole.cc mode change 100755 => 100644 misc/MoveConsoleWindow.cc delete mode 100644 misc/QueryFont.cc mode change 100755 => 100644 misc/SetBufferSize.cc mode change 100755 => 100644 misc/SetWindowRect.cc diff --git a/misc/GetBufferInfo.cc b/misc/GetBufferInfo.cc new file mode 100644 index 0000000..f8e2c92 --- /dev/null +++ b/misc/GetBufferInfo.cc @@ -0,0 +1,25 @@ +#include + +#include + +#include "TestUtil.cc" + +int main() { + const HANDLE conout = CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + ASSERT(conout != INVALID_HANDLE_VALUE); + + CONSOLE_SCREEN_BUFFER_INFO info = {}; + BOOL ret = GetConsoleScreenBufferInfo(conout, &info); + ASSERT(ret && "GetConsoleScreenBufferInfo failed"); + + trace("srWindow={L=%d,T=%d,R=%d,B=%d}", info.srWindow.Left, info.srWindow.Top, info.srWindow.Right, info.srWindow.Bottom); + printf("srWindow={L=%d,T=%d,R=%d,B=%d}\n", info.srWindow.Left, info.srWindow.Top, info.srWindow.Right, info.srWindow.Bottom); + + trace("dwSize=%d,%d", info.dwSize.X); + printf("dwSize=%d,%d\n", info.dwSize.X); + + return 0; +} diff --git a/misc/GetFont.cc b/misc/GetFont.cc new file mode 100644 index 0000000..3862531 --- /dev/null +++ b/misc/GetFont.cc @@ -0,0 +1,261 @@ +#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; +} diff --git a/misc/IsNewConsole.cc b/misc/IsNewConsole.cc new file mode 100644 index 0000000..a555f5a --- /dev/null +++ b/misc/IsNewConsole.cc @@ -0,0 +1,49 @@ +#include + +#include +#include + +#include "TestUtil.cc" + +const int SC_CONSOLE_MARK = 0xFFF2; +const int SC_CONSOLE_SELECT_ALL = 0xFFF5; + +static COORD getCursorPos(HANDLE conout) { + CONSOLE_SCREEN_BUFFER_INFO info = {}; + BOOL ret = GetConsoleScreenBufferInfo(conout, &info); + ASSERT(ret && "GetConsoleScreenBufferInfo failed"); + return info.dwCursorPosition; +} + +static void setCursorPos(HANDLE conout, COORD pos) { + BOOL ret = SetConsoleCursorPosition(conout, pos); + ASSERT(ret && "SetConsoleCursorPosition failed"); +} + +int main() { + const HANDLE conout = openConout(); + const HWND hwnd = GetConsoleWindow(); + ASSERT(hwnd != NULL && "GetConsoleWindow() returned NULL"); + + bool isWindows10NewConsole = false; + COORD pos = getCursorPos(conout); + setCursorPos(conout, { 1, 0 }); + + { + COORD posA = getCursorPos(conout); + SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0); + COORD posB = getCursorPos(conout); + isWindows10NewConsole = !memcmp(&posA, &posB, sizeof(posA)); + SendMessage(hwnd, WM_CHAR, 27, 0x00010001); // Send ESCAPE + } + + setCursorPos(conout, pos); + + if (isWindows10NewConsole) { + printf("New Windows 10 console\n"); + } else { + printf("Legacy console\n"); + } + + return 0; +} diff --git a/misc/MoveConsoleWindow.cc b/misc/MoveConsoleWindow.cc old mode 100755 new mode 100644 diff --git a/misc/QueryFont.cc b/misc/QueryFont.cc deleted file mode 100644 index 350e642..0000000 --- a/misc/QueryFont.cc +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include -#include -#include - -#include "TestUtil.cc" - -static void queryCurrentConsoleFont(HANDLE conout, BOOL max) { - CONSOLE_FONT_INFO info = {0}; - if (!GetCurrentConsoleFont(conout, max, &info)) { - cprintf(L"GetCurrentConsoleFont call failed\n"); - } else { - cprintf(L"info(max=%d): nFont=%u dwFontSize=(%d,%d)\n", - max, static_cast(info.nFont), - info.dwFontSize.X, info.dwFontSize.Y); - } -} - -static void queryCurrentConsoleFontEx(HANDLE conout, BOOL max) { - CONSOLE_FONT_INFOEX infoex = {0}; - infoex.cbSize = sizeof(infoex); - if (!GetCurrentConsoleFontEx(conout, max, &infoex)) { - cprintf(L"GetCurrentConsoleFontEx call failed\n"); - } else { - wchar_t faceName[LF_FACESIZE + 1]; - memcpy(faceName, infoex.FaceName, sizeof(faceName)); - faceName[LF_FACESIZE] = L'\0'; - cprintf(L"infoex(max=%d): nFont=%u dwFontSize=(%d,%d) " - L"FontFamily=0x%x FontWeight=%u " - L"FaceName=\"%ls\"", - max, static_cast(infoex.nFont), - infoex.dwFontSize.X, infoex.dwFontSize.Y, - infoex.FontFamily, infoex.FontWeight, - faceName); - cprintf(L" ("); - for (int i = 0; i < LF_FACESIZE; ++i) { - if (i > 0) { - cprintf(L" "); - } - cprintf(L"%X", infoex.FaceName[i]); - if (infoex.FaceName[i] == L'\0') { - break; - } - } - cprintf(L")\n"); - } -} - -int main() { - const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); - queryCurrentConsoleFont(conout, FALSE); - queryCurrentConsoleFont(conout, TRUE); - queryCurrentConsoleFontEx(conout, FALSE); - queryCurrentConsoleFontEx(conout, TRUE); - const COORD largest = GetLargestConsoleWindowSize(conout); - cprintf(L"largestConsoleWindowSize=(%d,%d)\n", largest.X, largest.Y); - for (int i = 0;; ++i) { - const COORD size = GetConsoleFontSize(conout, i); - if (size.X == 0 && size.Y == 0) { - break; - } - cprintf(L"font %d: %dx%d\n", i, size.X, size.Y); - } - HMODULE kernel32 = LoadLibraryW(L"kernel32.dll"); - FARPROC proc = GetProcAddress(kernel32, "GetNumberOfConsoleFonts"); - if (proc == NULL) { - cprintf(L"Could not get address of GetNumberOfConsoleFonts\n"); - } else { - cprintf(L"GetNumberOfConsoleFonts returned %d\n", - reinterpret_cast(proc)(conout)); - } - cprintf(L"InputCP=%u OutputCP=%u", GetConsoleCP(), GetConsoleOutputCP()); - return 0; -} diff --git a/misc/SetBufferSize.cc b/misc/SetBufferSize.cc old mode 100755 new mode 100644 diff --git a/misc/SetWindowRect.cc b/misc/SetWindowRect.cc old mode 100755 new mode 100644 diff --git a/misc/TestUtil.cc b/misc/TestUtil.cc index 5f9dceb..c832a12 100644 --- a/misc/TestUtil.cc +++ b/misc/TestUtil.cc @@ -161,3 +161,12 @@ static std::string narrowString(const std::wstring &input) assert(mblen2 == mblen); return std::string(tmp.data(), tmp.size()); } + +HANDLE openConout() { + const HANDLE conout = CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + ASSERT(conout != INVALID_HANDLE_VALUE); + return conout; +}