testConsoleBuf.cxx 28 KB

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