From 035c7fabc3b82cbc9a346c11abe2e9462b4c0379 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 30 Oct 2012 15:39:57 -0700 Subject: Imported Upstream version 2.8.9 --- Source/cmWin32ProcessExecution.cxx | 940 +++++++++++++++++++++++++++++++++++++ 1 file changed, 940 insertions(+) create mode 100644 Source/cmWin32ProcessExecution.cxx (limited to 'Source/cmWin32ProcessExecution.cxx') diff --git a/Source/cmWin32ProcessExecution.cxx b/Source/cmWin32ProcessExecution.cxx new file mode 100644 index 000000000..f37e0ff4e --- /dev/null +++ b/Source/cmWin32ProcessExecution.cxx @@ -0,0 +1,940 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmWin32ProcessExecution.h" + +#include "cmSystemTools.h" + +#include +#include +#include +#include +#include + +#if defined(__BORLANDC__) +# define STRICMP stricmp +# define TO_INTPTR(x) ((long)(x)) +#endif // Borland +#if defined(_MSC_VER) // Visual studio +# if ( _MSC_VER >= 1300 ) +# include +# define TO_INTPTR(x) ((intptr_t)(x)) +# else // Visual Studio 6 +# define TO_INTPTR(x) ((long)(x)) +# endif // Visual studio .NET +# define STRICMP _stricmp +#endif // Visual Studio +#if defined(__MINGW32__) +# include +# define TO_INTPTR(x) ((intptr_t)(x)) +# define STRICMP _stricmp +#endif // MinGW + +#define POPEN_1 1 +#define POPEN_2 2 +#define POPEN_3 3 +#define POPEN_4 4 + +#define cmMAX(x,y) (((x)<(y))?(y):(x)) + +void DisplayErrorMessage() +{ + LPVOID 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 + ); + // Process any inserts in lpMsgBuf. + // ... + // Display the string. + MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION ); + // Free the buffer. + LocalFree( lpMsgBuf ); +} + +// Code from a Borland web site with the following explaination : +/* In this article, I will explain how to spawn a console application + * and redirect its standard input/output using anonymous pipes. An + * anonymous pipe is a pipe that goes only in one direction (read + * pipe, write pipe, etc.). Maybe you are asking, "why would I ever + * need to do this sort of thing?" One example would be a Windows + * telnet server, where you spawn a shell and listen on a port and + * send and receive data between the shell and the socket + * client. (Windows does not really have a built-in remote + * shell). First, we should talk about pipes. A pipe in Windows is + * simply a method of communication, often between process. The SDK + * defines a pipe as "a communication conduit with two ends; + a process + * with a handle to one end can communicate with a process having a + * handle to the other end." In our case, we are using "anonymous" + * pipes, one-way pipes that "transfer data between a parent process + * and a child process or between two child processes of the same + * parent process." It's easiest to imagine a pipe as its namesake. An + * actual pipe running between processes that can carry data. We are + * using anonymous pipes because the console app we are spawning is a + * child process. We use the CreatePipe function which will create an + * anonymous pipe and return a read handle and a write handle. We will + * create two pipes, on for stdin and one for stdout. We will then + * monitor the read end of the stdout pipe to check for display on our + * child process. Every time there is something availabe for reading, + * we will display it in our app. Consequently, we check for input in + * our app and send it off to the write end of the stdin pipe. */ + +inline bool IsWinNT() +//check if we're running NT +{ + OSVERSIONINFO osv; + osv.dwOSVersionInfoSize = sizeof(osv); + GetVersionEx(&osv); + return (osv.dwPlatformId == VER_PLATFORM_WIN32_NT); +} + +//--------------------------------------------------------------------------- +bool cmWin32ProcessExecution::BorlandRunCommand( + const char* command, const char* dir, + std::string& output, int& retVal, bool verbose, int /* timeout */, + bool hideWindows) +{ + //verbose = true; + //std::cerr << std::endl + // << "WindowsRunCommand(" << command << ")" << std::endl + // << std::flush; + const int BUFFER_SIZE = 4096; + char buf[BUFFER_SIZE]; + +//i/o buffer + STARTUPINFO si; + SECURITY_ATTRIBUTES sa; + SECURITY_DESCRIPTOR sd; + +//security information for pipes + PROCESS_INFORMATION pi; + HANDLE newstdin,newstdout,read_stdout,write_stdin; + +//pipe handles + if (IsWinNT()) +//initialize security descriptor (Windows NT) + { + InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION); + SetSecurityDescriptorDacl(&sd, true, NULL, false); + sa.lpSecurityDescriptor = &sd; + + } + else sa.lpSecurityDescriptor = NULL; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = true; + +//allow inheritable handles + if (!CreatePipe(&newstdin,&write_stdin,&sa,0)) +//create stdin pipe + { + return false; + } + if (!CreatePipe(&read_stdout,&newstdout,&sa,0)) +//create stdout pipe + { + CloseHandle(newstdin); + CloseHandle(write_stdin); + return false; + + } + GetStartupInfo(&si); + +//set startupinfo for the spawned process + /* The dwFlags member tells CreateProcess how to make the + * process. STARTF_USESTDHANDLES validates the hStd* + * members. STARTF_USESHOWWINDOW validates the wShowWindow + * member. */ + + si.cb = sizeof(STARTUPINFO); + si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; + si.hStdOutput = newstdout; + si.hStdError = newstdout; + si.wShowWindow = SW_SHOWDEFAULT; + if(hideWindows) + { + si.wShowWindow = SW_HIDE; + } + +//set the new handles for the child process si.hStdInput = newstdin; + char* commandAndArgs = strcpy(new char[strlen(command)+1], command); + if (!CreateProcess(NULL,commandAndArgs,NULL,NULL,TRUE, + 0, // CREATE_NEW_CONSOLE, + NULL,dir,&si,&pi)) + { + std::cerr << "CreateProcess failed " << commandAndArgs << std::endl; + CloseHandle(newstdin); + CloseHandle(newstdout); + CloseHandle(read_stdout); + CloseHandle(write_stdin); + delete [] commandAndArgs; + return false; + + } + delete [] commandAndArgs; + unsigned long exit=0; + +//process exit code unsigned + unsigned long bread; + +//bytes read unsigned + unsigned long avail; + +//bytes available + memset(buf, 0, sizeof(buf)); + for(;;) +//main program loop + { + Sleep(10); +//check to see if there is any data to read from stdout + //std::cout << "Peek for data..." << std::endl; + PeekNamedPipe(read_stdout,buf,1023,&bread,&avail,NULL); + if (bread != 0) + { + memset(buf, 0, sizeof(buf)); + if (avail > 1023) + { + while (bread >= 1023) + { + //std::cout << "Read data..." << std::endl; + ReadFile(read_stdout,buf,1023,&bread,NULL); + + //read the stdout pipe + memset(buf, 0, sizeof(buf)); + output += buf; + if (verbose) + { + cmSystemTools::Stdout(buf); + } + } + } + else + { + ReadFile(read_stdout,buf,1023,&bread,NULL); + output += buf; + if(verbose) + { + cmSystemTools::Stdout(buf); + } + + } + + } + + //std::cout << "Check for process..." << std::endl; + GetExitCodeProcess(pi.hProcess,&exit); + +//while the process is running + if (exit != STILL_ACTIVE) break; + + } + WaitForSingleObject(pi.hProcess, INFINITE); + GetExitCodeProcess(pi.hProcess,&exit); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + CloseHandle(newstdin); + +//clean stuff up + CloseHandle(newstdout); + CloseHandle(read_stdout); + CloseHandle(write_stdin); + retVal = exit; + return true; + +} + +bool cmWin32ProcessExecution::StartProcess( + const char* cmd, const char* path, bool verbose) +{ + this->Initialize(); + this->Verbose = verbose; + return this->PrivateOpen(cmd, path, _O_RDONLY | _O_TEXT, POPEN_3); +} + +bool cmWin32ProcessExecution::Wait(int timeout) +{ + return this->PrivateClose(timeout); +} + +/* + * Internal dictionary mapping popen* file pointers to process handles, + * for use when retrieving the process exit code. See _PyPclose() below + * for more information on this dictionary's use. + */ +static void *_PyPopenProcs = NULL; + +static BOOL RealPopenCreateProcess(const char *cmdstring, + const char *path, + const char *szConsoleSpawn, + HANDLE hStdin, + HANDLE hStdout, + HANDLE hStderr, + HANDLE *hProcess, + bool hideWindows, + std::string& output) +{ + PROCESS_INFORMATION piProcInfo; + STARTUPINFO siStartInfo; + char *s1=0,*s2=0; + const char *s3 = " /c "; + int i = GetEnvironmentVariable("COMSPEC",NULL,0); + if (i) + { + char *comshell; + + s1 = (char *)malloc(i); + int x = GetEnvironmentVariable("COMSPEC", s1, i); + if (!x) + { + free(s1); + return x; + } + + /* Explicitly check if we are using COMMAND.COM. If we are + * then use the w9xpopen hack. + */ + comshell = s1 + x; + while (comshell >= s1 && *comshell != '\\') + --comshell; + ++comshell; + + if (GetVersion() < 0x80000000 && + STRICMP(comshell, "command.com") != 0) + { + /* NT/2000 and not using command.com. */ + x = i + (int)strlen(s3) + (int)strlen(cmdstring) + 1; + s2 = (char *)malloc(x); + ZeroMemory(s2, x); + //sprintf(s2, "%s%s%s", s1, s3, cmdstring); + sprintf(s2, "%s", cmdstring); + } + else + { + /* + * Oh gag, we're on Win9x or using COMMAND.COM. Use + * the workaround listed in KB: Q150956 + */ + char modulepath[_MAX_PATH]; + struct stat statinfo; + GetModuleFileName(NULL, modulepath, sizeof(modulepath)); + for (i = x = 0; modulepath[i]; i++) + if (modulepath[i] == '\\') + x = i+1; + modulepath[x] = '\0'; + /* Create the full-name to w9xpopen, so we can test it exists */ + strncat(modulepath, + szConsoleSpawn, + (sizeof(modulepath)/sizeof(modulepath[0])) + -strlen(modulepath)); + if (stat(modulepath, &statinfo) != 0) + { + /* Eeek - file-not-found - possibly an embedding + situation - see if we can locate it in sys.prefix + */ + strncpy(modulepath, + ".", + sizeof(modulepath)/sizeof(modulepath[0])); + if (modulepath[strlen(modulepath)-1] != '\\') + strcat(modulepath, "\\"); + strncat(modulepath, + szConsoleSpawn, + (sizeof(modulepath)/sizeof(modulepath[0])) + -strlen(modulepath)); + /* No where else to look - raise an easily identifiable + error, rather than leaving Windows to report + "file not found" - as the user is probably blissfully + unaware this shim EXE is used, and it will confuse them. + (well, it confused me for a while ;-) + */ + if (stat(modulepath, &statinfo) != 0) + { + std::cout + << "Can not locate '" << modulepath + << "' which is needed " + "for popen to work with your shell " + "or platform." << std::endl; + free(s1); + free(s2); + return FALSE; + } + } + x = i + (int)strlen(s3) + (int)strlen(cmdstring) + 1 + + (int)strlen(modulepath) + + (int)strlen(szConsoleSpawn) + 1; + if(s2) + { + free(s2); + } + s2 = (char *)malloc(x); + ZeroMemory(s2, x); + sprintf( + s2, + "%s %s%s%s", + modulepath, + s1, + s3, + cmdstring); + sprintf( + s2, + "%s %s", + modulepath, + cmdstring); + } + } + + /* Could be an else here to try cmd.exe / command.com in the path + Now we'll just error out.. */ + else + { + std::cout << "Cannot locate a COMSPEC environment variable to " + << "use as the shell" << std::endl; + free(s2); + free(s1); + return FALSE; + } + + ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + siStartInfo.hStdInput = hStdin; + siStartInfo.hStdOutput = hStdout; + siStartInfo.hStdError = hStderr; + siStartInfo.wShowWindow = SW_SHOWDEFAULT; + if(hideWindows) + { + siStartInfo.wShowWindow = SW_HIDE; + } + + //std::cout << "Create process: " << s2 << std::endl; + if (CreateProcess(NULL, + s2, + NULL, + NULL, + TRUE, + 0, //CREATE_NEW_CONSOLE, + NULL, + path, + &siStartInfo, + &piProcInfo) ) + { + /* Close the handles now so anyone waiting is woken. */ + CloseHandle(piProcInfo.hThread); + /* Return process handle */ + *hProcess = piProcInfo.hProcess; + //std::cout << "Process created..." << std::endl; + free(s2); + free(s1); + return TRUE; + } + + output += "CreateProcessError: "; + { + /* Format the error message. */ + char message[1024]; + DWORD original = GetLastError(); + DWORD length = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, 0, original, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + message, 1023, 0); + if(length < 1) + { + /* FormatMessage failed. Use a default message. */ + _snprintf(message, 1023, + "Process execution failed with error 0x%X. " + "FormatMessage failed with error 0x%X", + original, GetLastError()); + } + output += message; + } + output += "\n"; + output += "for command: "; + output += s2; + if(path) + { + output += "\nin dir: "; + output += path; + } + output += "\n"; + free(s2); + free(s1); + return FALSE; +} + +/* The following code is based off of KB: Q190351 */ + +bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring, + const char* path, + int mode, + int n) +{ + HANDLE hProcess; + + SECURITY_ATTRIBUTES saAttr; + BOOL fSuccess; + int fd1, fd2, fd3; + this->hChildStdinRd = 0; + this->hChildStdinWr = 0; + this->hChildStdoutRd = 0; + this->hChildStdoutWr = 0; + this->hChildStderrRd = 0; + this->hChildStderrWr = 0; + this->hChildStdinWrDup = 0; + this->hChildStdoutRdDup = 0; + this->hChildStderrRdDup = 0; + + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + fd1 = 0; + fd2 = 0; + fd3 = 0; + + if (!CreatePipe(&this->hChildStdinRd, &this->hChildStdinWr, &saAttr, 0)) + { + this->Output += "CreatePipeError\n"; + return false; + } + + /* Create new output read handle and the input write handle. Set + * the inheritance properties to FALSE. Otherwise, the child inherits + * the these handles; resulting in non-closeable handles to the pipes + * being created. */ + fSuccess = DuplicateHandle(GetCurrentProcess(), this->hChildStdinWr, + GetCurrentProcess(), &this->hChildStdinWrDup, 0, + FALSE, + DUPLICATE_SAME_ACCESS); + if (!fSuccess) + { + this->Output += "DuplicateHandleError\n"; + return false; + } + + + /* Close the inheritable version of ChildStdin + that we're using. */ + CloseHandle(hChildStdinWr); + + if (!CreatePipe(&this->hChildStdoutRd, &this->hChildStdoutWr, &saAttr, 0)) + { + this->Output += "CreatePipeError\n"; + return false; + } + + fSuccess = DuplicateHandle(GetCurrentProcess(), this->hChildStdoutRd, + GetCurrentProcess(), &this->hChildStdoutRdDup, 0, + FALSE, DUPLICATE_SAME_ACCESS); + if (!fSuccess) + { + this->Output += "DuplicateHandleError\n"; + return false; + } + + /* Close the inheritable version of ChildStdout + that we're using. */ + CloseHandle(hChildStdoutRd); + + if (n != POPEN_4) + { + if (!CreatePipe(&this->hChildStderrRd, &this->hChildStderrWr, &saAttr, 0)) + { + this->Output += "CreatePipeError\n"; + return false; + } + fSuccess = DuplicateHandle(GetCurrentProcess(), + this->hChildStderrRd, + GetCurrentProcess(), + &this->hChildStderrRdDup, 0, + FALSE, DUPLICATE_SAME_ACCESS); + if (!fSuccess) + { + this->Output += "DuplicateHandleError\n"; + return false; + } + /* Close the inheritable version of ChildStdErr that we're using. */ + CloseHandle(hChildStderrRd); + + } + + switch (n) + { + case POPEN_1: + switch (mode & (_O_RDONLY | _O_TEXT | _O_BINARY | _O_WRONLY)) + { + case _O_WRONLY | _O_TEXT: + /* Case for writing to child Stdin in text mode. */ + fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup), mode); + /* We don't care about these pipes anymore, + so close them. */ + break; + + case _O_RDONLY | _O_TEXT: + /* Case for reading from child Stdout in text mode. */ + fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup), mode); + /* We don't care about these pipes anymore, + so close them. */ + break; + + case _O_RDONLY | _O_BINARY: + /* Case for readinig from child Stdout in + binary mode. */ + fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup), mode); + /* We don't care about these pipes anymore, + so close them. */ + break; + + case _O_WRONLY | _O_BINARY: + /* Case for writing to child Stdin in binary mode. */ + fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup), mode); + /* We don't care about these pipes anymore, + so close them. */ + break; + } + break; + + case POPEN_2: + case POPEN_4: + //if ( 1 ) + { + fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup), mode); + fd2 = _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup), mode); + break; + } + + case POPEN_3: + //if ( 1) + { + fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup), mode); + fd2 = _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup), mode); + fd3 = _open_osfhandle(TO_INTPTR(this->hChildStderrRdDup), mode); + break; + } + } + + if (n == POPEN_4) + { + if (!RealPopenCreateProcess(cmdstring, + path, + this->ConsoleSpawn.c_str(), + this->hChildStdinRd, + this->hChildStdoutWr, + this->hChildStdoutWr, + &hProcess, this->HideWindows, + this->Output)) + { + if(fd1 >= 0) + { + close(fd1); + } + if(fd2 >= 0) + { + close(fd2); + } + if(fd3 >= 0) + { + close(fd3); + } + return 0; + } + } + else + { + if (!RealPopenCreateProcess(cmdstring, + path, + this->ConsoleSpawn.c_str(), + this->hChildStdinRd, + this->hChildStdoutWr, + this->hChildStderrWr, + &hProcess, this->HideWindows, + this->Output)) + { + if(fd1 >= 0) + { + close(fd1); + } + if(fd2 >= 0) + { + close(fd2); + } + if(fd3 >= 0) + { + close(fd3); + } + return 0; + } + } + + /* + * Insert the files we've created into the process dictionary + * all referencing the list with the process handle and the + * initial number of files (see description below in _PyPclose). + * Since if _PyPclose later tried to wait on a process when all + * handles weren't closed, it could create a deadlock with the + * child, we spend some energy here to try to ensure that we + * either insert all file handles into the dictionary or none + * at all. It's a little clumsy with the various popen modes + * and variable number of files involved. + */ + + /* Child is launched. Close the parents copy of those pipe + * handles that only the child should have open. You need to + * make sure that no handles to the write end of the output pipe + * are maintained in this process or else the pipe will not close + * when the child process exits and the ReadFile will hang. */ + this->ProcessHandle = hProcess; + if ( fd1 >= 0 ) + { + this->pStdIn = fd1; + } + if ( fd2 >= 0 ) + { + this->pStdOut = fd2; + } + if ( fd3 >= 0 ) + { + this->pStdErr = fd3; + } + + return true; +} + +bool cmWin32ProcessExecution::CloseHandles() +{ + if(this->pStdErr != -1 ) + { + // this will close this as well: this->hChildStderrRdDup + _close(this->pStdErr); + this->pStdErr = -1; + this->hChildStderrRdDup = 0; + } + if(this->pStdIn != -1 ) + { + // this will close this as well: this->hChildStdinWrDup + _close(this->pStdIn); + this->pStdIn = -1; + this->hChildStdinWrDup = 0; + } + if(this->pStdOut != -1 ) + { + // this will close this as well: this->hChildStdoutRdDup + _close(this->pStdOut); + this->pStdOut = -1; + this->hChildStdoutRdDup = 0; + } + + bool ret = true; + if (this->hChildStdinRd && !CloseHandle(this->hChildStdinRd)) + { + ret = false; + } + this->hChildStdinRd = 0; + // now close these two + if (this->hChildStdoutWr && !CloseHandle(this->hChildStdoutWr)) + { + ret = false; + } + this->hChildStdoutWr = 0; + if (this->hChildStderrWr && !CloseHandle(this->hChildStderrWr)) + { + ret = false; + } + this->hChildStderrWr = 0; + return ret; +} +cmWin32ProcessExecution::~cmWin32ProcessExecution() +{ + this->CloseHandles(); +} + +/* + * Wrapper for fclose() to use for popen* files, so we can retrieve the + * exit code for the child process and return as a result of the close. + * + * This function uses the _PyPopenProcs dictionary in order to map the + * input file pointer to information about the process that was + * originally created by the popen* call that created the file pointer. + * The dictionary uses the file pointer as a key (with one entry + * inserted for each file returned by the original popen* call) and a + * single list object as the value for all files from a single call. + * The list object contains the Win32 process handle at [0], and a file + * count at [1], which is initialized to the total number of file + * handles using that list. + * + * This function closes whichever handle it is passed, and decrements + * the file count in the dictionary for the process handle pointed to + * by this file. On the last close (when the file count reaches zero), + * this function will wait for the child process and then return its + * exit code as the result of the close() operation. This permits the + * files to be closed in any order - it is always the close() of the + * final handle that will return the exit code. + */ + + /* RED_FLAG 31-Aug-2000 Tim + * This is always called (today!) between a pair of + * Py_BEGIN_ALLOW_THREADS/ Py_END_ALLOW_THREADS + * macros. So the thread running this has no valid thread state, as + * far as Python is concerned. However, this calls some Python API + * functions that cannot be called safely without a valid thread + * state, in particular PyDict_GetItem. + * As a temporary hack (although it may last for years ...), we + * *rely* on not having a valid thread state in this function, in + * order to create our own "from scratch". + * This will deadlock if _PyPclose is ever called by a thread + * holding the global lock. + */ + +bool cmWin32ProcessExecution::PrivateClose(int /* timeout */) +{ + HANDLE hProcess = this->ProcessHandle; + + int result = -1; + DWORD exit_code; + + std::string output = ""; + bool done = false; + while(!done) + { + Sleep(10); + bool have_some = false; + struct _stat fsout; + struct _stat fserr; + int rout = _fstat(this->pStdOut, &fsout); + int rerr = _fstat(this->pStdErr, &fserr); + if ( rout && rerr ) + { + break; + } + if (fserr.st_size > 0) + { + char buffer[1024]; + int len = read(this->pStdErr, buffer, 1023); + buffer[len] = 0; + if ( this->Verbose ) + { + cmSystemTools::Stdout(buffer); + } + output += buffer; + have_some = true; + } + if (fsout.st_size > 0) + { + char buffer[1024]; + int len = read(this->pStdOut, buffer, 1023); + buffer[len] = 0; + if ( this->Verbose ) + { + cmSystemTools::Stdout(buffer); + } + output += buffer; + have_some = true; + } + unsigned long exitCode; + if ( ! have_some ) + { + GetExitCodeProcess(hProcess,&exitCode); + if (exitCode != STILL_ACTIVE) + { + break; + } + } + } + + + if (WaitForSingleObject(hProcess, INFINITE) != WAIT_FAILED && + GetExitCodeProcess(hProcess, &exit_code)) + { + result = exit_code; + } + else + { + /* Indicate failure - this will cause the file object + * to raise an I/O error and translate the last Win32 + * error code from errno. We do have a problem with + * last errors that overlap the normal errno table, + * but that's a consistent problem with the file object. + */ + if (result != EOF) + { + /* If the error wasn't from the fclose(), then + * set errno for the file object error handling. + */ + errno = GetLastError(); + } + result = -1; + } + + /* Free up the native handle at this point */ + CloseHandle(hProcess); + this->ExitValue = result; + this->Output += output; + bool ret = this->CloseHandles(); + if ( result < 0 || !ret) + { + return false; + } + return true; +} + +int cmWin32ProcessExecution::Windows9xHack(const char* command) +{ + BOOL bRet; + STARTUPINFO si; + PROCESS_INFORMATION pi; + DWORD exit_code=0; + + if (!command) + { + cmSystemTools::Error("Windows9xHack: Command not specified"); + return 1; + } + + /* Make child process use this app's standard files. */ + ZeroMemory(&si, sizeof si); + si.cb = sizeof si; + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + si.hStdError = GetStdHandle(STD_ERROR_HANDLE); + + + char * app = 0; + char* cmd = new char[ strlen(command) + 1 ]; + strcpy(cmd, command); + + bRet = CreateProcess( + app, cmd, + 0, 0, + TRUE, 0, + 0, 0, + &si, &pi + ); + delete [] cmd; + + if (bRet) + { + if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_FAILED) + { + GetExitCodeProcess(pi.hProcess, &exit_code); + } + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return exit_code; + } + + return 1; +} -- cgit v1.2.3