testConsoleBuf.cxx 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  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 = encodedTestString.compare(0, std::string::npos, buffer2,
  307. encodedTestString.size()) == 0
  308. ? 0
  309. : 1;
  310. }
  311. if (didFail != 0) {
  312. std::cerr << "Pipe's output didn't match expected output!"
  313. << std::endl;
  314. dumpBuffers<char>(encodedTestString.c_str(), buffer,
  315. encodedTestString.size());
  316. dumpBuffers<char>(encodedInputTestString.c_str(),
  317. buffer + encodedTestString.size() + 1,
  318. encodedInputTestString.size());
  319. dumpBuffers<char>(encodedTestString.c_str(), buffer2,
  320. encodedTestString.size());
  321. }
  322. } catch (const std::runtime_error& ex) {
  323. DWORD lastError = GetLastError();
  324. std::cerr << "In function testPipe, line " << __LINE__ << ": "
  325. << ex.what() << std::endl;
  326. displayError(lastError);
  327. }
  328. finishProcess(didFail == 0);
  329. }
  330. } catch (const std::runtime_error& ex) {
  331. DWORD lastError = GetLastError();
  332. std::cerr << "In function testPipe, line " << __LINE__ << ": " << ex.what()
  333. << std::endl;
  334. displayError(lastError);
  335. }
  336. finishPipe(inPipeRead, inPipeWrite);
  337. finishPipe(outPipeRead, outPipeWrite);
  338. finishPipe(errPipeRead, errPipeWrite);
  339. SetConsoleCP(currentCodepage);
  340. return didFail;
  341. }
  342. static int testFile()
  343. {
  344. int didFail = 1;
  345. HANDLE inFile = INVALID_HANDLE_VALUE;
  346. HANDLE outFile = INVALID_HANDLE_VALUE;
  347. HANDLE errFile = INVALID_HANDLE_VALUE;
  348. try {
  349. if ((inFile = createFile(L"stdinFile.txt")) == INVALID_HANDLE_VALUE ||
  350. (outFile = createFile(L"stdoutFile.txt")) == INVALID_HANDLE_VALUE ||
  351. (errFile = createFile(L"stderrFile.txt")) == INVALID_HANDLE_VALUE) {
  352. throw std::runtime_error("createFile failed!");
  353. }
  354. DWORD bytesWritten = 0;
  355. char buffer[200];
  356. char buffer2[200];
  357. int length;
  358. if ((length =
  359. WideCharToMultiByte(TestCodepage, 0, UnicodeInputTestString, -1,
  360. buffer, sizeof(buffer), NULL, NULL)) == 0) {
  361. throw std::runtime_error("WideCharToMultiByte failed!");
  362. }
  363. buffer[length - 1] = '\n';
  364. if (!WriteFile(inFile, buffer, length, &bytesWritten, NULL) ||
  365. bytesWritten == 0) {
  366. throw std::runtime_error("WriteFile failed!");
  367. }
  368. if (SetFilePointer(inFile, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
  369. throw std::runtime_error("SetFilePointer failed!");
  370. }
  371. if (createProcess(inFile, outFile, errFile)) {
  372. DWORD bytesRead = 0;
  373. try {
  374. DWORD status;
  375. if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) !=
  376. WAIT_OBJECT_0) {
  377. std::cerr.setf(std::ios::hex, std::ios::basefield);
  378. std::cerr << "WaitForSingleObject returned unexpected status 0x"
  379. << status << std::endl;
  380. std::cerr.unsetf(std::ios::hex);
  381. throw std::runtime_error("WaitForSingleObject failed!");
  382. }
  383. if (SetFilePointer(outFile, 0, 0, FILE_BEGIN) ==
  384. INVALID_SET_FILE_POINTER) {
  385. throw std::runtime_error("SetFilePointer#1 failed!");
  386. }
  387. if (!ReadFile(outFile, buffer, sizeof(buffer), &bytesRead, NULL) ||
  388. bytesRead == 0) {
  389. throw std::runtime_error("ReadFile#1 failed!");
  390. }
  391. buffer[bytesRead] = 0;
  392. if (memcmp(buffer, encodedTestString.c_str(),
  393. encodedTestString.size()) == 0 &&
  394. memcmp(buffer + encodedTestString.size() + 1,
  395. encodedInputTestString.c_str(),
  396. encodedInputTestString.size()) == 0) {
  397. bytesRead = 0;
  398. if (SetFilePointer(errFile, 0, 0, FILE_BEGIN) ==
  399. INVALID_SET_FILE_POINTER) {
  400. throw std::runtime_error("SetFilePointer#2 failed!");
  401. }
  402. if (!ReadFile(errFile, buffer2, sizeof(buffer2), &bytesRead, NULL) ||
  403. bytesRead == 0) {
  404. throw std::runtime_error("ReadFile#2 failed!");
  405. }
  406. buffer2[bytesRead] = 0;
  407. didFail = encodedTestString.compare(0, std::string::npos, buffer2,
  408. encodedTestString.size()) == 0
  409. ? 0
  410. : 1;
  411. }
  412. if (didFail != 0) {
  413. std::cerr << "File's output didn't match expected output!"
  414. << std::endl;
  415. dumpBuffers<char>(encodedTestString.c_str(), buffer,
  416. encodedTestString.size());
  417. dumpBuffers<char>(encodedInputTestString.c_str(),
  418. buffer + encodedTestString.size() + 1,
  419. encodedInputTestString.size());
  420. dumpBuffers<char>(encodedTestString.c_str(), buffer2,
  421. encodedTestString.size());
  422. }
  423. } catch (const std::runtime_error& ex) {
  424. DWORD lastError = GetLastError();
  425. std::cerr << "In function testFile, line " << __LINE__ << ": "
  426. << ex.what() << std::endl;
  427. displayError(lastError);
  428. }
  429. finishProcess(didFail == 0);
  430. }
  431. } catch (const std::runtime_error& ex) {
  432. DWORD lastError = GetLastError();
  433. std::cerr << "In function testFile, line " << __LINE__ << ": " << ex.what()
  434. << std::endl;
  435. displayError(lastError);
  436. }
  437. finishFile(inFile);
  438. finishFile(outFile);
  439. finishFile(errFile);
  440. return didFail;
  441. }
  442. #ifndef _WIN32_WINNT_VISTA
  443. #define _WIN32_WINNT_VISTA 0x0600
  444. #endif
  445. static int testConsole()
  446. {
  447. int didFail = 1;
  448. HANDLE parentIn = GetStdHandle(STD_INPUT_HANDLE);
  449. HANDLE parentOut = GetStdHandle(STD_OUTPUT_HANDLE);
  450. HANDLE parentErr = GetStdHandle(STD_ERROR_HANDLE);
  451. HANDLE hIn = parentIn;
  452. HANDLE hOut = parentOut;
  453. DWORD consoleMode;
  454. bool newConsole = false;
  455. bool forceNewConsole = false;
  456. bool restoreConsole = false;
  457. LPCWSTR TestFaceName = L"Lucida Console";
  458. const DWORD TestFontFamily = 0x00000036;
  459. const DWORD TestFontSize = 0x000c0000;
  460. HKEY hConsoleKey;
  461. WCHAR FaceName[200];
  462. FaceName[0] = 0;
  463. DWORD FaceNameSize = sizeof(FaceName);
  464. DWORD FontFamily = TestFontFamily;
  465. DWORD FontSize = TestFontSize;
  466. #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion
  467. #pragma warning(push)
  468. #ifdef __INTEL_COMPILER
  469. #pragma warning(disable : 1478)
  470. #else
  471. #pragma warning(disable : 4996)
  472. #endif
  473. #endif
  474. const bool isVistaOrGreater =
  475. LOBYTE(LOWORD(GetVersion())) >= HIBYTE(_WIN32_WINNT_VISTA);
  476. #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion
  477. #pragma warning(pop)
  478. #endif
  479. if (!isVistaOrGreater) {
  480. if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_READ | KEY_WRITE,
  481. &hConsoleKey) == ERROR_SUCCESS) {
  482. DWORD dwordSize = sizeof(DWORD);
  483. if (RegQueryValueExW(hConsoleKey, L"FontFamily", NULL, NULL,
  484. (LPBYTE)&FontFamily, &dwordSize) == ERROR_SUCCESS) {
  485. if (FontFamily != TestFontFamily) {
  486. RegQueryValueExW(hConsoleKey, L"FaceName", NULL, NULL,
  487. (LPBYTE)FaceName, &FaceNameSize);
  488. RegQueryValueExW(hConsoleKey, L"FontSize", NULL, NULL,
  489. (LPBYTE)&FontSize, &dwordSize);
  490. RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD,
  491. (BYTE*)&TestFontFamily, sizeof(TestFontFamily));
  492. RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ,
  493. (BYTE*)TestFaceName,
  494. (DWORD)((wcslen(TestFaceName) + 1) * sizeof(WCHAR)));
  495. RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD,
  496. (BYTE*)&TestFontSize, sizeof(TestFontSize));
  497. restoreConsole = true;
  498. forceNewConsole = true;
  499. }
  500. } else {
  501. std::cerr << "RegGetValueW(FontFamily) failed!" << std::endl;
  502. }
  503. RegCloseKey(hConsoleKey);
  504. } else {
  505. std::cerr << "RegOpenKeyExW(HKEY_CURRENT_USER\\Console) failed!"
  506. << std::endl;
  507. }
  508. }
  509. if (forceNewConsole || GetConsoleMode(parentOut, &consoleMode) == 0) {
  510. // Not a real console, let's create new one.
  511. FreeConsole();
  512. if (!AllocConsole()) {
  513. std::cerr << "AllocConsole failed!" << std::endl;
  514. return didFail;
  515. }
  516. SECURITY_ATTRIBUTES securityAttributes;
  517. securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  518. securityAttributes.bInheritHandle = TRUE;
  519. securityAttributes.lpSecurityDescriptor = NULL;
  520. hIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE,
  521. FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes,
  522. OPEN_EXISTING, 0, NULL);
  523. if (hIn == INVALID_HANDLE_VALUE) {
  524. DWORD lastError = GetLastError();
  525. std::cerr << "CreateFile(CONIN$)" << std::endl;
  526. displayError(lastError);
  527. }
  528. hOut = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
  529. FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes,
  530. OPEN_EXISTING, 0, NULL);
  531. if (hOut == INVALID_HANDLE_VALUE) {
  532. DWORD lastError = GetLastError();
  533. std::cerr << "CreateFile(CONOUT$)" << std::endl;
  534. displayError(lastError);
  535. }
  536. SetStdHandle(STD_INPUT_HANDLE, hIn);
  537. SetStdHandle(STD_OUTPUT_HANDLE, hOut);
  538. SetStdHandle(STD_ERROR_HANDLE, hOut);
  539. newConsole = true;
  540. }
  541. #if _WIN32_WINNT >= _WIN32_WINNT_VISTA
  542. if (isVistaOrGreater) {
  543. CONSOLE_FONT_INFOEX consoleFont;
  544. memset(&consoleFont, 0, sizeof(consoleFont));
  545. consoleFont.cbSize = sizeof(consoleFont);
  546. HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
  547. typedef BOOL(WINAPI * GetCurrentConsoleFontExFunc)(
  548. HANDLE hConsoleOutput, BOOL bMaximumWindow,
  549. PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
  550. typedef BOOL(WINAPI * SetCurrentConsoleFontExFunc)(
  551. HANDLE hConsoleOutput, BOOL bMaximumWindow,
  552. PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
  553. GetCurrentConsoleFontExFunc getConsoleFont =
  554. (GetCurrentConsoleFontExFunc)GetProcAddress(kernel32,
  555. "GetCurrentConsoleFontEx");
  556. SetCurrentConsoleFontExFunc setConsoleFont =
  557. (SetCurrentConsoleFontExFunc)GetProcAddress(kernel32,
  558. "SetCurrentConsoleFontEx");
  559. if (getConsoleFont(hOut, FALSE, &consoleFont)) {
  560. if (consoleFont.FontFamily != TestFontFamily) {
  561. consoleFont.FontFamily = TestFontFamily;
  562. wcscpy(consoleFont.FaceName, TestFaceName);
  563. if (!setConsoleFont(hOut, FALSE, &consoleFont)) {
  564. std::cerr << "SetCurrentConsoleFontEx failed!" << std::endl;
  565. }
  566. }
  567. } else {
  568. std::cerr << "GetCurrentConsoleFontEx failed!" << std::endl;
  569. }
  570. } else {
  571. #endif
  572. if (restoreConsole &&
  573. RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_WRITE,
  574. &hConsoleKey) == ERROR_SUCCESS) {
  575. RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD,
  576. (BYTE*)&FontFamily, sizeof(FontFamily));
  577. if (FaceName[0] != 0) {
  578. RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ, (BYTE*)FaceName,
  579. FaceNameSize);
  580. } else {
  581. RegDeleteValueW(hConsoleKey, L"FaceName");
  582. }
  583. RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD, (BYTE*)&FontSize,
  584. sizeof(FontSize));
  585. RegCloseKey(hConsoleKey);
  586. }
  587. #if _WIN32_WINNT >= _WIN32_WINNT_VISTA
  588. }
  589. #endif
  590. if (createProcess(NULL, NULL, NULL)) {
  591. try {
  592. DWORD status;
  593. if ((status = WaitForSingleObject(beforeInputEvent, waitTimeout)) !=
  594. WAIT_OBJECT_0) {
  595. std::cerr.setf(std::ios::hex, std::ios::basefield);
  596. std::cerr << "WaitForSingleObject returned unexpected status 0x"
  597. << status << std::endl;
  598. std::cerr.unsetf(std::ios::hex);
  599. throw std::runtime_error("WaitForSingleObject#1 failed!");
  600. }
  601. INPUT_RECORD inputBuffer[(sizeof(UnicodeInputTestString) /
  602. sizeof(UnicodeInputTestString[0])) *
  603. 2];
  604. memset(&inputBuffer, 0, sizeof(inputBuffer));
  605. unsigned int i;
  606. for (i = 0; i < (sizeof(UnicodeInputTestString) /
  607. sizeof(UnicodeInputTestString[0]) -
  608. 1);
  609. i++) {
  610. writeInputKeyEvent(&inputBuffer[i * 2], UnicodeInputTestString[i]);
  611. }
  612. writeInputKeyEvent(&inputBuffer[i * 2], VK_RETURN);
  613. DWORD eventsWritten = 0;
  614. // We need to wait a bit before writing to console so child process have
  615. // started waiting for input on stdin.
  616. Sleep(300);
  617. if (!WriteConsoleInputW(hIn, inputBuffer,
  618. sizeof(inputBuffer) / sizeof(inputBuffer[0]),
  619. &eventsWritten) ||
  620. eventsWritten == 0) {
  621. throw std::runtime_error("WriteConsoleInput failed!");
  622. }
  623. if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) !=
  624. WAIT_OBJECT_0) {
  625. std::cerr.setf(std::ios::hex, std::ios::basefield);
  626. std::cerr << "WaitForSingleObject returned unexpected status 0x"
  627. << status << std::endl;
  628. std::cerr.unsetf(std::ios::hex);
  629. throw std::runtime_error("WaitForSingleObject#2 failed!");
  630. }
  631. CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
  632. if (!GetConsoleScreenBufferInfo(hOut, &screenBufferInfo)) {
  633. throw std::runtime_error("GetConsoleScreenBufferInfo failed!");
  634. }
  635. COORD coord;
  636. DWORD charsRead = 0;
  637. coord.X = 0;
  638. coord.Y = screenBufferInfo.dwCursorPosition.Y - 4;
  639. WCHAR* outputBuffer = new WCHAR[screenBufferInfo.dwSize.X * 4];
  640. if (!ReadConsoleOutputCharacterW(hOut, outputBuffer,
  641. screenBufferInfo.dwSize.X * 4, coord,
  642. &charsRead) ||
  643. charsRead == 0) {
  644. delete[] outputBuffer;
  645. throw std::runtime_error("ReadConsoleOutputCharacter failed!");
  646. }
  647. std::wstring wideTestString = kwsys::Encoding::ToWide(encodedTestString);
  648. std::replace(wideTestString.begin(), wideTestString.end(), '\0', ' ');
  649. std::wstring wideInputTestString =
  650. kwsys::Encoding::ToWide(encodedInputTestString);
  651. if (memcmp(outputBuffer, wideTestString.c_str(),
  652. wideTestString.size() * sizeof(wchar_t)) == 0 &&
  653. memcmp(outputBuffer + screenBufferInfo.dwSize.X * 1,
  654. wideTestString.c_str(),
  655. wideTestString.size() * sizeof(wchar_t)) == 0 &&
  656. memcmp(outputBuffer + screenBufferInfo.dwSize.X * 2,
  657. UnicodeInputTestString,
  658. sizeof(UnicodeInputTestString) - sizeof(WCHAR)) == 0 &&
  659. memcmp(outputBuffer + screenBufferInfo.dwSize.X * 3,
  660. wideInputTestString.c_str(),
  661. (wideInputTestString.size() - 1) * sizeof(wchar_t)) == 0) {
  662. didFail = 0;
  663. } else {
  664. std::cerr << "Console's output didn't match expected output!"
  665. << std::endl;
  666. dumpBuffers<wchar_t>(wideTestString.c_str(), outputBuffer,
  667. wideTestString.size());
  668. dumpBuffers<wchar_t>(wideTestString.c_str(),
  669. outputBuffer + screenBufferInfo.dwSize.X * 1,
  670. wideTestString.size());
  671. dumpBuffers<wchar_t>(
  672. UnicodeInputTestString, outputBuffer + screenBufferInfo.dwSize.X * 2,
  673. (sizeof(UnicodeInputTestString) - 1) / sizeof(WCHAR));
  674. dumpBuffers<wchar_t>(wideInputTestString.c_str(),
  675. outputBuffer + screenBufferInfo.dwSize.X * 3,
  676. wideInputTestString.size() - 1);
  677. }
  678. delete[] outputBuffer;
  679. } catch (const std::runtime_error& ex) {
  680. DWORD lastError = GetLastError();
  681. std::cerr << "In function testConsole, line " << __LINE__ << ": "
  682. << ex.what() << std::endl;
  683. displayError(lastError);
  684. }
  685. finishProcess(didFail == 0);
  686. }
  687. if (newConsole) {
  688. SetStdHandle(STD_INPUT_HANDLE, parentIn);
  689. SetStdHandle(STD_OUTPUT_HANDLE, parentOut);
  690. SetStdHandle(STD_ERROR_HANDLE, parentErr);
  691. CloseHandle(hIn);
  692. CloseHandle(hOut);
  693. FreeConsole();
  694. }
  695. return didFail;
  696. }
  697. #endif
  698. int testConsoleBuf(int, char* [])
  699. {
  700. int ret = 0;
  701. #if defined(_WIN32)
  702. beforeInputEvent = CreateEventW(NULL,
  703. FALSE, // auto-reset event
  704. FALSE, // initial state is nonsignaled
  705. BeforeInputEventName); // object name
  706. if (!beforeInputEvent) {
  707. std::cerr << "CreateEvent#1 failed " << GetLastError() << std::endl;
  708. return 1;
  709. }
  710. afterOutputEvent = CreateEventW(NULL, FALSE, FALSE, AfterOutputEventName);
  711. if (!afterOutputEvent) {
  712. std::cerr << "CreateEvent#2 failed " << GetLastError() << std::endl;
  713. return 1;
  714. }
  715. encodedTestString = kwsys::Encoding::ToNarrow(std::wstring(
  716. UnicodeTestString, sizeof(UnicodeTestString) / sizeof(wchar_t) - 1));
  717. encodedInputTestString = kwsys::Encoding::ToNarrow(
  718. std::wstring(UnicodeInputTestString,
  719. sizeof(UnicodeInputTestString) / sizeof(wchar_t) - 1));
  720. encodedInputTestString += "\n";
  721. ret |= testPipe();
  722. ret |= testFile();
  723. ret |= testConsole();
  724. CloseHandle(beforeInputEvent);
  725. CloseHandle(afterOutputEvent);
  726. #endif
  727. return ret;
  728. }