| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <windows.h> |
| | #include <stdio.h> |
| | #include <string.h> |
| |
|
| | #include "TestUtil.cc" |
| |
|
| | const char *g_prefix = ""; |
| |
|
| | static void dumpHandles() { |
| | trace("%sSTDIN=0x%I64x STDOUT=0x%I64x STDERR=0x%I64x", |
| | g_prefix, |
| | (long long)GetStdHandle(STD_INPUT_HANDLE), |
| | (long long)GetStdHandle(STD_OUTPUT_HANDLE), |
| | (long long)GetStdHandle(STD_ERROR_HANDLE)); |
| | } |
| |
|
| | static const char *successOrFail(BOOL ret) { |
| | return ret ? "ok" : "FAILED"; |
| | } |
| |
|
| | static void startChildInSameConsole(const wchar_t *args, BOOL |
| | bInheritHandles=FALSE) { |
| | wchar_t program[1024]; |
| | wchar_t cmdline[1024]; |
| | GetModuleFileNameW(NULL, program, 1024); |
| | swprintf(cmdline, L"\"%ls\" %ls", program, args); |
| |
|
| | STARTUPINFOW sui; |
| | PROCESS_INFORMATION pi; |
| | memset(&sui, 0, sizeof(sui)); |
| | memset(&pi, 0, sizeof(pi)); |
| | sui.cb = sizeof(sui); |
| |
|
| | CreateProcessW(program, cmdline, |
| | NULL, NULL, |
| | bInheritHandles, |
| | 0, |
| | NULL, NULL, |
| | &sui, &pi); |
| | } |
| |
|
| | static void closeHandle(HANDLE h) { |
| | trace("%sClosing handle 0x%I64x...", g_prefix, (long long)h); |
| | trace("%sClosing handle 0x%I64x... %s", g_prefix, (long long)h, successOrFail(CloseHandle(h))); |
| | } |
| |
|
| | static HANDLE createBuffer() { |
| |
|
| | |
| | SECURITY_ATTRIBUTES sa = {0}; |
| | sa.nLength = sizeof(sa); |
| | sa.bInheritHandle = TRUE; |
| |
|
| | trace("%sCreating a new buffer...", g_prefix); |
| | HANDLE conout = CreateConsoleScreenBuffer( |
| | GENERIC_READ | GENERIC_WRITE, |
| | FILE_SHARE_READ | FILE_SHARE_WRITE, |
| | &sa, |
| | CONSOLE_TEXTMODE_BUFFER, NULL); |
| |
|
| | trace("%sCreating a new buffer... 0x%I64x", g_prefix, (long long)conout); |
| | return conout; |
| | } |
| |
|
| | static HANDLE openConout() { |
| |
|
| | |
| | SECURITY_ATTRIBUTES sa = {0}; |
| | sa.nLength = sizeof(sa); |
| | sa.bInheritHandle = TRUE; |
| |
|
| | trace("%sOpening CONOUT...", g_prefix); |
| | HANDLE conout = CreateFileW(L"CONOUT$", |
| | GENERIC_READ | GENERIC_WRITE, |
| | FILE_SHARE_READ | FILE_SHARE_WRITE, |
| | &sa, |
| | OPEN_EXISTING, 0, NULL); |
| | trace("%sOpening CONOUT... 0x%I64x", g_prefix, (long long)conout); |
| | return conout; |
| | } |
| |
|
| | static void setConsoleActiveScreenBuffer(HANDLE conout) { |
| | trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called...", |
| | g_prefix, (long long)conout); |
| | trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called... %s", |
| | g_prefix, (long long)conout, |
| | successOrFail(SetConsoleActiveScreenBuffer(conout))); |
| | } |
| |
|
| | static void writeTest(HANDLE conout, const char *msg) { |
| | char writeData[256]; |
| | sprintf(writeData, "%s%s\n", g_prefix, msg); |
| |
|
| | trace("%sWriting to 0x%I64x: '%s'...", |
| | g_prefix, (long long)conout, msg); |
| | DWORD actual = 0; |
| | BOOL ret = WriteConsoleA(conout, writeData, strlen(writeData), &actual, NULL); |
| | trace("%sWriting to 0x%I64x: '%s'... %s", |
| | g_prefix, (long long)conout, msg, |
| | successOrFail(ret && actual == strlen(writeData))); |
| | } |
| |
|
| | static void writeTest(const char *msg) { |
| | writeTest(GetStdHandle(STD_OUTPUT_HANDLE), msg); |
| | } |
| |
|
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | static void test1(int argc, char *argv[]) { |
| | if (!strcmp(argv[1], "1")) { |
| | startChildProcess(L"1:child"); |
| | return; |
| | } |
| |
|
| | HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE); |
| | writeTest(origBuffer, "<-- origBuffer -->"); |
| |
|
| | HANDLE newBuffer = createBuffer(); |
| | writeTest(newBuffer, "<-- newBuffer -->"); |
| | setConsoleActiveScreenBuffer(newBuffer); |
| | Sleep(2000); |
| |
|
| | writeTest(origBuffer, "TEST PASSED!"); |
| |
|
| | |
| | |
| | closeHandle(newBuffer); |
| |
|
| | while (true) { |
| | Sleep(1000); |
| | } |
| | } |
| |
|
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | static void test2(int argc, char *argv[]) { |
| | if (!strcmp(argv[1], "2")) { |
| | startChildProcess(L"2:parent"); |
| | return; |
| | } |
| |
|
| | if (!strcmp(argv[1], "2:parent")) { |
| | g_prefix = "parent: "; |
| | dumpHandles(); |
| | HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE); |
| | writeTest(origBuffer, "<-- origBuffer -->"); |
| |
|
| | HANDLE newBuffer = createBuffer(); |
| | writeTest(newBuffer, "<-- newBuffer -->"); |
| | setConsoleActiveScreenBuffer(newBuffer); |
| |
|
| | Sleep(1000); |
| | writeTest(newBuffer, "bInheritHandles=FALSE:"); |
| | startChildInSameConsole(L"2:child", FALSE); |
| | Sleep(1000); |
| | writeTest(newBuffer, "bInheritHandles=TRUE:"); |
| | startChildInSameConsole(L"2:child", TRUE); |
| |
|
| | Sleep(1000); |
| | trace("parent:----"); |
| |
|
| | |
| | |
| | |
| | closeHandle(newBuffer); |
| |
|
| | Sleep(600 * 1000); |
| | return; |
| | } |
| |
|
| | if (!strcmp(argv[1], "2:child")) { |
| | g_prefix = "child: "; |
| | dumpHandles(); |
| | |
| | |
| | trace("child:----"); |
| | writeTest("writing to STDOUT"); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | for (unsigned int i = 0x1; i <= 0xB0; ++i) { |
| | char msg[256]; |
| | sprintf(msg, "Write to handle 0x%x", i); |
| | HANDLE h = reinterpret_cast<HANDLE>(i); |
| | writeTest(h, msg); |
| | } |
| |
|
| | Sleep(600 * 1000); |
| | return; |
| | } |
| | } |
| |
|
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | static void testA_parentWork() { |
| | |
| | |
| | |
| | |
| | HANDLE dummy = openConout(); |
| |
|
| | Sleep(3000); |
| |
|
| | |
| | |
| |
|
| | HANDLE newBuffer = openConout(); |
| | writeTest(newBuffer, "step2: writing to newBuffer"); |
| |
|
| | Sleep(3000); |
| |
|
| | |
| | |
| |
|
| | closeHandle(newBuffer); |
| | } |
| |
|
| | static void testA_childWork() { |
| | HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE); |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | HANDLE newBuffer = createBuffer(); |
| |
|
| | setConsoleActiveScreenBuffer(newBuffer); |
| | writeTest(newBuffer, "<-- newBuffer -->"); |
| |
|
| | Sleep(9000); |
| | trace("child:----"); |
| |
|
| | |
| | writeTest(newBuffer, "TEST PASSED!"); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | Sleep(3000); |
| |
|
| | setConsoleActiveScreenBuffer(origBuffer); |
| | writeTest(origBuffer, "writing to origBuffer"); |
| |
|
| | closeHandle(newBuffer); |
| |
|
| | |
| | trace("child: console HWND=0x%I64x", (long long)GetConsoleWindow()); |
| |
|
| | |
| | |
| | |
| | |
| | } |
| |
|
| | static void testA(int argc, char *argv[]) { |
| |
|
| | if (!strcmp(argv[1], "A")) { |
| | startChildProcess(L"A:parent"); |
| | return; |
| | } |
| |
|
| | if (!strcmp(argv[1], "A:parent")) { |
| | g_prefix = "parent: "; |
| | trace("parent:----"); |
| | dumpHandles(); |
| | writeTest("<-- origBuffer -->"); |
| | startChildInSameConsole(L"A:child"); |
| | testA_parentWork(); |
| | Sleep(120000); |
| | return; |
| | } |
| |
|
| | if (!strcmp(argv[1], "A:child")) { |
| | g_prefix = "child: "; |
| | dumpHandles(); |
| | testA_childWork(); |
| | Sleep(120000); |
| | return; |
| | } |
| | } |
| |
|
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | static void testB(int argc, char *argv[]) { |
| | if (!strcmp(argv[1], "B")) { |
| | startChildProcess(L"B:parent"); |
| | return; |
| | } |
| |
|
| | if (!strcmp(argv[1], "B:parent")) { |
| | g_prefix = "parent: "; |
| | startChildInSameConsole(L"B:child"); |
| | writeTest("<-- origBuffer -->"); |
| | HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE); |
| |
|
| | |
| | |
| | |
| | trace("%s----", g_prefix); |
| | HANDLE newBuffer = createBuffer(); |
| | setConsoleActiveScreenBuffer(newBuffer); |
| | writeTest(newBuffer, "<-- newBuffer -->"); |
| |
|
| | |
| | |
| | |
| | Sleep(9000); |
| | trace("%s----", g_prefix); |
| | writeTest(newBuffer, "TEST PASSED!"); |
| |
|
| | |
| | |
| | |
| | Sleep(3000); |
| | trace("%s----", g_prefix); |
| | setConsoleActiveScreenBuffer(origBuffer); |
| | closeHandle(newBuffer); |
| | writeTest(origBuffer, "writing to the initial buffer"); |
| |
|
| | Sleep(60000); |
| | return; |
| | } |
| |
|
| | if (!strcmp(argv[1], "B:child")) { |
| | g_prefix = "child: "; |
| | Sleep(3000); |
| | trace("%s----", g_prefix); |
| |
|
| | |
| | |
| | |
| | HANDLE newBuffer = openConout(); |
| | writeTest(newBuffer, "writing to newBuffer"); |
| |
|
| | |
| | |
| | |
| | Sleep(3000); |
| | closeHandle(newBuffer); |
| |
|
| | Sleep(60000); |
| | return; |
| | } |
| | } |
| |
|
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | static void testC(int argc, char *argv[]) { |
| | if (!strcmp(argv[1], "C")) { |
| | startChildProcess(L"C:parent"); |
| | return; |
| | } |
| |
|
| | if (!strcmp(argv[1], "C:parent")) { |
| | startChildInSameConsole(L"C:child"); |
| | writeTest("<-- origBuffer -->"); |
| | g_prefix = "parent: "; |
| |
|
| | |
| | Sleep(4000); |
| | trace("%s---- t=4", g_prefix); |
| | const HANDLE newBuffer1 = openConout(); |
| |
|
| | |
| | Sleep(4000); |
| | trace("%s---- t=8", g_prefix); |
| | const HANDLE newBuffer2 = openConout(); |
| | closeHandle(newBuffer1); |
| |
|
| | |
| | Sleep(17000); |
| | trace("%s---- t=25", g_prefix); |
| | closeHandle(newBuffer2); |
| |
|
| | Sleep(240000); |
| | return; |
| | } |
| |
|
| | if (!strcmp(argv[1], "C:child")) { |
| | g_prefix = "child: "; |
| |
|
| | |
| | Sleep(2000); |
| | trace("%s---- t=2", g_prefix); |
| | const HANDLE newBuffer1 = createBuffer(); |
| | setConsoleActiveScreenBuffer(newBuffer1); |
| | writeTest(newBuffer1, "<-- newBuffer1 -->"); |
| |
|
| | |
| | Sleep(4000); |
| | trace("%s---- t=6", g_prefix); |
| | const HANDLE newBuffer2 = createBuffer(); |
| | setConsoleActiveScreenBuffer(newBuffer2); |
| | writeTest(newBuffer2, "<-- newBuffer2 -->"); |
| |
|
| | |
| | |
| | Sleep(4000); |
| | trace("%s---- t=10", g_prefix); |
| | setConsoleActiveScreenBuffer(newBuffer1); |
| | writeTest(newBuffer1, "write to newBuffer1: TEST PASSED!"); |
| |
|
| | |
| | Sleep(15000); |
| | trace("%s---- t=25", g_prefix); |
| | closeHandle(newBuffer2); |
| |
|
| | |
| | |
| | Sleep(10000); |
| | trace("%s---- t=35", g_prefix); |
| | closeHandle(newBuffer1); |
| |
|
| | Sleep(240000); |
| | return; |
| | } |
| | } |
| |
|
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | static void testD(int argc, char *argv[]) { |
| | if (!strcmp(argv[1], "D")) { |
| | startChildProcess(L"D:parent"); |
| | return; |
| | } |
| |
|
| | if (!strcmp(argv[1], "D:parent")) { |
| | g_prefix = "parent: "; |
| | HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE); |
| | writeTest(origBuffer, "<-- origBuffer -->"); |
| |
|
| | HANDLE newBuffer = createBuffer(); |
| | writeTest(newBuffer, "<-- newBuffer -->"); |
| | setConsoleActiveScreenBuffer(newBuffer); |
| |
|
| | |
| | |
| | |
| | Sleep(2000); |
| | trace("parent:----"); |
| | trace("parent: starting child process"); |
| | SetStdHandle(STD_OUTPUT_HANDLE, newBuffer); |
| | SetStdHandle(STD_ERROR_HANDLE, newBuffer); |
| | startChildInSameConsole(L"D:child"); |
| | SetStdHandle(STD_OUTPUT_HANDLE, origBuffer); |
| | SetStdHandle(STD_ERROR_HANDLE, origBuffer); |
| |
|
| | |
| | Sleep(4000); |
| | trace("parent:----"); |
| | writeTest(newBuffer, "TEST PASSED!"); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | Sleep(2000); |
| | closeHandle(newBuffer); |
| |
|
| | Sleep(120000); |
| | return; |
| | } |
| |
|
| | if (!strcmp(argv[1], "D:child")) { |
| | g_prefix = "child: "; |
| | |
| | trace("child:----"); |
| | dumpHandles(); |
| | writeTest("writing to newBuffer"); |
| |
|
| | |
| | Sleep(2000); |
| | trace("child:----"); |
| | if (GetStdHandle(STD_ERROR_HANDLE) != GetStdHandle(STD_OUTPUT_HANDLE)) { |
| | closeHandle(GetStdHandle(STD_ERROR_HANDLE)); |
| | } |
| | closeHandle(GetStdHandle(STD_OUTPUT_HANDLE)); |
| | closeHandle(GetStdHandle(STD_INPUT_HANDLE)); |
| |
|
| | Sleep(120000); |
| | return; |
| | } |
| | } |
| |
|
| |
|
| |
|
| | int main(int argc, char *argv[]) { |
| | if (argc == 1) { |
| | printf("USAGE: %s testnum\n", argv[0]); |
| | return 0; |
| | } |
| |
|
| | if (argv[1][0] == '1') { |
| | test1(argc, argv); |
| | } else if (argv[1][0] == '2') { |
| | test2(argc, argv); |
| | } else if (argv[1][0] == 'A') { |
| | testA(argc, argv); |
| | } else if (argv[1][0] == 'B') { |
| | testB(argc, argv); |
| | } else if (argv[1][0] == 'C') { |
| | testC(argc, argv); |
| | } else if (argv[1][0] == 'D') { |
| | testD(argc, argv); |
| | } |
| | return 0; |
| | } |
| |
|