d29b27f217f78ed707385d73e33b09f0253b0adc
[idea/community.git] / native / runner / runnerw / runnerw.cpp
1 #include <windows.h>
2 #include <stdio.h>
3 #include <tlhelp32.h>
4 #include <iostream>
5 #include <string>
6
7 void PrintUsage() {
8         printf("Usage: runnerw.exe <app> <args>\n");
9         printf("where <app> is console application and <args> it's arguments.\n");
10         printf("\n");
11         printf(
12                         "Runner invokes console application as a process with inherited input and output streams.\n");
13         printf(
14                         "Input stream is scanned for presence of 2 char 255(IAC) and 243(BRK) sequence and generates Ctrl-Break event in that case.\n");
15         printf(
16                         "Also in case of all type of event(Ctrl-C, Close, Shutdown etc) Ctrl-Break event is generated.\n");
17
18         exit(0);
19 }
20
21 void ErrorMessage(char *str) {
22
23         LPVOID msg;
24
25         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
26                         NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
27                         (LPTSTR) &msg, 0, NULL);
28
29         printf("%s: %s\n", str, msg);
30         LocalFree(msg);
31 }
32
33 void CtrlBreak() {
34         if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0)) {
35                 ErrorMessage("GenerateConsoleCtrlEvent");
36         }
37 }
38
39 BOOL is_iac = FALSE;
40
41 char IAC = 5;
42 char BRK = 3;
43
44 BOOL Scan(char buf[], int count) {
45         for (int i = 0; i < count; i++) {
46                 if (is_iac) {
47                         if (buf[i] == BRK) {
48                                 CtrlBreak();
49                                 return TRUE;
50                         } else {
51                                 is_iac = FALSE;
52                         }
53                 }
54                 if (buf[i] == IAC) {
55                         is_iac = TRUE;
56                 }
57         }
58
59         return FALSE;
60 }
61
62 BOOL CtrlHandler(DWORD fdwCtrlType) {
63         switch (fdwCtrlType) {
64         case CTRL_C_EVENT:
65         case CTRL_CLOSE_EVENT:
66         case CTRL_LOGOFF_EVENT:
67         case CTRL_SHUTDOWN_EVENT:
68                 CtrlBreak();
69                 return (TRUE);
70         case CTRL_BREAK_EVENT:
71                 return FALSE;
72         default:
73                 return FALSE;
74         }
75 }
76
77 struct StdInThreadParams
78 {
79         HANDLE hEvent;
80         HANDLE write_stdin;
81 };
82
83 DWORD WINAPI StdInThread(void *param)
84 {
85         StdInThreadParams *threadParams = (StdInThreadParams *) param;
86         char buf[1];
87         memset(buf, 0, sizeof(buf));
88
89         HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
90         while(true)
91         {
92                 DWORD cbRead = 0;
93                 DWORD cbWrite = 0;
94
95                 char c;
96                 ReadFile(hStdin, &c, 1, &cbRead, NULL);
97                 if (cbRead > 0)
98                 {
99                         buf[0] = c;
100                         bool ctrlBroken = Scan(buf, 1);
101                         WriteFile(threadParams->write_stdin, buf, 1, &cbWrite, NULL);
102                         if (ctrlBroken)
103                         {
104                                 SetEvent(threadParams->hEvent);
105                                 break;
106                         }
107                 }
108         }
109         return 0;
110 }
111
112 int main(int argc, char * argv[]) {
113         if (argc < 2) {
114                 PrintUsage();
115         }
116
117         std::string app(argv[1]);
118         std::string args("");
119
120         for (int i = 2; i < argc; i++) {
121                 args += " ";
122                 args += argv[i];
123         }
124
125         if (app.length() == 0) {
126                 PrintUsage();
127         }
128
129         STARTUPINFO si;
130         SECURITY_ATTRIBUTES sa;
131         PROCESS_INFORMATION pi;
132
133         HANDLE newstdin, write_stdin;
134
135         sa.lpSecurityDescriptor = NULL;
136
137         sa.nLength = sizeof(SECURITY_ATTRIBUTES);
138         sa.bInheritHandle = true;
139
140         if (!CreatePipe(&newstdin, &write_stdin, &sa, 0)) {
141                 ErrorMessage("CreatePipe");
142                 exit(0);
143         }
144
145         GetStartupInfo(&si);
146
147         si.dwFlags = STARTF_USESTDHANDLES;
148         si.wShowWindow = SW_HIDE;
149         si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
150         si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
151         si.hStdInput = newstdin;
152
153         char* c_app = new char[app.size() + 1];
154         strcpy(c_app, app.c_str());
155
156         char* c_args = new char[args.size() + 1];
157         strcpy(c_args, args.c_str());
158
159         SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE);
160
161         if (!CreateProcess(c_app, // Application name
162                         c_args, // Application arguments
163                         NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi)) {
164                 ErrorMessage("CreateProcess");
165                 CloseHandle(newstdin);
166                 CloseHandle(write_stdin);
167                 exit(0);
168         }
169
170         unsigned long exit = 0;
171         unsigned long b_read;
172         unsigned long avail;
173
174         HANDLE threadEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
175
176         StdInThreadParams params;
177         params.hEvent = threadEvent;
178         params.write_stdin = write_stdin;
179
180         CreateThread(NULL, 0, &StdInThread, &params, 0, NULL);
181
182         HANDLE objects_to_wait[2];
183         objects_to_wait[0] = threadEvent;
184         objects_to_wait[1] = pi.hProcess;
185
186         while(true)
187         {
188                 int rc = WaitForMultipleObjects(2, objects_to_wait, FALSE, INFINITE);
189                 if (rc == WAIT_OBJECT_0 + 1)
190                 {
191                         break;
192                 }
193         }
194
195         GetExitCodeProcess(pi.hProcess, &exit);
196
197         CloseHandle(pi.hThread);
198         CloseHandle(pi.hProcess);
199         CloseHandle(newstdin);
200         CloseHandle(write_stdin);
201         return exit;
202 }