5 const char *g_prefix = "";
7 static void dumpHandles() {
8 trace("%sSTDIN=0x%I64x STDOUT=0x%I64x STDERR=0x%I64x",
10 (long long)GetStdHandle(STD_INPUT_HANDLE),
11 (long long)GetStdHandle(STD_OUTPUT_HANDLE),
12 (long long)GetStdHandle(STD_ERROR_HANDLE));
15 static HANDLE createBuffer() {
17 // If sa isn't provided, the handle defaults to not-inheritable.
18 SECURITY_ATTRIBUTES sa = {0};
19 sa.nLength = sizeof(sa);
20 sa.bInheritHandle = TRUE;
22 trace("%sCreating a new buffer...", g_prefix);
23 HANDLE conout = CreateConsoleScreenBuffer(
24 GENERIC_READ | GENERIC_WRITE,
25 FILE_SHARE_READ | FILE_SHARE_WRITE,
27 CONSOLE_TEXTMODE_BUFFER, NULL);
29 trace("%sCreating a new buffer... 0x%I64x", g_prefix, (long long)conout);
33 static const char *successOrFail(BOOL ret) {
34 return ret ? "ok" : "FAILED";
37 static void setConsoleActiveScreenBuffer(HANDLE conout) {
38 trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called...",
39 g_prefix, (long long)conout);
40 trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called... %s",
41 g_prefix, (long long)conout,
42 successOrFail(SetConsoleActiveScreenBuffer(conout)));
45 static void writeTest(HANDLE conout, const char *msg) {
47 sprintf(writeData, "%s%s\n", g_prefix, msg);
49 trace("%sWriting to 0x%I64x: '%s'...",
50 g_prefix, (long long)conout, msg);
52 BOOL ret = WriteConsoleA(conout, writeData, strlen(writeData), &actual, NULL);
53 trace("%sWriting to 0x%I64x: '%s'... %s",
54 g_prefix, (long long)conout, msg,
55 successOrFail(ret && actual == strlen(writeData)));
58 static HANDLE startChildInSameConsole(const wchar_t *args, BOOL
59 bInheritHandles=FALSE) {
60 wchar_t program[1024];
61 wchar_t cmdline[1024];
62 GetModuleFileNameW(NULL, program, 1024);
63 swprintf(cmdline, L"\"%ls\" %ls", program, args);
66 PROCESS_INFORMATION pi;
67 memset(&sui, 0, sizeof(sui));
68 memset(&pi, 0, sizeof(pi));
71 CreateProcessW(program, cmdline,
73 /*bInheritHandles=*/bInheritHandles,
74 /*dwCreationFlags=*/0,
81 static HANDLE dup(HANDLE h, HANDLE targetProcess) {
82 HANDLE h2 = INVALID_HANDLE_VALUE;
83 BOOL ret = DuplicateHandle(
84 GetCurrentProcess(), h,
86 0, TRUE, DUPLICATE_SAME_ACCESS);
87 trace("dup(0x%I64x) to process 0x%I64x... %s, 0x%I64x",
89 (long long)targetProcess,
95 int main(int argc, char *argv[]) {
97 startChildProcess(L"parent");
101 if (!strcmp(argv[1], "parent")) {
102 g_prefix = "parent: ";
104 HANDLE hChild = startChildInSameConsole(L"child");
107 HANDLE orig1 = GetStdHandle(STD_OUTPUT_HANDLE);
108 HANDLE new1 = createBuffer();
111 setConsoleActiveScreenBuffer(new1);
113 // Handle duplication results to child process in same console:
114 // - Windows XP: fails
115 // - Windows 7 Ultimate SP1 32-bit: fails
116 // - Windows Server 2008 R2 Datacenter SP1 64-bit: fails
117 // - Windows 8 Enterprise 32-bit: succeeds
118 // - Windows 10: succeeds
119 HANDLE orig2 = dup(orig1, GetCurrentProcess());
120 HANDLE new2 = dup(new1, GetCurrentProcess());
125 // The writes to orig1/orig2 are invisible. The writes to new1/new2
127 writeTest(orig1, "write to orig1");
128 writeTest(orig2, "write to orig2");
129 writeTest(new1, "write to new1");
130 writeTest(new2, "write to new2");
136 if (!strcmp(argv[1], "child")) {
137 g_prefix = "child: ";
140 for (unsigned int i = 0x1; i <= 0xB0; ++i) {
142 sprintf(msg, "Write to handle 0x%x", i);
143 HANDLE h = reinterpret_cast<HANDLE>(i);