testConsoleBuf.cxx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. /*============================================================================
  2. KWSys - Kitware System Library
  3. Copyright 2000-2016 Kitware, Inc., Insight Software Consortium
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "kwsysPrivate.h"
  11. // Ignore Windows version levels defined by command-line flags. This
  12. // source needs access to all APIs available on the host in order for
  13. // the test to run properly. The test binary is not installed anyway.
  14. #undef _WIN32_WINNT
  15. #undef NTDDI_VERSION
  16. #include KWSYS_HEADER(Encoding.hxx)
  17. // Work-around CMake dependency scanning limitation. This must
  18. // duplicate the above list of headers.
  19. #if 0
  20. # include "Encoding.hxx.in"
  21. #endif
  22. #if defined(_WIN32)
  23. #include <windows.h>
  24. #include <string.h>
  25. #include <wchar.h>
  26. #include <iostream>
  27. #include <stdexcept>
  28. #include "testConsoleBuf.hxx"
  29. #if defined(_MSC_VER) && _MSC_VER >= 1800
  30. # define KWSYS_WINDOWS_DEPRECATED_GetVersion
  31. #endif
  32. // يونيكود
  33. static const WCHAR UnicodeInputTestString[] = L"\u064A\u0648\u0646\u064A\u0643\u0648\u062F!";
  34. static UINT TestCodepage = KWSYS_ENCODING_DEFAULT_CODEPAGE;
  35. static const DWORD waitTimeout = 10 * 1000;
  36. static STARTUPINFO startupInfo;
  37. static PROCESS_INFORMATION processInfo;
  38. static HANDLE syncEvent;
  39. static std::string encodedInputTestString;
  40. static std::string encodedTestString;
  41. //----------------------------------------------------------------------------
  42. static bool createProcess(HANDLE hIn, HANDLE hOut, HANDLE hErr)
  43. {
  44. BOOL bInheritHandles = FALSE;
  45. DWORD dwCreationFlags = 0;
  46. memset(&processInfo, 0, sizeof(processInfo));
  47. memset(&startupInfo, 0, sizeof(startupInfo));
  48. startupInfo.cb = sizeof(startupInfo);
  49. startupInfo.dwFlags = STARTF_USESHOWWINDOW;
  50. startupInfo.wShowWindow = SW_HIDE;
  51. if (hIn || hOut || hErr) {
  52. startupInfo.dwFlags |= STARTF_USESTDHANDLES;
  53. startupInfo.hStdInput = hIn;
  54. startupInfo.hStdOutput = hOut;
  55. startupInfo.hStdError = hErr;
  56. bInheritHandles = TRUE;
  57. }
  58. WCHAR cmd[MAX_PATH];
  59. if (GetModuleFileNameW(NULL, cmd, MAX_PATH) == 0) {
  60. std::cerr << "GetModuleFileName failed!" << std::endl;
  61. return false;
  62. }
  63. WCHAR *p = cmd + wcslen(cmd);
  64. while (p > cmd && *p != L'\\') p--;
  65. *(p+1) = 0;
  66. wcscat(cmd, cmdConsoleBufChild);
  67. wcscat(cmd, L".exe");
  68. bool success = CreateProcessW(NULL, // No module name (use command line)
  69. cmd, // Command line
  70. NULL, // Process handle not inheritable
  71. NULL, // Thread handle not inheritable
  72. bInheritHandles, // Set handle inheritance
  73. dwCreationFlags,
  74. NULL, // Use parent's environment block
  75. NULL, // Use parent's starting directory
  76. &startupInfo, // Pointer to STARTUPINFO structure
  77. &processInfo) != 0; // Pointer to PROCESS_INFORMATION structure
  78. if (!success) {
  79. DWORD lastError = GetLastError();
  80. std::cerr.setf(std::ios::hex, std::ios::basefield);
  81. std::cerr << "CreateProcess(" << kwsys::Encoding::ToNarrow(cmd)
  82. << ") failed with error: 0x" << lastError << "!" << std::endl;
  83. LPWSTR message;
  84. if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  85. NULL,
  86. lastError,
  87. 0,
  88. (LPWSTR)&message, 0,
  89. NULL)
  90. ) {
  91. std::cerr << "Error message: " << kwsys::Encoding::ToNarrow(message) << std::endl;
  92. HeapFree(GetProcessHeap(), 0, message);
  93. } else {
  94. std::cerr << "FormatMessage() failed with error: 0x" << GetLastError() << "!" << std::endl;
  95. }
  96. std::cerr.unsetf(std::ios::hex);
  97. }
  98. return success;
  99. }
  100. //----------------------------------------------------------------------------
  101. static void finishProcess(bool success)
  102. {
  103. if (success) {
  104. success = WaitForSingleObject(processInfo.hProcess, waitTimeout)
  105. == WAIT_OBJECT_0;
  106. };
  107. if (!success) {
  108. TerminateProcess(processInfo.hProcess, 1);
  109. }
  110. CloseHandle(processInfo.hProcess);
  111. CloseHandle(processInfo.hThread);
  112. }
  113. //----------------------------------------------------------------------------
  114. static bool createPipe(PHANDLE readPipe, PHANDLE writePipe)
  115. {
  116. SECURITY_ATTRIBUTES securityAttributes;
  117. securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  118. securityAttributes.bInheritHandle = TRUE;
  119. securityAttributes.lpSecurityDescriptor = NULL;
  120. return CreatePipe(readPipe, writePipe, &securityAttributes, 0) == 0
  121. ? false : true;
  122. }
  123. //----------------------------------------------------------------------------
  124. static void finishPipe(HANDLE readPipe, HANDLE writePipe)
  125. {
  126. if (readPipe != INVALID_HANDLE_VALUE) {
  127. CloseHandle(readPipe);
  128. }
  129. if (writePipe != INVALID_HANDLE_VALUE) {
  130. CloseHandle(writePipe);
  131. }
  132. }
  133. //----------------------------------------------------------------------------
  134. static HANDLE createFile(LPCWSTR fileName)
  135. {
  136. SECURITY_ATTRIBUTES securityAttributes;
  137. securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  138. securityAttributes.bInheritHandle = TRUE;
  139. securityAttributes.lpSecurityDescriptor = NULL;
  140. HANDLE file = CreateFileW(fileName,
  141. GENERIC_READ | GENERIC_WRITE,
  142. 0, // do not share
  143. &securityAttributes,
  144. CREATE_ALWAYS, // overwrite existing
  145. FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
  146. NULL); // no template
  147. if (file == INVALID_HANDLE_VALUE) {
  148. std::cerr << "CreateFile(" << kwsys::Encoding::ToNarrow(fileName)
  149. << ") failed!" << std::endl;
  150. }
  151. return file;
  152. }
  153. //----------------------------------------------------------------------------
  154. static void finishFile(HANDLE file)
  155. {
  156. if (file != INVALID_HANDLE_VALUE) {
  157. CloseHandle(file);
  158. }
  159. }
  160. //----------------------------------------------------------------------------
  161. #ifndef MAPVK_VK_TO_VSC
  162. # define MAPVK_VK_TO_VSC (0)
  163. #endif
  164. static void writeInputKeyEvent(INPUT_RECORD inputBuffer[], WCHAR chr)
  165. {
  166. inputBuffer[0].EventType = KEY_EVENT;
  167. inputBuffer[0].Event.KeyEvent.bKeyDown = TRUE;
  168. inputBuffer[0].Event.KeyEvent.wRepeatCount = 1;
  169. SHORT keyCode = VkKeyScanW(chr);
  170. if (keyCode == -1) {
  171. // Character can't be entered with current keyboard layout
  172. // Just set any, it doesn't really matter
  173. keyCode = 'K';
  174. }
  175. inputBuffer[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(keyCode);
  176. inputBuffer[0].Event.KeyEvent.wVirtualScanCode =
  177. MapVirtualKey(inputBuffer[0].Event.KeyEvent.wVirtualKeyCode,
  178. MAPVK_VK_TO_VSC);
  179. inputBuffer[0].Event.KeyEvent.uChar.UnicodeChar = chr;
  180. inputBuffer[0].Event.KeyEvent.dwControlKeyState = 0;
  181. if ((HIBYTE(keyCode) & 1) == 1) {
  182. inputBuffer[0].Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
  183. }
  184. if ((HIBYTE(keyCode) & 2) == 2) {
  185. inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_CTRL_PRESSED;
  186. }
  187. if ((HIBYTE(keyCode) & 4) == 4) {
  188. inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED;
  189. }
  190. inputBuffer[1].EventType = inputBuffer[0].EventType;
  191. inputBuffer[1].Event.KeyEvent.bKeyDown = FALSE;
  192. inputBuffer[1].Event.KeyEvent.wRepeatCount = 1;
  193. inputBuffer[1].Event.KeyEvent.wVirtualKeyCode = inputBuffer[0].Event.
  194. KeyEvent.wVirtualKeyCode;
  195. inputBuffer[1].Event.KeyEvent.wVirtualScanCode = inputBuffer[0].Event.
  196. KeyEvent.wVirtualScanCode;
  197. inputBuffer[1].Event.KeyEvent.uChar.UnicodeChar = inputBuffer[0].Event.
  198. KeyEvent.uChar.UnicodeChar;
  199. inputBuffer[1].Event.KeyEvent.dwControlKeyState = 0;
  200. }
  201. //----------------------------------------------------------------------------
  202. static int testPipe()
  203. {
  204. int didFail = 1;
  205. HANDLE inPipeRead = INVALID_HANDLE_VALUE;
  206. HANDLE inPipeWrite = INVALID_HANDLE_VALUE;
  207. HANDLE outPipeRead = INVALID_HANDLE_VALUE;
  208. HANDLE outPipeWrite = INVALID_HANDLE_VALUE;
  209. HANDLE errPipeRead = INVALID_HANDLE_VALUE;
  210. HANDLE errPipeWrite = INVALID_HANDLE_VALUE;
  211. UINT currentCodepage = GetConsoleCP();
  212. char buffer[200];
  213. try {
  214. if (!createPipe(&inPipeRead, &inPipeWrite) ||
  215. !createPipe(&outPipeRead, &outPipeWrite) ||
  216. !createPipe(&errPipeRead, &errPipeWrite)) {
  217. throw std::runtime_error("createFile failed!");
  218. }
  219. if (TestCodepage == CP_ACP) {
  220. TestCodepage = GetACP();
  221. }
  222. if (!SetConsoleCP(TestCodepage)) {
  223. throw std::runtime_error("SetConsoleCP failed!");
  224. }
  225. DWORD bytesWritten = 0;
  226. if (!WriteFile(inPipeWrite, encodedInputTestString.c_str(),
  227. (DWORD)encodedInputTestString.size(), &bytesWritten, NULL)
  228. || bytesWritten == 0) {
  229. throw std::runtime_error("WriteFile failed!");
  230. }
  231. if (createProcess(inPipeRead, outPipeWrite, errPipeWrite)) {
  232. try {
  233. Sleep(100);
  234. if (WaitForSingleObject(syncEvent, waitTimeout) != WAIT_OBJECT_0) {
  235. throw std::runtime_error("WaitForSingleObject failed!");
  236. }
  237. DWORD bytesRead = 0;
  238. if (!ReadFile(outPipeRead, buffer, sizeof(buffer), &bytesRead, NULL)
  239. || bytesRead == 0) {
  240. throw std::runtime_error("ReadFile failed!");
  241. }
  242. if ((bytesRead < encodedTestString.size() + 1 + encodedInputTestString.size()
  243. && !ReadFile(outPipeRead, buffer + bytesRead,
  244. sizeof(buffer) - bytesRead, &bytesRead, NULL))
  245. || bytesRead == 0) {
  246. throw std::runtime_error("ReadFile failed!");
  247. }
  248. if (memcmp(buffer, encodedTestString.c_str(),
  249. encodedTestString.size()) == 0 &&
  250. memcmp(buffer + encodedTestString.size() + 1,
  251. encodedInputTestString.c_str(),
  252. encodedInputTestString.size()) == 0) {
  253. bytesRead = 0;
  254. if (!ReadFile(errPipeRead, buffer, sizeof(buffer), &bytesRead, NULL)
  255. || bytesRead == 0) {
  256. throw std::runtime_error("ReadFile failed!");
  257. }
  258. buffer[bytesRead - 1] = 0;
  259. didFail = encodedTestString.compare(buffer) == 0 ? 0 : 1;
  260. }
  261. if (didFail != 0) {
  262. std::cerr << "Pipe's output didn't match expected output!" << std::endl << std::flush;
  263. }
  264. } catch (const std::runtime_error &ex) {
  265. std::cerr << ex.what() << std::endl << std::flush;
  266. }
  267. finishProcess(didFail == 0);
  268. }
  269. } catch (const std::runtime_error &ex) {
  270. std::cerr << ex.what() << std::endl << std::flush;
  271. }
  272. finishPipe(inPipeRead, inPipeWrite);
  273. finishPipe(outPipeRead, outPipeWrite);
  274. finishPipe(errPipeRead, errPipeWrite);
  275. SetConsoleCP(currentCodepage);
  276. return didFail;
  277. }
  278. //----------------------------------------------------------------------------
  279. static int testFile()
  280. {
  281. int didFail = 1;
  282. HANDLE inFile = INVALID_HANDLE_VALUE;
  283. HANDLE outFile = INVALID_HANDLE_VALUE;
  284. HANDLE errFile = INVALID_HANDLE_VALUE;
  285. try {
  286. if ((inFile = createFile(L"stdinFile.txt")) == INVALID_HANDLE_VALUE ||
  287. (outFile = createFile(L"stdoutFile.txt")) == INVALID_HANDLE_VALUE ||
  288. (errFile = createFile(L"stderrFile.txt")) == INVALID_HANDLE_VALUE) {
  289. throw std::runtime_error("createFile failed!");
  290. }
  291. int length = 0;
  292. DWORD bytesWritten = 0;
  293. char buffer[200];
  294. if ((length = WideCharToMultiByte(TestCodepage, 0, UnicodeInputTestString, -1,
  295. buffer, sizeof(buffer),
  296. NULL, NULL)) == 0) {
  297. throw std::runtime_error("WideCharToMultiByte failed!");
  298. }
  299. buffer[length - 1] = '\n';
  300. if (!WriteFile(inFile, buffer, length, &bytesWritten, NULL)
  301. || bytesWritten == 0) {
  302. throw std::runtime_error("WriteFile failed!");
  303. }
  304. if (SetFilePointer(inFile, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
  305. throw std::runtime_error("SetFilePointer failed!");
  306. }
  307. if (createProcess(inFile, outFile, errFile)) {
  308. DWORD bytesRead = 0;
  309. try {
  310. Sleep(100);
  311. if (WaitForSingleObject(syncEvent, waitTimeout) != WAIT_OBJECT_0) {
  312. throw std::runtime_error("WaitForSingleObject failed!");
  313. }
  314. if (SetFilePointer(outFile, 0, 0, FILE_BEGIN)
  315. == INVALID_SET_FILE_POINTER) {
  316. throw std::runtime_error("SetFilePointer failed!");
  317. }
  318. if (!ReadFile(outFile, buffer, sizeof(buffer), &bytesRead, NULL)
  319. || bytesRead == 0) {
  320. throw std::runtime_error("ReadFile failed!");
  321. }
  322. buffer[bytesRead - 1] = 0;
  323. if (memcmp(buffer, encodedTestString.c_str(),
  324. encodedTestString.size()) == 0 &&
  325. memcmp(buffer + encodedTestString.size() + 1,
  326. encodedInputTestString.c_str(),
  327. encodedInputTestString.size() - 1) == 0) {
  328. bytesRead = 0;
  329. if (SetFilePointer(errFile, 0, 0, FILE_BEGIN)
  330. == INVALID_SET_FILE_POINTER) {
  331. throw std::runtime_error("SetFilePointer failed!");
  332. }
  333. if (!ReadFile(errFile, buffer, sizeof(buffer), &bytesRead, NULL)
  334. || bytesRead == 0) {
  335. throw std::runtime_error("ReadFile failed!");
  336. }
  337. buffer[bytesRead - 1] = 0;
  338. didFail = encodedTestString.compare(buffer) == 0 ? 0 : 1;
  339. }
  340. if (didFail != 0) {
  341. std::cerr << "File's output didn't match expected output!" << std::endl << std::flush;
  342. }
  343. } catch (const std::runtime_error &ex) {
  344. std::cerr << ex.what() << std::endl << std::flush;
  345. }
  346. finishProcess(didFail == 0);
  347. }
  348. } catch (const std::runtime_error &ex) {
  349. std::cerr << ex.what() << std::endl << std::flush;
  350. }
  351. finishFile(inFile);
  352. finishFile(outFile);
  353. finishFile(errFile);
  354. return didFail;
  355. }
  356. #ifndef _WIN32_WINNT_VISTA
  357. # define _WIN32_WINNT_VISTA 0x0600
  358. #endif
  359. //----------------------------------------------------------------------------
  360. static int testConsole()
  361. {
  362. int didFail = 1;
  363. HANDLE parentIn = GetStdHandle(STD_INPUT_HANDLE);
  364. HANDLE parentOut = GetStdHandle(STD_OUTPUT_HANDLE);
  365. HANDLE parentErr = GetStdHandle(STD_ERROR_HANDLE);
  366. HANDLE hIn = parentIn;
  367. HANDLE hOut = parentOut;
  368. DWORD consoleMode;
  369. bool newConsole = false;
  370. bool forceNewConsole = false;
  371. bool restoreConsole = false;
  372. LPCWSTR TestFaceName = L"Lucida Console";
  373. const DWORD TestFontFamily = 0x00000036;
  374. const DWORD TestFontSize = 0x000c0000;
  375. HKEY hConsoleKey;
  376. WCHAR FaceName[200];
  377. DWORD FaceNameSize = sizeof(FaceName);
  378. DWORD FontFamily = TestFontFamily;
  379. DWORD FontSize = TestFontSize;
  380. #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion
  381. # pragma warning (push)
  382. # ifdef __INTEL_COMPILER
  383. # pragma warning (disable:1478)
  384. # else
  385. # pragma warning (disable:4996)
  386. # endif
  387. #endif
  388. const bool isVistaOrGreater = LOBYTE(LOWORD(GetVersion())) >= HIBYTE(_WIN32_WINNT_VISTA);
  389. #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion
  390. # pragma warning (pop)
  391. #endif
  392. if (!isVistaOrGreater) {
  393. if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_READ | KEY_WRITE,
  394. &hConsoleKey) == ERROR_SUCCESS) {
  395. DWORD dwordSize = sizeof(DWORD);
  396. if (RegQueryValueExW(hConsoleKey, L"FontFamily", NULL, NULL,
  397. (LPBYTE)&FontFamily, &dwordSize) == ERROR_SUCCESS) {
  398. if (FontFamily != TestFontFamily) {
  399. RegQueryValueExW(hConsoleKey, L"FaceName", NULL, NULL,
  400. (LPBYTE)FaceName, &FaceNameSize);
  401. RegQueryValueExW(hConsoleKey, L"FontSize", NULL, NULL,
  402. (LPBYTE)&FontSize, &dwordSize);
  403. RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD,
  404. (BYTE *)&TestFontFamily, sizeof(TestFontFamily));
  405. RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ,
  406. (BYTE *)TestFaceName, (DWORD)((wcslen(TestFaceName) + 1) * sizeof(WCHAR)));
  407. RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD,
  408. (BYTE *)&TestFontSize, sizeof(TestFontSize));
  409. restoreConsole = true;
  410. forceNewConsole = true;
  411. }
  412. } else {
  413. std::cerr << "RegGetValueW(FontFamily) failed!" << std::endl << std::flush;
  414. }
  415. RegCloseKey(hConsoleKey);
  416. } else {
  417. std::cerr << "RegOpenKeyExW(HKEY_CURRENT_USER\\Console) failed!" << std::endl << std::flush;
  418. }
  419. }
  420. if (forceNewConsole || GetConsoleMode(parentOut, &consoleMode) == 0) {
  421. // Not a real console, let's create new one.
  422. FreeConsole();
  423. if (!AllocConsole()) {
  424. std::cerr << "AllocConsole failed!" << std::endl << std::flush;
  425. return didFail;
  426. }
  427. SECURITY_ATTRIBUTES securityAttributes;
  428. securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  429. securityAttributes.bInheritHandle = TRUE;
  430. securityAttributes.lpSecurityDescriptor = NULL;
  431. hIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, 0,
  432. &securityAttributes, OPEN_EXISTING, 0, NULL);
  433. hOut = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, 0,
  434. &securityAttributes, OPEN_EXISTING, 0, NULL);
  435. SetStdHandle(STD_INPUT_HANDLE, hIn);
  436. SetStdHandle(STD_OUTPUT_HANDLE, hOut);
  437. SetStdHandle(STD_ERROR_HANDLE, hOut);
  438. newConsole = true;
  439. }
  440. #if _WIN32_WINNT >= _WIN32_WINNT_VISTA
  441. if (isVistaOrGreater) {
  442. CONSOLE_FONT_INFOEX consoleFont;
  443. memset(&consoleFont, 0, sizeof(consoleFont));
  444. consoleFont.cbSize = sizeof(consoleFont);
  445. HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
  446. typedef BOOL (WINAPI *GetCurrentConsoleFontExFunc)(HANDLE hConsoleOutput, BOOL bMaximumWindow, PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
  447. typedef BOOL (WINAPI *SetCurrentConsoleFontExFunc)(HANDLE hConsoleOutput, BOOL bMaximumWindow, PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
  448. GetCurrentConsoleFontExFunc getConsoleFont = (GetCurrentConsoleFontExFunc)GetProcAddress(kernel32, "GetCurrentConsoleFontEx");
  449. SetCurrentConsoleFontExFunc setConsoleFont = (SetCurrentConsoleFontExFunc)GetProcAddress(kernel32, "SetCurrentConsoleFontEx");
  450. if (getConsoleFont(hOut, FALSE, &consoleFont)) {
  451. if (consoleFont.FontFamily != TestFontFamily) {
  452. consoleFont.FontFamily = TestFontFamily;
  453. wcscpy(consoleFont.FaceName, TestFaceName);
  454. if (!setConsoleFont(hOut, FALSE, &consoleFont)) {
  455. std::cerr << "SetCurrentConsoleFontEx failed!" << std::endl << std::flush;
  456. }
  457. }
  458. } else {
  459. std::cerr << "GetCurrentConsoleFontEx failed!" << std::endl << std::flush;
  460. }
  461. } else {
  462. #endif
  463. if (restoreConsole && RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0,
  464. KEY_WRITE, &hConsoleKey) == ERROR_SUCCESS) {
  465. RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD,
  466. (BYTE *)&FontFamily, sizeof(FontFamily));
  467. RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ,
  468. (BYTE *)FaceName, FaceNameSize);
  469. RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD,
  470. (BYTE *)&FontSize, sizeof(FontSize));
  471. RegCloseKey(hConsoleKey);
  472. }
  473. #if _WIN32_WINNT >= _WIN32_WINNT_VISTA
  474. }
  475. #endif
  476. if (createProcess(NULL, NULL, NULL)) {
  477. try {
  478. if (WaitForSingleObject(syncEvent, waitTimeout) != WAIT_OBJECT_0) {
  479. throw std::runtime_error("WaitForSingleObject failed!");
  480. }
  481. INPUT_RECORD inputBuffer[(sizeof(UnicodeInputTestString) /
  482. sizeof(UnicodeInputTestString[0])) * 2];
  483. memset(&inputBuffer, 0, sizeof(inputBuffer));
  484. unsigned int i = 0;
  485. for (i = 0; i < (sizeof(UnicodeInputTestString) /
  486. sizeof(UnicodeInputTestString[0]) - 1); i++) {
  487. writeInputKeyEvent(&inputBuffer[i*2], UnicodeInputTestString[i]);
  488. }
  489. writeInputKeyEvent(&inputBuffer[i*2], VK_RETURN);
  490. DWORD eventsWritten = 0;
  491. if (!WriteConsoleInputW(hIn, inputBuffer, sizeof(inputBuffer) /
  492. sizeof(inputBuffer[0]),
  493. &eventsWritten) || eventsWritten == 0) {
  494. throw std::runtime_error("WriteConsoleInput failed!");
  495. }
  496. if (WaitForSingleObject(syncEvent, waitTimeout) != WAIT_OBJECT_0) {
  497. throw std::runtime_error("WaitForSingleObject failed!");
  498. }
  499. CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
  500. if (!GetConsoleScreenBufferInfo(hOut, &screenBufferInfo)) {
  501. throw std::runtime_error("GetConsoleScreenBufferInfo failed!");
  502. }
  503. COORD coord;
  504. DWORD charsRead = 0;
  505. coord.X = 0;
  506. coord.Y = screenBufferInfo.dwCursorPosition.Y - 4;
  507. WCHAR *outputBuffer = new WCHAR[screenBufferInfo.dwSize.X * 4];
  508. if (!ReadConsoleOutputCharacterW(hOut, outputBuffer,
  509. screenBufferInfo.dwSize.X * 4, coord, &charsRead)
  510. || charsRead == 0) {
  511. delete[] outputBuffer;
  512. throw std::runtime_error("ReadConsoleOutputCharacter failed!");
  513. }
  514. std::wstring wideTestString = kwsys::Encoding::ToWide(encodedTestString);
  515. std::wstring wideInputTestString = kwsys::Encoding::ToWide(encodedInputTestString);
  516. if (memcmp(outputBuffer, wideTestString.c_str(), wideTestString.size()) == 0 &&
  517. memcmp(outputBuffer + screenBufferInfo.dwSize.X * 1,
  518. wideTestString.c_str(), wideTestString.size()) == 0 &&
  519. memcmp(outputBuffer + screenBufferInfo.dwSize.X * 2,
  520. UnicodeInputTestString, sizeof(UnicodeInputTestString) -
  521. sizeof(WCHAR)) == 0 &&
  522. memcmp(outputBuffer + screenBufferInfo.dwSize.X * 3,
  523. wideInputTestString.c_str(), wideInputTestString.size() - 1) == 0
  524. ) {
  525. didFail = 0;
  526. } else {
  527. std::cerr << "Console's output didn't match expected output!" << std::endl << std::flush;
  528. }
  529. delete[] outputBuffer;
  530. } catch (const std::runtime_error &ex) {
  531. std::cerr << ex.what() << std::endl << std::flush;
  532. }
  533. finishProcess(didFail == 0);
  534. }
  535. if (newConsole) {
  536. SetStdHandle(STD_INPUT_HANDLE, parentIn);
  537. SetStdHandle(STD_OUTPUT_HANDLE, parentOut);
  538. SetStdHandle(STD_ERROR_HANDLE, parentErr);
  539. CloseHandle(hIn);
  540. CloseHandle(hOut);
  541. FreeConsole();
  542. }
  543. return didFail;
  544. }
  545. #endif
  546. //----------------------------------------------------------------------------
  547. int testConsoleBuf(int, char*[])
  548. {
  549. int ret = 0;
  550. #if defined(_WIN32)
  551. syncEvent = CreateEventW(NULL,
  552. FALSE, // auto-reset event
  553. FALSE, // initial state is nonsignaled
  554. SyncEventName); // object name
  555. if (!syncEvent) {
  556. std::cerr << "CreateEvent failed " << GetLastError() << std::endl;
  557. return 1;
  558. }
  559. encodedTestString = kwsys::Encoding::ToNarrow(UnicodeTestString);
  560. encodedInputTestString = kwsys::Encoding::ToNarrow(UnicodeInputTestString);
  561. encodedInputTestString += "\n";
  562. ret |= testPipe();
  563. ret |= testFile();
  564. ret |= testConsole();
  565. CloseHandle(syncEvent);
  566. #endif
  567. return ret;
  568. }