1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmWin32ProcessExecution.cxx,v $
6 Date: $Date: 2007/09/27 18:16:20 $
7 Version: $Revision: 1.32 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html 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"
27 #if defined(__BORLANDC__)
28 # define STRICMP stricmp
29 # define TO_INTPTR(x) ((long)(x))
30 #else // Visual studio
31 # if ( _MSC_VER >= 1300 )
33 # define TO_INTPTR(x) ((intptr_t)(x))
34 # else // Visual Studio 6
35 # define TO_INTPTR(x) ((long)(x))
36 # endif // Visual studio .NET
37 # define STRICMP _stricmp
45 #define cmMAX(x,y) (((x)<(y))?(y):(x))
47 void DisplayErrorMessage()
51 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
52 FORMAT_MESSAGE_FROM_SYSTEM
|
53 FORMAT_MESSAGE_IGNORE_INSERTS
,
56 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), // Default language
61 // Process any inserts in lpMsgBuf.
63 // Display the string.
64 MessageBox( NULL
, (LPCTSTR
)lpMsgBuf
, "Error", MB_OK
| MB_ICONINFORMATION
);
66 LocalFree( lpMsgBuf
);
69 // Code from a Borland web site with the following explaination :
70 /* In this article, I will explain how to spawn a console application
71 * and redirect its standard input/output using anonymous pipes. An
72 * anonymous pipe is a pipe that goes only in one direction (read
73 * pipe, write pipe, etc.). Maybe you are asking, "why would I ever
74 * need to do this sort of thing?" One example would be a Windows
75 * telnet server, where you spawn a shell and listen on a port and
76 * send and receive data between the shell and the socket
77 * client. (Windows does not really have a built-in remote
78 * shell). First, we should talk about pipes. A pipe in Windows is
79 * simply a method of communication, often between process. The SDK
80 * defines a pipe as "a communication conduit with two ends;
82 * with a handle to one end can communicate with a process having a
83 * handle to the other end." In our case, we are using "anonymous"
84 * pipes, one-way pipes that "transfer data between a parent process
85 * and a child process or between two child processes of the same
86 * parent process." It's easiest to imagine a pipe as its namesake. An
87 * actual pipe running between processes that can carry data. We are
88 * using anonymous pipes because the console app we are spawning is a
89 * child process. We use the CreatePipe function which will create an
90 * anonymous pipe and return a read handle and a write handle. We will
91 * create two pipes, on for stdin and one for stdout. We will then
92 * monitor the read end of the stdout pipe to check for display on our
93 * child process. Every time there is something availabe for reading,
94 * we will display it in our app. Consequently, we check for input in
95 * our app and send it off to the write end of the stdin pipe. */
98 //check if we're running NT
101 osv
.dwOSVersionInfoSize
= sizeof(osv
);
103 return (osv
.dwPlatformId
== VER_PLATFORM_WIN32_NT
);
106 //---------------------------------------------------------------------------
107 bool cmWin32ProcessExecution::BorlandRunCommand(
108 const char* command
, const char* dir
,
109 std::string
& output
, int& retVal
, bool verbose
, int /* timeout */,
113 //std::cerr << std::endl
114 // << "WindowsRunCommand(" << command << ")" << std::endl
116 const int BUFFER_SIZE
= 4096;
117 char buf
[BUFFER_SIZE
];
121 SECURITY_ATTRIBUTES sa
;
122 SECURITY_DESCRIPTOR sd
;
124 //security information for pipes
125 PROCESS_INFORMATION pi
;
126 HANDLE newstdin
,newstdout
,read_stdout
,write_stdin
;
130 //initialize security descriptor (Windows NT)
132 InitializeSecurityDescriptor(&sd
,SECURITY_DESCRIPTOR_REVISION
);
133 SetSecurityDescriptorDacl(&sd
, true, NULL
, false);
134 sa
.lpSecurityDescriptor
= &sd
;
137 else sa
.lpSecurityDescriptor
= NULL
;
138 sa
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
139 sa
.bInheritHandle
= true;
141 //allow inheritable handles
142 if (!CreatePipe(&newstdin
,&write_stdin
,&sa
,0))
147 if (!CreatePipe(&read_stdout
,&newstdout
,&sa
,0))
150 CloseHandle(newstdin
);
151 CloseHandle(write_stdin
);
157 //set startupinfo for the spawned process
158 /* The dwFlags member tells CreateProcess how to make the
159 * process. STARTF_USESTDHANDLES validates the hStd*
160 * members. STARTF_USESHOWWINDOW validates the wShowWindow
163 si
.cb
= sizeof(STARTUPINFO
);
164 si
.dwFlags
= STARTF_USESTDHANDLES
|STARTF_USESHOWWINDOW
;
165 si
.hStdOutput
= newstdout
;
166 si
.hStdError
= newstdout
;
167 si
.wShowWindow
= SW_SHOWDEFAULT
;
170 si
.wShowWindow
= SW_HIDE
;
173 //set the new handles for the child process si.hStdInput = newstdin;
174 char* commandAndArgs
= strcpy(new char[strlen(command
)+1], command
);
175 if (!CreateProcess(NULL
,commandAndArgs
,NULL
,NULL
,TRUE
,
176 0, // CREATE_NEW_CONSOLE,
179 std::cerr
<< "CreateProcess failed " << commandAndArgs
<< std::endl
;
180 CloseHandle(newstdin
);
181 CloseHandle(newstdout
);
182 CloseHandle(read_stdout
);
183 CloseHandle(write_stdin
);
184 delete [] commandAndArgs
;
188 delete [] commandAndArgs
;
189 unsigned long exit
=0;
191 //process exit code unsigned
194 //bytes read unsigned
198 memset(buf
, 0, sizeof(buf
));
203 //check to see if there is any data to read from stdout
204 //std::cout << "Peek for data..." << std::endl;
205 PeekNamedPipe(read_stdout
,buf
,1023,&bread
,&avail
,NULL
);
208 memset(buf
, 0, sizeof(buf
));
211 while (bread
>= 1023)
213 //std::cout << "Read data..." << std::endl;
214 ReadFile(read_stdout
,buf
,1023,&bread
,NULL
);
216 //read the stdout pipe
217 memset(buf
, 0, sizeof(buf
));
221 cmSystemTools::Stdout(buf
);
227 ReadFile(read_stdout
,buf
,1023,&bread
,NULL
);
231 cmSystemTools::Stdout(buf
);
238 //std::cout << "Check for process..." << std::endl;
239 GetExitCodeProcess(pi
.hProcess
,&exit
);
241 //while the process is running
242 if (exit
!= STILL_ACTIVE
) break;
245 WaitForSingleObject(pi
.hProcess
, INFINITE
);
246 GetExitCodeProcess(pi
.hProcess
,&exit
);
247 CloseHandle(pi
.hThread
);
248 CloseHandle(pi
.hProcess
);
249 CloseHandle(newstdin
);
252 CloseHandle(newstdout
);
253 CloseHandle(read_stdout
);
254 CloseHandle(write_stdin
);
260 bool cmWin32ProcessExecution::StartProcess(
261 const char* cmd
, const char* path
, bool verbose
)
264 this->Verbose
= verbose
;
265 return this->PrivateOpen(cmd
, path
, _O_RDONLY
| _O_TEXT
, POPEN_3
);
268 bool cmWin32ProcessExecution::Wait(int timeout
)
270 return this->PrivateClose(timeout
);
274 * Internal dictionary mapping popen* file pointers to process handles,
275 * for use when retrieving the process exit code. See _PyPclose() below
276 * for more information on this dictionary's use.
278 static void *_PyPopenProcs
= NULL
;
280 static BOOL
RealPopenCreateProcess(const char *cmdstring
,
282 const char *szConsoleSpawn
,
290 PROCESS_INFORMATION piProcInfo
;
291 STARTUPINFO siStartInfo
;
292 char *s1
=0,*s2
=0, *s3
= " /c ";
293 int i
= GetEnvironmentVariable("COMSPEC",NULL
,0);
298 s1
= (char *)malloc(i
);
299 int x
= GetEnvironmentVariable("COMSPEC", s1
, i
);
306 /* Explicitly check if we are using COMMAND.COM. If we are
307 * then use the w9xpopen hack.
310 while (comshell
>= s1
&& *comshell
!= '\\')
314 if (GetVersion() < 0x80000000 &&
315 STRICMP(comshell
, "command.com") != 0)
317 /* NT/2000 and not using command.com. */
318 x
= i
+ (int)strlen(s3
) + (int)strlen(cmdstring
) + 1;
319 s2
= (char *)malloc(x
);
321 //sprintf(s2, "%s%s%s", s1, s3, cmdstring);
322 sprintf(s2
, "%s", cmdstring
);
327 * Oh gag, we're on Win9x or using COMMAND.COM. Use
328 * the workaround listed in KB: Q150956
330 char modulepath
[_MAX_PATH
];
331 struct stat statinfo
;
332 GetModuleFileName(NULL
, modulepath
, sizeof(modulepath
));
333 for (i
= x
= 0; modulepath
[i
]; i
++)
334 if (modulepath
[i
] == '\\')
336 modulepath
[x
] = '\0';
337 /* Create the full-name to w9xpopen, so we can test it exists */
340 (sizeof(modulepath
)/sizeof(modulepath
[0]))
341 -strlen(modulepath
));
342 if (stat(modulepath
, &statinfo
) != 0)
344 /* Eeek - file-not-found - possibly an embedding
345 situation - see if we can locate it in sys.prefix
349 sizeof(modulepath
)/sizeof(modulepath
[0]));
350 if (modulepath
[strlen(modulepath
)-1] != '\\')
351 strcat(modulepath
, "\\");
354 (sizeof(modulepath
)/sizeof(modulepath
[0]))
355 -strlen(modulepath
));
356 /* No where else to look - raise an easily identifiable
357 error, rather than leaving Windows to report
358 "file not found" - as the user is probably blissfully
359 unaware this shim EXE is used, and it will confuse them.
360 (well, it confused me for a while ;-)
362 if (stat(modulepath
, &statinfo
) != 0)
365 << "Can not locate '" << modulepath
366 << "' which is needed "
367 "for popen to work with your shell "
368 "or platform." << std::endl
;
374 x
= i
+ (int)strlen(s3
) + (int)strlen(cmdstring
) + 1 +
375 (int)strlen(modulepath
) +
376 (int)strlen(szConsoleSpawn
) + 1;
381 s2
= (char *)malloc(x
);
398 /* Could be an else here to try cmd.exe / command.com in the path
399 Now we'll just error out.. */
402 std::cout
<< "Cannot locate a COMSPEC environment variable to "
403 << "use as the shell" << std::endl
;
409 ZeroMemory(&siStartInfo
, sizeof(STARTUPINFO
));
410 siStartInfo
.cb
= sizeof(STARTUPINFO
);
411 siStartInfo
.dwFlags
= STARTF_USESTDHANDLES
| STARTF_USESHOWWINDOW
;
412 siStartInfo
.hStdInput
= hStdin
;
413 siStartInfo
.hStdOutput
= hStdout
;
414 siStartInfo
.hStdError
= hStderr
;
415 siStartInfo
.wShowWindow
= SW_SHOWDEFAULT
;
418 siStartInfo
.wShowWindow
= SW_HIDE
;
421 //std::cout << "Create process: " << s2 << std::endl;
422 if (CreateProcess(NULL
,
427 0, //CREATE_NEW_CONSOLE,
433 /* Close the handles now so anyone waiting is woken. */
434 CloseHandle(piProcInfo
.hThread
);
435 /* Return process handle */
436 *hProcess
= piProcInfo
.hProcess
;
437 //std::cout << "Process created..." << std::endl;
443 output
+= "CreateProcessError: ";
445 /* Format the error message. */
447 DWORD original
= GetLastError();
448 DWORD length
= FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
|
449 FORMAT_MESSAGE_IGNORE_INSERTS
, 0, original
,
450 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
454 /* FormatMessage failed. Use a default message. */
455 _snprintf(message
, 1023,
456 "Process execution failed with error 0x%X. "
457 "FormatMessage failed with error 0x%X",
458 original
, GetLastError());
463 output
+= "for command: ";
467 output
+= "\nin dir: ";
476 /* The following code is based off of KB: Q190351 */
478 bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring
,
485 SECURITY_ATTRIBUTES saAttr
;
488 this->hChildStdinRd
= 0;
489 this->hChildStdinWr
= 0;
490 this->hChildStdoutRd
= 0;
491 this->hChildStdoutWr
= 0;
492 this->hChildStderrRd
= 0;
493 this->hChildStderrWr
= 0;
494 this->hChildStdinWrDup
= 0;
495 this->hChildStdoutRdDup
= 0;
496 this->hChildStderrRdDup
= 0;
498 saAttr
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
499 saAttr
.bInheritHandle
= TRUE
;
500 saAttr
.lpSecurityDescriptor
= NULL
;
506 if (!CreatePipe(&this->hChildStdinRd
, &this->hChildStdinWr
, &saAttr
, 0))
508 this->Output
+= "CreatePipeError\n";
512 /* Create new output read handle and the input write handle. Set
513 * the inheritance properties to FALSE. Otherwise, the child inherits
514 * the these handles; resulting in non-closeable handles to the pipes
516 fSuccess
= DuplicateHandle(GetCurrentProcess(), this->hChildStdinWr
,
517 GetCurrentProcess(), &this->hChildStdinWrDup
, 0,
519 DUPLICATE_SAME_ACCESS
);
522 this->Output
+= "DuplicateHandleError\n";
527 /* Close the inheritable version of ChildStdin
529 CloseHandle(hChildStdinWr
);
531 if (!CreatePipe(&this->hChildStdoutRd
, &this->hChildStdoutWr
, &saAttr
, 0))
533 this->Output
+= "CreatePipeError\n";
537 fSuccess
= DuplicateHandle(GetCurrentProcess(), this->hChildStdoutRd
,
538 GetCurrentProcess(), &this->hChildStdoutRdDup
, 0,
539 FALSE
, DUPLICATE_SAME_ACCESS
);
542 this->Output
+= "DuplicateHandleError\n";
546 /* Close the inheritable version of ChildStdout
548 CloseHandle(hChildStdoutRd
);
552 if (!CreatePipe(&this->hChildStderrRd
, &this->hChildStderrWr
, &saAttr
, 0))
554 this->Output
+= "CreatePipeError\n";
557 fSuccess
= DuplicateHandle(GetCurrentProcess(),
558 this->hChildStderrRd
,
560 &this->hChildStderrRdDup
, 0,
561 FALSE
, DUPLICATE_SAME_ACCESS
);
564 this->Output
+= "DuplicateHandleError\n";
567 /* Close the inheritable version of ChildStdErr that we're using. */
568 CloseHandle(hChildStderrRd
);
575 switch (mode
& (_O_RDONLY
| _O_TEXT
| _O_BINARY
| _O_WRONLY
))
577 case _O_WRONLY
| _O_TEXT
:
578 /* Case for writing to child Stdin in text mode. */
579 fd1
= _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup
), mode
);
580 /* We don't care about these pipes anymore,
584 case _O_RDONLY
| _O_TEXT
:
585 /* Case for reading from child Stdout in text mode. */
586 fd1
= _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup
), mode
);
587 /* We don't care about these pipes anymore,
591 case _O_RDONLY
| _O_BINARY
:
592 /* Case for readinig from child Stdout in
594 fd1
= _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup
), mode
);
595 /* We don't care about these pipes anymore,
599 case _O_WRONLY
| _O_BINARY
:
600 /* Case for writing to child Stdin in binary mode. */
601 fd1
= _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup
), mode
);
602 /* We don't care about these pipes anymore,
612 fd1
= _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup
), mode
);
613 fd2
= _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup
), mode
);
620 fd1
= _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup
), mode
);
621 fd2
= _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup
), mode
);
622 fd3
= _open_osfhandle(TO_INTPTR(this->hChildStderrRdDup
), mode
);
629 if (!RealPopenCreateProcess(cmdstring
,
631 this->ConsoleSpawn
.c_str(),
633 this->hChildStdoutWr
,
634 this->hChildStdoutWr
,
635 &hProcess
, this->HideWindows
,
655 if (!RealPopenCreateProcess(cmdstring
,
657 this->ConsoleSpawn
.c_str(),
659 this->hChildStdoutWr
,
660 this->hChildStderrWr
,
661 &hProcess
, this->HideWindows
,
681 * Insert the files we've created into the process dictionary
682 * all referencing the list with the process handle and the
683 * initial number of files (see description below in _PyPclose).
684 * Since if _PyPclose later tried to wait on a process when all
685 * handles weren't closed, it could create a deadlock with the
686 * child, we spend some energy here to try to ensure that we
687 * either insert all file handles into the dictionary or none
688 * at all. It's a little clumsy with the various popen modes
689 * and variable number of files involved.
692 /* Child is launched. Close the parents copy of those pipe
693 * handles that only the child should have open. You need to
694 * make sure that no handles to the write end of the output pipe
695 * are maintained in this process or else the pipe will not close
696 * when the child process exits and the ReadFile will hang. */
697 this->ProcessHandle
= hProcess
;
714 bool cmWin32ProcessExecution::CloseHandles()
716 if(this->pStdErr
!= -1 )
718 _close(this->pStdErr
);
721 if(this->pStdIn
!= -1 )
723 _close(this->pStdIn
);
726 if(this->pStdOut
!= -1 )
728 _close(this->pStdOut
);
733 if (this->hChildStdinRd
&& !CloseHandle(this->hChildStdinRd
))
737 this->hChildStdinRd
= 0;
738 if(this->hChildStdoutRdDup
&& !CloseHandle(this->hChildStdoutRdDup
))
742 this->hChildStdoutRdDup
= 0;
743 if(this->hChildStderrRdDup
&& !CloseHandle(this->hChildStderrRdDup
))
747 this->hChildStderrRdDup
= 0;
748 if(this->hChildStdinWrDup
&& !CloseHandle(this->hChildStdinWrDup
))
752 this->hChildStdinWrDup
= 0;
753 if (this->hChildStdoutWr
&& !CloseHandle(this->hChildStdoutWr
))
757 this->hChildStdoutWr
= 0;
758 if (this->hChildStderrWr
&& !CloseHandle(this->hChildStderrWr
))
762 this->hChildStderrWr
= 0;
765 cmWin32ProcessExecution::~cmWin32ProcessExecution()
767 this->CloseHandles();
771 * Wrapper for fclose() to use for popen* files, so we can retrieve the
772 * exit code for the child process and return as a result of the close.
774 * This function uses the _PyPopenProcs dictionary in order to map the
775 * input file pointer to information about the process that was
776 * originally created by the popen* call that created the file pointer.
777 * The dictionary uses the file pointer as a key (with one entry
778 * inserted for each file returned by the original popen* call) and a
779 * single list object as the value for all files from a single call.
780 * The list object contains the Win32 process handle at [0], and a file
781 * count at [1], which is initialized to the total number of file
782 * handles using that list.
784 * This function closes whichever handle it is passed, and decrements
785 * the file count in the dictionary for the process handle pointed to
786 * by this file. On the last close (when the file count reaches zero),
787 * this function will wait for the child process and then return its
788 * exit code as the result of the close() operation. This permits the
789 * files to be closed in any order - it is always the close() of the
790 * final handle that will return the exit code.
793 /* RED_FLAG 31-Aug-2000 Tim
794 * This is always called (today!) between a pair of
795 * Py_BEGIN_ALLOW_THREADS/ Py_END_ALLOW_THREADS
796 * macros. So the thread running this has no valid thread state, as
797 * far as Python is concerned. However, this calls some Python API
798 * functions that cannot be called safely without a valid thread
799 * state, in particular PyDict_GetItem.
800 * As a temporary hack (although it may last for years ...), we
801 * *rely* on not having a valid thread state in this function, in
802 * order to create our own "from scratch".
803 * This will deadlock if _PyPclose is ever called by a thread
804 * holding the global lock.
807 bool cmWin32ProcessExecution::PrivateClose(int /* timeout */)
809 HANDLE hProcess
= this->ProcessHandle
;
814 std::string output
= "";
819 bool have_some
= false;
822 int rout
= _fstat(this->pStdOut
, &fsout
);
823 int rerr
= _fstat(this->pStdErr
, &fserr
);
828 if (fserr
.st_size
> 0)
831 int len
= read(this->pStdErr
, buffer
, 1023);
835 cmSystemTools::Stdout(buffer
);
840 if (fsout
.st_size
> 0)
843 int len
= read(this->pStdOut
, buffer
, 1023);
847 cmSystemTools::Stdout(buffer
);
852 unsigned long exitCode
;
855 GetExitCodeProcess(hProcess
,&exitCode
);
856 if (exitCode
!= STILL_ACTIVE
)
864 if (WaitForSingleObject(hProcess
, INFINITE
) != WAIT_FAILED
&&
865 GetExitCodeProcess(hProcess
, &exit_code
))
871 /* Indicate failure - this will cause the file object
872 * to raise an I/O error and translate the last Win32
873 * error code from errno. We do have a problem with
874 * last errors that overlap the normal errno table,
875 * but that's a consistent problem with the file object.
879 /* If the error wasn't from the fclose(), then
880 * set errno for the file object error handling.
882 errno
= GetLastError();
887 /* Free up the native handle at this point */
888 CloseHandle(hProcess
);
889 this->ExitValue
= result
;
890 this->Output
+= output
;
891 bool ret
= this->CloseHandles();
892 if ( result
< 0 || !ret
)
899 int cmWin32ProcessExecution::Windows9xHack(const char* command
)
903 PROCESS_INFORMATION pi
;
908 cmSystemTools::Error("Windows9xHack: Command not specified");
912 /* Make child process use this app's standard files. */
913 ZeroMemory(&si
, sizeof si
);
915 si
.dwFlags
= STARTF_USESTDHANDLES
;
916 si
.hStdInput
= GetStdHandle(STD_INPUT_HANDLE
);
917 si
.hStdOutput
= GetStdHandle(STD_OUTPUT_HANDLE
);
918 si
.hStdError
= GetStdHandle(STD_ERROR_HANDLE
);
922 char* cmd
= new char[ strlen(command
) + 1 ];
923 strcpy(cmd
, command
);
925 bRet
= CreateProcess(
936 if (WaitForSingleObject(pi
.hProcess
, INFINITE
) != WAIT_FAILED
)
938 GetExitCodeProcess(pi
.hProcess
, &exit_code
);
940 CloseHandle(pi
.hProcess
);
941 CloseHandle(pi
.hThread
);