aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/winpty/misc/ScreenBufferTest2.cc
blob: 2b648c94093d4fd4e568ecacfdaa5bc0006c2356 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#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() {

    // If sa isn't provided, the handle defaults to not-inheritable.
    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=*/bInheritHandles,
                   /*dwCreationFlags=*/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");

        // Windows 10.
        HANDLE orig1 = GetStdHandle(STD_OUTPUT_HANDLE);
        HANDLE new1 = createBuffer();

        Sleep(2000);
        setConsoleActiveScreenBuffer(new1);

        // Handle duplication results to child process in same console:
        //  - Windows XP:                                       fails
        //  - Windows 7 Ultimate SP1 32-bit:                    fails
        //  - Windows Server 2008 R2 Datacenter SP1 64-bit:     fails
        //  - Windows 8 Enterprise 32-bit:                      succeeds
        //  - Windows 10:                                       succeeds
        HANDLE orig2 = dup(orig1, GetCurrentProcess());
        HANDLE new2 = dup(new1, GetCurrentProcess());

        dup(orig1, hChild);
        dup(new1, hChild);

        // The writes to orig1/orig2 are invisible.  The writes to new1/new2
        // are visible.
        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;
}