blob: 8b41e40a30ca0f8891f0927c8065c09891c59828 [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
***********************************************************************/
/*
* starter.c
*
* This is a small utility for windows spawner
*/
//#define UNICODE
//#define _UNICODE
#define STRICT
#include <Windows.h>
#include <process.h>
#include <tchar.h>
#include <stdio.h>
// #define DEBUG_MONITOR
#define MAX_CMD_LINE_LENGTH (2049)
int copyTo(char * target, const char * source, int cpyLength, int availSpace);
///////////////////////////////////////////////////////////////////////////////
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;
}
extern "C" int _tmain(int argc, TCHAR* argv[]) {
// Make sure that we've been passed the right number of arguments
if (argc < 5) {
_tprintf(__TEXT("Usage: %s (Three InheritableEventHandles) (CommandLineToSpawn)\n"),
argv[0]);
return(0);
}
// Construct the full command line
TCHAR szCmdLine[MAX_CMD_LINE_LENGTH] = { 0 };
int nPos = 0;
for(int i = 4; i < argc; ++i)
{
int nCpyLen;
if(0 > (nCpyLen = copyTo(szCmdLine + nPos, argv[i], _tcslen(argv[i]), MAX_CMD_LINE_LENGTH - nPos)))
{
#ifdef DEBUG_MONITOR
OutputDebugString("Not enough space to build command line\n");
#endif
return 0;
}
nPos += nCpyLen;
szCmdLine[nPos] = _T(' ');
++nPos;
}
szCmdLine[nPos] = _T('\0');
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
DWORD dwExitCode = 0;
#ifdef DEBUG_MONITOR
int currentPID = GetCurrentProcessId();
char buffer[MAX_CMD_LINE_LENGTH];
#endif
BOOL exitProc = FALSE;
HANDLE waitEvent = OpenEvent(EVENT_ALL_ACCESS, TRUE, argv[2]);
HANDLE h[3];
h[0] = OpenEvent(EVENT_ALL_ACCESS, TRUE, argv[1]);
h[2] = OpenEvent(EVENT_ALL_ACCESS, TRUE, argv[3]); // This is a terminate event
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
#ifdef DEBUG_MONITOR
sprintf(buffer, "starter start command: %s\n", szCmdLine);
OutputDebugString(buffer);
#endif
// OutputDebugString(szCmdLine);
// Spawn the other processes as part of this Process Group
BOOL f = CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE,
0, NULL, NULL, &si, &pi);
if (f)
{
SetEvent(waitEvent); // Means thar process has been spawned
CloseHandle(pi.hThread);
h[1] = pi.hProcess;
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
sprintf(buffer, "starter (PID %i) received CTRL-C event\n", currentPID);
OutputDebugString(buffer);
#endif
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
sprintf(buffer, "starter: launched process has been terminated(PID %i)\n", currentPID);
OutputDebugString(buffer);
#endif
GetExitCodeProcess(pi.hProcess, &dwExitCode);
exitProc = TRUE;
break;
case WAIT_OBJECT_0 + 2: // Kill
#ifdef DEBUG_MONITOR
sprintf(buffer, "starter received KILL event (PID %i)\n", currentPID);
OutputDebugString(buffer);
#endif
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
TerminateProcess(h[1], 0);
exitProc = TRUE;
break;
default:
// Unexpected code
LPTSTR lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
OutputDebugString(lpMsgBuf);
// Free the buffer.
LocalFree( lpMsgBuf );
exitProc = TRUE;
break;
}
}
CloseHandle(pi.hProcess);
}
CloseHandle(waitEvent);
CloseHandle(h[0]);
CloseHandle(h[2]);
return(dwExitCode);
}
// Return number of bytes in target or -1 in case of error
int copyTo(LPTSTR target, LPCTSTR 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(_tcschr(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;
}
//////////////////////////////// End of File //////////////////////////////////