// This file is included into test programs using #include #include #include #include #include #include #include #include #include "../shared/DebugClient.h" // Launch this test program again, in a new console that we will destroy. static void startChildProcess(const wchar_t *args) { wchar_t program[1024]; wchar_t cmdline[1024]; GetModuleFileNameW(NULL, program, 1024); swprintf(cmdline, L"\"%ls\" %ls", program, args); STARTUPINFOW sui; PROCESS_INFORMATION pi; memset(&sui, 0, sizeof(sui)); memset(&pi, 0, sizeof(pi)); sui.cb = sizeof(sui); CreateProcessW(program, cmdline, NULL, NULL, /*bInheritHandles=*/FALSE, /*dwCreationFlags=*/CREATE_NEW_CONSOLE, NULL, NULL, &sui, &pi); } static void setBufferSize(HANDLE conout, int x, int y) { COORD size = { static_cast(x), static_cast(y) }; BOOL success = SetConsoleScreenBufferSize(conout, size); trace("setBufferSize: (%d,%d), result=%d", x, y, success); } static void setWindowPos(HANDLE conout, int x, int y, int w, int h) { SMALL_RECT r = { static_cast(x), static_cast(y), static_cast(x + w - 1), static_cast(y + h - 1) }; BOOL success = SetConsoleWindowInfo(conout, /*bAbsolute=*/TRUE, &r); trace("setWindowPos: (%d,%d,%d,%d), result=%d", x, y, w, h, success); } static void setCursorPos(HANDLE conout, int x, int y) { COORD coord = { static_cast(x), static_cast(y) }; SetConsoleCursorPosition(conout, coord); } static void setBufferSize(int x, int y) { setBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), x, y); } static void setWindowPos(int x, int y, int w, int h) { setWindowPos(GetStdHandle(STD_OUTPUT_HANDLE), x, y, w, h); } static void setCursorPos(int x, int y) { setCursorPos(GetStdHandle(STD_OUTPUT_HANDLE), x, y); } static void countDown(int sec) { for (int i = sec; i > 0; --i) { printf("%d.. ", i); fflush(stdout); Sleep(1000); } printf("\n"); } static void writeBox(int x, int y, int w, int h, char ch, int attributes=7) { CHAR_INFO info = { 0 }; info.Char.AsciiChar = ch; info.Attributes = attributes; std::vector buf(w * h, info); HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); COORD bufSize = { static_cast(w), static_cast(h) }; COORD bufCoord = { 0, 0 }; SMALL_RECT writeRegion = { static_cast(x), static_cast(y), static_cast(x + w - 1), static_cast(y + h - 1) }; WriteConsoleOutputA(conout, buf.data(), bufSize, bufCoord, &writeRegion); } static void setChar(int x, int y, char ch, int attributes=7) { writeBox(x, y, 1, 1, ch, attributes); } static void fillChar(int x, int y, int repeat, char ch) { COORD coord = { static_cast(x), static_cast(y) }; DWORD actual = 0; FillConsoleOutputCharacterA( GetStdHandle(STD_OUTPUT_HANDLE), ch, repeat, coord, &actual); } static void repeatChar(int count, char ch) { for (int i = 0; i < count; ++i) { putchar(ch); } fflush(stdout); } // I don't know why, but wprintf fails to print this face name, // "MS ゴシック" (aka MS Gothic). It helps to use wprintf instead of printf, and // it helps to call `setlocale(LC_ALL, "")`, but the Japanese symbols are // ultimately converted to `?` symbols, even though MS Gothic is able to // display its own name, and the current code page is 932 (Shift-JIS). static void cvfprintf(HANDLE conout, const wchar_t *fmt, va_list ap) { wchar_t buffer[256]; vswprintf(buffer, 256 - 1, fmt, ap); buffer[255] = L'\0'; DWORD actual = 0; if (!WriteConsoleW(conout, buffer, wcslen(buffer), &actual, NULL)) { wprintf(L"WriteConsoleW call failed!\n"); } } static void cfprintf(HANDLE conout, const wchar_t *fmt, ...) { va_list ap; va_start(ap, fmt); cvfprintf(conout, fmt, ap); va_end(ap); } static void cprintf(const wchar_t *fmt, ...) { va_list ap; va_start(ap, fmt); cvfprintf(GetStdHandle(STD_OUTPUT_HANDLE), fmt, ap); va_end(ap); } static std::string narrowString(const std::wstring &input) { int mblen = WideCharToMultiByte( CP_UTF8, 0, input.data(), input.size(), NULL, 0, NULL, NULL); if (mblen <= 0) { return std::string(); } std::vector tmp(mblen); int mblen2 = WideCharToMultiByte( CP_UTF8, 0, input.data(), input.size(), tmp.data(), tmp.size(), NULL, NULL); assert(mblen2 == mblen); return std::string(tmp.data(), tmp.size()); }