
/******************************************************************************
 Code derived from the following at http://www.microsoft.com/msj/0698/win320698.aspx
 Module name: MainApp.cpp
 Written by:  Jeffrey Richter
 Purpose:     Runs a set of processes with the ability to kill them all.
******************************************************************************/
 
 //#define UNICODE
 //#define _UNICODE
 
#define STRICT
#include <Windows.h>
#include <process.h>
#include <tchar.h>
#include <stdio.h>
 
/******************************************************************************
  This program launches the httpd.exe process and sets it up with an event
  to respond to when it is required to terminate.
*******************************************************************************/
 
///////////////////////////////////////////////////////////////////////////////

// Event used to forcibly kill the spawned Process Group
// Used to terminate the httpd.exe (upon receiving this event, a Ctrl-C is sent)
HANDLE g_heventTerminateProcessGroup = NULL;
 
///////////////////////////////////////////////////////////////////////////////
 
unsigned int _stdcall StartProcessGroup(void* pv) 
{
  // Construct the path of our spawn-helper application
  TCHAR szCmdLine[MAX_PATH];
  GetModuleFileName(NULL, szCmdLine, MAX_PATH);
  *(_tcsrchr(szCmdLine, __TEXT('\\')) + 1) = 0; // truncate EXE filename
  _stprintf(_tcschr(szCmdLine, 0), __TEXT("StartHttpdChild.exe %d"), 
	    g_heventTerminateProcessGroup);
  
  // Our command-line arguments indicate the process that we want to run
  for (int x = 2; x < __argc; x++) {
    _tcscat(szCmdLine, __TEXT(" ")); 
    _tcscat(szCmdLine, __targv[x]); 
  }
  
  STARTUPINFO si = { sizeof(si) };
  si.dwFlags     = STARTF_USESHOWWINDOW;
  si.wShowWindow = SW_HIDE;  // Processes in the Process Group are hidden
  
  PROCESS_INFORMATION pi;
  
  // Spawn the process (make sure it inherits our event handle)
  BOOL f = CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 
			 CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
  
  DWORD dw = 0;  // Return value
  
  if (f) {
    // The process was successfully spawned, wait for it to terminate
    CloseHandle(pi.hThread);
    WaitForSingleObject(pi.hProcess, INFINITE);
    GetExitCodeProcess(pi.hProcess, &dw);  // Its exit code is ours
    CloseHandle(pi.hProcess);
  } else {
    // Couldn't spawn the process group application
  }
  return(dw);
}
 
////////////////////////////////////////////////////////////////////////////////

// If using the following non-GUI method definition, need to launch
// the StartHttpd.exe program with: cmd /c StartHttpd.exe
// int _tmain( int argc, TCHAR *argv[] ) 


extern "C" int WINAPI _tWinMain(HINSTANCE hinst, HINSTANCE hinstExePrev, 
                                 LPTSTR pszCmdLine, int nShowCmd) 
{
  if(__argc != 3) {
    MessageBox(NULL, "Usage: starthttpd.exe <event-name> <httpd.exe program path>",
	       TEXT("Error"), MB_OK);
    return(-1);
  }
  
  DWORD dwThreadId;
  
  // Create an inheritable event handle to use as our IPC mechanism
  // to terminate the processes in the process group
  // NOTE: Keep this handle forthe entire lifetime of this application
  
  g_heventTerminateProcessGroup = CreateEvent(NULL, TRUE, FALSE, __argv[1]);
  SetHandleInformation(g_heventTerminateProcessGroup, 
		       HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
  
  // Spawn the processes in the process group.
  ResetEvent(g_heventTerminateProcessGroup);   // Do this before each spawn
  HANDLE hThread = (HANDLE) _beginthreadex(NULL, 0, StartProcessGroup, 
					   NULL, 0, (UINT*) &dwThreadId);
  
  WaitForSingleObject(hThread, INFINITE);
  
  // The spawned processes have terminated, clean up
  CloseHandle(hThread);
  
  // When this application is terminating, close the event
  CloseHandle(g_heventTerminateProcessGroup);
  
  return(0);
}
 
//////////////////////////////// End of File //////////////////////////////////

