1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-05 15:25:49 +02:00

Update the starter/spawner to use named pipes.

Patch from alex.
This commit is contained in:
Alain Magloire 2004-02-12 21:12:51 +00:00
parent 385ac1b870
commit c2ba759a8c
13 changed files with 482 additions and 203 deletions

View file

@ -1,3 +1,8 @@
2004-02-12 Alex Chapiro
Update starter and spawner to use named pipes.
Update the binaries.
2003-08-29 Alex Chapiro 2003-08-29 Alex Chapiro
This patch just increase command line buffer up to OS limit (2K). It also This patch just increase command line buffer up to OS limit (2K). It also

View file

@ -1,3 +1,17 @@
/**********************************************************************
* Copyright (c) 2002-2004 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 v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*
* Spawner.h
*
* This is a part of JNI implementation of spawner
***********************************************************************/
/* DO NOT EDIT THIS FILE - it is machine generated */ /* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h> #include <jni.h>
/* Header for class org_eclipse_cdt_utils_spawner_Spawner */ /* Header for class org_eclipse_cdt_utils_spawner_Spawner */
@ -40,9 +54,15 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_raise
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_waitFor JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_waitFor
(JNIEnv *, jobject, jint); (JNIEnv *, jobject, jint);
// #define DEBUG_MONITOR
int interruptProcess(int pid); int interruptProcess(int pid);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
// #define DEBUG_MONITOR
#endif #endif

View file

@ -1,3 +1,18 @@
/**********************************************************************
* Copyright (c) 2002-2004 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 v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*
* SpawnerInputStream.h
*
* This is a part of JNI implementation of spawner
***********************************************************************/
/* DO NOT EDIT THIS FILE - it is machine generated */ /* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h> #include <jni.h>
/* Header for class com_qnx_tools_utils_spawner_SpawnerInputStream */ /* Header for class com_qnx_tools_utils_spawner_SpawnerInputStream */

View file

@ -1,3 +1,17 @@
/**********************************************************************
* Copyright (c) 2002-2004 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 v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*
* SpawnerOutputStream.h
*
* This is a part of JNI implementation of spawner
***********************************************************************/
/* DO NOT EDIT THIS FILE - it is machine generated */ /* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h> #include <jni.h>
/* Header for class com_qnx_tools_utils_spawner_SpawnerOutputStream */ /* Header for class com_qnx_tools_utils_spawner_SpawnerOutputStream */

View file

@ -1,12 +1,16 @@
/********************************************************************** /**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others. * Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5 * are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html * http://www.eclipse.org/legal/cpl-v10.html
* *
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
*
* StdAfx.c
*
* This is a part of JNI implementation of spawner
***********************************************************************/ ***********************************************************************/
// stdafx.cpp : source file that includes just the standard includes // stdafx.cpp : source file that includes just the standard includes
// spawner.pch will be the pre-compiled header // spawner.pch will be the pre-compiled header

View file

@ -1,13 +1,18 @@
/********************************************************************** /**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others. * Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5 * are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html * http://www.eclipse.org/legal/cpl-v10.html
* *
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
*
* StdAfx.h
*
* This is a part of JNI implementation of spawner
***********************************************************************/ ***********************************************************************/
// stdafx.h : include file for standard system include files, // stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but // or project specific include files that are used frequently, but
// are changed infrequently // are changed infrequently

View file

@ -1,59 +1,76 @@
/********************************************************************** /**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others. * Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5 * are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html * http://www.eclipse.org/legal/cpl-v10.html
* *
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
***********************************************************************/ *
/*
* Win32ProcessEx.c * Win32ProcessEx.c
* *
* This is a JNI implementation of spawner * This is a JNI implementation of spawner
*/ ***********************************************************************/
#include "stdafx.h" #include "stdafx.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <process.h> #include <process.h>
#include "Spawner.h" #include "Spawner.h"
#include "jni.h"
#include "io.h"
#define PIPE_SIZE 512 // Size of pipe buffer
#define MAX_CMD_SIZE 2049 // Maximum size of command line
#define MAX_ENV_SIZE 4096 // Initial size of environment block
#define PIPE_NAME_LENGTH 100 // Size of pipe name buffer
#define PIPE_TIMEOUT 10000 // Default time-out value, in milliseconds.
#include "jni.h" #define MAX_PROCS (100) // Maximum number of simultaneiously runnig processes
#include "io.h"
// #define DEBUG_MONITOR
#define PIPE_SIZE 512
#define MAX_CMD_SIZE 2049
#define MAX_ENV_SIZE 4096
#define MAX_PROCS (100)
// Theses are VM helpers
typedef JNIEXPORT void * (JNICALL * JVM_GetThreadInterruptEvent)(); typedef JNIEXPORT void * (JNICALL * JVM_GetThreadInterruptEvent)();
typedef JNIEXPORT char * (JNICALL * JVM_NativePath)(const char *); typedef JNIEXPORT char * (JNICALL * JVM_NativePath)(const char *);
// Process description block. Should be created for each launched process
typedef struct _procInfo { typedef struct _procInfo {
int pid; // Process ID int pid; // Process ID
int uid; // quasi-unique process ID int uid; // quasi-unique process ID; we have to create it to avoid duplicated pid
// (actually this impossible from OS point of view but it is still possible
// a clash of new created and already finished process with one and the same PID.
// 3 events connected to this process (see starter)
HANDLE eventBreak; HANDLE eventBreak;
HANDLE eventWait; HANDLE eventWait;
HANDLE eventTerminate; HANDLE eventTerminate;
} procInfo_t, * pProcInfo_t; } procInfo_t, * pProcInfo_t;
static int procCounter = 0; static int procCounter = 0; // Number of running processes
// This is a VM helper
JNIEXPORT void JNICALL ThrowByName(JNIEnv *env, const char *name, const char *msg); JNIEXPORT void JNICALL ThrowByName(JNIEnv *env, const char *name, const char *msg);
pProcInfo_t createProcInfo();
pProcInfo_t findProcInfo(int pid); // Creates _procInfo block for every launched procss
pProcInfo_t createProcInfo();
// Find process description for this pid
pProcInfo_t findProcInfo(int pid);
// We launch separate thread for each project to trap it termination
unsigned int _stdcall waitProcTermination(void* pv) ; unsigned int _stdcall waitProcTermination(void* pv) ;
// This is a helper function to prevent losing of quotatin marks
static int copyTo(char * target, const char * source, int cpyLenght, int availSpace); static int copyTo(char * target, const char * source, int cpyLenght, int availSpace);
// Use this function to clean project descriptor and return it to the pool of available blocks.
static void cleanUpProcBlock(pProcInfo_t pCurProcInfo); static void cleanUpProcBlock(pProcInfo_t pCurProcInfo);
// Signal codes
typedef enum { typedef enum {
SIG_NOOP, SIG_NOOP,
SIG_HUP, SIG_HUP,
@ -65,20 +82,27 @@ typedef enum {
extern CRITICAL_SECTION cs; extern CRITICAL_SECTION cs;
extern TCHAR path[MAX_PATH]; extern TCHAR path[MAX_PATH]; // Directory where spawner.dll is located
static HMODULE hVM = NULL; static HMODULE hVM = NULL; // VM handler
static pProcInfo_t pInfo = NULL; static pProcInfo_t pInfo = NULL;
static int nCounter = 0; // We use it to build unique synchronisation object names
/////////////////////////////////////////////////////////////////////////////////////
// Launcher; launchess process and traps its termination
// Arguments: (see Spawner.java)
// [in] cmdarray - array of command line elements
// [in] envp - array of environment variables
// [in] dir - working directory
// [out] channels - streams handlers
/////////////////////////////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
(JNIEnv * env, jobject process, jobjectArray cmdarray, jobjectArray envp, jstring dir, jintArray channels) (JNIEnv * env, jobject process, jobjectArray cmdarray, jobjectArray envp, jstring dir, jintArray channels)
{ {
HANDLE stdHandles[3];
HANDLE hread[3], hwrite[3];
SECURITY_ATTRIBUTES sa;
PROCESS_INFORMATION pi = {0}; PROCESS_INFORMATION pi = {0};
STARTUPINFO si; STARTUPINFO si;
DWORD flags = 0; DWORD flags = 0;
@ -91,6 +115,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
jsize nCmdTokens = 0; jsize nCmdTokens = 0;
jsize nEnvVars = 0; jsize nEnvVars = 0;
int i; int i;
DWORD pid = GetCurrentProcessId();
int nPos; int nPos;
pProcInfo_t pCurProcInfo; pProcInfo_t pCurProcInfo;
DWORD dwThreadId; DWORD dwThreadId;
@ -100,6 +125,10 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
#ifdef DEBUG_MONITOR #ifdef DEBUG_MONITOR
char buffer[1000]; char buffer[1000];
#endif #endif
int nLocalCounter;
char inPipeName[PIPE_NAME_LENGTH];
char outPipeName[PIPE_NAME_LENGTH];
char errPipeName[PIPE_NAME_LENGTH];
if((HIBYTE(LOWORD(GetVersion()))) & 0x80) if((HIBYTE(LOWORD(GetVersion()))) & 0x80)
{ {
@ -113,25 +142,39 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
return 0; return 0;
} }
sa.nLength = sizeof(sa); ZeroMemory(stdHandles, sizeof(stdHandles));
sa.lpSecurityDescriptor = 0;
sa.bInheritHandle = TRUE;
memset(hread, 0, sizeof(hread)); // Create pipe names
memset(hwrite, 0, sizeof(hwrite)); EnterCriticalSection(&cs);
if (!(CreatePipe(&hread[0], &hwrite[0], &sa, PIPE_SIZE) && sprintf(inPipeName, "\\\\.\\pipe\\stdin%08i%010i", pid, nCounter);
CreatePipe(&hread[1], &hwrite[1], &sa, PIPE_SIZE) && sprintf(outPipeName, "\\\\.\\pipe\\stdout%08i%010i", pid, nCounter);
CreatePipe(&hread[2], &hwrite[2], &sa, PIPE_SIZE))) sprintf(errPipeName, "\\\\.\\pipe\\stderr%08i%010i", pid, nCounter);
{ nLocalCounter = nCounter;
CloseHandle(hread[0]); ++nCounter;
CloseHandle(hread[1]); LeaveCriticalSection(&cs);
CloseHandle(hread[2]);
CloseHandle(hwrite[0]);
CloseHandle(hwrite[1]); if ((INVALID_HANDLE_VALUE == (stdHandles[0] = CreateNamedPipe(inPipeName, PIPE_ACCESS_OUTBOUND,
CloseHandle(hwrite[2]); PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, PIPE_SIZE, PIPE_SIZE, PIPE_TIMEOUT, NULL))) ||
(INVALID_HANDLE_VALUE == (stdHandles[1] = CreateNamedPipe(outPipeName, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, PIPE_SIZE, PIPE_SIZE, PIPE_TIMEOUT, NULL))) ||
(INVALID_HANDLE_VALUE == (stdHandles[2] = CreateNamedPipe(errPipeName, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, PIPE_SIZE, PIPE_SIZE, PIPE_TIMEOUT, NULL)))) {
CloseHandle(stdHandles[0]);
CloseHandle(stdHandles[1]);
CloseHandle(stdHandles[2]);
ThrowByName(env, "java/io/IOException", "CreatePipe"); ThrowByName(env, "java/io/IOException", "CreatePipe");
return 0; return 0;
} }
#ifdef DEBUG_MONITOR
sprintf(buffer, "Opened pipes: %s, %s, %s\n", inPipeName, outPipeName, errPipeName);
OutputDebugString(buffer);
#endif
nCmdTokens = (*env) -> GetArrayLength(env, cmdarray); nCmdTokens = (*env) -> GetArrayLength(env, cmdarray);
nEnvVars = (*env) -> GetArrayLength(env, envp); nEnvVars = (*env) -> GetArrayLength(env, envp);
@ -144,17 +187,18 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
return 0; return 0;
} }
// Construct starter's command line
sprintf(eventBreakName, "SABreak%p", pCurProcInfo); sprintf(eventBreakName, "SABreak%p", pCurProcInfo);
sprintf(eventWaitName, "SAWait%p", pCurProcInfo); sprintf(eventWaitName, "SAWait%p", pCurProcInfo);
sprintf(eventTerminateName, "SATerm%p", pCurProcInfo); sprintf(eventTerminateName, "SATerm%p", pCurProcInfo);
pCurProcInfo -> eventBreak = CreateEvent(NULL, TRUE, FALSE, eventBreakName); pCurProcInfo -> eventBreak = CreateEvent(NULL, TRUE, FALSE, eventBreakName);
ResetEvent(pCurProcInfo -> eventBreak); ResetEvent(pCurProcInfo -> eventBreak);
pCurProcInfo -> eventWait = CreateEvent(NULL, TRUE, FALSE, eventWaitName); pCurProcInfo -> eventWait = CreateEvent(NULL, TRUE, FALSE, eventWaitName);
ResetEvent(pCurProcInfo -> eventWait);
pCurProcInfo -> eventTerminate = CreateEvent(NULL, TRUE, FALSE, eventTerminateName); pCurProcInfo -> eventTerminate = CreateEvent(NULL, TRUE, FALSE, eventTerminateName);
ResetEvent(pCurProcInfo -> eventTerminate); ResetEvent(pCurProcInfo -> eventTerminate);
nPos = sprintf(szCmdLine, "%sstarter.exe %s %s %s ", path, eventBreakName, eventWaitName, eventTerminateName); nPos = sprintf(szCmdLine, "%sstarter.exe %i %i %s %s %s ", path, pid, nLocalCounter, eventBreakName, eventWaitName, eventTerminateName);
// Prepare command line // Prepare command line
for(i = 0; i < nCmdTokens; ++i) for(i = 0; i < nCmdTokens; ++i)
@ -229,21 +273,16 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
} }
memset(&si, 0, sizeof(si)); ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si); si.cb = sizeof(si);
si.dwFlags |= STARTF_USESTDHANDLES;
si.dwFlags |= STARTF_USESHOWWINDOW; si.dwFlags |= STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE; // Processes in the Process Group are hidden si.wShowWindow = SW_HIDE; // Processes in the Process Group are hidden
si.hStdInput = hread[0];
si.hStdOutput = hwrite[1];
si.hStdError = hwrite[2];
SetHandleInformation(stdHandles[0], HANDLE_FLAG_INHERIT, FALSE);
SetHandleInformation(hwrite[0], HANDLE_FLAG_INHERIT, FALSE); SetHandleInformation(stdHandles[1], HANDLE_FLAG_INHERIT, FALSE);
SetHandleInformation(hread[1], HANDLE_FLAG_INHERIT, FALSE); SetHandleInformation(stdHandles[2], HANDLE_FLAG_INHERIT, FALSE);
SetHandleInformation(hread[2], HANDLE_FLAG_INHERIT, FALSE);
flags = CREATE_NEW_CONSOLE; flags = CREATE_NEW_CONSOLE;
flags |= CREATE_NO_WINDOW; flags |= CREATE_NO_WINDOW;
@ -251,14 +290,15 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
#ifdef DEBUG_MONITOR #ifdef DEBUG_MONITOR
OutputDebugString(szCmdLine); OutputDebugString(szCmdLine);
#endif #endif
// launches starter; we need it to create another console group to correctly process
// emulation of SYSint signal (Ctrl-C)
ret = CreateProcess(0, /* executable name */ ret = CreateProcess(0, /* executable name */
szCmdLine, /* command line */ szCmdLine, /* command line */
0, /* process security attribute */ 0, /* process security attribute */
0, /* thread security attribute */ 0, /* thread security attribute */
TRUE, /* inherits system handles */ FALSE, /* inherits system handles */
flags, /* normal attached process */ flags, /* normal attached process */
envBlk, /* environment block */ envBlk, /* environment block */
cwd, /* change to the new current directory */ cwd, /* change to the new current directory */
&si, /* (in) startup information */ &si, /* (in) startup information */
&pi); /* (out) process information */ &pi); /* (out) process information */
@ -270,18 +310,13 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
free(szEnvBlock); free(szEnvBlock);
CloseHandle(hread[0]); if (!ret) // Launching error
CloseHandle(hwrite[1]);
CloseHandle(hwrite[2]);
if (!ret)
{ {
LPTSTR lpMsgBuf; LPTSTR lpMsgBuf;
CloseHandle(hwrite[0]); CloseHandle(stdHandles[0]);
CloseHandle(hread[1]); CloseHandle(stdHandles[1]);
CloseHandle(hread[2]); CloseHandle(stdHandles[2]);
FormatMessage( FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_SYSTEM |
@ -327,18 +362,19 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
} }
else else
{ {
#ifdef DEBUG_MONITOR
sprintf(buffer, "Process %i created\n", pi.dwProcessId);
OutputDebugString(buffer);
#endif
ret = (long)(pCurProcInfo -> uid); ret = (long)(pCurProcInfo -> uid);
file_handles[0] = (int)hwrite[0];
file_handles[1] = (int)hread[1]; // Prepare stream handlers to return to java program
file_handles[2] = (int)hread[2]; file_handles[0] = (int)stdHandles[0];
file_handles[1] = (int)stdHandles[1];
file_handles[2] = (int)stdHandles[2];
(*env) -> SetIntArrayRegion(env, channels, 0, 3, file_handles); (*env) -> SetIntArrayRegion(env, channels, 0, 3, file_handles);
} }
CloseHandle(h[1]); CloseHandle(h[1]);
LeaveCriticalSection(&cs); LeaveCriticalSection(&cs);
#ifdef DEBUG_MONITOR
OutputDebugString("Process started\n");
#endif
} }
@ -348,6 +384,13 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
} }
/////////////////////////////////////////////////////////////////////////////////////
// Launcher; just launches process and don't care about it any more
// Arguments: (see Spawner.java)
// [in] cmdarray - array of command line elements
// [in] envp - array of environment variables
// [in] dir - working directory
/////////////////////////////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
(JNIEnv * env, jobject process, jobjectArray cmdarray, jobjectArray envp, jstring dir) (JNIEnv * env, jobject process, jobjectArray cmdarray, jobjectArray envp, jstring dir)
{ {
@ -389,7 +432,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
{ {
if(0 > (nCpyLen = copyTo(szCmdLine + nPos, str, len, MAX_CMD_SIZE - nPos))) if(0 > (nCpyLen = copyTo(szCmdLine + nPos, str, len, MAX_CMD_SIZE - nPos)))
{ {
ThrowByName(env, "java/io/IOException", "Too long command line"); ThrowByName(env, "java/io/Exception", "Too long command line");
return 0; return 0;
} }
nPos += nCpyLen; nPos += nCpyLen;
@ -418,7 +461,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
szEnvBlock = (char *)realloc(szEnvBlock, nBlkSize); szEnvBlock = (char *)realloc(szEnvBlock, nBlkSize);
if(NULL == szEnvBlock) if(NULL == szEnvBlock)
{ {
ThrowByName(env, "java/io/IOException", "Not enough memory"); ThrowByName(env, "java/io/Exception", "Not enough memory");
return 0; return 0;
} }
} }
@ -446,7 +489,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
} }
memset(&si, 0, sizeof(si)); ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si); si.cb = sizeof(si);
@ -472,7 +515,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
free(cwd); free(cwd);
free(szEnvBlock); free(szEnvBlock);
if (!ret) if (!ret) // error
{ {
LPTSTR lpMsgBuf; LPTSTR lpMsgBuf;
@ -494,6 +537,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
} }
else else
{ {
// Clean-up
CloseHandle(pi.hThread); CloseHandle(pi.hThread);
CloseHandle(pi.hProcess); CloseHandle(pi.hProcess);
ret = (long)pi.dwProcessId; //hProcess; ret = (long)pi.dwProcessId; //hProcess;
@ -505,6 +549,12 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
} }
/////////////////////////////////////////////////////////////////////////////////////
// Emulation of the signal raising
// Arguments: (see Spawner.java)
// [in] uid - unique process ID
// [in] signal - signal to raise
/////////////////////////////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_raise JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_raise
(JNIEnv * env, jobject process, jint uid, jint signal) (JNIEnv * env, jobject process, jint uid, jint signal)
{ {
@ -570,13 +620,18 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_raise
} }
/////////////////////////////////////////////////////////////////////////////////////
// Wait for process termination
// Arguments: (see Spawner.java)
// [in] uid - unique process ID
/////////////////////////////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_waitFor JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_waitFor
(JNIEnv * env, jobject process, jint uid) (JNIEnv * env, jobject process, jint uid)
{ {
long exit_code; long exit_code;
int what=0; int what=0;
HANDLE hProc; HANDLE hProc;
pProcInfo_t pCurProcInfo = findProcInfo(uid); pProcInfo_t pCurProcInfo = findProcInfo(uid);
@ -590,25 +645,31 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_waitFor
what = WaitForSingleObject(hProc, INFINITE); what = WaitForSingleObject(hProc, INFINITE);
if (what == WAIT_OBJECT_0) if (what == WAIT_OBJECT_0)
{ {
GetExitCodeProcess(hProc, &exit_code); GetExitCodeProcess(hProc, &exit_code);
} }
if(hProc) if(hProc)
CloseHandle(hProc); CloseHandle(hProc);
return exit_code; return exit_code;
} }
// Utilities // Utilities
/////////////////////////////////////////////////////////////////////////////////////
// Throws Java exception (will be trapped by VM).
// Arguments:
// [in] name - name of exception class
// [in] message to assign thi event
/////////////////////////////////////////////////////////////////////////////////////
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
ThrowByName(JNIEnv *env, const char *name, const char *msg) ThrowByName(JNIEnv *env, const char *name, const char *msg)
{ {
@ -624,6 +685,11 @@ ThrowByName(JNIEnv *env, const char *name, const char *msg)
/////////////////////////////////////////////////////////////////////////////////////
// Create process description block.
// Arguments: no
// Return : pointer to the process descriptor
/////////////////////////////////////////////////////////////////////////////////////
pProcInfo_t createProcInfo() pProcInfo_t createProcInfo()
{ {
int i; int i;
@ -634,7 +700,7 @@ pProcInfo_t createProcInfo()
if(NULL == pInfo) if(NULL == pInfo)
{ {
pInfo = malloc(sizeof(procInfo_t) * MAX_PROCS); pInfo = malloc(sizeof(procInfo_t) * MAX_PROCS);
memset(pInfo, 0, sizeof(procInfo_t) * MAX_PROCS); ZeroMemory(pInfo, sizeof(procInfo_t) * MAX_PROCS);
} }
for(i = 0; i < MAX_PROCS; ++i) for(i = 0; i < MAX_PROCS; ++i)
@ -653,6 +719,11 @@ pProcInfo_t createProcInfo()
return p; return p;
} }
/////////////////////////////////////////////////////////////////////////////////////
// Using unique process ID finds process descriptor
// Arguments: no
// Return : pointer to the process descriptor
/////////////////////////////////////////////////////////////////////////////////////
pProcInfo_t findProcInfo(int uid) pProcInfo_t findProcInfo(int uid)
{ {
int i; int i;
@ -672,6 +743,11 @@ pProcInfo_t findProcInfo(int uid)
return p; return p;
} }
/////////////////////////////////////////////////////////////////////////////////////
// Cleans up vacant process descriptor
// Arguments:
// pCurProcInfo - pointer to descriptor to clean up
// Return : no
void cleanUpProcBlock(pProcInfo_t pCurProcInfo) void cleanUpProcBlock(pProcInfo_t pCurProcInfo)
{ {
if(0 != pCurProcInfo -> eventBreak) if(0 != pCurProcInfo -> eventBreak)
@ -693,11 +769,16 @@ void cleanUpProcBlock(pProcInfo_t pCurProcInfo)
pCurProcInfo -> pid = 0; pCurProcInfo -> pid = 0;
} }
/////////////////////////////////////////////////////////////////////////////////////
// Running in separae thread and waiting for the process termination
// Arguments:
// pv - (int)pv is a pid
// Return : always 0
/////////////////////////////////////////////////////////////////////////////////////
unsigned int _stdcall waitProcTermination(void* pv) unsigned int _stdcall waitProcTermination(void* pv)
{ {
int i; int i;
int pid = (int)pv; int pid = (int)pv;
DWORD rc = 0;
#ifdef DEBUG_MONITOR #ifdef DEBUG_MONITOR
char buffer[1000]; char buffer[1000];
#endif #endif
@ -742,7 +823,15 @@ unsigned int _stdcall waitProcTermination(void* pv)
return 0; return 0;
} }
// Return number of bytes in target or -1 in case of error /////////////////////////////////////////////////////////////////////////////////////
// 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(char * target, const char * source, int cpyLength, int availSpace) int copyTo(char * target, const char * source, int cpyLength, int availSpace)
{ {
BOOL bSlash = FALSE; BOOL bSlash = FALSE;

View file

@ -1,23 +1,25 @@
/********************************************************************** /**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others. * Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5 * are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html * http://www.eclipse.org/legal/cpl-v10.html
* *
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
*
* raise.c
*
* This is a part of JNI implementation of spawner
* Includes implementation of JNI methods (see Spawner.java)
***********************************************************************/ ***********************************************************************/
/*
* This is a JNI implementation of access to standard i/o streams
*/
#include "stdafx.h" #include "stdafx.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "spawner.h"
#include "SpawnerInputStream.h" #include "SpawnerInputStream.h"
#include "SpawnerOutputStream.h" #include "SpawnerOutputStream.h"
#include "jni.h" #include "jni.h"
#include "io.h" #include "io.h"
@ -37,35 +39,87 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_rea
{ {
BYTE tmpBuf[BUFF_SIZE]; BYTE tmpBuf[BUFF_SIZE];
int nBuffOffset = 0; int nBuffOffset = 0;
#ifdef DEBUG_MONITOR
char buffer[1000];
#endif
OVERLAPPED overlapped;
overlapped.Offset = 0;
overlapped.OffsetHigh = 0;
overlapped.hEvent = CreateEvent(NULL, // no security attribute
TRUE, // manual-reset event
TRUE, // initial state = signaled
NULL); // unnamed event object
if(NULL == overlapped.hEvent) {
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
);
ThrowByName(env, "java/io/IOException", lpMsgBuf);
}
#ifdef DEBUG_MONITOR
sprintf(buffer, "Start read %i\n", fd);
OutputDebugString(buffer);
#endif
while(len > nBuffOffset) while(len > nBuffOffset)
{ {
int nNumberOfBytesToRead = min(len - nBuffOffset, BUFF_SIZE); int nNumberOfBytesToRead = min(len - nBuffOffset, BUFF_SIZE);
int nNumberOfBytesRead; int nNumberOfBytesRead;
if(0 == ReadFile((HANDLE)fd, tmpBuf, nNumberOfBytesToRead, &nNumberOfBytesRead, NULL )) if(0 == ReadFile((HANDLE)fd, tmpBuf, nNumberOfBytesToRead, &nNumberOfBytesRead, &overlapped ))
{ {
LPTSTR lpMsgBuf;
int err = GetLastError(); int err = GetLastError();
if(err == ERROR_IO_PENDING)
{
// asynchronous i/o is still in progress
// check on the results of the asynchronous read
if(GetOverlappedResult((HANDLE)fd, &overlapped,
&nNumberOfBytesRead, TRUE))
err = 0;
// if there was a problem ...
else
err = GetLastError();
}
if(err == ERROR_BROKEN_PIPE) // Pipe was closed if(err == ERROR_BROKEN_PIPE) // Pipe was closed
return 0; break;
if(err != ERROR_MORE_DATA) // Otherwise error means just that there are more data if(err != 0)
{ // than buffer can accept {
FormatMessage( LPTSTR lpMsgBuf;
FORMAT_MESSAGE_ALLOCATE_BUFFER | #ifdef DEBUG_MONITOR
FORMAT_MESSAGE_FROM_SYSTEM | char buffer[200];
FORMAT_MESSAGE_IGNORE_INSERTS, sprintf(buffer, "Read failed - %i, error %i\n", fd, err);
NULL, OutputDebugString(buffer);
err, #endif
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language if(err != ERROR_MORE_DATA) // Otherwise error means just that there are more data
(LPTSTR) &lpMsgBuf, { // than buffer can accept
0, FormatMessage(
NULL FORMAT_MESSAGE_ALLOCATE_BUFFER |
); FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
ThrowByName(env, "java/io/IOException", lpMsgBuf); ThrowByName(env, "java/io/IOException", lpMsgBuf);
LocalFree( lpMsgBuf ); LocalFree( lpMsgBuf );
return 0; nBuffOffset = 0;
break;
}
} }
} }
if(nNumberOfBytesRead > 0) if(nNumberOfBytesRead > 0)
@ -76,6 +130,11 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_rea
if(nNumberOfBytesRead != nNumberOfBytesToRead) if(nNumberOfBytesRead != nNumberOfBytesToRead)
break; break;
} }
CloseHandle(overlapped.hEvent);
#ifdef DEBUG_MONITOR
sprintf(buffer, "End read %i\n", fd);
OutputDebugString(buffer);
#endif
return nBuffOffset; // This is a real full readed length return nBuffOffset; // This is a real full readed length
} }
@ -88,7 +147,19 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_rea
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_close0 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_close0
(JNIEnv * env, jobject proc, jint fd) (JNIEnv * env, jobject proc, jint fd)
{ {
return (CloseHandle((HANDLE)fd) ? 0 : -1); int rc;
#ifdef DEBUG_MONITOR
char buffer[1000];
sprintf(buffer, "Close %i\n", fd);
OutputDebugString(buffer);
#endif
DisconnectNamedPipe((HANDLE)fd);
rc = (CloseHandle((HANDLE)fd) ? 0 : -1);
#ifdef DEBUG_MONITOR
sprintf(buffer, "Closed %i\n", fd);
OutputDebugString(buffer);
#endif
return (rc ? GetLastError() : 0);
} }
/* /*
@ -102,6 +173,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_wr
BYTE tmpBuf[BUFF_SIZE]; BYTE tmpBuf[BUFF_SIZE];
int nBuffOffset = 0; int nBuffOffset = 0;
while(len > nBuffOffset) while(len > nBuffOffset)
{ {
int nNumberOfBytesToWrite = min(len - nBuffOffset, BUFF_SIZE); int nNumberOfBytesToWrite = min(len - nBuffOffset, BUFF_SIZE);
@ -139,5 +211,17 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_wr
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_close0 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_close0
(JNIEnv * env, jobject proc, jint fd) (JNIEnv * env, jobject proc, jint fd)
{ {
return (CloseHandle((HANDLE)fd) ? 0 : -1); int rc;
#ifdef DEBUG_MONITOR
char buffer[1000];
sprintf(buffer, "Close %i\n", fd);
OutputDebugString(buffer);
#endif
DisconnectNamedPipe((HANDLE)fd);
rc = (CloseHandle((HANDLE)fd) ? 0 : -1);
#ifdef DEBUG_MONITOR
sprintf(buffer, "Closed %i\n", fd);
OutputDebugString(buffer);
#endif
return (rc ? GetLastError() : 0);
} }

View file

@ -1,16 +1,17 @@
/********************************************************************** /**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others. * Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5 * are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html * http://www.eclipse.org/legal/cpl-v10.html
* *
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
*
* raise.c
*
* This is a part of JNI implementation of spawner
***********************************************************************/ ***********************************************************************/
/*
* This is a JNI implementation of spawner
*/
#include "stdafx.h" #include "stdafx.h"
#include "Spawner.h" #include "Spawner.h"
@ -19,10 +20,17 @@
extern void JNICALL ThrowByName(JNIEnv *env, const char *name, const char *msg); extern void JNICALL ThrowByName(JNIEnv *env, const char *name, const char *msg);
// #define DEBUG_MONITOR
static HWND consoleHWND; static HWND consoleHWND;
/////////////////////////////////////////////////////////////////////////////////////
// Check if window is a console of process with pid
// Arguments:
// hwnd - window handler
// arg - process PID
// Return : TRUE if yes
/////////////////////////////////////////////////////////////////////////////////////
static BOOL CALLBACK static BOOL CALLBACK
find_child_console (HWND hwnd, LPARAM arg) find_child_console (HWND hwnd, LPARAM arg)
{ {
@ -46,35 +54,13 @@ find_child_console (HWND hwnd, LPARAM arg)
return TRUE; return TRUE;
} }
/*
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_raise__Ljava_lang_Object_2
(JNIEnv * env, jobject process, jobject jpid)
{
jint pid;
jclass integerClass = (*env) -> FindClass(env, "java/lang/Integer");
jmethodID intValue;
if(NULL == integerClass) {
ThrowByName(env, "java/lang/IOException", "Cannot find Integer class");
return -1;
}
if(!((*env) -> IsInstanceOf(env, jpid, integerClass))) {
ThrowByName(env, "java/lang/IOException", "Wrong argument");
return -1;
}
intValue = (*env) -> GetMethodID(env, integerClass, "intValue", "()I");
if(NULL == intValue) {
ThrowByName(env, "java/lang/IOException", "Cannot find intValue method in Integer class");
return -1;
}
pid = (*env) -> CallIntMethod(env, jpid, intValue);
return interruptProcess(pid);
}
*/
/////////////////////////////////////////////////////////////////////////////////////
// Function implements interrupt process (Ctrl-C emulation)
// Arguments:
// pid - process' pid
// Return : 0 if OK or error code
/////////////////////////////////////////////////////////////////////////////////////
int interruptProcess(int pid) int interruptProcess(int pid)
{ {
#ifdef DEBUG_MONITOR #ifdef DEBUG_MONITOR
@ -89,10 +75,13 @@ int interruptProcess(int pid)
sprintf(buffer, "Try to interrupt process %i\n", pid); sprintf(buffer, "Try to interrupt process %i\n", pid);
OutputDebugString(buffer); OutputDebugString(buffer);
#endif #endif
// Find console
EnumWindows (find_child_console, (LPARAM) pid); EnumWindows (find_child_console, (LPARAM) pid);
if(NULL != consoleHWND) if(NULL != consoleHWND) // Yes, we found out it
{ {
// We are going to switch focus to console,
// send Ctrl-C and then restore focus
BYTE control_scan_code = (BYTE) MapVirtualKey (VK_CONTROL, 0); BYTE control_scan_code = (BYTE) MapVirtualKey (VK_CONTROL, 0);
/* Fake Ctrl-C for SIGINT, and Ctrl-Break for SIGQUIT. */ /* Fake Ctrl-C for SIGINT, and Ctrl-Break for SIGQUIT. */
BYTE vk_c_code = 'C'; BYTE vk_c_code = 'C';
@ -100,7 +89,7 @@ int interruptProcess(int pid)
BYTE c_scan_code = (BYTE) MapVirtualKey (vk_c_code, 0); BYTE c_scan_code = (BYTE) MapVirtualKey (vk_c_code, 0);
BYTE break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0); BYTE break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0);
HWND foreground_window; HWND foreground_window;
foreground_window = GetForegroundWindow (); foreground_window = GetForegroundWindow ();
if (foreground_window) if (foreground_window)
@ -128,17 +117,6 @@ int interruptProcess(int pid)
/* Set the foreground window to the child. */ /* Set the foreground window to the child. */
if (SetForegroundWindow (consoleHWND)) if (SetForegroundWindow (consoleHWND))
{ {
/*
if(0 != c_scan_code) {
// Generate keystrokes as if user had typed Ctrl-C.
keybd_event (VK_CONTROL, control_scan_code, 0, 0);
keybd_event (vk_c_code, c_scan_code, 0, 0);
keybd_event (vk_c_code, c_scan_code, KEYEVENTF_KEYUP, 0);
keybd_event (VK_CONTROL, control_scan_code, KEYEVENTF_KEYUP, 0);
}
*/
/* Sleep for a bit to give time for respond */
Sleep (100);
if(0 != break_scan_code) { if(0 != break_scan_code) {
/* Generate keystrokes as if user had typed Ctrl-Break */ /* Generate keystrokes as if user had typed Ctrl-Break */
keybd_event (VK_CONTROL, control_scan_code, 0, 0); keybd_event (VK_CONTROL, control_scan_code, 0, 0);

View file

@ -1,22 +1,26 @@
/********************************************************************** /**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others. * Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5 * are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html * http://www.eclipse.org/legal/cpl-v10.html
* *
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
*
* spawner.c
*
* This is a part of JNI implementation of spawner
***********************************************************************/ ***********************************************************************/
// spawner.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h" #include "stdafx.h"
#include "spawner.h"
CRITICAL_SECTION cs; CRITICAL_SECTION cs;
TCHAR path[MAX_PATH + 1] = {_T('\0') };
TCHAR path[MAX_PATH + 1] = {_T('\0') }; // Directory where spawner.dll is located
BOOL APIENTRY DllMain( HANDLE hModule, BOOL APIENTRY DllMain( HANDLE hModule,
@ -48,4 +52,3 @@ BOOL APIENTRY DllMain( HANDLE hModule,
return TRUE; return TRUE;
} }

View file

@ -1,22 +1,19 @@
/********************************************************************** /**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others. * Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5 * are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html * http://www.eclipse.org/legal/cpl-v10.html
* *
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
***********************************************************************/ *
/* * starter.cpp
* starter.c
* *
* This is a small utility for windows spawner * This is a small utility for windows spawner
*/ ***********************************************************************/
//#define UNICODE
//#define _UNICODE
#define STRICT #define STRICT
#include <Windows.h> #include <Windows.h>
@ -24,8 +21,9 @@
#include <tchar.h> #include <tchar.h>
#include <stdio.h> #include <stdio.h>
// #define DEBUG_MONITOR //#define DEBUG_MONITOR
#define MAX_CMD_LINE_LENGTH (2049) #define MAX_CMD_LINE_LENGTH (2049)
#define PIPE_NAME_LENGTH 100
int copyTo(char * target, const char * source, int cpyLength, int availSpace); int copyTo(char * target, const char * source, int cpyLength, int availSpace);
@ -58,8 +56,8 @@ BOOL WINAPI HandlerRoutine( DWORD dwCtrlType) // control signal type
extern "C" int _tmain(int argc, TCHAR* argv[]) { extern "C" int _tmain(int argc, TCHAR* argv[]) {
// Make sure that we've been passed the right number of arguments // Make sure that we've been passed the right number of arguments
if (argc < 5) { if (argc < 7) {
_tprintf(__TEXT("Usage: %s (Three InheritableEventHandles) (CommandLineToSpawn)\n"), _tprintf(__TEXT("Usage: %s (Three InheritableEventHandles) (CommandLineToSpawn)\n"),
argv[0]); argv[0]);
return(0); return(0);
@ -69,7 +67,7 @@ extern "C" int _tmain(int argc, TCHAR* argv[]) {
TCHAR szCmdLine[MAX_CMD_LINE_LENGTH] = { 0 }; TCHAR szCmdLine[MAX_CMD_LINE_LENGTH] = { 0 };
int nPos = 0; int nPos = 0;
for(int i = 4; i < argc; ++i) for(int i = 6; i < argc; ++i)
{ {
int nCpyLen; int nCpyLen;
if(0 > (nCpyLen = copyTo(szCmdLine + nPos, argv[i], _tcslen(argv[i]), MAX_CMD_LINE_LENGTH - nPos))) if(0 > (nCpyLen = copyTo(szCmdLine + nPos, argv[i], _tcslen(argv[i]), MAX_CMD_LINE_LENGTH - nPos)))
@ -94,28 +92,81 @@ extern "C" int _tmain(int argc, TCHAR* argv[]) {
#endif #endif
BOOL exitProc = FALSE; BOOL exitProc = FALSE;
HANDLE waitEvent = OpenEvent(EVENT_ALL_ACCESS, TRUE, argv[2]); HANDLE waitEvent = OpenEvent(EVENT_ALL_ACCESS, TRUE, argv[4]);
HANDLE h[3]; HANDLE h[3];
h[0] = OpenEvent(EVENT_ALL_ACCESS, TRUE, argv[1]); h[0] = OpenEvent(EVENT_ALL_ACCESS, TRUE, argv[3]);
h[2] = OpenEvent(EVENT_ALL_ACCESS, TRUE, argv[3]); // This is a terminate event h[2] = OpenEvent(EVENT_ALL_ACCESS, TRUE, argv[5]); // This is a terminate event
SetConsoleCtrlHandler(HandlerRoutine, TRUE); SetConsoleCtrlHandler(HandlerRoutine, TRUE);
int parentPid = strtol(argv[1], NULL, 10);
int nCounter = strtol(argv[2], NULL, 10);
char inPipeName[PIPE_NAME_LENGTH];
char outPipeName[PIPE_NAME_LENGTH];
char errPipeName[PIPE_NAME_LENGTH];
sprintf(inPipeName, "\\\\.\\pipe\\stdin%08i%010i", parentPid, nCounter);
sprintf(outPipeName, "\\\\.\\pipe\\stdout%08i%010i", parentPid, nCounter);
sprintf(errPipeName, "\\\\.\\pipe\\stderr%08i%010i", parentPid, nCounter);
#ifdef DEBUG_MONITOR #ifdef DEBUG_MONITOR
sprintf(buffer, "starter start command: %s\n", szCmdLine); sprintf(buffer, "Pipes: %s, %s, %s\n", inPipeName, outPipeName, errPipeName);
OutputDebugString(buffer); OutputDebugString(buffer);
#endif #endif
HANDLE stdHandles[3];
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
if((INVALID_HANDLE_VALUE == (stdHandles[0] = CreateFile(inPipeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, &sa))) ||
(INVALID_HANDLE_VALUE == (stdHandles[1] = CreateFile(outPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))) ||
(INVALID_HANDLE_VALUE == (stdHandles[2] = CreateFile(errPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))))
{
#ifdef DEBUG_MONITOR
sprintf(buffer, "Failed to open pipe %i, %i, %i: %i\n", stdHandles[0], stdHandles[1], stdHandles[2], GetLastError());
OutputDebugString(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
sprintf(buffer, "Failed to reassign standard streams: %i\n", GetLastError());
OutputDebugString(buffer);
#endif
CloseHandle(stdHandles[0]);
CloseHandle(stdHandles[1]);
CloseHandle(stdHandles[2]);
return -1;;
}
// OutputDebugString(szCmdLine);
// Spawn the other processes as part of this Process Group // Spawn the other processes as part of this Process Group
BOOL f = CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, BOOL f = CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE,
0, NULL, NULL, &si, &pi); 0, NULL, NULL, &si, &pi);
// We don't need them any more
CloseHandle(stdHandles[0]);
CloseHandle(stdHandles[1]);
CloseHandle(stdHandles[2]);
if (f) if (f)
{ {
#ifdef DEBUG_MONITOR
sprintf(buffer, "Process %i started\n", pi.dwProcessId);
OutputDebugString(buffer);
#endif
SetEvent(waitEvent); // Means thar process has been spawned SetEvent(waitEvent); // Means thar process has been spawned
CloseHandle(pi.hThread); CloseHandle(pi.hThread);
h[1] = pi.hProcess; h[1] = pi.hProcess;
while(!exitProc) while(!exitProc)
{ {
// Wait for the spawned-process to die or for the event // Wait for the spawned-process to die or for the event
@ -151,6 +202,7 @@ extern "C" int _tmain(int argc, TCHAR* argv[]) {
break; break;
default: default:
// Unexpected code // Unexpected code
#ifdef DEBUG_MONITOR
LPTSTR lpMsgBuf; LPTSTR lpMsgBuf;
FormatMessage( FormatMessage(
@ -167,6 +219,7 @@ extern "C" int _tmain(int argc, TCHAR* argv[]) {
OutputDebugString(lpMsgBuf); OutputDebugString(lpMsgBuf);
// Free the buffer. // Free the buffer.
LocalFree( lpMsgBuf ); LocalFree( lpMsgBuf );
#endif
exitProc = TRUE; exitProc = TRUE;
break; break;
} }
@ -177,12 +230,21 @@ extern "C" int _tmain(int argc, TCHAR* argv[]) {
CloseHandle(waitEvent); CloseHandle(waitEvent);
CloseHandle(h[0]); CloseHandle(h[0]);
CloseHandle(h[1]);
CloseHandle(h[2]); CloseHandle(h[2]);
return(dwExitCode); return(dwExitCode);
} }
// Return number of bytes in target or -1 in case of error /////////////////////////////////////////////////////////////////////////////////////
// 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(LPTSTR target, LPCTSTR source, int cpyLength, int availSpace) int copyTo(LPTSTR target, LPCTSTR source, int cpyLength, int availSpace)
{ {
BOOL bSlash = FALSE; BOOL bSlash = FALSE;