testConsoleBuf.cxx 28 KB

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