|
#include <windows.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 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 const char *successOrFail(BOOL ret) { |
|
return ret ? "ok" : "FAILED"; |
|
} |
|
|
|
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 HANDLE 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); |
|
|
|
return pi.hProcess; |
|
} |
|
|
|
static HANDLE dup(HANDLE h, HANDLE targetProcess) { |
|
HANDLE h2 = INVALID_HANDLE_VALUE; |
|
BOOL ret = DuplicateHandle( |
|
GetCurrentProcess(), h, |
|
targetProcess, &h2, |
|
0, TRUE, DUPLICATE_SAME_ACCESS); |
|
trace("dup(0x%I64x) to process 0x%I64x... %s, 0x%I64x", |
|
(long long)h, |
|
(long long)targetProcess, |
|
successOrFail(ret), |
|
(long long)h2); |
|
return h2; |
|
} |
|
|
|
int main(int argc, char *argv[]) { |
|
if (argc == 1) { |
|
startChildProcess(L"parent"); |
|
return 0; |
|
} |
|
|
|
if (!strcmp(argv[1], "parent")) { |
|
g_prefix = "parent: "; |
|
dumpHandles(); |
|
HANDLE hChild = startChildInSameConsole(L"child"); |
|
|
|
|
|
HANDLE orig1 = GetStdHandle(STD_OUTPUT_HANDLE); |
|
HANDLE new1 = createBuffer(); |
|
|
|
Sleep(2000); |
|
setConsoleActiveScreenBuffer(new1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HANDLE orig2 = dup(orig1, GetCurrentProcess()); |
|
HANDLE new2 = dup(new1, GetCurrentProcess()); |
|
|
|
dup(orig1, hChild); |
|
dup(new1, hChild); |
|
|
|
|
|
|
|
writeTest(orig1, "write to orig1"); |
|
writeTest(orig2, "write to orig2"); |
|
writeTest(new1, "write to new1"); |
|
writeTest(new2, "write to new2"); |
|
|
|
Sleep(120000); |
|
return 0; |
|
} |
|
|
|
if (!strcmp(argv[1], "child")) { |
|
g_prefix = "child: "; |
|
dumpHandles(); |
|
Sleep(4000); |
|
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(120000); |
|
return 0; |
|
} |
|
|
|
return 0; |
|
} |
|
|