diff --git a/Source/cmWin32ProcessExecution.cxx b/Source/cmWin32ProcessExecution.cxx index c13f30333..9670e4263 100644 --- a/Source/cmWin32ProcessExecution.cxx +++ b/Source/cmWin32ProcessExecution.cxx @@ -25,6 +25,19 @@ #include #include +#if defined(__BORLANDC__) +# define STRICMP stricmp +# define TO_INTPTR(x) ((long)(x)) +#else // 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 // Borland + #define POPEN_1 1 #define POPEN_2 2 #define POPEN_3 3 @@ -34,6 +47,7 @@ #define win32_error(x,y) std::cout << "Win32_Error(" << x << ", " << y << ")" << std::endl, false + bool cmWin32ProcessExecution::StartProcess( const char* cmd, const char* path, bool verbose) { @@ -47,6 +61,25 @@ bool cmWin32ProcessExecution::Wait(int timeout) return this->PrivateClose(timeout); } +#define PERROR(str) //::ErrorMessage(__LINE__, str) +static void ErrorMessage(int line, char *str) //display detailed error info +{ + DWORD lastmsg = GetLastError(); + LPVOID msg; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + lastmsg, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &msg, + 0, + NULL + ); + printf("%d - %s: %s (%d)\n",line,str,msg, lastmsg); + LocalFree(msg); + ::SetLastError(ERROR_SUCCESS); +} + /* * Internal dictionary mapping popen* file pointers to process handles, * for use when retrieving the process exit code. See _PyPclose() below @@ -62,19 +95,27 @@ static BOOL RealPopenCreateProcess(const char *cmdstring, HANDLE hStderr, HANDLE *hProcess) { + PERROR("Start"); + //std::cout << "Run: " << cmdstring << std::endl; + PERROR("Start"); PROCESS_INFORMATION piProcInfo; + PERROR("PROCESS_INFORMATION"); STARTUPINFO siStartInfo; + PERROR("STARTUPINFO"); char *s1,*s2, *s3 = " /c "; int i; int x; - if (i = GetEnvironmentVariable("COMSPEC",NULL,0)) { + PERROR("GetEnvironmentVariable"); char *comshell; s1 = (char *)_alloca(i); if (!(x = GetEnvironmentVariable("COMSPEC", s1, i))) + { + PERROR("GetEnvironmentVariable"); return x; + } /* Explicitly check if we are using COMMAND.COM. If we are * then use the w9xpopen hack. @@ -85,7 +126,7 @@ static BOOL RealPopenCreateProcess(const char *cmdstring, ++comshell; if (GetVersion() < 0x80000000 && - _stricmp(comshell, "command.com") != 0) + STRICMP(comshell, "command.com") != 0) { /* NT/2000 and not using command.com. */ x = i + (int)strlen(s3) + (int)strlen(cmdstring) + 1; @@ -187,11 +228,13 @@ static BOOL RealPopenCreateProcess(const char *cmdstring, &siStartInfo, &piProcInfo) ) { + PERROR("CreateProcess"); /* Close the handles now so anyone waiting is woken. */ CloseHandle(piProcInfo.hThread); - + PERROR("Close Handle"); /* Return process handle */ *hProcess = piProcInfo.hProcess; + //std::cout << "Process created..." << std::endl; return TRUE; } win32_error("CreateProcess", s2); @@ -212,7 +255,7 @@ bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring, SECURITY_ATTRIBUTES saAttr; BOOL fSuccess; int fd1, fd2, fd3; - FILE *f1, *f2, *f3; + //FILE *f1, *f2, *f3; long file_count; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); @@ -220,8 +263,11 @@ bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring, saAttr.lpSecurityDescriptor = NULL; if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) + { return win32_error("CreatePipe", NULL); - + } + PERROR("CreatePipe"); + /* 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 @@ -232,10 +278,13 @@ bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring, DUPLICATE_SAME_ACCESS); if (!fSuccess) return win32_error("DuplicateHandle", NULL); + PERROR("DuplicateHandle"); + /* Close the inheritable version of ChildStdin that we're using. */ CloseHandle(hChildStdinWr); + PERROR("CloseHandle"); if (!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) return win32_error("CreatePipe", NULL); @@ -245,24 +294,29 @@ bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring, FALSE, DUPLICATE_SAME_ACCESS); if (!fSuccess) return win32_error("DuplicateHandle", NULL); + PERROR("DuplicateHandle"); /* Close the inheritable version of ChildStdout that we're using. */ CloseHandle(hChildStdoutRd); + PERROR("CloseHandle"); if (n != POPEN_4) { if (!CreatePipe(&hChildStderrRd, &hChildStderrWr, &saAttr, 0)) return win32_error("CreatePipe", NULL); - fSuccess = DuplicateHandle(GetCurrentProcess(), + PERROR("CreatePipe"); + fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStderrRd, GetCurrentProcess(), &hChildStderrRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS); if (!fSuccess) return win32_error("DuplicateHandle", NULL); + PERROR("DuplicateHandle"); /* Close the inheritable version of ChildStdErr that we're using. */ CloseHandle(hChildStderrRd); + PERROR("CloseHandle"); } switch (n) @@ -272,43 +326,47 @@ bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring, { case _O_WRONLY | _O_TEXT: /* Case for writing to child Stdin in text mode. */ - fd1 = _open_osfhandle((intptr_t)hChildStdinWrDup, mode); - f1 = _fdopen(fd1, "w"); + fd1 = _open_osfhandle(TO_INTPTR(hChildStdinWrDup), mode); + //f1 = _fdopen(fd1, "w"); /* We don't care about these pipes anymore, so close them. */ CloseHandle(hChildStdoutRdDup); CloseHandle(hChildStderrRdDup); + PERROR("CloseHandle"); break; case _O_RDONLY | _O_TEXT: /* Case for reading from child Stdout in text mode. */ - fd1 = _open_osfhandle((intptr_t)hChildStdoutRdDup, mode); - f1 = _fdopen(fd1, "r"); + fd1 = _open_osfhandle(TO_INTPTR(hChildStdoutRdDup), mode); + //f1 = _fdopen(fd1, "r"); /* We don't care about these pipes anymore, so close them. */ CloseHandle(hChildStdinWrDup); CloseHandle(hChildStderrRdDup); + PERROR("CloseHandle"); break; case _O_RDONLY | _O_BINARY: /* Case for readinig from child Stdout in binary mode. */ - fd1 = _open_osfhandle((intptr_t)hChildStdoutRdDup, mode); - f1 = _fdopen(fd1, "rb"); + fd1 = _open_osfhandle(TO_INTPTR(hChildStdoutRdDup), mode); + //f1 = _fdopen(fd1, "rb"); /* We don't care about these pipes anymore, so close them. */ CloseHandle(hChildStdinWrDup); CloseHandle(hChildStderrRdDup); + PERROR("CloseHandle"); break; case _O_WRONLY | _O_BINARY: /* Case for writing to child Stdin in binary mode. */ - fd1 = _open_osfhandle((intptr_t)hChildStdinWrDup, mode); - f1 = _fdopen(fd1, "wb"); + fd1 = _open_osfhandle(TO_INTPTR(hChildStdinWrDup), mode); + //f1 = _fdopen(fd1, "wb"); /* We don't care about these pipes anymore, so close them. */ CloseHandle(hChildStdoutRdDup); CloseHandle(hChildStderrRdDup); + PERROR("CloseHandle"); break; } file_count = 1; @@ -331,13 +389,17 @@ bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring, m2 = "wb"; } - fd1 = _open_osfhandle((intptr_t)hChildStdinWrDup, mode); - f1 = _fdopen(fd1, m2); - fd2 = _open_osfhandle((intptr_t)hChildStdoutRdDup, mode); - f2 = _fdopen(fd2, m1); + fd1 = _open_osfhandle(TO_INTPTR(hChildStdinWrDup), mode); + //f1 = _fdopen(fd1, m2); + fd2 = _open_osfhandle(TO_INTPTR(hChildStdoutRdDup), mode); + //f2 = _fdopen(fd2, m1); + PERROR("_open_osfhandle"); if (n != 4) + { CloseHandle(hChildStderrRdDup); + PERROR("CloseHandle"); + } file_count = 2; break; @@ -359,12 +421,14 @@ bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring, m2 = "wb"; } - fd1 = _open_osfhandle((intptr_t)hChildStdinWrDup, mode); - f1 = _fdopen(fd1, m2); - fd2 = _open_osfhandle((intptr_t)hChildStdoutRdDup, mode); - f2 = _fdopen(fd2, m1); - fd3 = _open_osfhandle((intptr_t)hChildStderrRdDup, mode); - f3 = _fdopen(fd3, m1); + + fd1 = _open_osfhandle(TO_INTPTR(hChildStdinWrDup), mode); + //f1 = _fdopen(fd1, m2); + fd2 = _open_osfhandle(TO_INTPTR(hChildStdoutRdDup), mode); + //f2 = _fdopen(fd2, m1); + fd3 = _open_osfhandle(TO_INTPTR(hChildStderrRdDup), mode); + //f3 = _fdopen(fd3, m1); + PERROR("_open_osfhandle"); file_count = 3; break; @@ -414,29 +478,34 @@ bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring, if (!CloseHandle(hChildStdinRd)) return win32_error("CloseHandle", NULL); + PERROR("CloseHandle"); if (!CloseHandle(hChildStdoutWr)) return win32_error("CloseHandle", NULL); + PERROR("CloseHandle"); if ((n != 4) && (!CloseHandle(hChildStderrWr))) return win32_error("CloseHandle", NULL); + PERROR("CloseHandle"); this->m_ProcessHandle = hProcess; - if ( f1 ) + if ( fd1 >= 0 ) { - this->m_StdIn = f1; + // this->m_StdIn = f1; this->m_pStdIn = fd1; } - if ( f2 ) + if ( fd2 >= 0 ) { - this->m_StdOut = f2; + // this->m_StdOut = f2; this->m_pStdOut = fd2; } - if ( f3 ) + if ( fd3 >= 0 ) { - this->m_StdErr = f3; + // this->m_StdErr = f3; this->m_pStdErr = fd3; } + //std::cout << "Process created for real..." << std::endl; + //std::cout << fd1 << " " << fd2 << " " << fd3 << std::endl; return true; } @@ -502,6 +571,7 @@ bool cmWin32ProcessExecution::PrivateClose(int timeout) } if (fserr.st_size > 0) { + //std::cout << "Some error" << std::endl; int dist = fserr.st_size; char buffer[1023]; int len = read(this->m_pStdErr, buffer, 1023); @@ -514,6 +584,7 @@ bool cmWin32ProcessExecution::PrivateClose(int timeout) } if (fsout.st_size > 0) { + //std::cout << "Some output" << std::endl; int dist = fsout.st_size; char buffer[1023]; int len = read(this->m_pStdOut, buffer, 1023); @@ -528,9 +599,13 @@ bool cmWin32ProcessExecution::PrivateClose(int timeout) GetExitCodeProcess(hProcess,&exitCode); if (exitCode != STILL_ACTIVE) { + //std::cout << "STILL_ACTIVE = " << STILL_ACTIVE << std::endl; + //std::cout << "Process is not active any more: " << exitCode << std::endl; break; } } + + //std::cout << "Waiting for process to close" << std::endl; if (WaitForSingleObject(hProcess, INFINITE) != WAIT_FAILED && GetExitCodeProcess(hProcess, &exit_code)) @@ -554,6 +629,8 @@ bool cmWin32ProcessExecution::PrivateClose(int timeout) } result = -1; } + + //std::cout << "Process closed with error code: " << result << std::endl; /* Free up the native handle at this point */ CloseHandle(hProcess); diff --git a/Source/cmWin32ProcessExecution.h b/Source/cmWin32ProcessExecution.h index 49ab00e97..b149a6bda 100644 --- a/Source/cmWin32ProcessExecution.h +++ b/Source/cmWin32ProcessExecution.h @@ -27,7 +27,6 @@ #include "cmStandardIncludes.h" #include "windows.h" -#include "stdio.h" class cmMakefile; @@ -45,21 +44,59 @@ public: this->SetConsoleSpawn("w9xpopen.exe"); this->Initialize(); } + + /** + * Initialize the process execution datastructure. Do not call while + * running the process. + */ void Initialize() { this->m_ProcessHandle = 0; this->m_ExitValue = -1; - this->m_StdIn = 0; - this->m_StdOut = 0; - this->m_StdErr = 0; + // Comment this out. Maybe we will need it in the future. + // file IO access to the process might be cool. + //this->m_StdIn = 0; + //this->m_StdOut = 0; + //this->m_StdErr = 0; + this->m_pStdIn = -1; + this->m_pStdOut = -1; + this->m_pStdErr = -1; } + + /** + * Start the process in the directory path. Make sure that the + * executable is either in the path or specify the full path. The + * argument verbose specifies wether or not to display output while + * it is being generated. + */ bool StartProcess(const char*, const char* path, bool verbose); + + /** + * Wait for the process to finish. If timeout is specified, it will + * break the process after timeout expires. (Timeout code is not yet + * implemented. + */ bool Wait(int timeout); + + /** + * Get the output of the process (mixed stdout and stderr) as + * std::string. + */ const std::string GetOutput() const { return this->m_Output; } + + /** + * Get the return value of the process. If the process is still + * running, the return value is -1. + */ int GetExitValue() const { return this->m_ExitValue; } + /** + * On Windows 9x there is a bug in the process execution code which + * may result in blocking. That is why this workaround is + * used. Specify the console spawn, which should run the + * Windows9xHack code. + */ void SetConsoleSpawn(const char* prog) { this->m_ConsoleSpawn = prog; } - static int Windows9xHack(const char* command); private: @@ -67,10 +104,13 @@ private: bool PrivateClose(int timeout); HANDLE m_ProcessHandle; - FILE* m_StdIn; - FILE* m_StdOut; - FILE* m_StdErr; - + + // Comment this out. Maybe we will need it in the future. + // file IO access to the process might be cool. + // FILE* m_StdIn; + // FILE* m_StdOut; + // FILE* m_StdErr; + int m_pStdIn; int m_pStdOut; int m_pStdErr;