01fc6b154dbfc327debf058decae82b542dbcd04
[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 = 255;
42 char BRK = 243;
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                         } else {
50                                 is_iac = FALSE;
51                         }
52                 }
53                 if (buf[i] == IAC) {
54                         is_iac = TRUE;
55                 }
56         }
57
58         return FALSE;
59 }
60
61 BOOL CtrlHandler(DWORD fdwCtrlType) {
62         switch (fdwCtrlType) {
63         case CTRL_C_EVENT:
64         case CTRL_CLOSE_EVENT:
65         case CTRL_LOGOFF_EVENT:
66         case CTRL_SHUTDOWN_EVENT:
67                 CtrlBreak();
68                 return (TRUE);
69         case CTRL_BREAK_EVENT:
70                 return FALSE;
71         default:
72                 return FALSE;
73         }
74 }
75
76 int main(int argc, char * argv[]) {
77         if (argc < 2) {
78                 PrintUsage();
79         }
80
81         std::string app(argv[1]);
82         std::string args("");
83
84         for (int i = 2; i < argc; i++) {
85                 args += " ";
86                 args += argv[i];
87         }
88
89         if (app.length() == 0) {
90                 PrintUsage();
91         }
92
93         STARTUPINFO si;
94         SECURITY_ATTRIBUTES sa;
95         PROCESS_INFORMATION pi;
96
97         HANDLE newstdin, write_stdin;
98
99         sa.lpSecurityDescriptor = NULL;
100
101         sa.nLength = sizeof(SECURITY_ATTRIBUTES);
102         sa.bInheritHandle = true;
103
104         if (!CreatePipe(&newstdin, &write_stdin, &sa, 0)) {
105                 ErrorMessage("CreatePipe");
106                 exit(0);
107         }
108
109         GetStartupInfo(&si);
110
111         si.dwFlags = STARTF_USESTDHANDLES;
112         si.wShowWindow = SW_HIDE;
113         si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
114         si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
115         si.hStdInput = newstdin;
116
117         char* c_app = new char[app.size() + 1];
118         strcpy(c_app, app.c_str());
119
120         char* c_args = new char[args.size() + 1];
121         strcpy(c_args, args.c_str());
122
123         SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE);
124
125         if (!CreateProcess(c_app, // Application name
126                         c_args, // Application arguments
127                         NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi)) {
128                 ErrorMessage("CreateProcess");
129                 CloseHandle(newstdin);
130                 CloseHandle(write_stdin);
131                 exit(0);
132         }
133
134         unsigned long exit = 0;
135         unsigned long b_read;
136         unsigned long b_write;
137         unsigned long avail;
138
139         char buf[1];
140         memset(buf, 0, sizeof(buf));
141
142         for (;;) {
143                 GetExitCodeProcess(pi.hProcess, &exit);
144
145                 if (exit != STILL_ACTIVE)
146                         break;
147
148                 char c;
149                 std::cin >> c;
150                 buf[0] = c;
151                 Scan(buf, 1);
152                 WriteFile(write_stdin, buf, 1, &b_write, NULL);
153         }
154
155         CloseHandle(pi.hThread);
156         CloseHandle(pi.hProcess);
157         CloseHandle(newstdin);
158         CloseHandle(write_stdin);
159 }