/*============================================================================ Name : spawner.cpp System : Safe GUI Language : C++ Purpose : Implementation of 'FmeSpawner' class Author Date Changes made ------------------ ------------ ------------------------------- Dale Lutz Jan 26, 1996 Original definition Matt Adam Nov 5, 1999 OOPized the functions into a class Copyright (c) 1994 - 1996, Safe Software Inc. All Rights Reserved This software may not be copied or reproduced, in all or in part, without the prior written consent of Safe Software Inc. The entire risk as to the results and performance of the software, supporting text and other information contained in this file (collectively called the "Software") is with the user. Although Safe Software Incorporated has used considerable efforts in preparing the Software, Safe Software Incorporated does not warrant the accuracy or completeness of the Software. In no event will Safe Software Incorporated be liable for damages, including loss of profits or consequential damages, arising out of the use of the Software. Overview: ========== This class spawns an FME process and tracks pipes in and out of it to get error/information messages. ============================================================================ */ #include "stdafx.h" #include "fmespawner.h" #include "vfme.h" #include "mainfrm.h" //=========================================================================== // A few global constants static char* version = "FME Spawn Package Version 1.0.1 Jan 26, 1996"; //=========================================================================== FmeSpawner::FmeSpawner() { lineBufPos_ = 0; inputFileNumber_ = 0; processHandle_ = NULL; } //=========================================================================== // Return 1 if it fails, 0 if its good. int FmeSpawner::start(const char* command, const char *execDir) { SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; CreatePipe(&wrfd_[0], &wrfd_[1], &sa, 0); CreatePipe(&rdfd_[0], &rdfd_[1], &sa, 0); PROCESS_INFORMATION processinfo; memset(&processinfo,0,sizeof(processinfo)); STARTUPINFO startinfo; memset(&startinfo,0,sizeof(startinfo)); startinfo.cb = sizeof(startinfo); startinfo.dwFlags = STARTF_USESTDHANDLES; startinfo.hStdInput = wrfd_[0]; startinfo.hStdOutput = rdfd_[1]; startinfo.hStdError = rdfd_[1]; if ( CreateProcess(NULL, /* executable */ (char*) command, /* cmdline */ NULL, /* Process security */ NULL, /* Thread security */ TRUE, /* Inherited handles */ DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP|IDLE_PRIORITY_CLASS, NULL, /* environment char ** */ execDir, /* directory */ &startinfo, &processinfo) ) { // If we get here, it worked! processHandle_ = processinfo.hProcess; Sleep(0); } else { // printf("warning: failed to create process\n"); // It failed if we get here -- lets clean up our handles // and return 1 CloseHandle(wrfd_[0]); CloseHandle(wrfd_[1]); CloseHandle(rdfd_[0]); CloseHandle(rdfd_[1]); return 1; } inputFileNumber_ = _open_osfhandle((long) rdfd_[0],_O_RDONLY); // Okay, it all looks good...set the current buffer position to 0 lineBufPos_ = 0; return 0; } //=========================================================================== // return -1 when there's no new line, // -2 if the program ended // >= 0 otherwise int FmeSpawner::getLine(char* buf, int len) { // find out if we're doing timing or not CVFmeApp *theApp = (CVFmeApp *)AfxGetApp(); bool isTiming = theApp->GetAppFrame()->GetTranslationDialog()->GetLogTiming() && theApp->GetAppFrame()->GetTranslationDialog()->IsTranslating(); char aCharacter; DWORD bytes = 0; // If the process has died we will return straight away DWORD status = 0; /* GetExitCodeProcess(processHandle_,&status); if (status != STILL_ACTIVE) { // The process died on us...return -2 return -2; } */ // The process is not dead, so check if there is // any action on the pipe while (1) // each situtaion has its own return { PeekNamedPipe(rdfd_[0],NULL,NULL,NULL,&bytes,NULL); if (bytes == 0) { // If the process has died we will return straight away DWORD status = 0; GetExitCodeProcess(processHandle_,&status); if (status != STILL_ACTIVE) { // The process died on us...return -2 return -2; } Sleep(500); //wait before trying again. // Nov 23 -- in order to use 'abort' to kill this thing, // we will return every 1/2 second even if we haven't got anything new return -1; // nothing new } if (read( inputFileNumber_, &aCharacter, 1 ) == NULL ) { return -2; // something is wrong } else { if (aCharacter == '\n') { // Just terminate the string, copy it over, // and return. // We need to be careful not to overflow their buffer if (lineBufPos_ >= len) lineBufPos_ = len - 1; lineBuffer_[lineBufPos_] = 0; lineBufPos_ = 0; // reset for next time int retCode = 1; if (strstr(lineBuffer_,"|STATRP|")) { // It was a status report retCode = 0; } else if(strstr(lineBuffer_,"|INFORM|")) { // It was informational retCode = 1; } else if(strstr(lineBuffer_,"|STATS |")) { // It was statistics retCode = 2; } else if(strstr(lineBuffer_,"|WARN |")) { // It was warning retCode = 3; } else if(strstr(lineBuffer_,"|FATAL |")) { // It was fatal retCode = 4; } else if(strstr(lineBuffer_,"|ERROR |")) { // It was informational retCode = 5; } // Now strip off all the leading pipes. char *messageText = lineBuffer_; // if we're timing, and if this is a STATRP message, rip off all // the pipes so that we remove the timing information if (retCode == 0 && isTiming) { char *nextPipePos = NULL; while (nextPipePos = strstr(messageText,"|")) { messageText = nextPipePos+1; } } // otherwise, if we're not timing, then strip off the pipe // information if (!isTiming) { if ( (strlen(messageText) > 8) && (strstr(messageText, "|"))) { messageText += 8; } } strcpy(buf,messageText); return retCode; } else { lineBuffer_[lineBufPos_] = aCharacter; lineBufPos_++; if (lineBufPos_ >= kLineBufSize) lineBufPos_--; } } } } //=========================================================================== int FmeSpawner::end() { // Just close up a bunch of nice handles. CloseHandle(wrfd_[0]); CloseHandle(wrfd_[1]); CloseHandle(rdfd_[0]); CloseHandle(rdfd_[1]); return 0; } //=========================================================================== int FmeSpawner::abort() { // Just terminate our little process UINT status = 0; TerminateProcess(processHandle_,status); // For now, we won't check any return codes or // anything like that. return 0; }