Add class for process execution on Windows
This commit is contained in:
parent
2f1052b0e5
commit
c310600df5
|
@ -72,6 +72,8 @@ IF (WIN32)
|
|||
cmLocalVisualStudio6Generator.h
|
||||
cmGlobalVisualStudio7Generator.h
|
||||
cmLocalVisualStudio7Generator.h
|
||||
cmWin32ProcessExecution.cxx
|
||||
cmWin32ProcessExecution.h
|
||||
)
|
||||
IF( NOT BORLAND )
|
||||
LINK_LIBRARIES( rpcrt4.lib )
|
||||
|
|
|
@ -0,0 +1,614 @@
|
|||
/*=========================================================================
|
||||
|
||||
Program: Insight Segmentation & Registration Toolkit
|
||||
Module: $RCSfile$
|
||||
Language: C++
|
||||
Date: $Date$
|
||||
Version: $Revision$
|
||||
|
||||
Copyright (c) 2002 Insight Consortium. All rights reserved.
|
||||
See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE. See the above copyright notices for more information.
|
||||
|
||||
=========================================================================*/
|
||||
#include "cmWin32ProcessExecution.h"
|
||||
|
||||
#include "cmSystemTools.h"
|
||||
|
||||
#include <malloc.h>
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <windows.h>
|
||||
|
||||
#define POPEN_1 1
|
||||
#define POPEN_2 2
|
||||
#define POPEN_3 3
|
||||
#define POPEN_4 4
|
||||
|
||||
#define cmMAX(x,y) (((x)<(y))?(y):(x))
|
||||
|
||||
#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)
|
||||
{
|
||||
this->Initialize();
|
||||
this->m_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)
|
||||
{
|
||||
PROCESS_INFORMATION piProcInfo;
|
||||
STARTUPINFO siStartInfo;
|
||||
char *s1,*s2, *s3 = " /c ";
|
||||
int i;
|
||||
int x;
|
||||
|
||||
if (i = GetEnvironmentVariable("COMSPEC",NULL,0))
|
||||
{
|
||||
char *comshell;
|
||||
|
||||
s1 = (char *)_alloca(i);
|
||||
if (!(x = GetEnvironmentVariable("COMSPEC", s1, i)))
|
||||
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 + strlen(s3) + strlen(cmdstring) + 1;
|
||||
s2 = (char *)_alloca(x);
|
||||
ZeroMemory(s2, x);
|
||||
sprintf(s2, "%s%s%s", s1, s3, cmdstring);
|
||||
//std::cout << "s1: " << s1 << " s2: " << s2 << " s3: " << s3
|
||||
// << std::endl;
|
||||
}
|
||||
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 '" << szConsoleSpawn
|
||||
<< "' which is needed "
|
||||
"for popen to work with your shell "
|
||||
"or platform." << std::endl;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
x = i + strlen(s3) + strlen(cmdstring) + 1 +
|
||||
strlen(modulepath) +
|
||||
strlen(szConsoleSpawn) + 1;
|
||||
|
||||
s2 = (char *)_alloca(x);
|
||||
ZeroMemory(s2, x);
|
||||
sprintf(
|
||||
s2,
|
||||
"%s \"%s%s%s\"",
|
||||
modulepath,
|
||||
s1,
|
||||
s3,
|
||||
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;
|
||||
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_HIDE;
|
||||
|
||||
if (CreateProcess(NULL,
|
||||
s2,
|
||||
NULL,
|
||||
NULL,
|
||||
TRUE,
|
||||
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;
|
||||
return TRUE;
|
||||
}
|
||||
win32_error("CreateProcess", s2);
|
||||
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 hChildStdinRd, hChildStdinWr, hChildStdoutRd, hChildStdoutWr,
|
||||
hChildStderrRd, hChildStderrWr, hChildStdinWrDup, hChildStdoutRdDup,
|
||||
hChildStderrRdDup, hProcess; /* hChildStdoutWrDup; */
|
||||
|
||||
SECURITY_ATTRIBUTES saAttr;
|
||||
BOOL fSuccess;
|
||||
int fd1, fd2, fd3;
|
||||
FILE *f1, *f2, *f3;
|
||||
long file_count;
|
||||
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
saAttr.lpSecurityDescriptor = NULL;
|
||||
|
||||
if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
|
||||
return win32_error("CreatePipe", NULL);
|
||||
|
||||
/* 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(), hChildStdinWr,
|
||||
GetCurrentProcess(), &hChildStdinWrDup, 0,
|
||||
FALSE,
|
||||
DUPLICATE_SAME_ACCESS);
|
||||
if (!fSuccess)
|
||||
return win32_error("DuplicateHandle", NULL);
|
||||
|
||||
/* Close the inheritable version of ChildStdin
|
||||
that we're using. */
|
||||
CloseHandle(hChildStdinWr);
|
||||
|
||||
if (!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
|
||||
return win32_error("CreatePipe", NULL);
|
||||
|
||||
fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
|
||||
GetCurrentProcess(), &hChildStdoutRdDup, 0,
|
||||
FALSE, DUPLICATE_SAME_ACCESS);
|
||||
if (!fSuccess)
|
||||
return win32_error("DuplicateHandle", NULL);
|
||||
|
||||
/* Close the inheritable version of ChildStdout
|
||||
that we're using. */
|
||||
CloseHandle(hChildStdoutRd);
|
||||
|
||||
if (n != POPEN_4)
|
||||
{
|
||||
if (!CreatePipe(&hChildStderrRd, &hChildStderrWr, &saAttr, 0))
|
||||
return win32_error("CreatePipe", NULL);
|
||||
fSuccess = DuplicateHandle(GetCurrentProcess(),
|
||||
hChildStderrRd,
|
||||
GetCurrentProcess(),
|
||||
&hChildStderrRdDup, 0,
|
||||
FALSE, DUPLICATE_SAME_ACCESS);
|
||||
if (!fSuccess)
|
||||
return win32_error("DuplicateHandle", NULL);
|
||||
/* 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((long)hChildStdinWrDup, mode);
|
||||
f1 = _fdopen(fd1, "w");
|
||||
/* We don't care about these pipes anymore,
|
||||
so close them. */
|
||||
CloseHandle(hChildStdoutRdDup);
|
||||
CloseHandle(hChildStderrRdDup);
|
||||
break;
|
||||
|
||||
case _O_RDONLY | _O_TEXT:
|
||||
/* Case for reading from child Stdout in text mode. */
|
||||
fd1 = _open_osfhandle((long)hChildStdoutRdDup, mode);
|
||||
f1 = _fdopen(fd1, "r");
|
||||
/* We don't care about these pipes anymore,
|
||||
so close them. */
|
||||
CloseHandle(hChildStdinWrDup);
|
||||
CloseHandle(hChildStderrRdDup);
|
||||
break;
|
||||
|
||||
case _O_RDONLY | _O_BINARY:
|
||||
/* Case for readinig from child Stdout in
|
||||
binary mode. */
|
||||
fd1 = _open_osfhandle((long)hChildStdoutRdDup, mode);
|
||||
f1 = _fdopen(fd1, "rb");
|
||||
/* We don't care about these pipes anymore,
|
||||
so close them. */
|
||||
CloseHandle(hChildStdinWrDup);
|
||||
CloseHandle(hChildStderrRdDup);
|
||||
break;
|
||||
|
||||
case _O_WRONLY | _O_BINARY:
|
||||
/* Case for writing to child Stdin in binary mode. */
|
||||
fd1 = _open_osfhandle((long)hChildStdinWrDup, mode);
|
||||
f1 = _fdopen(fd1, "wb");
|
||||
/* We don't care about these pipes anymore,
|
||||
so close them. */
|
||||
CloseHandle(hChildStdoutRdDup);
|
||||
CloseHandle(hChildStderrRdDup);
|
||||
break;
|
||||
}
|
||||
file_count = 1;
|
||||
break;
|
||||
|
||||
case POPEN_2:
|
||||
case POPEN_4:
|
||||
if ( 1 )
|
||||
{
|
||||
char *m1, *m2;
|
||||
|
||||
if (mode && _O_TEXT)
|
||||
{
|
||||
m1 = "r";
|
||||
m2 = "w";
|
||||
}
|
||||
else
|
||||
{
|
||||
m1 = "rb";
|
||||
m2 = "wb";
|
||||
}
|
||||
|
||||
fd1 = _open_osfhandle((long)hChildStdinWrDup, mode);
|
||||
f1 = _fdopen(fd1, m2);
|
||||
fd2 = _open_osfhandle((long)hChildStdoutRdDup, mode);
|
||||
f2 = _fdopen(fd2, m1);
|
||||
|
||||
if (n != 4)
|
||||
CloseHandle(hChildStderrRdDup);
|
||||
|
||||
file_count = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case POPEN_3:
|
||||
if ( 1)
|
||||
{
|
||||
char *m1, *m2;
|
||||
|
||||
if (mode && _O_TEXT)
|
||||
{
|
||||
m1 = "r";
|
||||
m2 = "w";
|
||||
}
|
||||
else
|
||||
{
|
||||
m1 = "rb";
|
||||
m2 = "wb";
|
||||
}
|
||||
|
||||
fd1 = _open_osfhandle((long)hChildStdinWrDup, mode);
|
||||
f1 = _fdopen(fd1, m2);
|
||||
fd2 = _open_osfhandle((long)hChildStdoutRdDup, mode);
|
||||
f2 = _fdopen(fd2, m1);
|
||||
fd3 = _open_osfhandle((long)hChildStderrRdDup, mode);
|
||||
f3 = _fdopen(fd3, m1);
|
||||
|
||||
file_count = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (n == POPEN_4)
|
||||
{
|
||||
if (!RealPopenCreateProcess(cmdstring,
|
||||
path,
|
||||
this->m_ConsoleSpawn.c_str(),
|
||||
hChildStdinRd,
|
||||
hChildStdoutWr,
|
||||
hChildStdoutWr,
|
||||
&hProcess))
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!RealPopenCreateProcess(cmdstring,
|
||||
path,
|
||||
this->m_ConsoleSpawn.c_str(),
|
||||
hChildStdinRd,
|
||||
hChildStdoutWr,
|
||||
hChildStderrWr,
|
||||
&hProcess))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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. */
|
||||
|
||||
if (!CloseHandle(hChildStdinRd))
|
||||
return win32_error("CloseHandle", NULL);
|
||||
|
||||
if (!CloseHandle(hChildStdoutWr))
|
||||
return win32_error("CloseHandle", NULL);
|
||||
|
||||
if ((n != 4) && (!CloseHandle(hChildStderrWr)))
|
||||
return win32_error("CloseHandle", NULL);
|
||||
|
||||
this->m_ProcessHandle = hProcess;
|
||||
if ( f1 )
|
||||
{
|
||||
this->m_StdIn = f1;
|
||||
this->m_pStdIn = fd1;
|
||||
}
|
||||
if ( f2 )
|
||||
{
|
||||
this->m_StdOut = f2;
|
||||
this->m_pStdOut = fd2;
|
||||
}
|
||||
if ( f3 )
|
||||
{
|
||||
this->m_StdErr = f3;
|
||||
this->m_pStdErr = fd3;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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->m_ProcessHandle;
|
||||
|
||||
int result = -1;
|
||||
DWORD exit_code;
|
||||
|
||||
std::string output = "";
|
||||
bool done = false;
|
||||
int stdoutloc = 0;
|
||||
int stderrloc = 0;
|
||||
while(!done)
|
||||
{
|
||||
Sleep(10);
|
||||
struct _stat fsout;
|
||||
struct _stat fserr;
|
||||
int rout = _fstat(this->m_pStdOut, &fsout);
|
||||
int rerr = _fstat(this->m_pStdErr, &fserr);
|
||||
if ( rout && rerr )
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (fserr.st_size > 0)
|
||||
{
|
||||
int dist = fserr.st_size;
|
||||
char buffer[1023];
|
||||
int len = read(this->m_pStdErr, buffer, 1023);
|
||||
buffer[len] = 0;
|
||||
if ( this->m_Verbose )
|
||||
{
|
||||
std::cout << buffer << std::flush;
|
||||
}
|
||||
output += buffer;
|
||||
}
|
||||
if (fsout.st_size > 0)
|
||||
{
|
||||
int dist = fsout.st_size;
|
||||
char buffer[1023];
|
||||
int len = read(this->m_pStdOut, buffer, 1023);
|
||||
buffer[len] = 0;
|
||||
if ( this->m_Verbose )
|
||||
{
|
||||
std::cout << buffer << std::flush;
|
||||
}
|
||||
output += buffer;
|
||||
}
|
||||
unsigned long exitCode;
|
||||
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->m_ExitValue = result;
|
||||
this->m_Output = output;
|
||||
if ( result < 0 )
|
||||
{
|
||||
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* cmd = new char[ strlen(command) + 1 ];
|
||||
strcpy(cmd, command);
|
||||
|
||||
bRet = CreateProcess(
|
||||
NULL, cmd,
|
||||
NULL, NULL,
|
||||
TRUE, 0,
|
||||
NULL, NULL,
|
||||
&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;
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*=========================================================================
|
||||
|
||||
Program: Insight Segmentation & Registration Toolkit
|
||||
Module: $RCSfile$
|
||||
Language: C++
|
||||
Date: $Date$
|
||||
Version: $Revision$
|
||||
|
||||
Copyright (c) 2002 Insight Consortium. All rights reserved.
|
||||
See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE. See the above copyright notices for more information.
|
||||
|
||||
=========================================================================*/
|
||||
#ifndef cmWin32ProcessExecution_h
|
||||
#define cmWin32ProcessExecution_h
|
||||
|
||||
/*
|
||||
* Portable 'popen' replacement for Win32.
|
||||
*
|
||||
* Written by Bill Tutt <billtut@microsoft.com>. Minor tweaks
|
||||
* and 2.0 integration by Fredrik Lundh <fredrik@pythonware.com>
|
||||
* Return code handling by David Bolen <db3l@fitlinxx.com>.
|
||||
*/
|
||||
|
||||
#include "cmStandardIncludes.h"
|
||||
#include "windows.h"
|
||||
|
||||
class cmMakefile;
|
||||
|
||||
/** \class cmWin32ProcessExecution
|
||||
* \brief A process executor for windows
|
||||
*
|
||||
* cmWin32ProcessExecution is a class that provides a "clean" way of
|
||||
* executing processes on Windows.
|
||||
*/
|
||||
class cmWin32ProcessExecution
|
||||
{
|
||||
public:
|
||||
cmWin32ProcessExecution()
|
||||
{
|
||||
this->SetConsoleSpawn("w9xpopen.exe");
|
||||
this->Initialize();
|
||||
}
|
||||
void Initialize()
|
||||
{
|
||||
this->m_ProcessHandle = 0;
|
||||
this->m_ExitValue = -1;
|
||||
this->m_StdIn = 0;
|
||||
this->m_StdOut = 0;
|
||||
this->m_StdErr = 0;
|
||||
}
|
||||
bool StartProcess(const char*, const char* path, bool verbose);
|
||||
bool Wait(int timeout);
|
||||
const std::string GetOutput() const { return this->m_Output; }
|
||||
int GetExitValue() const { return this->m_ExitValue; }
|
||||
|
||||
void SetConsoleSpawn(const char* prog) { this->m_ConsoleSpawn = prog; }
|
||||
|
||||
static int Windows9xHack(const char* command);
|
||||
|
||||
private:
|
||||
bool PrivateOpen(const char*, const char*, int, int);
|
||||
bool PrivateClose(int timeout);
|
||||
|
||||
HANDLE m_ProcessHandle;
|
||||
FILE* m_StdIn;
|
||||
FILE* m_StdOut;
|
||||
FILE* m_StdErr;
|
||||
|
||||
int m_pStdIn;
|
||||
int m_pStdOut;
|
||||
int m_pStdErr;
|
||||
|
||||
int m_ExitValue;
|
||||
|
||||
std::string m_Output;
|
||||
std::string m_ConsoleSpawn;
|
||||
bool m_Verbose;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue