ENH: make sure CTEST_CURL_OPTIONS work from script mode
[cmake.git] / Source / cmWin32ProcessExecution.cxx
blobfd4032af8624aec42da2e5b721b4e8236c3b3b03
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmWin32ProcessExecution.cxx,v $
5 Language: C++
6 Date: $Date: 2008-09-04 21:02:25 $
7 Version: $Revision: 1.33 $
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"
21 #include <malloc.h>
22 #include <io.h>
23 #include <fcntl.h>
24 #include <sys/stat.h>
25 #include <windows.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 )
32 # include <stddef.h>
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
38 #endif // Borland
40 #define POPEN_1 1
41 #define POPEN_2 2
42 #define POPEN_3 3
43 #define POPEN_4 4
45 #define cmMAX(x,y) (((x)<(y))?(y):(x))
47 void DisplayErrorMessage()
49 LPVOID lpMsgBuf;
50 FormatMessage(
51 FORMAT_MESSAGE_ALLOCATE_BUFFER |
52 FORMAT_MESSAGE_FROM_SYSTEM |
53 FORMAT_MESSAGE_IGNORE_INSERTS,
54 NULL,
55 GetLastError(),
56 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
57 (LPTSTR) &lpMsgBuf,
59 NULL
61 // Process any inserts in lpMsgBuf.
62 // ...
63 // Display the string.
64 MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
65 // Free the buffer.
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;
81 a process
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. */
97 inline bool IsWinNT()
98 //check if we're running NT
100 OSVERSIONINFO osv;
101 osv.dwOSVersionInfoSize = sizeof(osv);
102 GetVersionEx(&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 */,
110 bool hideWindows)
112 //verbose = true;
113 //std::cerr << std::endl
114 // << "WindowsRunCommand(" << command << ")" << std::endl
115 // << std::flush;
116 const int BUFFER_SIZE = 4096;
117 char buf[BUFFER_SIZE];
119 //i/o buffer
120 STARTUPINFO si;
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;
128 //pipe handles
129 if (IsWinNT())
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))
143 //create stdin pipe
145 return false;
147 if (!CreatePipe(&read_stdout,&newstdout,&sa,0))
148 //create stdout pipe
150 CloseHandle(newstdin);
151 CloseHandle(write_stdin);
152 return false;
155 GetStartupInfo(&si);
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
161 * member. */
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;
168 if(hideWindows)
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,
177 NULL,dir,&si,&pi))
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;
185 return false;
188 delete [] commandAndArgs;
189 unsigned long exit=0;
191 //process exit code unsigned
192 unsigned long bread;
194 //bytes read unsigned
195 unsigned long avail;
197 //bytes available
198 memset(buf, 0, sizeof(buf));
199 for(;;)
200 //main program loop
202 Sleep(10);
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);
206 if (bread != 0)
208 memset(buf, 0, sizeof(buf));
209 if (avail > 1023)
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));
218 output += buf;
219 if (verbose)
221 cmSystemTools::Stdout(buf);
225 else
227 ReadFile(read_stdout,buf,1023,&bread,NULL);
228 output += buf;
229 if(verbose)
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);
251 //clean stuff up
252 CloseHandle(newstdout);
253 CloseHandle(read_stdout);
254 CloseHandle(write_stdin);
255 retVal = exit;
256 return true;
260 bool cmWin32ProcessExecution::StartProcess(
261 const char* cmd, const char* path, bool verbose)
263 this->Initialize();
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,
281 const char *path,
282 const char *szConsoleSpawn,
283 HANDLE hStdin,
284 HANDLE hStdout,
285 HANDLE hStderr,
286 HANDLE *hProcess,
287 bool hideWindows,
288 std::string& output)
290 PROCESS_INFORMATION piProcInfo;
291 STARTUPINFO siStartInfo;
292 char *s1=0,*s2=0, *s3 = " /c ";
293 int i = GetEnvironmentVariable("COMSPEC",NULL,0);
294 if (i)
296 char *comshell;
298 s1 = (char *)malloc(i);
299 int x = GetEnvironmentVariable("COMSPEC", s1, i);
300 if (!x)
302 free(s1);
303 return x;
306 /* Explicitly check if we are using COMMAND.COM. If we are
307 * then use the w9xpopen hack.
309 comshell = s1 + x;
310 while (comshell >= s1 && *comshell != '\\')
311 --comshell;
312 ++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);
320 ZeroMemory(s2, x);
321 //sprintf(s2, "%s%s%s", s1, s3, cmdstring);
322 sprintf(s2, "%s", cmdstring);
324 else
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] == '\\')
335 x = i+1;
336 modulepath[x] = '\0';
337 /* Create the full-name to w9xpopen, so we can test it exists */
338 strncat(modulepath,
339 szConsoleSpawn,
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
347 strncpy(modulepath,
348 ".",
349 sizeof(modulepath)/sizeof(modulepath[0]));
350 if (modulepath[strlen(modulepath)-1] != '\\')
351 strcat(modulepath, "\\");
352 strncat(modulepath,
353 szConsoleSpawn,
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)
364 std::cout
365 << "Can not locate '" << modulepath
366 << "' which is needed "
367 "for popen to work with your shell "
368 "or platform." << std::endl;
369 free(s1);
370 free(s2);
371 return FALSE;
374 x = i + (int)strlen(s3) + (int)strlen(cmdstring) + 1 +
375 (int)strlen(modulepath) +
376 (int)strlen(szConsoleSpawn) + 1;
377 if(s2)
379 free(s2);
381 s2 = (char *)malloc(x);
382 ZeroMemory(s2, x);
383 sprintf(
385 "%s %s%s%s",
386 modulepath,
389 cmdstring);
390 sprintf(
392 "%s %s",
393 modulepath,
394 cmdstring);
398 /* Could be an else here to try cmd.exe / command.com in the path
399 Now we'll just error out.. */
400 else
402 std::cout << "Cannot locate a COMSPEC environment variable to "
403 << "use as the shell" << std::endl;
404 free(s2);
405 free(s1);
406 return FALSE;
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;
416 if(hideWindows)
418 siStartInfo.wShowWindow = SW_HIDE;
421 //std::cout << "Create process: " << s2 << std::endl;
422 if (CreateProcess(NULL,
424 NULL,
425 NULL,
426 TRUE,
427 0, //CREATE_NEW_CONSOLE,
428 NULL,
429 path,
430 &siStartInfo,
431 &piProcInfo) )
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;
438 free(s2);
439 free(s1);
440 return TRUE;
443 output += "CreateProcessError: ";
445 /* Format the error message. */
446 char message[1024];
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),
451 message, 1023, 0);
452 if(length < 1)
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());
460 output += message;
462 output += "\n";
463 output += "for command: ";
464 output += s2;
465 if(path)
467 output += "\nin dir: ";
468 output += path;
470 output += "\n";
471 free(s2);
472 free(s1);
473 return FALSE;
476 /* The following code is based off of KB: Q190351 */
478 bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring,
479 const char* path,
480 int mode,
481 int n)
483 HANDLE hProcess;
485 SECURITY_ATTRIBUTES saAttr;
486 BOOL fSuccess;
487 int fd1, fd2, fd3;
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;
502 fd1 = 0;
503 fd2 = 0;
504 fd3 = 0;
506 if (!CreatePipe(&this->hChildStdinRd, &this->hChildStdinWr, &saAttr, 0))
508 this->Output += "CreatePipeError\n";
509 return false;
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
515 * being created. */
516 fSuccess = DuplicateHandle(GetCurrentProcess(), this->hChildStdinWr,
517 GetCurrentProcess(), &this->hChildStdinWrDup, 0,
518 FALSE,
519 DUPLICATE_SAME_ACCESS);
520 if (!fSuccess)
522 this->Output += "DuplicateHandleError\n";
523 return false;
527 /* Close the inheritable version of ChildStdin
528 that we're using. */
529 CloseHandle(hChildStdinWr);
531 if (!CreatePipe(&this->hChildStdoutRd, &this->hChildStdoutWr, &saAttr, 0))
533 this->Output += "CreatePipeError\n";
534 return false;
537 fSuccess = DuplicateHandle(GetCurrentProcess(), this->hChildStdoutRd,
538 GetCurrentProcess(), &this->hChildStdoutRdDup, 0,
539 FALSE, DUPLICATE_SAME_ACCESS);
540 if (!fSuccess)
542 this->Output += "DuplicateHandleError\n";
543 return false;
546 /* Close the inheritable version of ChildStdout
547 that we're using. */
548 CloseHandle(hChildStdoutRd);
550 if (n != POPEN_4)
552 if (!CreatePipe(&this->hChildStderrRd, &this->hChildStderrWr, &saAttr, 0))
554 this->Output += "CreatePipeError\n";
555 return false;
557 fSuccess = DuplicateHandle(GetCurrentProcess(),
558 this->hChildStderrRd,
559 GetCurrentProcess(),
560 &this->hChildStderrRdDup, 0,
561 FALSE, DUPLICATE_SAME_ACCESS);
562 if (!fSuccess)
564 this->Output += "DuplicateHandleError\n";
565 return false;
567 /* Close the inheritable version of ChildStdErr that we're using. */
568 CloseHandle(hChildStderrRd);
572 switch (n)
574 case POPEN_1:
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,
581 so close them. */
582 break;
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,
588 so close them. */
589 break;
591 case _O_RDONLY | _O_BINARY:
592 /* Case for readinig from child Stdout in
593 binary mode. */
594 fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup), mode);
595 /* We don't care about these pipes anymore,
596 so close them. */
597 break;
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,
603 so close them. */
604 break;
606 break;
608 case POPEN_2:
609 case POPEN_4:
610 //if ( 1 )
612 fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup), mode);
613 fd2 = _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup), mode);
614 break;
617 case POPEN_3:
618 //if ( 1)
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);
623 break;
627 if (n == POPEN_4)
629 if (!RealPopenCreateProcess(cmdstring,
630 path,
631 this->ConsoleSpawn.c_str(),
632 this->hChildStdinRd,
633 this->hChildStdoutWr,
634 this->hChildStdoutWr,
635 &hProcess, this->HideWindows,
636 this->Output))
638 if(fd1 >= 0)
640 close(fd1);
642 if(fd2 >= 0)
644 close(fd2);
646 if(fd3 >= 0)
648 close(fd3);
650 return 0;
653 else
655 if (!RealPopenCreateProcess(cmdstring,
656 path,
657 this->ConsoleSpawn.c_str(),
658 this->hChildStdinRd,
659 this->hChildStdoutWr,
660 this->hChildStderrWr,
661 &hProcess, this->HideWindows,
662 this->Output))
664 if(fd1 >= 0)
666 close(fd1);
668 if(fd2 >= 0)
670 close(fd2);
672 if(fd3 >= 0)
674 close(fd3);
676 return 0;
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;
698 if ( fd1 >= 0 )
700 this->pStdIn = fd1;
702 if ( fd2 >= 0 )
704 this->pStdOut = fd2;
706 if ( fd3 >= 0 )
708 this->pStdErr = fd3;
711 return true;
714 bool cmWin32ProcessExecution::CloseHandles()
716 if(this->pStdErr != -1 )
718 // this will close this as well: this->hChildStderrRdDup
719 _close(this->pStdErr);
720 this->pStdErr = -1;
721 this->hChildStderrRdDup = 0;
723 if(this->pStdIn != -1 )
725 // this will close this as well: this->hChildStdinWrDup
726 _close(this->pStdIn);
727 this->pStdIn = -1;
728 this->hChildStdinWrDup = 0;
730 if(this->pStdOut != -1 )
732 // this will close this as well: this->hChildStdoutRdDup
733 _close(this->pStdOut);
734 this->pStdOut = -1;
735 this->hChildStdoutRdDup = 0;
738 bool ret = true;
739 if (this->hChildStdinRd && !CloseHandle(this->hChildStdinRd))
741 ret = false;
743 this->hChildStdinRd = 0;
744 // now close these two
745 if (this->hChildStdoutWr && !CloseHandle(this->hChildStdoutWr))
747 ret = false;
749 this->hChildStdoutWr = 0;
750 if (this->hChildStderrWr && !CloseHandle(this->hChildStderrWr))
752 ret = false;
754 this->hChildStderrWr = 0;
755 return ret;
757 cmWin32ProcessExecution::~cmWin32ProcessExecution()
759 this->CloseHandles();
763 * Wrapper for fclose() to use for popen* files, so we can retrieve the
764 * exit code for the child process and return as a result of the close.
766 * This function uses the _PyPopenProcs dictionary in order to map the
767 * input file pointer to information about the process that was
768 * originally created by the popen* call that created the file pointer.
769 * The dictionary uses the file pointer as a key (with one entry
770 * inserted for each file returned by the original popen* call) and a
771 * single list object as the value for all files from a single call.
772 * The list object contains the Win32 process handle at [0], and a file
773 * count at [1], which is initialized to the total number of file
774 * handles using that list.
776 * This function closes whichever handle it is passed, and decrements
777 * the file count in the dictionary for the process handle pointed to
778 * by this file. On the last close (when the file count reaches zero),
779 * this function will wait for the child process and then return its
780 * exit code as the result of the close() operation. This permits the
781 * files to be closed in any order - it is always the close() of the
782 * final handle that will return the exit code.
785 /* RED_FLAG 31-Aug-2000 Tim
786 * This is always called (today!) between a pair of
787 * Py_BEGIN_ALLOW_THREADS/ Py_END_ALLOW_THREADS
788 * macros. So the thread running this has no valid thread state, as
789 * far as Python is concerned. However, this calls some Python API
790 * functions that cannot be called safely without a valid thread
791 * state, in particular PyDict_GetItem.
792 * As a temporary hack (although it may last for years ...), we
793 * *rely* on not having a valid thread state in this function, in
794 * order to create our own "from scratch".
795 * This will deadlock if _PyPclose is ever called by a thread
796 * holding the global lock.
799 bool cmWin32ProcessExecution::PrivateClose(int /* timeout */)
801 HANDLE hProcess = this->ProcessHandle;
803 int result = -1;
804 DWORD exit_code;
806 std::string output = "";
807 bool done = false;
808 while(!done)
810 Sleep(10);
811 bool have_some = false;
812 struct _stat fsout;
813 struct _stat fserr;
814 int rout = _fstat(this->pStdOut, &fsout);
815 int rerr = _fstat(this->pStdErr, &fserr);
816 if ( rout && rerr )
818 break;
820 if (fserr.st_size > 0)
822 char buffer[1024];
823 int len = read(this->pStdErr, buffer, 1023);
824 buffer[len] = 0;
825 if ( this->Verbose )
827 cmSystemTools::Stdout(buffer);
829 output += buffer;
830 have_some = true;
832 if (fsout.st_size > 0)
834 char buffer[1024];
835 int len = read(this->pStdOut, buffer, 1023);
836 buffer[len] = 0;
837 if ( this->Verbose )
839 cmSystemTools::Stdout(buffer);
841 output += buffer;
842 have_some = true;
844 unsigned long exitCode;
845 if ( ! have_some )
847 GetExitCodeProcess(hProcess,&exitCode);
848 if (exitCode != STILL_ACTIVE)
850 break;
856 if (WaitForSingleObject(hProcess, INFINITE) != WAIT_FAILED &&
857 GetExitCodeProcess(hProcess, &exit_code))
859 result = exit_code;
861 else
863 /* Indicate failure - this will cause the file object
864 * to raise an I/O error and translate the last Win32
865 * error code from errno. We do have a problem with
866 * last errors that overlap the normal errno table,
867 * but that's a consistent problem with the file object.
869 if (result != EOF)
871 /* If the error wasn't from the fclose(), then
872 * set errno for the file object error handling.
874 errno = GetLastError();
876 result = -1;
879 /* Free up the native handle at this point */
880 CloseHandle(hProcess);
881 this->ExitValue = result;
882 this->Output += output;
883 bool ret = this->CloseHandles();
884 if ( result < 0 || !ret)
886 return false;
888 return true;
891 int cmWin32ProcessExecution::Windows9xHack(const char* command)
893 BOOL bRet;
894 STARTUPINFO si;
895 PROCESS_INFORMATION pi;
896 DWORD exit_code=0;
898 if (!command)
900 cmSystemTools::Error("Windows9xHack: Command not specified");
901 return 1;
904 /* Make child process use this app's standard files. */
905 ZeroMemory(&si, sizeof si);
906 si.cb = sizeof si;
907 si.dwFlags = STARTF_USESTDHANDLES;
908 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
909 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
910 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
913 char * app = 0;
914 char* cmd = new char[ strlen(command) + 1 ];
915 strcpy(cmd, command);
917 bRet = CreateProcess(
918 app, cmd,
919 0, 0,
920 TRUE, 0,
921 0, 0,
922 &si, &pi
924 delete [] cmd;
926 if (bRet)
928 if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_FAILED)
930 GetExitCodeProcess(pi.hProcess, &exit_code);
932 CloseHandle(pi.hProcess);
933 CloseHandle(pi.hThread);
934 return exit_code;
937 return 1;