Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/org.eclipse.cdt.core.win32/library/starter/starter.cpp962
1 files changed, 481 insertions, 481 deletions
diff --git a/core/org.eclipse.cdt.core.win32/library/starter/starter.cpp b/core/org.eclipse.cdt.core.win32/library/starter/starter.cpp
index 29de0b5ced4..8cdcbcc840d 100644
--- a/core/org.eclipse.cdt.core.win32/library/starter/starter.cpp
+++ b/core/org.eclipse.cdt.core.win32/library/starter/starter.cpp
@@ -1,481 +1,481 @@
-/*******************************************************************************
- * Copyright (c) 2002, 2007 QNX Software Systems and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * QNX Software Systems - initial API and implementation
- * Wind River Systems, Inc.
- *
- * starter.cpp
- *
- * This is a small utility for windows spawner
- *******************************************************************************/
-
-#define STRICT
-#define _WIN32_WINNT 0x0500
-#include <windows.h>
-#include <process.h>
-#include <tchar.h>
-#include <stdio.h>
-#include <psapi.h>
-
-//#define DEBUG_MONITOR
-#define MAX_CMD_LINE_LENGTH (2049)
-#define PIPE_NAME_LENGTH 100
-
-int copyTo(wchar_t * target, const wchar_t * source, int cpyLength,
- int availSpace);
-void DisplayErrorMessage();
-
-//BOOL KillProcessEx(DWORD dwProcessId); // Handle of the process
-
-///////////////////////////////////////////////////////////////////////////////
-BOOL WINAPI HandlerRoutine( DWORD dwCtrlType) // control signal type
-{
- BOOL ret = TRUE;
- switch(dwCtrlType)
- {
- case CTRL_C_EVENT:
- break;
- case CTRL_BREAK_EVENT:
- break;
- case CTRL_CLOSE_EVENT:
- ret = FALSE;
- break;
- case CTRL_LOGOFF_EVENT:
- ret = FALSE;
- break;
- case CTRL_SHUTDOWN_EVENT:
- ret = FALSE;
- break;
- default:
- break;
- }
- return ret;
-}
-
-// The default here means we haven't checked yet
-// i.e. cygwin is true but the bin dir hasn't been captured
-wchar_t * cygwinBin = NULL;
-bool _isCygwin = true;
-
-bool isCygwin(HANDLE process) {
- // Have we checked before?
- if (cygwinBin != NULL || !_isCygwin)
- return _isCygwin;
-
- // See if this process loaded cygwin, need a different SIGINT for them
- HMODULE mods[1024];
- DWORD needed;
- if (EnumProcessModules(process, mods, sizeof(mods), &needed)) {
- int i;
- needed /= sizeof(HMODULE);
- for (i = 0; i < needed; ++i ) {
- wchar_t modName[MAX_PATH];
- if (GetModuleFileNameEx(process, mods[i], modName, MAX_PATH)) {
- wchar_t * p = wcsrchr(modName, L'\\');
- if (p) {
- *p = 0; // Null terminate there for future reference
- if (!wcscmp(++p, L"cygwin1.dll")) {
- _isCygwin = true;
- // Store away the bind dir
- cygwinBin = wcsdup(modName);
- return _isCygwin;
- }
- }
- }
- }
- }
-
- _isCygwin = false;
- return _isCygwin;
-}
-
-bool runCygwinCommand(wchar_t * command) {
- wchar_t cygcmd[1024];
- swprintf(cygcmd, L"%s\\%s", cygwinBin, command);
-
- STARTUPINFO si;
- ZeroMemory(&si, sizeof(si));
- si.cb = sizeof(si);
- PROCESS_INFORMATION pi;
- ZeroMemory(&pi, sizeof(pi));
- if (CreateProcess(NULL, cygcmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
- WaitForSingleObject(pi.hProcess, INFINITE);
- CloseHandle(pi.hThread);
- CloseHandle(pi.hProcess);
- return true;
- } else if (CreateProcess(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
- WaitForSingleObject(pi.hProcess, INFINITE);
- CloseHandle(pi.hThread);
- CloseHandle(pi.hProcess);
- return true;
- }
- return false;
-}
-
-void ensureSize(wchar_t** ptr, int* psize, int requiredLength) {
- int size= *psize;
- if (requiredLength > size) {
- size= 2*size;
- if (size < requiredLength) {
- size= requiredLength;
- }
- *ptr= (wchar_t *)realloc(*ptr, size * sizeof(wchar_t));
- if (NULL == *ptr) {
- *psize= 0;
- } else {
- *psize= size;
- }
- }
-}
-
-int main() {
-
- int argc;
- wchar_t ** argv = CommandLineToArgvW(GetCommandLine(), &argc);
-
- // Make sure that we've been passed the right number of arguments
- if (argc < 7) {
- _tprintf(_T("Usage: %s (Three InheritableEventHandles) (CommandLineToSpawn)\n"),
- argv[0]);
- return(0);
- }
-
- // Construct the full command line
- int nCmdLineLength= MAX_CMD_LINE_LENGTH;
- wchar_t * szCmdLine= (wchar_t *)malloc(nCmdLineLength * sizeof(wchar_t));
- szCmdLine[0]= 0;
- int nPos = 0;
-
- for(int i = 6; i < argc; ++i)
- {
- int nCpyLen;
- int len= wcslen(argv[i]);
- int requiredSize= nPos+len+2;
- if (requiredSize > 32*1024) {
-#ifdef DEBUG_MONITOR
- OutputDebugStringW(_T("Command line too long!\n"));
-#endif
- return 0;
- }
- ensureSize(&szCmdLine, &nCmdLineLength, requiredSize);
- if (NULL == szCmdLine) {
-#ifdef DEBUG_MONITOR
- OutputDebugStringW(_T("Not enough memory to build cmd line!\n"));
-#endif
- return 0;
- }
- if(0 > (nCpyLen = copyTo(szCmdLine + nPos, argv[i], len, nCmdLineLength - nPos)))
- {
-#ifdef DEBUG_MONITOR
- OutputDebugStringW(_T("Not enough space to build command line\n"));
-#endif
- return 0;
- }
- nPos += nCpyLen;
- szCmdLine[nPos] = _T(' ');
- ++nPos;
- }
- szCmdLine[nPos] = _T('\0');
-
- STARTUPINFOW si = {sizeof(si)};
- PROCESS_INFORMATION pi = {0};
- DWORD dwExitCode = 0;
-#ifdef DEBUG_MONITOR
- int currentPID = GetCurrentProcessId();
- wchar_t buffer[MAX_CMD_LINE_LENGTH];
-#endif
-
- BOOL exitProc = FALSE;
- HANDLE waitEvent = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[4]);
- HANDLE h[3];
- h[0] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[3]);
- h[2] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[5]); // This is a terminate event
- SetConsoleCtrlHandler(HandlerRoutine, TRUE);
-
- int parentPid = wcstol(argv[1], NULL, 10);
- int nCounter = wcstol(argv[2], NULL, 10);
- wchar_t inPipeName[PIPE_NAME_LENGTH];
- wchar_t outPipeName[PIPE_NAME_LENGTH];
- wchar_t errPipeName[PIPE_NAME_LENGTH];
-
- swprintf(inPipeName, L"\\\\.\\pipe\\stdin%08i%010i", parentPid, nCounter);
- swprintf(outPipeName, L"\\\\.\\pipe\\stdout%08i%010i", parentPid, nCounter);
- swprintf(errPipeName, L"\\\\.\\pipe\\stderr%08i%010i", parentPid, nCounter);
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("Pipes: %s, %s, %s\n"), inPipeName, outPipeName, errPipeName);
- OutputDebugStringW(buffer);
-#endif
-
- HANDLE stdHandles[3];
-
- SECURITY_ATTRIBUTES sa;
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.bInheritHandle = TRUE;
- sa.lpSecurityDescriptor = NULL;
-
- if((INVALID_HANDLE_VALUE == (stdHandles[0] = CreateFileW(inPipeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, &sa))) ||
- (INVALID_HANDLE_VALUE == (stdHandles[1] = CreateFileW(outPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))) ||
- (INVALID_HANDLE_VALUE == (stdHandles[2] = CreateFileW(errPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))))
- {
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("Failed to open pipe %i, %i, %i: %i\n"), stdHandles[0], stdHandles[1], stdHandles[2], GetLastError());
- OutputDebugStringW(buffer);
-#endif
- CloseHandle(stdHandles[0]);
- CloseHandle(stdHandles[1]);
- CloseHandle(stdHandles[2]);
- return -1;;
- }
- SetHandleInformation(stdHandles[0], HANDLE_FLAG_INHERIT, TRUE);
- SetHandleInformation(stdHandles[1], HANDLE_FLAG_INHERIT, TRUE);
- SetHandleInformation(stdHandles[2], HANDLE_FLAG_INHERIT, TRUE);
-
- if(!SetStdHandle(STD_INPUT_HANDLE, stdHandles[0]) ||
- !SetStdHandle(STD_OUTPUT_HANDLE, stdHandles[1]) ||
- !SetStdHandle(STD_ERROR_HANDLE, stdHandles[2])) {
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("Failed to reassign standard streams: %i\n"), GetLastError());
- OutputDebugStringW(buffer);
-#endif
- CloseHandle(stdHandles[0]);
- CloseHandle(stdHandles[1]);
- CloseHandle(stdHandles[2]);
- return -1;;
- }
-
-#ifdef DEBUG_MONITOR
- wchar_t * lpvEnv = GetEnvironmentStringsW();
-
- // If the returned pointer is NULL, exit.
- if (lpvEnv == NULL)
- OutputDebugStringW(_T("Cannot Read Environment\n"));
- else {
- // Variable strings are separated by NULL byte, and the block is
- // terminated by a NULL byte.
-
- OutputDebugStringW(_T("Starter: Environment\n"));
- for (wchar_t * lpszVariable = (wchar_t *) lpvEnv; *lpszVariable; lpszVariable+=wcslen(lpszVariable) + 1) {
- swprintf(buffer, _T("%s\n"), lpszVariable);
- OutputDebugStringW(buffer);
- }
-
- FreeEnvironmentStringsW(lpvEnv);
- }
-#endif
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("Starting: %s\n"), szCmdLine);
- OutputDebugStringW(buffer);
-#endif
- // Create job object
- HANDLE hJob = CreateJobObject(NULL, NULL);
-
- // Spawn the other processes as part of this Process Group
- BOOL f = CreateProcessW(NULL, szCmdLine, NULL, NULL, TRUE,
- 0, NULL, NULL, &si, &pi);
-
- // We don't need them any more
- CloseHandle(stdHandles[0]);
- CloseHandle(stdHandles[1]);
- CloseHandle(stdHandles[2]);
-
- if (f) {
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("Process %i started\n"), pi.dwProcessId);
- OutputDebugStringW(buffer);
-#endif
- SetEvent(waitEvent); // Means thar process has been spawned
- CloseHandle(pi.hThread);
- h[1] = pi.hProcess;
-
- if(NULL != hJob) {
- if(!AssignProcessToJobObject(hJob, pi.hProcess)) {
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("Cannot assign process %i to a job\n"), pi.dwProcessId);
- OutputDebugStringW(buffer);
- DisplayErrorMessage();
-#endif
- }
- }
-
- while(!exitProc)
- {
- // Wait for the spawned-process to die or for the event
- // indicating that the processes should be forcibly killed.
- switch (WaitForMultipleObjects(3, h, FALSE, INFINITE))
- {
- case WAIT_OBJECT_0 + 0: // Send Ctrl-C
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("starter (PID %i) received CTRL-C event\n"), currentPID);
- OutputDebugStringW(buffer);
-#endif
- if (isCygwin(h[1])) {
- // Need to issue a kill command
- wchar_t kill[1024];
- swprintf(kill, L"kill -SIGINT %d", pi.dwProcessId);
- if (!runCygwinCommand(kill)) {
- // fall back to console event
- GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
- }
- } else {
- GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
- }
-
- SetEvent(waitEvent);
- break;
-
- case WAIT_OBJECT_0 + 1: // App terminated normally
- // Make it's exit code our exit code
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("starter: launched process has been terminated(PID %i)\n"),
- pi.dwProcessId);
- OutputDebugStringW(buffer);
-#endif
- GetExitCodeProcess(pi.hProcess, &dwExitCode);
- exitProc = TRUE;
- break;
-
- case WAIT_OBJECT_0 + 2: // Kill
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("starter received KILL event (PID %i)\n"), currentPID);
- OutputDebugStringW(buffer);
-#endif
- if (isCygwin(h[1])) {
- // Need to issue a kill command
- wchar_t kill[1024];
- swprintf(kill, L"kill -SIGTERM %d", pi.dwProcessId);
- if (!runCygwinCommand(kill)) {
- // fall back to console event
- GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
- }
- } else {
- GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
- }
-
- SetEvent(waitEvent);
-
- if(NULL != hJob) {
- if(!TerminateJobObject(hJob, (DWORD)-1)) {
-#ifdef DEBUG_MONITOR
- OutputDebugStringW(_T("Cannot terminate job\n"));
- DisplayErrorMessage();
-#endif
- }
- } else
- exitProc = TRUE;
- break;
- default:
- // Unexpected code
-#ifdef DEBUG_MONITOR
- DisplayErrorMessage();
-#endif
- exitProc = TRUE;
- break;
- }
-
- }
- CloseHandle(pi.hProcess);
- } else {
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("Cannot start: %s\n"), szCmdLine);
- OutputDebugStringW(buffer);
-
- DisplayErrorMessage();
-#endif
- }
-
- if (NULL != szCmdLine)
- {
- free(szCmdLine);
- }
-
- CloseHandle(waitEvent);
- CloseHandle(h[0]);
- CloseHandle(h[1]);
- CloseHandle(h[2]);
-
- return(dwExitCode);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////
-// Use this utility program to process correctly quotation marks in the command line
-// Arguments:
-// target - string to copy to
-// source - string to copy from
-// cpyLength - copy length
-// availSpace - size of the target buffer
-// Return :number of bytes used in target, or -1 in case of error
-/////////////////////////////////////////////////////////////////////////////////////
-int copyTo(wchar_t * target, const wchar_t * source, int cpyLength,
- int availSpace) {
- BOOL bSlash = FALSE;
- int i = 0, j = 0;
- int totCpyLength = cpyLength;
-
-#define QUOTATION_DO 0
-#define QUOTATION_DONE 1
-#define QUOTATION_NONE 2
-
- int nQuotationMode = 0;
- if (availSpace <= cpyLength) // = to reserve space for '\0'
- return -1;
-
- if ((_T('\"') == *source) && (_T('\"') == *(source + cpyLength - 1))) {
- // Already done
- nQuotationMode = QUOTATION_DONE;
- } else if (wcschr(source, _T(' '))== NULL) {
- // No reason to quotate term becase it doesn't have embedded spaces
- nQuotationMode = QUOTATION_NONE;
- } else {
- // Needs to be quotated
- nQuotationMode = QUOTATION_DO;
- *target = _T('\"');
- ++j;
- }
-
- for (; i < cpyLength; ++i, ++j) {
- if (source[i] == _T('\\'))
- bSlash = TRUE;
- else
- // Don't escape embracing quotation marks
- if ((source[i] == _T('\"')) && !((nQuotationMode == QUOTATION_DONE) && ((i == 0) || (i == (cpyLength - 1))) )) {
- if (!bSlash) {
- if (j == availSpace)
- return -1;
- target[j] = _T('\\');
- ++j;
- }
- bSlash = FALSE;
- } else
- bSlash = FALSE;
-
- if (j == availSpace)
- return -1;
- target[j] = source[i];
- }
-
- if (nQuotationMode == QUOTATION_DO) {
- if (j == availSpace)
- return -1;
- target[j] = _T('\"');
- ++j;
- }
- return j;
-}
-
-void DisplayErrorMessage() {
- wchar_t * lpMsgBuf;
- FormatMessageW(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- (wchar_t *) &lpMsgBuf, 0, NULL);
- OutputDebugStringW(lpMsgBuf);
- // Free the buffer.
- LocalFree(lpMsgBuf);
-}
-
-//////////////////////////////// End of File //////////////////////////////////
+/*******************************************************************************
+ * Copyright (c) 2002, 2007 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - initial API and implementation
+ * Wind River Systems, Inc.
+ *
+ * starter.cpp
+ *
+ * This is a small utility for windows spawner
+ *******************************************************************************/
+
+#define STRICT
+#define _WIN32_WINNT 0x0500
+#include <windows.h>
+#include <process.h>
+#include <tchar.h>
+#include <stdio.h>
+#include <psapi.h>
+
+//#define DEBUG_MONITOR
+#define MAX_CMD_LINE_LENGTH (2049)
+#define PIPE_NAME_LENGTH 100
+
+int copyTo(wchar_t * target, const wchar_t * source, int cpyLength,
+ int availSpace);
+void DisplayErrorMessage();
+
+//BOOL KillProcessEx(DWORD dwProcessId); // Handle of the process
+
+///////////////////////////////////////////////////////////////////////////////
+BOOL WINAPI HandlerRoutine( DWORD dwCtrlType) // control signal type
+{
+ BOOL ret = TRUE;
+ switch(dwCtrlType)
+ {
+ case CTRL_C_EVENT:
+ break;
+ case CTRL_BREAK_EVENT:
+ break;
+ case CTRL_CLOSE_EVENT:
+ ret = FALSE;
+ break;
+ case CTRL_LOGOFF_EVENT:
+ ret = FALSE;
+ break;
+ case CTRL_SHUTDOWN_EVENT:
+ ret = FALSE;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+// The default here means we haven't checked yet
+// i.e. cygwin is true but the bin dir hasn't been captured
+wchar_t * cygwinBin = NULL;
+bool _isCygwin = true;
+
+bool isCygwin(HANDLE process) {
+ // Have we checked before?
+ if (cygwinBin != NULL || !_isCygwin)
+ return _isCygwin;
+
+ // See if this process loaded cygwin, need a different SIGINT for them
+ HMODULE mods[1024];
+ DWORD needed;
+ if (EnumProcessModules(process, mods, sizeof(mods), &needed)) {
+ int i;
+ needed /= sizeof(HMODULE);
+ for (i = 0; i < needed; ++i ) {
+ wchar_t modName[MAX_PATH];
+ if (GetModuleFileNameEx(process, mods[i], modName, MAX_PATH)) {
+ wchar_t * p = wcsrchr(modName, L'\\');
+ if (p) {
+ *p = 0; // Null terminate there for future reference
+ if (!wcscmp(++p, L"cygwin1.dll")) {
+ _isCygwin = true;
+ // Store away the bind dir
+ cygwinBin = wcsdup(modName);
+ return _isCygwin;
+ }
+ }
+ }
+ }
+ }
+
+ _isCygwin = false;
+ return _isCygwin;
+}
+
+bool runCygwinCommand(wchar_t * command) {
+ wchar_t cygcmd[1024];
+ swprintf(cygcmd, L"%s\\%s", cygwinBin, command);
+
+ STARTUPINFO si;
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ PROCESS_INFORMATION pi;
+ ZeroMemory(&pi, sizeof(pi));
+ if (CreateProcess(NULL, cygcmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+ return true;
+ } else if (CreateProcess(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+ return true;
+ }
+ return false;
+}
+
+void ensureSize(wchar_t** ptr, int* psize, int requiredLength) {
+ int size= *psize;
+ if (requiredLength > size) {
+ size= 2*size;
+ if (size < requiredLength) {
+ size= requiredLength;
+ }
+ *ptr= (wchar_t *)realloc(*ptr, size * sizeof(wchar_t));
+ if (NULL == *ptr) {
+ *psize= 0;
+ } else {
+ *psize= size;
+ }
+ }
+}
+
+int main() {
+
+ int argc;
+ wchar_t ** argv = CommandLineToArgvW(GetCommandLine(), &argc);
+
+ // Make sure that we've been passed the right number of arguments
+ if (argc < 7) {
+ _tprintf(_T("Usage: %s (Three InheritableEventHandles) (CommandLineToSpawn)\n"),
+ argv[0]);
+ return(0);
+ }
+
+ // Construct the full command line
+ int nCmdLineLength= MAX_CMD_LINE_LENGTH;
+ wchar_t * szCmdLine= (wchar_t *)malloc(nCmdLineLength * sizeof(wchar_t));
+ szCmdLine[0]= 0;
+ int nPos = 0;
+
+ for(int i = 6; i < argc; ++i)
+ {
+ int nCpyLen;
+ int len= wcslen(argv[i]);
+ int requiredSize= nPos+len+2;
+ if (requiredSize > 32*1024) {
+#ifdef DEBUG_MONITOR
+ OutputDebugStringW(_T("Command line too long!\n"));
+#endif
+ return 0;
+ }
+ ensureSize(&szCmdLine, &nCmdLineLength, requiredSize);
+ if (NULL == szCmdLine) {
+#ifdef DEBUG_MONITOR
+ OutputDebugStringW(_T("Not enough memory to build cmd line!\n"));
+#endif
+ return 0;
+ }
+ if(0 > (nCpyLen = copyTo(szCmdLine + nPos, argv[i], len, nCmdLineLength - nPos)))
+ {
+#ifdef DEBUG_MONITOR
+ OutputDebugStringW(_T("Not enough space to build command line\n"));
+#endif
+ return 0;
+ }
+ nPos += nCpyLen;
+ szCmdLine[nPos] = _T(' ');
+ ++nPos;
+ }
+ szCmdLine[nPos] = _T('\0');
+
+ STARTUPINFOW si = {sizeof(si)};
+ PROCESS_INFORMATION pi = {0};
+ DWORD dwExitCode = 0;
+#ifdef DEBUG_MONITOR
+ int currentPID = GetCurrentProcessId();
+ wchar_t buffer[MAX_CMD_LINE_LENGTH];
+#endif
+
+ BOOL exitProc = FALSE;
+ HANDLE waitEvent = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[4]);
+ HANDLE h[3];
+ h[0] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[3]);
+ h[2] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[5]); // This is a terminate event
+ SetConsoleCtrlHandler(HandlerRoutine, TRUE);
+
+ int parentPid = wcstol(argv[1], NULL, 10);
+ int nCounter = wcstol(argv[2], NULL, 10);
+ wchar_t inPipeName[PIPE_NAME_LENGTH];
+ wchar_t outPipeName[PIPE_NAME_LENGTH];
+ wchar_t errPipeName[PIPE_NAME_LENGTH];
+
+ swprintf(inPipeName, L"\\\\.\\pipe\\stdin%08i%010i", parentPid, nCounter);
+ swprintf(outPipeName, L"\\\\.\\pipe\\stdout%08i%010i", parentPid, nCounter);
+ swprintf(errPipeName, L"\\\\.\\pipe\\stderr%08i%010i", parentPid, nCounter);
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, _T("Pipes: %s, %s, %s\n"), inPipeName, outPipeName, errPipeName);
+ OutputDebugStringW(buffer);
+#endif
+
+ HANDLE stdHandles[3];
+
+ SECURITY_ATTRIBUTES sa;
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL;
+
+ if((INVALID_HANDLE_VALUE == (stdHandles[0] = CreateFileW(inPipeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, &sa))) ||
+ (INVALID_HANDLE_VALUE == (stdHandles[1] = CreateFileW(outPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))) ||
+ (INVALID_HANDLE_VALUE == (stdHandles[2] = CreateFileW(errPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))))
+ {
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, _T("Failed to open pipe %i, %i, %i: %i\n"), stdHandles[0], stdHandles[1], stdHandles[2], GetLastError());
+ OutputDebugStringW(buffer);
+#endif
+ CloseHandle(stdHandles[0]);
+ CloseHandle(stdHandles[1]);
+ CloseHandle(stdHandles[2]);
+ return -1;;
+ }
+ SetHandleInformation(stdHandles[0], HANDLE_FLAG_INHERIT, TRUE);
+ SetHandleInformation(stdHandles[1], HANDLE_FLAG_INHERIT, TRUE);
+ SetHandleInformation(stdHandles[2], HANDLE_FLAG_INHERIT, TRUE);
+
+ if(!SetStdHandle(STD_INPUT_HANDLE, stdHandles[0]) ||
+ !SetStdHandle(STD_OUTPUT_HANDLE, stdHandles[1]) ||
+ !SetStdHandle(STD_ERROR_HANDLE, stdHandles[2])) {
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, _T("Failed to reassign standard streams: %i\n"), GetLastError());
+ OutputDebugStringW(buffer);
+#endif
+ CloseHandle(stdHandles[0]);
+ CloseHandle(stdHandles[1]);
+ CloseHandle(stdHandles[2]);
+ return -1;;
+ }
+
+#ifdef DEBUG_MONITOR
+ wchar_t * lpvEnv = GetEnvironmentStringsW();
+
+ // If the returned pointer is NULL, exit.
+ if (lpvEnv == NULL)
+ OutputDebugStringW(_T("Cannot Read Environment\n"));
+ else {
+ // Variable strings are separated by NULL byte, and the block is
+ // terminated by a NULL byte.
+
+ OutputDebugStringW(_T("Starter: Environment\n"));
+ for (wchar_t * lpszVariable = (wchar_t *) lpvEnv; *lpszVariable; lpszVariable+=wcslen(lpszVariable) + 1) {
+ swprintf(buffer, _T("%s\n"), lpszVariable);
+ OutputDebugStringW(buffer);
+ }
+
+ FreeEnvironmentStringsW(lpvEnv);
+ }
+#endif
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, _T("Starting: %s\n"), szCmdLine);
+ OutputDebugStringW(buffer);
+#endif
+ // Create job object
+ HANDLE hJob = CreateJobObject(NULL, NULL);
+
+ // Spawn the other processes as part of this Process Group
+ BOOL f = CreateProcessW(NULL, szCmdLine, NULL, NULL, TRUE,
+ 0, NULL, NULL, &si, &pi);
+
+ // We don't need them any more
+ CloseHandle(stdHandles[0]);
+ CloseHandle(stdHandles[1]);
+ CloseHandle(stdHandles[2]);
+
+ if (f) {
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, _T("Process %i started\n"), pi.dwProcessId);
+ OutputDebugStringW(buffer);
+#endif
+ SetEvent(waitEvent); // Means thar process has been spawned
+ CloseHandle(pi.hThread);
+ h[1] = pi.hProcess;
+
+ if(NULL != hJob) {
+ if(!AssignProcessToJobObject(hJob, pi.hProcess)) {
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, _T("Cannot assign process %i to a job\n"), pi.dwProcessId);
+ OutputDebugStringW(buffer);
+ DisplayErrorMessage();
+#endif
+ }
+ }
+
+ while(!exitProc)
+ {
+ // Wait for the spawned-process to die or for the event
+ // indicating that the processes should be forcibly killed.
+ switch (WaitForMultipleObjects(3, h, FALSE, INFINITE))
+ {
+ case WAIT_OBJECT_0 + 0: // Send Ctrl-C
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, _T("starter (PID %i) received CTRL-C event\n"), currentPID);
+ OutputDebugStringW(buffer);
+#endif
+ if (isCygwin(h[1])) {
+ // Need to issue a kill command
+ wchar_t kill[1024];
+ swprintf(kill, L"kill -SIGINT %d", pi.dwProcessId);
+ if (!runCygwinCommand(kill)) {
+ // fall back to console event
+ GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
+ }
+ } else {
+ GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
+ }
+
+ SetEvent(waitEvent);
+ break;
+
+ case WAIT_OBJECT_0 + 1: // App terminated normally
+ // Make it's exit code our exit code
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, _T("starter: launched process has been terminated(PID %i)\n"),
+ pi.dwProcessId);
+ OutputDebugStringW(buffer);
+#endif
+ GetExitCodeProcess(pi.hProcess, &dwExitCode);
+ exitProc = TRUE;
+ break;
+
+ case WAIT_OBJECT_0 + 2: // Kill
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, _T("starter received KILL event (PID %i)\n"), currentPID);
+ OutputDebugStringW(buffer);
+#endif
+ if (isCygwin(h[1])) {
+ // Need to issue a kill command
+ wchar_t kill[1024];
+ swprintf(kill, L"kill -SIGTERM %d", pi.dwProcessId);
+ if (!runCygwinCommand(kill)) {
+ // fall back to console event
+ GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
+ }
+ } else {
+ GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
+ }
+
+ SetEvent(waitEvent);
+
+ if(NULL != hJob) {
+ if(!TerminateJobObject(hJob, (DWORD)-1)) {
+#ifdef DEBUG_MONITOR
+ OutputDebugStringW(_T("Cannot terminate job\n"));
+ DisplayErrorMessage();
+#endif
+ }
+ } else
+ exitProc = TRUE;
+ break;
+ default:
+ // Unexpected code
+#ifdef DEBUG_MONITOR
+ DisplayErrorMessage();
+#endif
+ exitProc = TRUE;
+ break;
+ }
+
+ }
+ CloseHandle(pi.hProcess);
+ } else {
+#ifdef DEBUG_MONITOR
+ swprintf(buffer, _T("Cannot start: %s\n"), szCmdLine);
+ OutputDebugStringW(buffer);
+
+ DisplayErrorMessage();
+#endif
+ }
+
+ if (NULL != szCmdLine)
+ {
+ free(szCmdLine);
+ }
+
+ CloseHandle(waitEvent);
+ CloseHandle(h[0]);
+ CloseHandle(h[1]);
+ CloseHandle(h[2]);
+
+ return(dwExitCode);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Use this utility program to process correctly quotation marks in the command line
+// Arguments:
+// target - string to copy to
+// source - string to copy from
+// cpyLength - copy length
+// availSpace - size of the target buffer
+// Return :number of bytes used in target, or -1 in case of error
+/////////////////////////////////////////////////////////////////////////////////////
+int copyTo(wchar_t * target, const wchar_t * source, int cpyLength,
+ int availSpace) {
+ BOOL bSlash = FALSE;
+ int i = 0, j = 0;
+ int totCpyLength = cpyLength;
+
+#define QUOTATION_DO 0
+#define QUOTATION_DONE 1
+#define QUOTATION_NONE 2
+
+ int nQuotationMode = 0;
+ if (availSpace <= cpyLength) // = to reserve space for '\0'
+ return -1;
+
+ if ((_T('\"') == *source) && (_T('\"') == *(source + cpyLength - 1))) {
+ // Already done
+ nQuotationMode = QUOTATION_DONE;
+ } else if (wcschr(source, _T(' '))== NULL) {
+ // No reason to quotate term becase it doesn't have embedded spaces
+ nQuotationMode = QUOTATION_NONE;
+ } else {
+ // Needs to be quotated
+ nQuotationMode = QUOTATION_DO;
+ *target = _T('\"');
+ ++j;
+ }
+
+ for (; i < cpyLength; ++i, ++j) {
+ if (source[i] == _T('\\'))
+ bSlash = TRUE;
+ else
+ // Don't escape embracing quotation marks
+ if ((source[i] == _T('\"')) && !((nQuotationMode == QUOTATION_DONE) && ((i == 0) || (i == (cpyLength - 1))) )) {
+ if (!bSlash) {
+ if (j == availSpace)
+ return -1;
+ target[j] = _T('\\');
+ ++j;
+ }
+ bSlash = FALSE;
+ } else
+ bSlash = FALSE;
+
+ if (j == availSpace)
+ return -1;
+ target[j] = source[i];
+ }
+
+ if (nQuotationMode == QUOTATION_DO) {
+ if (j == availSpace)
+ return -1;
+ target[j] = _T('\"');
+ ++j;
+ }
+ return j;
+}
+
+void DisplayErrorMessage() {
+ wchar_t * lpMsgBuf;
+ FormatMessageW(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (wchar_t *) &lpMsgBuf, 0, NULL);
+ OutputDebugStringW(lpMsgBuf);
+ // Free the buffer.
+ LocalFree(lpMsgBuf);
+}
+
+//////////////////////////////// End of File //////////////////////////////////

Back to the top