testConsoleBuf.cxx 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  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. nullptr, errorCode, 0, (LPWSTR)&message, 0, nullptr)) {
  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(nullptr, 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(nullptr, // No module name (use command line)
  125. cmd, // Command line
  126. nullptr, // Process handle not inheritable
  127. nullptr, // Thread handle not inheritable
  128. bInheritHandles, // Set handle inheritance
  129. dwCreationFlags,
  130. nullptr, // Use parent's environment block
  131. nullptr, // 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 = nullptr;
  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 = nullptr;
  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. nullptr); // 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. nullptr) ||
  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,
  283. nullptr) ||
  284. bytesRead == 0) {
  285. throw std::runtime_error("ReadFile#1 failed!");
  286. }
  287. buffer[bytesRead] = 0;
  288. if ((bytesRead <
  289. encodedTestString.size() + 1 + encodedInputTestString.size() &&
  290. !ReadFile(outPipeRead, buffer + bytesRead,
  291. sizeof(buffer) - bytesRead, &bytesRead, nullptr)) ||
  292. bytesRead == 0) {
  293. throw std::runtime_error("ReadFile#2 failed!");
  294. }
  295. if (memcmp(buffer, encodedTestString.c_str(),
  296. encodedTestString.size()) == 0 &&
  297. memcmp(buffer + encodedTestString.size() + 1,
  298. encodedInputTestString.c_str(),
  299. encodedInputTestString.size()) == 0) {
  300. bytesRead = 0;
  301. if (!ReadFile(errPipeRead, buffer2, sizeof(buffer2), &bytesRead,
  302. nullptr) ||
  303. bytesRead == 0) {
  304. throw std::runtime_error("ReadFile#3 failed!");
  305. }
  306. buffer2[bytesRead] = 0;
  307. didFail = encodedTestString.compare(0, std::string::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 = WideCharToMultiByte(TestCodepage, 0, UnicodeInputTestString,
  360. -1, buffer, sizeof(buffer), nullptr,
  361. nullptr)) == 0) {
  362. throw std::runtime_error("WideCharToMultiByte failed!");
  363. }
  364. buffer[length - 1] = '\n';
  365. if (!WriteFile(inFile, buffer, length, &bytesWritten, nullptr) ||
  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, nullptr) ||
  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,
  404. nullptr) ||
  405. bytesRead == 0) {
  406. throw std::runtime_error("ReadFile#2 failed!");
  407. }
  408. buffer2[bytesRead] = 0;
  409. didFail = encodedTestString.compare(0, std::string::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. # elif defined __clang__
  473. # pragma clang diagnostic push
  474. # pragma clang diagnostic ignored "-Wdeprecated-declarations"
  475. # else
  476. # pragma warning(disable : 4996)
  477. # endif
  478. # endif
  479. const bool isVistaOrGreater =
  480. LOBYTE(LOWORD(GetVersion())) >= HIBYTE(_WIN32_WINNT_VISTA);
  481. # ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion
  482. # ifdef __clang__
  483. # pragma clang diagnostic pop
  484. # else
  485. # pragma warning(pop)
  486. # endif
  487. # endif
  488. if (!isVistaOrGreater) {
  489. if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_READ | KEY_WRITE,
  490. &hConsoleKey) == ERROR_SUCCESS) {
  491. DWORD dwordSize = sizeof(DWORD);
  492. if (RegQueryValueExW(hConsoleKey, L"FontFamily", nullptr, nullptr,
  493. (LPBYTE)&FontFamily, &dwordSize) == ERROR_SUCCESS) {
  494. if (FontFamily != TestFontFamily) {
  495. RegQueryValueExW(hConsoleKey, L"FaceName", nullptr, nullptr,
  496. (LPBYTE)FaceName, &FaceNameSize);
  497. RegQueryValueExW(hConsoleKey, L"FontSize", nullptr, nullptr,
  498. (LPBYTE)&FontSize, &dwordSize);
  499. RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD,
  500. (BYTE*)&TestFontFamily, sizeof(TestFontFamily));
  501. RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ,
  502. (BYTE*)TestFaceName,
  503. (DWORD)((wcslen(TestFaceName) + 1) * sizeof(WCHAR)));
  504. RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD,
  505. (BYTE*)&TestFontSize, sizeof(TestFontSize));
  506. restoreConsole = true;
  507. forceNewConsole = true;
  508. }
  509. } else {
  510. std::cerr << "RegGetValueW(FontFamily) failed!" << std::endl;
  511. }
  512. RegCloseKey(hConsoleKey);
  513. } else {
  514. std::cerr << "RegOpenKeyExW(HKEY_CURRENT_USER\\Console) failed!"
  515. << std::endl;
  516. }
  517. }
  518. if (forceNewConsole || GetConsoleMode(parentOut, &consoleMode) == 0) {
  519. // Not a real console, let's create new one.
  520. FreeConsole();
  521. if (!AllocConsole()) {
  522. std::cerr << "AllocConsole failed!" << std::endl;
  523. return didFail;
  524. }
  525. SECURITY_ATTRIBUTES securityAttributes;
  526. securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  527. securityAttributes.bInheritHandle = TRUE;
  528. securityAttributes.lpSecurityDescriptor = nullptr;
  529. hIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE,
  530. FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes,
  531. OPEN_EXISTING, 0, nullptr);
  532. if (hIn == INVALID_HANDLE_VALUE) {
  533. DWORD lastError = GetLastError();
  534. std::cerr << "CreateFile(CONIN$)" << std::endl;
  535. displayError(lastError);
  536. }
  537. hOut = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
  538. FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes,
  539. OPEN_EXISTING, 0, nullptr);
  540. if (hOut == INVALID_HANDLE_VALUE) {
  541. DWORD lastError = GetLastError();
  542. std::cerr << "CreateFile(CONOUT$)" << std::endl;
  543. displayError(lastError);
  544. }
  545. SetStdHandle(STD_INPUT_HANDLE, hIn);
  546. SetStdHandle(STD_OUTPUT_HANDLE, hOut);
  547. SetStdHandle(STD_ERROR_HANDLE, hOut);
  548. newConsole = true;
  549. }
  550. # if _WIN32_WINNT >= _WIN32_WINNT_VISTA
  551. if (isVistaOrGreater) {
  552. CONSOLE_FONT_INFOEX consoleFont;
  553. memset(&consoleFont, 0, sizeof(consoleFont));
  554. consoleFont.cbSize = sizeof(consoleFont);
  555. HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
  556. typedef BOOL(WINAPI * GetCurrentConsoleFontExFunc)(
  557. HANDLE hConsoleOutput, BOOL bMaximumWindow,
  558. PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
  559. typedef BOOL(WINAPI * SetCurrentConsoleFontExFunc)(
  560. HANDLE hConsoleOutput, BOOL bMaximumWindow,
  561. PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
  562. GetCurrentConsoleFontExFunc getConsoleFont =
  563. (GetCurrentConsoleFontExFunc)GetProcAddress(kernel32,
  564. "GetCurrentConsoleFontEx");
  565. SetCurrentConsoleFontExFunc setConsoleFont =
  566. (SetCurrentConsoleFontExFunc)GetProcAddress(kernel32,
  567. "SetCurrentConsoleFontEx");
  568. if (getConsoleFont(hOut, FALSE, &consoleFont)) {
  569. if (consoleFont.FontFamily != TestFontFamily) {
  570. consoleFont.FontFamily = TestFontFamily;
  571. wcscpy(consoleFont.FaceName, TestFaceName);
  572. if (!setConsoleFont(hOut, FALSE, &consoleFont)) {
  573. std::cerr << "SetCurrentConsoleFontEx failed!" << std::endl;
  574. }
  575. }
  576. } else {
  577. std::cerr << "GetCurrentConsoleFontEx failed!" << std::endl;
  578. }
  579. } else {
  580. # endif
  581. if (restoreConsole &&
  582. RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_WRITE,
  583. &hConsoleKey) == ERROR_SUCCESS) {
  584. RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD,
  585. (BYTE*)&FontFamily, sizeof(FontFamily));
  586. if (FaceName[0] != 0) {
  587. RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ, (BYTE*)FaceName,
  588. FaceNameSize);
  589. } else {
  590. RegDeleteValueW(hConsoleKey, L"FaceName");
  591. }
  592. RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD, (BYTE*)&FontSize,
  593. sizeof(FontSize));
  594. RegCloseKey(hConsoleKey);
  595. }
  596. # if _WIN32_WINNT >= _WIN32_WINNT_VISTA
  597. }
  598. # endif
  599. if (createProcess(nullptr, nullptr, nullptr)) {
  600. try {
  601. DWORD status;
  602. if ((status = WaitForSingleObject(beforeInputEvent, waitTimeout)) !=
  603. WAIT_OBJECT_0) {
  604. std::cerr.setf(std::ios::hex, std::ios::basefield);
  605. std::cerr << "WaitForSingleObject returned unexpected status 0x"
  606. << status << std::endl;
  607. std::cerr.unsetf(std::ios::hex);
  608. throw std::runtime_error("WaitForSingleObject#1 failed!");
  609. }
  610. INPUT_RECORD inputBuffer[(sizeof(UnicodeInputTestString) /
  611. sizeof(UnicodeInputTestString[0])) *
  612. 2];
  613. memset(&inputBuffer, 0, sizeof(inputBuffer));
  614. unsigned int i;
  615. for (i = 0; i < (sizeof(UnicodeInputTestString) /
  616. sizeof(UnicodeInputTestString[0]) -
  617. 1);
  618. i++) {
  619. writeInputKeyEvent(&inputBuffer[i * 2], UnicodeInputTestString[i]);
  620. }
  621. writeInputKeyEvent(&inputBuffer[i * 2], VK_RETURN);
  622. DWORD eventsWritten = 0;
  623. // We need to wait a bit before writing to console so child process have
  624. // started waiting for input on stdin.
  625. Sleep(300);
  626. if (!WriteConsoleInputW(hIn, inputBuffer,
  627. sizeof(inputBuffer) / sizeof(inputBuffer[0]),
  628. &eventsWritten) ||
  629. eventsWritten == 0) {
  630. throw std::runtime_error("WriteConsoleInput failed!");
  631. }
  632. if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) !=
  633. WAIT_OBJECT_0) {
  634. std::cerr.setf(std::ios::hex, std::ios::basefield);
  635. std::cerr << "WaitForSingleObject returned unexpected status 0x"
  636. << status << std::endl;
  637. std::cerr.unsetf(std::ios::hex);
  638. throw std::runtime_error("WaitForSingleObject#2 failed!");
  639. }
  640. CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
  641. if (!GetConsoleScreenBufferInfo(hOut, &screenBufferInfo)) {
  642. throw std::runtime_error("GetConsoleScreenBufferInfo failed!");
  643. }
  644. COORD coord;
  645. DWORD charsRead = 0;
  646. coord.X = 0;
  647. coord.Y = screenBufferInfo.dwCursorPosition.Y - 4;
  648. WCHAR* outputBuffer = new WCHAR[screenBufferInfo.dwSize.X * 4];
  649. if (!ReadConsoleOutputCharacterW(hOut, outputBuffer,
  650. screenBufferInfo.dwSize.X * 4, coord,
  651. &charsRead) ||
  652. charsRead == 0) {
  653. delete[] outputBuffer;
  654. throw std::runtime_error("ReadConsoleOutputCharacter failed!");
  655. }
  656. std::wstring wideTestString = kwsys::Encoding::ToWide(encodedTestString);
  657. std::replace(wideTestString.begin(), wideTestString.end(), '\0', ' ');
  658. std::wstring wideInputTestString =
  659. kwsys::Encoding::ToWide(encodedInputTestString);
  660. if (memcmp(outputBuffer, wideTestString.c_str(),
  661. wideTestString.size() * sizeof(wchar_t)) == 0 &&
  662. memcmp(outputBuffer + screenBufferInfo.dwSize.X * 1,
  663. wideTestString.c_str(),
  664. wideTestString.size() * sizeof(wchar_t)) == 0 &&
  665. memcmp(outputBuffer + screenBufferInfo.dwSize.X * 2,
  666. UnicodeInputTestString,
  667. sizeof(UnicodeInputTestString) - sizeof(WCHAR)) == 0 &&
  668. memcmp(outputBuffer + screenBufferInfo.dwSize.X * 3,
  669. wideInputTestString.c_str(),
  670. (wideInputTestString.size() - 1) * sizeof(wchar_t)) == 0) {
  671. didFail = 0;
  672. } else {
  673. std::cerr << "Console's output didn't match expected output!"
  674. << std::endl;
  675. dumpBuffers<wchar_t>(wideTestString.c_str(), outputBuffer,
  676. wideTestString.size());
  677. dumpBuffers<wchar_t>(wideTestString.c_str(),
  678. outputBuffer + screenBufferInfo.dwSize.X * 1,
  679. wideTestString.size());
  680. dumpBuffers<wchar_t>(
  681. UnicodeInputTestString, outputBuffer + screenBufferInfo.dwSize.X * 2,
  682. (sizeof(UnicodeInputTestString) - 1) / sizeof(WCHAR));
  683. dumpBuffers<wchar_t>(wideInputTestString.c_str(),
  684. outputBuffer + screenBufferInfo.dwSize.X * 3,
  685. wideInputTestString.size() - 1);
  686. }
  687. delete[] outputBuffer;
  688. } catch (const std::runtime_error& ex) {
  689. DWORD lastError = GetLastError();
  690. std::cerr << "In function testConsole, line " << __LINE__ << ": "
  691. << ex.what() << std::endl;
  692. displayError(lastError);
  693. }
  694. finishProcess(didFail == 0);
  695. }
  696. if (newConsole) {
  697. SetStdHandle(STD_INPUT_HANDLE, parentIn);
  698. SetStdHandle(STD_OUTPUT_HANDLE, parentOut);
  699. SetStdHandle(STD_ERROR_HANDLE, parentErr);
  700. CloseHandle(hIn);
  701. CloseHandle(hOut);
  702. FreeConsole();
  703. }
  704. return didFail;
  705. }
  706. #endif
  707. int testConsoleBuf(int, char* [])
  708. {
  709. int ret = 0;
  710. #if defined(_WIN32)
  711. beforeInputEvent = CreateEventW(nullptr,
  712. FALSE, // auto-reset event
  713. FALSE, // initial state is nonsignaled
  714. BeforeInputEventName); // object name
  715. if (!beforeInputEvent) {
  716. std::cerr << "CreateEvent#1 failed " << GetLastError() << std::endl;
  717. return 1;
  718. }
  719. afterOutputEvent = CreateEventW(nullptr, FALSE, FALSE, AfterOutputEventName);
  720. if (!afterOutputEvent) {
  721. std::cerr << "CreateEvent#2 failed " << GetLastError() << std::endl;
  722. return 1;
  723. }
  724. encodedTestString = kwsys::Encoding::ToNarrow(std::wstring(
  725. UnicodeTestString, sizeof(UnicodeTestString) / sizeof(wchar_t) - 1));
  726. encodedInputTestString = kwsys::Encoding::ToNarrow(
  727. std::wstring(UnicodeInputTestString,
  728. sizeof(UnicodeInputTestString) / sizeof(wchar_t) - 1));
  729. encodedInputTestString += "\n";
  730. ret |= testPipe();
  731. ret |= testFile();
  732. ret |= testConsole();
  733. CloseHandle(beforeInputEvent);
  734. CloseHandle(afterOutputEvent);
  735. #endif
  736. return ret;
  737. }