testConsoleBuf.cxx 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
  3. #include "kwsysPrivate.h"
  4. // Ignore Windows version levels defined by command-line flags. This
  5. // source needs access to all APIs available on the host in order for
  6. // the test to run properly. The test binary is not installed anyway.
  7. #undef _WIN32_WINNT
  8. #undef NTDDI_VERSION
  9. #include KWSYS_HEADER(Encoding.hxx)
  10. // Work-around CMake dependency scanning limitation. This must
  11. // duplicate the above list of headers.
  12. #if 0
  13. #include "Encoding.hxx.in"
  14. #endif
  15. #if defined(_WIN32)
  16. #include <algorithm>
  17. #include <iomanip>
  18. #include <iostream>
  19. #include <stdexcept>
  20. #include <string.h>
  21. #include <wchar.h>
  22. #include <windows.h>
  23. #include "testConsoleBuf.hxx"
  24. #if defined(_MSC_VER) && _MSC_VER >= 1800
  25. #define KWSYS_WINDOWS_DEPRECATED_GetVersion
  26. #endif
  27. // يونيكود
  28. static const WCHAR UnicodeInputTestString[] =
  29. L"\u064A\u0648\u0646\u064A\u0643\u0648\u062F!";
  30. static UINT TestCodepage = KWSYS_ENCODING_DEFAULT_CODEPAGE;
  31. static const DWORD waitTimeout = 10 * 1000;
  32. static STARTUPINFO startupInfo;
  33. static PROCESS_INFORMATION processInfo;
  34. static HANDLE beforeInputEvent;
  35. static HANDLE afterOutputEvent;
  36. static std::string encodedInputTestString;
  37. static std::string encodedTestString;
  38. static void displayError(DWORD errorCode)
  39. {
  40. std::cerr.setf(std::ios::hex, std::ios::basefield);
  41. std::cerr << "Failed with error: 0x" << errorCode << "!" << std::endl;
  42. LPWSTR message;
  43. if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  44. FORMAT_MESSAGE_FROM_SYSTEM,
  45. NULL, errorCode, 0, (LPWSTR)&message, 0, NULL)) {
  46. std::cerr << "Error message: " << kwsys::Encoding::ToNarrow(message)
  47. << std::endl;
  48. HeapFree(GetProcessHeap(), 0, message);
  49. } else {
  50. std::cerr << "FormatMessage() failed with error: 0x" << GetLastError()
  51. << "!" << std::endl;
  52. }
  53. std::cerr.unsetf(std::ios::hex);
  54. }
  55. std::basic_streambuf<char>* errstream(const char* unused)
  56. {
  57. static_cast<void>(unused);
  58. return std::cerr.rdbuf();
  59. }
  60. std::basic_streambuf<wchar_t>* errstream(const wchar_t* unused)
  61. {
  62. static_cast<void>(unused);
  63. return std::wcerr.rdbuf();
  64. }
  65. template <typename T>
  66. static void dumpBuffers(const T* expected, const T* received, size_t size)
  67. {
  68. std::basic_ostream<T> err(errstream(expected));
  69. err << "Expected output: '" << std::basic_string<T>(expected, size) << "'"
  70. << std::endl;
  71. if (err.fail()) {
  72. err.clear();
  73. err << "--- Error while outputting ---" << std::endl;
  74. }
  75. err << "Received output: '" << std::basic_string<T>(received, size) << "'"
  76. << std::endl;
  77. if (err.fail()) {
  78. err.clear();
  79. err << "--- Error while outputting ---" << std::endl;
  80. }
  81. std::cerr << "Expected output | Received output" << std::endl;
  82. for (size_t i = 0; i < size; i++) {
  83. std::cerr << std::setbase(16) << std::setfill('0') << " "
  84. << "0x" << std::setw(8) << static_cast<unsigned int>(expected[i])
  85. << " | "
  86. << "0x" << std::setw(8)
  87. << static_cast<unsigned int>(received[i]);
  88. if (static_cast<unsigned int>(expected[i]) !=
  89. static_cast<unsigned int>(received[i])) {
  90. std::cerr << " MISMATCH!";
  91. }
  92. std::cerr << std::endl;
  93. }
  94. std::cerr << std::endl;
  95. }
  96. static bool createProcess(HANDLE hIn, HANDLE hOut, HANDLE hErr)
  97. {
  98. BOOL bInheritHandles = FALSE;
  99. DWORD dwCreationFlags = 0;
  100. memset(&processInfo, 0, sizeof(processInfo));
  101. memset(&startupInfo, 0, sizeof(startupInfo));
  102. startupInfo.cb = sizeof(startupInfo);
  103. startupInfo.dwFlags = STARTF_USESHOWWINDOW;
  104. startupInfo.wShowWindow = SW_HIDE;
  105. if (hIn || hOut || hErr) {
  106. startupInfo.dwFlags |= STARTF_USESTDHANDLES;
  107. startupInfo.hStdInput = hIn;
  108. startupInfo.hStdOutput = hOut;
  109. startupInfo.hStdError = hErr;
  110. bInheritHandles = TRUE;
  111. }
  112. WCHAR cmd[MAX_PATH];
  113. if (GetModuleFileNameW(NULL, cmd, MAX_PATH) == 0) {
  114. std::cerr << "GetModuleFileName failed!" << std::endl;
  115. return false;
  116. }
  117. WCHAR* p = cmd + wcslen(cmd);
  118. while (p > cmd && *p != L'\\')
  119. p--;
  120. *(p + 1) = 0;
  121. wcscat(cmd, cmdConsoleBufChild);
  122. wcscat(cmd, L".exe");
  123. bool success =
  124. CreateProcessW(NULL, // No module name (use command line)
  125. cmd, // Command line
  126. NULL, // Process handle not inheritable
  127. NULL, // Thread handle not inheritable
  128. bInheritHandles, // Set handle inheritance
  129. dwCreationFlags,
  130. NULL, // Use parent's environment block
  131. NULL, // Use parent's starting directory
  132. &startupInfo, // Pointer to STARTUPINFO structure
  133. &processInfo) !=
  134. 0; // Pointer to PROCESS_INFORMATION structure
  135. if (!success) {
  136. DWORD lastError = GetLastError();
  137. std::cerr << "CreateProcess(" << kwsys::Encoding::ToNarrow(cmd) << ")"
  138. << std::endl;
  139. displayError(lastError);
  140. }
  141. return success;
  142. }
  143. static void finishProcess(bool success)
  144. {
  145. if (success) {
  146. success =
  147. WaitForSingleObject(processInfo.hProcess, waitTimeout) == WAIT_OBJECT_0;
  148. };
  149. if (!success) {
  150. TerminateProcess(processInfo.hProcess, 1);
  151. }
  152. CloseHandle(processInfo.hProcess);
  153. CloseHandle(processInfo.hThread);
  154. }
  155. static bool createPipe(PHANDLE readPipe, PHANDLE writePipe)
  156. {
  157. SECURITY_ATTRIBUTES securityAttributes;
  158. securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  159. securityAttributes.bInheritHandle = TRUE;
  160. securityAttributes.lpSecurityDescriptor = NULL;
  161. return CreatePipe(readPipe, writePipe, &securityAttributes, 0) == 0 ? false
  162. : true;
  163. }
  164. static void finishPipe(HANDLE readPipe, HANDLE writePipe)
  165. {
  166. if (readPipe != INVALID_HANDLE_VALUE) {
  167. CloseHandle(readPipe);
  168. }
  169. if (writePipe != INVALID_HANDLE_VALUE) {
  170. CloseHandle(writePipe);
  171. }
  172. }
  173. static HANDLE createFile(LPCWSTR fileName)
  174. {
  175. SECURITY_ATTRIBUTES securityAttributes;
  176. securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  177. securityAttributes.bInheritHandle = TRUE;
  178. securityAttributes.lpSecurityDescriptor = NULL;
  179. HANDLE file =
  180. CreateFileW(fileName, GENERIC_READ | GENERIC_WRITE,
  181. 0, // do not share
  182. &securityAttributes,
  183. CREATE_ALWAYS, // overwrite existing
  184. FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
  185. NULL); // no template
  186. if (file == INVALID_HANDLE_VALUE) {
  187. DWORD lastError = GetLastError();
  188. std::cerr << "CreateFile(" << kwsys::Encoding::ToNarrow(fileName) << ")"
  189. << std::endl;
  190. displayError(lastError);
  191. }
  192. return file;
  193. }
  194. static void finishFile(HANDLE file)
  195. {
  196. if (file != INVALID_HANDLE_VALUE) {
  197. CloseHandle(file);
  198. }
  199. }
  200. #ifndef MAPVK_VK_TO_VSC
  201. #define MAPVK_VK_TO_VSC (0)
  202. #endif
  203. static void writeInputKeyEvent(INPUT_RECORD inputBuffer[], WCHAR chr)
  204. {
  205. inputBuffer[0].EventType = KEY_EVENT;
  206. inputBuffer[0].Event.KeyEvent.bKeyDown = TRUE;
  207. inputBuffer[0].Event.KeyEvent.wRepeatCount = 1;
  208. SHORT keyCode = VkKeyScanW(chr);
  209. if (keyCode == -1) {
  210. // Character can't be entered with current keyboard layout
  211. // Just set any, it doesn't really matter
  212. keyCode = 'K';
  213. }
  214. inputBuffer[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(keyCode);
  215. inputBuffer[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(
  216. inputBuffer[0].Event.KeyEvent.wVirtualKeyCode, MAPVK_VK_TO_VSC);
  217. inputBuffer[0].Event.KeyEvent.uChar.UnicodeChar = chr;
  218. inputBuffer[0].Event.KeyEvent.dwControlKeyState = 0;
  219. if ((HIBYTE(keyCode) & 1) == 1) {
  220. inputBuffer[0].Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
  221. }
  222. if ((HIBYTE(keyCode) & 2) == 2) {
  223. inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_CTRL_PRESSED;
  224. }
  225. if ((HIBYTE(keyCode) & 4) == 4) {
  226. inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED;
  227. }
  228. inputBuffer[1].EventType = inputBuffer[0].EventType;
  229. inputBuffer[1].Event.KeyEvent.bKeyDown = FALSE;
  230. inputBuffer[1].Event.KeyEvent.wRepeatCount = 1;
  231. inputBuffer[1].Event.KeyEvent.wVirtualKeyCode =
  232. inputBuffer[0].Event.KeyEvent.wVirtualKeyCode;
  233. inputBuffer[1].Event.KeyEvent.wVirtualScanCode =
  234. inputBuffer[0].Event.KeyEvent.wVirtualScanCode;
  235. inputBuffer[1].Event.KeyEvent.uChar.UnicodeChar =
  236. inputBuffer[0].Event.KeyEvent.uChar.UnicodeChar;
  237. inputBuffer[1].Event.KeyEvent.dwControlKeyState = 0;
  238. }
  239. static int testPipe()
  240. {
  241. int didFail = 1;
  242. HANDLE inPipeRead = INVALID_HANDLE_VALUE;
  243. HANDLE inPipeWrite = INVALID_HANDLE_VALUE;
  244. HANDLE outPipeRead = INVALID_HANDLE_VALUE;
  245. HANDLE outPipeWrite = INVALID_HANDLE_VALUE;
  246. HANDLE errPipeRead = INVALID_HANDLE_VALUE;
  247. HANDLE errPipeWrite = INVALID_HANDLE_VALUE;
  248. UINT currentCodepage = GetConsoleCP();
  249. char buffer[200];
  250. char buffer2[200];
  251. try {
  252. if (!createPipe(&inPipeRead, &inPipeWrite) ||
  253. !createPipe(&outPipeRead, &outPipeWrite) ||
  254. !createPipe(&errPipeRead, &errPipeWrite)) {
  255. throw std::runtime_error("createFile failed!");
  256. }
  257. if (TestCodepage == CP_ACP) {
  258. TestCodepage = GetACP();
  259. }
  260. if (!SetConsoleCP(TestCodepage)) {
  261. throw std::runtime_error("SetConsoleCP failed!");
  262. }
  263. DWORD bytesWritten = 0;
  264. if (!WriteFile(inPipeWrite, encodedInputTestString.c_str(),
  265. (DWORD)encodedInputTestString.size(), &bytesWritten,
  266. NULL) ||
  267. bytesWritten == 0) {
  268. throw std::runtime_error("WriteFile failed!");
  269. }
  270. if (createProcess(inPipeRead, outPipeWrite, errPipeWrite)) {
  271. try {
  272. DWORD status;
  273. if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) !=
  274. WAIT_OBJECT_0) {
  275. std::cerr.setf(std::ios::hex, std::ios::basefield);
  276. std::cerr << "WaitForSingleObject returned unexpected status 0x"
  277. << status << std::endl;
  278. std::cerr.unsetf(std::ios::hex);
  279. throw std::runtime_error("WaitForSingleObject failed!");
  280. }
  281. DWORD bytesRead = 0;
  282. if (!ReadFile(outPipeRead, buffer, sizeof(buffer), &bytesRead, NULL) ||
  283. bytesRead == 0) {
  284. throw std::runtime_error("ReadFile#1 failed!");
  285. }
  286. buffer[bytesRead] = 0;
  287. if ((bytesRead <
  288. encodedTestString.size() + 1 + encodedInputTestString.size() &&
  289. !ReadFile(outPipeRead, buffer + bytesRead,
  290. sizeof(buffer) - bytesRead, &bytesRead, NULL)) ||
  291. bytesRead == 0) {
  292. throw std::runtime_error("ReadFile#2 failed!");
  293. }
  294. if (memcmp(buffer, encodedTestString.c_str(),
  295. encodedTestString.size()) == 0 &&
  296. memcmp(buffer + encodedTestString.size() + 1,
  297. encodedInputTestString.c_str(),
  298. encodedInputTestString.size()) == 0) {
  299. bytesRead = 0;
  300. if (!ReadFile(errPipeRead, buffer2, sizeof(buffer2), &bytesRead,
  301. NULL) ||
  302. bytesRead == 0) {
  303. throw std::runtime_error("ReadFile#3 failed!");
  304. }
  305. buffer2[bytesRead] = 0;
  306. didFail =
  307. encodedTestString.compare(0, encodedTestString.npos, buffer2,
  308. encodedTestString.size()) == 0
  309. ? 0
  310. : 1;
  311. }
  312. if (didFail != 0) {
  313. std::cerr << "Pipe's output didn't match expected output!"
  314. << std::endl;
  315. dumpBuffers<char>(encodedTestString.c_str(), buffer,
  316. encodedTestString.size());
  317. dumpBuffers<char>(encodedInputTestString.c_str(),
  318. buffer + encodedTestString.size() + 1,
  319. encodedInputTestString.size());
  320. dumpBuffers<char>(encodedTestString.c_str(), buffer2,
  321. encodedTestString.size());
  322. }
  323. } catch (const std::runtime_error& ex) {
  324. DWORD lastError = GetLastError();
  325. std::cerr << "In function testPipe, line " << __LINE__ << ": "
  326. << ex.what() << std::endl;
  327. displayError(lastError);
  328. }
  329. finishProcess(didFail == 0);
  330. }
  331. } catch (const std::runtime_error& ex) {
  332. DWORD lastError = GetLastError();
  333. std::cerr << "In function testPipe, line " << __LINE__ << ": " << ex.what()
  334. << std::endl;
  335. displayError(lastError);
  336. }
  337. finishPipe(inPipeRead, inPipeWrite);
  338. finishPipe(outPipeRead, outPipeWrite);
  339. finishPipe(errPipeRead, errPipeWrite);
  340. SetConsoleCP(currentCodepage);
  341. return didFail;
  342. }
  343. static int testFile()
  344. {
  345. int didFail = 1;
  346. HANDLE inFile = INVALID_HANDLE_VALUE;
  347. HANDLE outFile = INVALID_HANDLE_VALUE;
  348. HANDLE errFile = INVALID_HANDLE_VALUE;
  349. try {
  350. if ((inFile = createFile(L"stdinFile.txt")) == INVALID_HANDLE_VALUE ||
  351. (outFile = createFile(L"stdoutFile.txt")) == INVALID_HANDLE_VALUE ||
  352. (errFile = createFile(L"stderrFile.txt")) == INVALID_HANDLE_VALUE) {
  353. throw std::runtime_error("createFile failed!");
  354. }
  355. DWORD bytesWritten = 0;
  356. char buffer[200];
  357. char buffer2[200];
  358. int length;
  359. if ((length =
  360. WideCharToMultiByte(TestCodepage, 0, UnicodeInputTestString, -1,
  361. buffer, sizeof(buffer), NULL, NULL)) == 0) {
  362. throw std::runtime_error("WideCharToMultiByte failed!");
  363. }
  364. buffer[length - 1] = '\n';
  365. if (!WriteFile(inFile, buffer, length, &bytesWritten, NULL) ||
  366. bytesWritten == 0) {
  367. throw std::runtime_error("WriteFile failed!");
  368. }
  369. if (SetFilePointer(inFile, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
  370. throw std::runtime_error("SetFilePointer failed!");
  371. }
  372. if (createProcess(inFile, outFile, errFile)) {
  373. DWORD bytesRead = 0;
  374. try {
  375. DWORD status;
  376. if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) !=
  377. WAIT_OBJECT_0) {
  378. std::cerr.setf(std::ios::hex, std::ios::basefield);
  379. std::cerr << "WaitForSingleObject returned unexpected status 0x"
  380. << status << std::endl;
  381. std::cerr.unsetf(std::ios::hex);
  382. throw std::runtime_error("WaitForSingleObject failed!");
  383. }
  384. if (SetFilePointer(outFile, 0, 0, FILE_BEGIN) ==
  385. INVALID_SET_FILE_POINTER) {
  386. throw std::runtime_error("SetFilePointer#1 failed!");
  387. }
  388. if (!ReadFile(outFile, buffer, sizeof(buffer), &bytesRead, NULL) ||
  389. bytesRead == 0) {
  390. throw std::runtime_error("ReadFile#1 failed!");
  391. }
  392. buffer[bytesRead] = 0;
  393. if (memcmp(buffer, encodedTestString.c_str(),
  394. encodedTestString.size()) == 0 &&
  395. memcmp(buffer + encodedTestString.size() + 1,
  396. encodedInputTestString.c_str(),
  397. encodedInputTestString.size()) == 0) {
  398. bytesRead = 0;
  399. if (SetFilePointer(errFile, 0, 0, FILE_BEGIN) ==
  400. INVALID_SET_FILE_POINTER) {
  401. throw std::runtime_error("SetFilePointer#2 failed!");
  402. }
  403. if (!ReadFile(errFile, buffer2, sizeof(buffer2), &bytesRead, NULL) ||
  404. bytesRead == 0) {
  405. throw std::runtime_error("ReadFile#2 failed!");
  406. }
  407. buffer2[bytesRead] = 0;
  408. didFail =
  409. encodedTestString.compare(0, encodedTestString.npos, buffer2,
  410. encodedTestString.size()) == 0
  411. ? 0
  412. : 1;
  413. }
  414. if (didFail != 0) {
  415. std::cerr << "File's output didn't match expected output!"
  416. << std::endl;
  417. dumpBuffers<char>(encodedTestString.c_str(), buffer,
  418. encodedTestString.size());
  419. dumpBuffers<char>(encodedInputTestString.c_str(),
  420. buffer + encodedTestString.size() + 1,
  421. encodedInputTestString.size());
  422. dumpBuffers<char>(encodedTestString.c_str(), buffer2,
  423. encodedTestString.size());
  424. }
  425. } catch (const std::runtime_error& ex) {
  426. DWORD lastError = GetLastError();
  427. std::cerr << "In function testFile, line " << __LINE__ << ": "
  428. << ex.what() << std::endl;
  429. displayError(lastError);
  430. }
  431. finishProcess(didFail == 0);
  432. }
  433. } catch (const std::runtime_error& ex) {
  434. DWORD lastError = GetLastError();
  435. std::cerr << "In function testFile, line " << __LINE__ << ": " << ex.what()
  436. << std::endl;
  437. displayError(lastError);
  438. }
  439. finishFile(inFile);
  440. finishFile(outFile);
  441. finishFile(errFile);
  442. return didFail;
  443. }
  444. #ifndef _WIN32_WINNT_VISTA
  445. #define _WIN32_WINNT_VISTA 0x0600
  446. #endif
  447. static int testConsole()
  448. {
  449. int didFail = 1;
  450. HANDLE parentIn = GetStdHandle(STD_INPUT_HANDLE);
  451. HANDLE parentOut = GetStdHandle(STD_OUTPUT_HANDLE);
  452. HANDLE parentErr = GetStdHandle(STD_ERROR_HANDLE);
  453. HANDLE hIn = parentIn;
  454. HANDLE hOut = parentOut;
  455. DWORD consoleMode;
  456. bool newConsole = false;
  457. bool forceNewConsole = false;
  458. bool restoreConsole = false;
  459. LPCWSTR TestFaceName = L"Lucida Console";
  460. const DWORD TestFontFamily = 0x00000036;
  461. const DWORD TestFontSize = 0x000c0000;
  462. HKEY hConsoleKey;
  463. WCHAR FaceName[200];
  464. FaceName[0] = 0;
  465. DWORD FaceNameSize = sizeof(FaceName);
  466. DWORD FontFamily = TestFontFamily;
  467. DWORD FontSize = TestFontSize;
  468. #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion
  469. #pragma warning(push)
  470. #ifdef __INTEL_COMPILER
  471. #pragma warning(disable : 1478)
  472. #else
  473. #pragma warning(disable : 4996)
  474. #endif
  475. #endif
  476. const bool isVistaOrGreater =
  477. LOBYTE(LOWORD(GetVersion())) >= HIBYTE(_WIN32_WINNT_VISTA);
  478. #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion
  479. #pragma warning(pop)
  480. #endif
  481. if (!isVistaOrGreater) {
  482. if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_READ | KEY_WRITE,
  483. &hConsoleKey) == ERROR_SUCCESS) {
  484. DWORD dwordSize = sizeof(DWORD);
  485. if (RegQueryValueExW(hConsoleKey, L"FontFamily", NULL, NULL,
  486. (LPBYTE)&FontFamily, &dwordSize) == ERROR_SUCCESS) {
  487. if (FontFamily != TestFontFamily) {
  488. RegQueryValueExW(hConsoleKey, L"FaceName", NULL, NULL,
  489. (LPBYTE)FaceName, &FaceNameSize);
  490. RegQueryValueExW(hConsoleKey, L"FontSize", NULL, NULL,
  491. (LPBYTE)&FontSize, &dwordSize);
  492. RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD,
  493. (BYTE*)&TestFontFamily, sizeof(TestFontFamily));
  494. RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ,
  495. (BYTE*)TestFaceName,
  496. (DWORD)((wcslen(TestFaceName) + 1) * sizeof(WCHAR)));
  497. RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD,
  498. (BYTE*)&TestFontSize, sizeof(TestFontSize));
  499. restoreConsole = true;
  500. forceNewConsole = true;
  501. }
  502. } else {
  503. std::cerr << "RegGetValueW(FontFamily) failed!" << std::endl;
  504. }
  505. RegCloseKey(hConsoleKey);
  506. } else {
  507. std::cerr << "RegOpenKeyExW(HKEY_CURRENT_USER\\Console) failed!"
  508. << std::endl;
  509. }
  510. }
  511. if (forceNewConsole || GetConsoleMode(parentOut, &consoleMode) == 0) {
  512. // Not a real console, let's create new one.
  513. FreeConsole();
  514. if (!AllocConsole()) {
  515. std::cerr << "AllocConsole failed!" << std::endl;
  516. return didFail;
  517. }
  518. SECURITY_ATTRIBUTES securityAttributes;
  519. securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  520. securityAttributes.bInheritHandle = TRUE;
  521. securityAttributes.lpSecurityDescriptor = NULL;
  522. hIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE,
  523. FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes,
  524. OPEN_EXISTING, 0, NULL);
  525. if (hIn == INVALID_HANDLE_VALUE) {
  526. DWORD lastError = GetLastError();
  527. std::cerr << "CreateFile(CONIN$)" << std::endl;
  528. displayError(lastError);
  529. }
  530. hOut = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
  531. FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes,
  532. OPEN_EXISTING, 0, NULL);
  533. if (hOut == INVALID_HANDLE_VALUE) {
  534. DWORD lastError = GetLastError();
  535. std::cerr << "CreateFile(CONOUT$)" << std::endl;
  536. displayError(lastError);
  537. }
  538. SetStdHandle(STD_INPUT_HANDLE, hIn);
  539. SetStdHandle(STD_OUTPUT_HANDLE, hOut);
  540. SetStdHandle(STD_ERROR_HANDLE, hOut);
  541. newConsole = true;
  542. }
  543. #if _WIN32_WINNT >= _WIN32_WINNT_VISTA
  544. if (isVistaOrGreater) {
  545. CONSOLE_FONT_INFOEX consoleFont;
  546. memset(&consoleFont, 0, sizeof(consoleFont));
  547. consoleFont.cbSize = sizeof(consoleFont);
  548. HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
  549. typedef BOOL(WINAPI * GetCurrentConsoleFontExFunc)(
  550. HANDLE hConsoleOutput, BOOL bMaximumWindow,
  551. PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
  552. typedef BOOL(WINAPI * SetCurrentConsoleFontExFunc)(
  553. HANDLE hConsoleOutput, BOOL bMaximumWindow,
  554. PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
  555. GetCurrentConsoleFontExFunc getConsoleFont =
  556. (GetCurrentConsoleFontExFunc)GetProcAddress(kernel32,
  557. "GetCurrentConsoleFontEx");
  558. SetCurrentConsoleFontExFunc setConsoleFont =
  559. (SetCurrentConsoleFontExFunc)GetProcAddress(kernel32,
  560. "SetCurrentConsoleFontEx");
  561. if (getConsoleFont(hOut, FALSE, &consoleFont)) {
  562. if (consoleFont.FontFamily != TestFontFamily) {
  563. consoleFont.FontFamily = TestFontFamily;
  564. wcscpy(consoleFont.FaceName, TestFaceName);
  565. if (!setConsoleFont(hOut, FALSE, &consoleFont)) {
  566. std::cerr << "SetCurrentConsoleFontEx failed!" << std::endl;
  567. }
  568. }
  569. } else {
  570. std::cerr << "GetCurrentConsoleFontEx failed!" << std::endl;
  571. }
  572. } else {
  573. #endif
  574. if (restoreConsole &&
  575. RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_WRITE,
  576. &hConsoleKey) == ERROR_SUCCESS) {
  577. RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD,
  578. (BYTE*)&FontFamily, sizeof(FontFamily));
  579. if (FaceName[0] != 0) {
  580. RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ, (BYTE*)FaceName,
  581. FaceNameSize);
  582. } else {
  583. RegDeleteValueW(hConsoleKey, L"FaceName");
  584. }
  585. RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD, (BYTE*)&FontSize,
  586. sizeof(FontSize));
  587. RegCloseKey(hConsoleKey);
  588. }
  589. #if _WIN32_WINNT >= _WIN32_WINNT_VISTA
  590. }
  591. #endif
  592. if (createProcess(NULL, NULL, NULL)) {
  593. try {
  594. DWORD status;
  595. if ((status = WaitForSingleObject(beforeInputEvent, waitTimeout)) !=
  596. WAIT_OBJECT_0) {
  597. std::cerr.setf(std::ios::hex, std::ios::basefield);
  598. std::cerr << "WaitForSingleObject returned unexpected status 0x"
  599. << status << std::endl;
  600. std::cerr.unsetf(std::ios::hex);
  601. throw std::runtime_error("WaitForSingleObject#1 failed!");
  602. }
  603. INPUT_RECORD inputBuffer[(sizeof(UnicodeInputTestString) /
  604. sizeof(UnicodeInputTestString[0])) *
  605. 2];
  606. memset(&inputBuffer, 0, sizeof(inputBuffer));
  607. unsigned int i;
  608. for (i = 0; i < (sizeof(UnicodeInputTestString) /
  609. sizeof(UnicodeInputTestString[0]) -
  610. 1);
  611. i++) {
  612. writeInputKeyEvent(&inputBuffer[i * 2], UnicodeInputTestString[i]);
  613. }
  614. writeInputKeyEvent(&inputBuffer[i * 2], VK_RETURN);
  615. DWORD eventsWritten = 0;
  616. // We need to wait a bit before writing to console so child process have
  617. // started waiting for input on stdin.
  618. Sleep(300);
  619. if (!WriteConsoleInputW(hIn, inputBuffer,
  620. sizeof(inputBuffer) / sizeof(inputBuffer[0]),
  621. &eventsWritten) ||
  622. eventsWritten == 0) {
  623. throw std::runtime_error("WriteConsoleInput failed!");
  624. }
  625. if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) !=
  626. WAIT_OBJECT_0) {
  627. std::cerr.setf(std::ios::hex, std::ios::basefield);
  628. std::cerr << "WaitForSingleObject returned unexpected status 0x"
  629. << status << std::endl;
  630. std::cerr.unsetf(std::ios::hex);
  631. throw std::runtime_error("WaitForSingleObject#2 failed!");
  632. }
  633. CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
  634. if (!GetConsoleScreenBufferInfo(hOut, &screenBufferInfo)) {
  635. throw std::runtime_error("GetConsoleScreenBufferInfo failed!");
  636. }
  637. COORD coord;
  638. DWORD charsRead = 0;
  639. coord.X = 0;
  640. coord.Y = screenBufferInfo.dwCursorPosition.Y - 4;
  641. WCHAR* outputBuffer = new WCHAR[screenBufferInfo.dwSize.X * 4];
  642. if (!ReadConsoleOutputCharacterW(hOut, outputBuffer,
  643. screenBufferInfo.dwSize.X * 4, coord,
  644. &charsRead) ||
  645. charsRead == 0) {
  646. delete[] outputBuffer;
  647. throw std::runtime_error("ReadConsoleOutputCharacter failed!");
  648. }
  649. std::wstring wideTestString = kwsys::Encoding::ToWide(encodedTestString);
  650. std::replace(wideTestString.begin(), wideTestString.end(), '\0', ' ');
  651. std::wstring wideInputTestString =
  652. kwsys::Encoding::ToWide(encodedInputTestString);
  653. if (memcmp(outputBuffer, wideTestString.c_str(),
  654. wideTestString.size() * sizeof(wchar_t)) == 0 &&
  655. memcmp(outputBuffer + screenBufferInfo.dwSize.X * 1,
  656. wideTestString.c_str(),
  657. wideTestString.size() * sizeof(wchar_t)) == 0 &&
  658. memcmp(outputBuffer + screenBufferInfo.dwSize.X * 2,
  659. UnicodeInputTestString,
  660. sizeof(UnicodeInputTestString) - sizeof(WCHAR)) == 0 &&
  661. memcmp(outputBuffer + screenBufferInfo.dwSize.X * 3,
  662. wideInputTestString.c_str(),
  663. (wideInputTestString.size() - 1) * sizeof(wchar_t)) == 0) {
  664. didFail = 0;
  665. } else {
  666. std::cerr << "Console's output didn't match expected output!"
  667. << std::endl;
  668. dumpBuffers<wchar_t>(wideTestString.c_str(), outputBuffer,
  669. wideTestString.size());
  670. dumpBuffers<wchar_t>(wideTestString.c_str(),
  671. outputBuffer + screenBufferInfo.dwSize.X * 1,
  672. wideTestString.size());
  673. dumpBuffers<wchar_t>(
  674. UnicodeInputTestString, outputBuffer + screenBufferInfo.dwSize.X * 2,
  675. (sizeof(UnicodeInputTestString) - 1) / sizeof(WCHAR));
  676. dumpBuffers<wchar_t>(wideInputTestString.c_str(),
  677. outputBuffer + screenBufferInfo.dwSize.X * 3,
  678. wideInputTestString.size() - 1);
  679. }
  680. delete[] outputBuffer;
  681. } catch (const std::runtime_error& ex) {
  682. DWORD lastError = GetLastError();
  683. std::cerr << "In function testConsole, line " << __LINE__ << ": "
  684. << ex.what() << std::endl;
  685. displayError(lastError);
  686. }
  687. finishProcess(didFail == 0);
  688. }
  689. if (newConsole) {
  690. SetStdHandle(STD_INPUT_HANDLE, parentIn);
  691. SetStdHandle(STD_OUTPUT_HANDLE, parentOut);
  692. SetStdHandle(STD_ERROR_HANDLE, parentErr);
  693. CloseHandle(hIn);
  694. CloseHandle(hOut);
  695. FreeConsole();
  696. }
  697. return didFail;
  698. }
  699. #endif
  700. int testConsoleBuf(int, char* [])
  701. {
  702. int ret = 0;
  703. #if defined(_WIN32)
  704. beforeInputEvent = CreateEventW(NULL,
  705. FALSE, // auto-reset event
  706. FALSE, // initial state is nonsignaled
  707. BeforeInputEventName); // object name
  708. if (!beforeInputEvent) {
  709. std::cerr << "CreateEvent#1 failed " << GetLastError() << std::endl;
  710. return 1;
  711. }
  712. afterOutputEvent = CreateEventW(NULL, FALSE, FALSE, AfterOutputEventName);
  713. if (!afterOutputEvent) {
  714. std::cerr << "CreateEvent#2 failed " << GetLastError() << std::endl;
  715. return 1;
  716. }
  717. encodedTestString = kwsys::Encoding::ToNarrow(std::wstring(
  718. UnicodeTestString, sizeof(UnicodeTestString) / sizeof(wchar_t) - 1));
  719. encodedInputTestString = kwsys::Encoding::ToNarrow(
  720. std::wstring(UnicodeInputTestString,
  721. sizeof(UnicodeInputTestString) / sizeof(wchar_t) - 1));
  722. encodedInputTestString += "\n";
  723. ret |= testPipe();
  724. ret |= testFile();
  725. ret |= testConsole();
  726. CloseHandle(beforeInputEvent);
  727. CloseHandle(afterOutputEvent);
  728. #endif
  729. return ret;
  730. }