1 /*=========================================================================
3 Program: Insight Segmentation & Registration Toolkit
4 Module: $RCSfile: cmWin32ProcessExecution.cxx,v $
6 Date: $Date: 2002-10-04 14:38:14 $
7 Version: $Revision: 1.9 $
9 Copyright (c) 2002 Insight Consortium. All rights reserved.
10 See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmWin32ProcessExecution.h"
19 #include "cmSystemTools.h"
28 #if defined(__BORLANDC__)
29 # define STRICMP stricmp
30 # define TO_INTPTR(x) ((long)(x))
31 #else // Visual studio
32 # if ( _MSC_VER >= 1300 )
34 # define TO_INTPTR(x) ((intptr_t)(x))
35 # else // Visual Studio 6
36 # define TO_INTPTR(x) ((long)(x))
37 # endif // Visual studio .NET
38 # define STRICMP _stricmp
46 #define cmMAX(x,y) (((x)<(y))?(y):(x))
48 #define win32_error(x,y) std::cout << "Win32_Error(" << x << ", " << y << ")" << std::endl, false
51 void DisplayErrorMessage()
55 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
56 FORMAT_MESSAGE_FROM_SYSTEM
|
57 FORMAT_MESSAGE_IGNORE_INSERTS
,
60 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), // Default language
65 // Process any inserts in lpMsgBuf.
67 // Display the string.
68 MessageBox( NULL
, (LPCTSTR
)lpMsgBuf
, "Error", MB_OK
| MB_ICONINFORMATION
);
70 LocalFree( lpMsgBuf
);
73 // Code from a Borland web site with the following explaination :
74 /* In this article, I will explain how to spawn a console application
75 * and redirect its standard input/output using anonymous pipes. An
76 * anonymous pipe is a pipe that goes only in one direction (read
77 * pipe, write pipe, etc.). Maybe you are asking, "why would I ever
78 * need to do this sort of thing?" One example would be a Windows
79 * telnet server, where you spawn a shell and listen on a port and
80 * send and receive data between the shell and the socket
81 * client. (Windows does not really have a built-in remote
82 * shell). First, we should talk about pipes. A pipe in Windows is
83 * simply a method of communication, often between process. The SDK
84 * defines a pipe as "a communication conduit with two ends;
86 * with a handle to one end can communicate with a process having a
87 * handle to the other end." In our case, we are using "anonymous"
88 * pipes, one-way pipes that "transfer data between a parent process
89 * and a child process or between two child processes of the same
90 * parent process." It's easiest to imagine a pipe as its namesake. An
91 * actual pipe running between processes that can carry data. We are
92 * using anonymous pipes because the console app we are spawning is a
93 * child process. We use the CreatePipe function which will create an
94 * anonymous pipe and return a read handle and a write handle. We will
95 * create two pipes, on for stdin and one for stdout. We will then
96 * monitor the read end of the stdout pipe to check for display on our
97 * child process. Every time there is something availabe for reading,
98 * we will display it in our app. Consequently, we check for input in
99 * our app and send it off to the write end of the stdin pipe. */
101 inline bool IsWinNT()
102 //check if we're running NT
105 osv
.dwOSVersionInfoSize
= sizeof(osv
);
107 return (osv
.dwPlatformId
== VER_PLATFORM_WIN32_NT
);
110 //---------------------------------------------------------------------------
111 bool cmWin32ProcessExecution::BorlandRunCommand(
112 const char* command
, const char* dir
,
113 std::string
& output
, int& retVal
, bool verbose
, int /* timeout */)
116 //std::cerr << std::endl
117 // << "WindowsRunCommand(" << command << ")" << std::endl
119 const int BUFFER_SIZE
= 4096;
120 char buf
[BUFFER_SIZE
];
124 SECURITY_ATTRIBUTES sa
;
125 SECURITY_DESCRIPTOR sd
;
127 //security information for pipes
128 PROCESS_INFORMATION pi
;
129 HANDLE newstdin
,newstdout
,read_stdout
,write_stdin
;
133 //initialize security descriptor (Windows NT)
135 InitializeSecurityDescriptor(&sd
,SECURITY_DESCRIPTOR_REVISION
);
136 SetSecurityDescriptorDacl(&sd
, true, NULL
, false);
137 sa
.lpSecurityDescriptor
= &sd
;
140 else sa
.lpSecurityDescriptor
= NULL
;
141 sa
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
142 sa
.bInheritHandle
= true;
144 //allow inheritable handles
145 if (!CreatePipe(&newstdin
,&write_stdin
,&sa
,0))
148 std::cerr
<< "CreatePipe" << std::endl
;
152 if (!CreatePipe(&read_stdout
,&newstdout
,&sa
,0))
155 std::cerr
<< "CreatePipe" << std::endl
;
156 CloseHandle(newstdin
);
157 CloseHandle(write_stdin
);
163 //set startupinfo for the spawned process
164 /* The dwFlags member tells CreateProcess how to make the
165 * process. STARTF_USESTDHANDLES validates the hStd*
166 * members. STARTF_USESHOWWINDOW validates the wShowWindow
169 si
.cb
= sizeof(STARTUPINFO
);
170 si
.dwFlags
= STARTF_USESTDHANDLES
|STARTF_USESHOWWINDOW
;
171 si
.hStdOutput
= newstdout
;
172 si
.hStdError
= newstdout
;
173 si
.wShowWindow
= SW_HIDE
;
175 //set the new handles for the child process si.hStdInput = newstdin;
176 char* commandAndArgs
= strcpy(new char[strlen(command
)+1], command
);
177 if (!CreateProcess(NULL
,commandAndArgs
,NULL
,NULL
,TRUE
,CREATE_NEW_CONSOLE
,
180 std::cerr
<< "CreateProcess failed " << commandAndArgs
<< std::endl
;
181 CloseHandle(newstdin
);
182 CloseHandle(newstdout
);
183 CloseHandle(read_stdout
);
184 CloseHandle(write_stdin
);
185 delete [] commandAndArgs
;
189 delete [] commandAndArgs
;
190 unsigned long exit
=0;
192 //process exit code unsigned
195 //bytes read unsigned
199 memset(buf
, 0, sizeof(buf
));
204 //check to see if there is any data to read from stdout
205 //std::cout << "Peek for data..." << std::endl;
206 PeekNamedPipe(read_stdout
,buf
,1023,&bread
,&avail
,NULL
);
209 memset(buf
, 0, sizeof(buf
));
212 while (bread
>= 1023)
214 //std::cout << "Read data..." << std::endl;
215 ReadFile(read_stdout
,buf
,1023,&bread
,NULL
);
217 //read the stdout pipe
218 memset(buf
, 0, sizeof(buf
));
222 std::cout
<< buf
<< std::flush
;
228 ReadFile(read_stdout
,buf
,1023,&bread
,NULL
);
232 std::cout
<< buf
<< std::flush
;
239 //std::cout << "Check for process..." << std::endl;
240 GetExitCodeProcess(pi
.hProcess
,&exit
);
242 //while the process is running
243 if (exit
!= STILL_ACTIVE
) break;
246 WaitForSingleObject(pi
.hProcess
, INFINITE
);
247 GetExitCodeProcess(pi
.hProcess
,&exit
);
248 CloseHandle(pi
.hThread
);
249 CloseHandle(pi
.hProcess
);
250 CloseHandle(newstdin
);
253 CloseHandle(newstdout
);
254 CloseHandle(read_stdout
);
255 CloseHandle(write_stdin
);
261 bool cmWin32ProcessExecution::StartProcess(
262 const char* cmd
, const char* path
, bool verbose
)
265 this->m_Verbose
= verbose
;
266 return this->PrivateOpen(cmd
, path
, _O_RDONLY
| _O_TEXT
, POPEN_3
);
269 bool cmWin32ProcessExecution::Wait(int timeout
)
271 return this->PrivateClose(timeout
);
275 * Internal dictionary mapping popen* file pointers to process handles,
276 * for use when retrieving the process exit code. See _PyPclose() below
277 * for more information on this dictionary's use.
279 static void *_PyPopenProcs
= NULL
;
281 static BOOL
RealPopenCreateProcess(const char *cmdstring
,
283 const char *szConsoleSpawn
,
289 PROCESS_INFORMATION piProcInfo
;
290 STARTUPINFO siStartInfo
;
291 char *s1
,*s2
, *s3
= " /c ";
294 if (i
= GetEnvironmentVariable("COMSPEC",NULL
,0))
298 s1
= (char *)_alloca(i
);
299 if (!(x
= GetEnvironmentVariable("COMSPEC", s1
, i
)))
304 /* Explicitly check if we are using COMMAND.COM. If we are
305 * then use the w9xpopen hack.
308 while (comshell
>= s1
&& *comshell
!= '\\')
312 if (GetVersion() < 0x80000000 &&
313 STRICMP(comshell
, "command.com") != 0)
315 /* NT/2000 and not using command.com. */
316 x
= i
+ (int)strlen(s3
) + (int)strlen(cmdstring
) + 1;
317 s2
= (char *)_alloca(x
);
319 sprintf(s2
, "%s%s%s", s1
, s3
, cmdstring
);
324 * Oh gag, we're on Win9x or using COMMAND.COM. Use
325 * the workaround listed in KB: Q150956
327 char modulepath
[_MAX_PATH
];
328 struct stat statinfo
;
329 GetModuleFileName(NULL
, modulepath
, sizeof(modulepath
));
330 for (i
= x
= 0; modulepath
[i
]; i
++)
331 if (modulepath
[i
] == '\\')
333 modulepath
[x
] = '\0';
334 /* Create the full-name to w9xpopen, so we can test it exists */
337 (sizeof(modulepath
)/sizeof(modulepath
[0]))
338 -strlen(modulepath
));
339 if (stat(modulepath
, &statinfo
) != 0)
341 /* Eeek - file-not-found - possibly an embedding
342 situation - see if we can locate it in sys.prefix
346 sizeof(modulepath
)/sizeof(modulepath
[0]));
347 if (modulepath
[strlen(modulepath
)-1] != '\\')
348 strcat(modulepath
, "\\");
351 (sizeof(modulepath
)/sizeof(modulepath
[0]))
352 -strlen(modulepath
));
353 /* No where else to look - raise an easily identifiable
354 error, rather than leaving Windows to report
355 "file not found" - as the user is probably blissfully
356 unaware this shim EXE is used, and it will confuse them.
357 (well, it confused me for a while ;-)
359 if (stat(modulepath
, &statinfo
) != 0)
362 << "Can not locate '" << modulepath
363 << "' which is needed "
364 "for popen to work with your shell "
365 "or platform." << std::endl
;
369 x
= i
+ (int)strlen(s3
) + (int)strlen(cmdstring
) + 1 +
370 (int)strlen(modulepath
) +
371 (int)strlen(szConsoleSpawn
) + 1;
373 s2
= (char *)_alloca(x
);
390 /* Could be an else here to try cmd.exe / command.com in the path
391 Now we'll just error out.. */
394 std::cout
<< "Cannot locate a COMSPEC environment variable to "
395 << "use as the shell" << std::endl
;
399 ZeroMemory(&siStartInfo
, sizeof(STARTUPINFO
));
400 siStartInfo
.cb
= sizeof(STARTUPINFO
);
401 siStartInfo
.dwFlags
= STARTF_USESTDHANDLES
| STARTF_USESHOWWINDOW
;
402 siStartInfo
.hStdInput
= hStdin
;
403 siStartInfo
.hStdOutput
= hStdout
;
404 siStartInfo
.hStdError
= hStderr
;
405 siStartInfo
.wShowWindow
= SW_HIDE
;
407 if (CreateProcess(NULL
,
418 /* Close the handles now so anyone waiting is woken. */
419 CloseHandle(piProcInfo
.hThread
);
420 /* Return process handle */
421 *hProcess
= piProcInfo
.hProcess
;
422 //std::cout << "Process created..." << std::endl;
425 win32_error("CreateProcess", s2
);
429 /* The following code is based off of KB: Q190351 */
431 bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring
,
436 HANDLE hChildStdinRd
, hChildStdinWr
, hChildStdoutRd
, hChildStdoutWr
,
437 hChildStderrRd
, hChildStderrWr
, hChildStdinWrDup
, hChildStdoutRdDup
,
438 hChildStderrRdDup
, hProcess
; /* hChildStdoutWrDup; */
440 SECURITY_ATTRIBUTES saAttr
;
443 //FILE *f1, *f2, *f3;
445 saAttr
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
446 saAttr
.bInheritHandle
= TRUE
;
447 saAttr
.lpSecurityDescriptor
= NULL
;
449 if (!CreatePipe(&hChildStdinRd
, &hChildStdinWr
, &saAttr
, 0))
451 return win32_error("CreatePipe", NULL
);
454 /* Create new output read handle and the input write handle. Set
455 * the inheritance properties to FALSE. Otherwise, the child inherits
456 * the these handles; resulting in non-closeable handles to the pipes
458 fSuccess
= DuplicateHandle(GetCurrentProcess(), hChildStdinWr
,
459 GetCurrentProcess(), &hChildStdinWrDup
, 0,
461 DUPLICATE_SAME_ACCESS
);
463 return win32_error("DuplicateHandle", NULL
);
466 /* Close the inheritable version of ChildStdin
468 CloseHandle(hChildStdinWr
);
470 if (!CreatePipe(&hChildStdoutRd
, &hChildStdoutWr
, &saAttr
, 0))
471 return win32_error("CreatePipe", NULL
);
473 fSuccess
= DuplicateHandle(GetCurrentProcess(), hChildStdoutRd
,
474 GetCurrentProcess(), &hChildStdoutRdDup
, 0,
475 FALSE
, DUPLICATE_SAME_ACCESS
);
477 return win32_error("DuplicateHandle", NULL
);
479 /* Close the inheritable version of ChildStdout
481 CloseHandle(hChildStdoutRd
);
485 if (!CreatePipe(&hChildStderrRd
, &hChildStderrWr
, &saAttr
, 0))
486 return win32_error("CreatePipe", NULL
);
487 fSuccess
= DuplicateHandle(GetCurrentProcess(),
490 &hChildStderrRdDup
, 0,
491 FALSE
, DUPLICATE_SAME_ACCESS
);
493 return win32_error("DuplicateHandle", NULL
);
494 /* Close the inheritable version of ChildStdErr that we're using. */
495 CloseHandle(hChildStderrRd
);
502 switch (mode
& (_O_RDONLY
| _O_TEXT
| _O_BINARY
| _O_WRONLY
))
504 case _O_WRONLY
| _O_TEXT
:
505 /* Case for writing to child Stdin in text mode. */
506 fd1
= _open_osfhandle(TO_INTPTR(hChildStdinWrDup
), mode
);
507 //f1 = _fdopen(fd1, "w");
508 /* We don't care about these pipes anymore,
510 CloseHandle(hChildStdoutRdDup
);
511 CloseHandle(hChildStderrRdDup
);
514 case _O_RDONLY
| _O_TEXT
:
515 /* Case for reading from child Stdout in text mode. */
516 fd1
= _open_osfhandle(TO_INTPTR(hChildStdoutRdDup
), mode
);
517 //f1 = _fdopen(fd1, "r");
518 /* We don't care about these pipes anymore,
520 CloseHandle(hChildStdinWrDup
);
521 CloseHandle(hChildStderrRdDup
);
524 case _O_RDONLY
| _O_BINARY
:
525 /* Case for readinig from child Stdout in
527 fd1
= _open_osfhandle(TO_INTPTR(hChildStdoutRdDup
), mode
);
528 //f1 = _fdopen(fd1, "rb");
529 /* We don't care about these pipes anymore,
531 CloseHandle(hChildStdinWrDup
);
532 CloseHandle(hChildStderrRdDup
);
535 case _O_WRONLY
| _O_BINARY
:
536 /* Case for writing to child Stdin in binary mode. */
537 fd1
= _open_osfhandle(TO_INTPTR(hChildStdinWrDup
), mode
);
538 //f1 = _fdopen(fd1, "wb");
539 /* We don't care about these pipes anymore,
541 CloseHandle(hChildStdoutRdDup
);
542 CloseHandle(hChildStderrRdDup
);
551 // Comment this out. Maybe we will need it in the future.
552 // file IO access to the process might be cool.
555 //if (mode && _O_TEXT)
566 fd1
= _open_osfhandle(TO_INTPTR(hChildStdinWrDup
), mode
);
567 //f1 = _fdopen(fd1, m2);
568 fd2
= _open_osfhandle(TO_INTPTR(hChildStdoutRdDup
), mode
);
569 //f2 = _fdopen(fd2, m1);
573 CloseHandle(hChildStderrRdDup
);
582 // Comment this out. Maybe we will need it in the future.
583 // file IO access to the process might be cool.
586 //if (mode && _O_TEXT)
598 fd1
= _open_osfhandle(TO_INTPTR(hChildStdinWrDup
), mode
);
599 //f1 = _fdopen(fd1, m2);
600 fd2
= _open_osfhandle(TO_INTPTR(hChildStdoutRdDup
), mode
);
601 //f2 = _fdopen(fd2, m1);
602 fd3
= _open_osfhandle(TO_INTPTR(hChildStderrRdDup
), mode
);
603 //f3 = _fdopen(fd3, m1);
611 if (!RealPopenCreateProcess(cmdstring
,
613 this->m_ConsoleSpawn
.c_str(),
622 if (!RealPopenCreateProcess(cmdstring
,
624 this->m_ConsoleSpawn
.c_str(),
633 * Insert the files we've created into the process dictionary
634 * all referencing the list with the process handle and the
635 * initial number of files (see description below in _PyPclose).
636 * Since if _PyPclose later tried to wait on a process when all
637 * handles weren't closed, it could create a deadlock with the
638 * child, we spend some energy here to try to ensure that we
639 * either insert all file handles into the dictionary or none
640 * at all. It's a little clumsy with the various popen modes
641 * and variable number of files involved.
644 /* Child is launched. Close the parents copy of those pipe
645 * handles that only the child should have open. You need to
646 * make sure that no handles to the write end of the output pipe
647 * are maintained in this process or else the pipe will not close
648 * when the child process exits and the ReadFile will hang. */
650 if (!CloseHandle(hChildStdinRd
))
651 return win32_error("CloseHandle", NULL
);
653 if (!CloseHandle(hChildStdoutWr
))
654 return win32_error("CloseHandle", NULL
);
656 if ((n
!= 4) && (!CloseHandle(hChildStderrWr
)))
657 return win32_error("CloseHandle", NULL
);
659 this->m_ProcessHandle
= hProcess
;
662 // this->m_StdIn = f1;
663 this->m_pStdIn
= fd1
;
667 // this->m_StdOut = f2;
668 this->m_pStdOut
= fd2
;
672 // this->m_StdErr = f3;
673 this->m_pStdErr
= fd3
;
680 * Wrapper for fclose() to use for popen* files, so we can retrieve the
681 * exit code for the child process and return as a result of the close.
683 * This function uses the _PyPopenProcs dictionary in order to map the
684 * input file pointer to information about the process that was
685 * originally created by the popen* call that created the file pointer.
686 * The dictionary uses the file pointer as a key (with one entry
687 * inserted for each file returned by the original popen* call) and a
688 * single list object as the value for all files from a single call.
689 * The list object contains the Win32 process handle at [0], and a file
690 * count at [1], which is initialized to the total number of file
691 * handles using that list.
693 * This function closes whichever handle it is passed, and decrements
694 * the file count in the dictionary for the process handle pointed to
695 * by this file. On the last close (when the file count reaches zero),
696 * this function will wait for the child process and then return its
697 * exit code as the result of the close() operation. This permits the
698 * files to be closed in any order - it is always the close() of the
699 * final handle that will return the exit code.
702 /* RED_FLAG 31-Aug-2000 Tim
703 * This is always called (today!) between a pair of
704 * Py_BEGIN_ALLOW_THREADS/ Py_END_ALLOW_THREADS
705 * macros. So the thread running this has no valid thread state, as
706 * far as Python is concerned. However, this calls some Python API
707 * functions that cannot be called safely without a valid thread
708 * state, in particular PyDict_GetItem.
709 * As a temporary hack (although it may last for years ...), we
710 * *rely* on not having a valid thread state in this function, in
711 * order to create our own "from scratch".
712 * This will deadlock if _PyPclose is ever called by a thread
713 * holding the global lock.
716 bool cmWin32ProcessExecution::PrivateClose(int /* timeout */)
718 HANDLE hProcess
= this->m_ProcessHandle
;
723 std::string output
= "";
728 bool have_some
= false;
731 int rout
= _fstat(this->m_pStdOut
, &fsout
);
732 int rerr
= _fstat(this->m_pStdErr
, &fserr
);
737 if (fserr
.st_size
> 0)
740 int len
= read(this->m_pStdErr
, buffer
, 1023);
742 if ( this->m_Verbose
)
744 std::cout
<< buffer
<< std::flush
;
749 if (fsout
.st_size
> 0)
752 int len
= read(this->m_pStdOut
, buffer
, 1023);
754 if ( this->m_Verbose
)
756 std::cout
<< buffer
<< std::flush
;
761 unsigned long exitCode
;
764 GetExitCodeProcess(hProcess
,&exitCode
);
765 if (exitCode
!= STILL_ACTIVE
)
773 if (WaitForSingleObject(hProcess
, INFINITE
) != WAIT_FAILED
&&
774 GetExitCodeProcess(hProcess
, &exit_code
))
780 /* Indicate failure - this will cause the file object
781 * to raise an I/O error and translate the last Win32
782 * error code from errno. We do have a problem with
783 * last errors that overlap the normal errno table,
784 * but that's a consistent problem with the file object.
788 /* If the error wasn't from the fclose(), then
789 * set errno for the file object error handling.
791 errno
= GetLastError();
796 /* Free up the native handle at this point */
797 CloseHandle(hProcess
);
798 this->m_ExitValue
= result
;
799 this->m_Output
= output
;
807 int cmWin32ProcessExecution::Windows9xHack(const char* command
)
811 PROCESS_INFORMATION pi
;
816 cmSystemTools::Error("Windows9xHack: Command not specified");
820 /* Make child process use this app's standard files. */
821 ZeroMemory(&si
, sizeof si
);
823 si
.dwFlags
= STARTF_USESTDHANDLES
;
824 si
.hStdInput
= GetStdHandle(STD_INPUT_HANDLE
);
825 si
.hStdOutput
= GetStdHandle(STD_OUTPUT_HANDLE
);
826 si
.hStdError
= GetStdHandle(STD_ERROR_HANDLE
);
830 char* cmd
= new char[ strlen(command
) + 1 ];
831 strcpy(cmd
, command
);
833 bRet
= CreateProcess(
844 if (WaitForSingleObject(pi
.hProcess
, INFINITE
) != WAIT_FAILED
)
846 GetExitCodeProcess(pi
.hProcess
, &exit_code
);
848 CloseHandle(pi
.hProcess
);
849 CloseHandle(pi
.hThread
);