8 printf("Usage: runnerw.exe <app> <args>\n");
9 printf("where <app> is console application and <args> it's arguments.\n");
12 "Runner invokes console application as a process with inherited input and output streams.\n");
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");
16 "Also in case of all type of event(Ctrl-C, Close, Shutdown etc) Ctrl-Break event is generated.\n");
21 void ErrorMessage(char *str) {
25 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
26 NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
27 (LPTSTR) &msg, 0, NULL);
29 printf("%s: %s\n", str, msg);
34 if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0)) {
35 ErrorMessage("GenerateConsoleCtrlEvent");
44 BOOL Scan(char buf[], int count) {
45 for (int i = 0; i < count; i++) {
62 BOOL CtrlHandler(DWORD fdwCtrlType) {
63 switch (fdwCtrlType) {
65 case CTRL_CLOSE_EVENT:
66 case CTRL_LOGOFF_EVENT:
67 case CTRL_SHUTDOWN_EVENT:
70 case CTRL_BREAK_EVENT:
77 struct StdInThreadParams {
82 DWORD WINAPI StdInThread(void *param) {
83 StdInThreadParams *threadParams = (StdInThreadParams *) param;
85 memset(buf, 0, sizeof(buf));
87 HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
93 ReadFile(hStdin, &c, 1, &cbRead, NULL);
96 bool ctrlBroken = Scan(buf, 1);
97 WriteFile(threadParams->write_stdin, buf, 1, &cbWrite, NULL);
99 SetEvent(threadParams->hEvent);
107 bool hasEnding(std::string const &fullString, std::string const &ending) {
108 if (fullString.length() > ending.length()) {
109 return (0 == fullString.compare(fullString.length() - ending.length(),
110 ending.length(), ending));
116 int main(int argc, char * argv[]) {
121 std::string app(argv[1]);
122 std::string args("");
124 for (int i = 1; i < argc; i++) {
128 if (strchr(argv[i], ' ')) {
137 // if (app.length() == 0) {
142 SECURITY_ATTRIBUTES sa;
143 PROCESS_INFORMATION pi;
145 HANDLE newstdin, write_stdin;
147 sa.lpSecurityDescriptor = NULL;
149 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
150 sa.bInheritHandle = true;
152 if (!CreatePipe(&newstdin, &write_stdin, &sa, 0)) {
153 ErrorMessage("CreatePipe");
159 si.dwFlags = STARTF_USESTDHANDLES;
160 si.wShowWindow = SW_HIDE;
161 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
162 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
163 si.hStdInput = newstdin;
165 if (hasEnding(app, std::string(".bat"))) {
166 // in MSDN it is said to do so, but actually that doesn't work
167 // args = "/c " + args;
177 c_app = new char[app.size() + 1];
178 strcpy(c_app, app.c_str());
182 char* c_args = new char[args.size() + 1];
183 strcpy(c_args, args.c_str());
185 SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE);
187 if (!CreateProcess(c_app, // Application name
188 c_args, // Application arguments
189 NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi)) {
190 ErrorMessage("CreateProcess");
191 CloseHandle(newstdin);
192 CloseHandle(write_stdin);
196 unsigned long exit = 0;
197 unsigned long b_read;
200 HANDLE threadEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
202 StdInThreadParams params;
203 params.hEvent = threadEvent;
204 params.write_stdin = write_stdin;
206 CreateThread(NULL, 0, &StdInThread, ¶ms, 0, NULL);
208 HANDLE objects_to_wait[2];
209 objects_to_wait[0] = threadEvent;
210 objects_to_wait[1] = pi.hProcess;
213 int rc = WaitForMultipleObjects(2, objects_to_wait, FALSE, INFINITE);
214 if (rc == WAIT_OBJECT_0 + 1) {
219 GetExitCodeProcess(pi.hProcess, &exit);
221 CloseHandle(pi.hThread);
222 CloseHandle(pi.hProcess);
223 CloseHandle(newstdin);
224 CloseHandle(write_stdin);