Imported Upstream version 2.8.9
[platform/upstream/cmake.git] / Source / cmWin32ProcessExecution.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12 #include "cmWin32ProcessExecution.h"
13
14 #include "cmSystemTools.h"   
15
16 #include <malloc.h>
17 #include <io.h>
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #include <windows.h>
21
22 #if defined(__BORLANDC__)
23 #  define STRICMP stricmp
24 #  define TO_INTPTR(x) ((long)(x))
25 #endif // Borland
26 #if defined(_MSC_VER) // Visual studio
27 #  if ( _MSC_VER >= 1300 )
28 #    include <stddef.h>
29 #    define TO_INTPTR(x) ((intptr_t)(x))
30 #  else // Visual Studio 6
31 #    define TO_INTPTR(x) ((long)(x))
32 #  endif // Visual studio .NET
33 #  define STRICMP _stricmp
34 #endif // Visual Studio
35 #if defined(__MINGW32__)
36 # include <stdint.h>
37 # define TO_INTPTR(x) ((intptr_t)(x))
38 # define STRICMP _stricmp
39 #endif // MinGW
40
41 #define POPEN_1 1
42 #define POPEN_2 2
43 #define POPEN_3 3
44 #define POPEN_4 4
45
46 #define cmMAX(x,y) (((x)<(y))?(y):(x))
47
48 void DisplayErrorMessage()
49 {
50   LPVOID lpMsgBuf;
51   FormatMessage( 
52     FORMAT_MESSAGE_ALLOCATE_BUFFER | 
53     FORMAT_MESSAGE_FROM_SYSTEM | 
54     FORMAT_MESSAGE_IGNORE_INSERTS,
55     NULL,
56     GetLastError(),
57     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
58     (LPTSTR) &lpMsgBuf,
59     0,
60     NULL 
61     );
62   // Process any inserts in lpMsgBuf.
63   // ... 
64   // Display the string.
65   MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
66   // Free the buffer.
67   LocalFree( lpMsgBuf );
68 }
69  
70 // Code from a Borland web site with the following explaination : 
71 /* In this article, I will explain how to spawn a console application
72  * and redirect its standard input/output using anonymous pipes. An
73  * anonymous pipe is a pipe that goes only in one direction (read
74  * pipe, write pipe, etc.). Maybe you are asking, "why would I ever
75  * need to do this sort of thing?" One example would be a Windows
76  * telnet server, where you spawn a shell and listen on a port and
77  * send and receive data between the shell and the socket
78  * client. (Windows does not really have a built-in remote
79  * shell). First, we should talk about pipes. A pipe in Windows is
80  * simply a method of communication, often between process. The SDK
81  * defines a pipe as "a communication conduit with two ends;
82  a process
83  * with a handle to one end can communicate with a process having a
84  * handle to the other end." In our case, we are using "anonymous"
85  * pipes, one-way pipes that "transfer data between a parent process
86  * and a child process or between two child processes of the same
87  * parent process." It's easiest to imagine a pipe as its namesake. An
88  * actual pipe running between processes that can carry data. We are
89  * using anonymous pipes because the console app we are spawning is a
90  * child process. We use the CreatePipe function which will create an
91  * anonymous pipe and return a read handle and a write handle. We will
92  * create two pipes, on for stdin and one for stdout. We will then
93  * monitor the read end of the stdout pipe to check for display on our
94  * child process. Every time there is something availabe for reading,
95  * we will display it in our app. Consequently, we check for input in
96  * our app and send it off to the write end of the stdin pipe. */ 
97
98 inline bool IsWinNT() 
99 //check if we're running NT 
100 {
101   OSVERSIONINFO osv;
102   osv.dwOSVersionInfoSize = sizeof(osv);
103   GetVersionEx(&osv);
104   return (osv.dwPlatformId == VER_PLATFORM_WIN32_NT); 
105 }
106
107 //--------------------------------------------------------------------------- 
108 bool cmWin32ProcessExecution::BorlandRunCommand(
109   const char* command, const char* dir, 
110   std::string& output, int& retVal, bool verbose, int /* timeout */, 
111   bool hideWindows) 
112 {
113   //verbose = true;
114   //std::cerr << std::endl 
115   //        << "WindowsRunCommand(" << command << ")" << std::endl 
116   //        << std::flush;
117   const int BUFFER_SIZE = 4096;
118   char buf[BUFFER_SIZE];
119  
120 //i/o buffer 
121   STARTUPINFO si;
122   SECURITY_ATTRIBUTES sa;
123   SECURITY_DESCRIPTOR sd;
124  
125 //security information for pipes 
126   PROCESS_INFORMATION pi;
127   HANDLE newstdin,newstdout,read_stdout,write_stdin;
128  
129 //pipe handles 
130   if (IsWinNT()) 
131 //initialize security descriptor (Windows NT) 
132     {
133     InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
134     SetSecurityDescriptorDacl(&sd, true, NULL, false);
135     sa.lpSecurityDescriptor = &sd;
136  
137     }
138   else sa.lpSecurityDescriptor = NULL;
139   sa.nLength = sizeof(SECURITY_ATTRIBUTES);
140   sa.bInheritHandle = true;
141  
142 //allow inheritable handles 
143   if (!CreatePipe(&newstdin,&write_stdin,&sa,0)) 
144 //create stdin pipe 
145     {
146     return false;
147     }
148   if (!CreatePipe(&read_stdout,&newstdout,&sa,0)) 
149 //create stdout pipe 
150     {
151     CloseHandle(newstdin);
152     CloseHandle(write_stdin);
153     return false;
154  
155     }
156   GetStartupInfo(&si);
157  
158 //set startupinfo for the spawned process 
159   /* The dwFlags member tells CreateProcess how to make the
160    * process. STARTF_USESTDHANDLES validates the hStd*
161    * members. STARTF_USESHOWWINDOW validates the wShowWindow
162    * member. */ 
163   
164   si.cb = sizeof(STARTUPINFO);
165   si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
166   si.hStdOutput = newstdout;
167   si.hStdError = newstdout;
168   si.wShowWindow = SW_SHOWDEFAULT;
169   if(hideWindows)
170     {
171     si.wShowWindow = SW_HIDE;
172     }
173  
174 //set the new handles for the child process si.hStdInput = newstdin;
175   char* commandAndArgs = strcpy(new char[strlen(command)+1], command);
176   if (!CreateProcess(NULL,commandAndArgs,NULL,NULL,TRUE,
177                      0, // CREATE_NEW_CONSOLE, 
178                      NULL,dir,&si,&pi)) 
179     {
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;
186     return false;
187  
188     }
189   delete [] commandAndArgs;
190   unsigned long exit=0;
191  
192 //process exit code unsigned 
193   unsigned long bread;
194  
195 //bytes read unsigned 
196   unsigned long avail;
197  
198 //bytes available 
199   memset(buf, 0, sizeof(buf));
200   for(;;) 
201 //main program loop 
202     {
203     Sleep(10);
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);
207     if (bread != 0) 
208       {
209       memset(buf, 0, sizeof(buf));
210       if (avail > 1023) 
211         {
212         while (bread >= 1023) 
213           {
214           //std::cout << "Read data..." << std::endl;
215           ReadFile(read_stdout,buf,1023,&bread,NULL);
216  
217           //read the stdout pipe 
218           memset(buf, 0, sizeof(buf));
219           output += buf;
220           if (verbose)
221             {
222             cmSystemTools::Stdout(buf);
223             }
224           }
225         }
226       else 
227         {
228         ReadFile(read_stdout,buf,1023,&bread,NULL);
229         output += buf;
230         if(verbose) 
231           {
232           cmSystemTools::Stdout(buf);
233           }
234  
235         }
236  
237       }
238  
239     //std::cout << "Check for process..." << std::endl;
240     GetExitCodeProcess(pi.hProcess,&exit);
241  
242 //while the process is running 
243     if (exit != STILL_ACTIVE) break;
244  
245     }
246   WaitForSingleObject(pi.hProcess, INFINITE);
247   GetExitCodeProcess(pi.hProcess,&exit);
248   CloseHandle(pi.hThread);
249   CloseHandle(pi.hProcess);
250   CloseHandle(newstdin);
251  
252 //clean stuff up 
253   CloseHandle(newstdout);
254   CloseHandle(read_stdout);
255   CloseHandle(write_stdin);
256   retVal = exit;
257   return true;
258  
259 }
260
261 bool cmWin32ProcessExecution::StartProcess(
262   const char* cmd, const char* path, bool verbose)
263 {
264   this->Initialize();
265   this->Verbose = verbose;
266   return this->PrivateOpen(cmd, path, _O_RDONLY | _O_TEXT, POPEN_3);
267 }
268
269 bool cmWin32ProcessExecution::Wait(int timeout)
270 {
271   return this->PrivateClose(timeout);
272 }
273
274 /*
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.
278  */
279 static void *_PyPopenProcs = NULL;
280
281 static BOOL RealPopenCreateProcess(const char *cmdstring,
282                                    const char *path, 
283                                    const char *szConsoleSpawn,
284                                    HANDLE hStdin,
285                                    HANDLE hStdout,
286                                    HANDLE hStderr,
287                                    HANDLE *hProcess,
288                                    bool hideWindows,
289                                    std::string& output)
290 {
291   PROCESS_INFORMATION piProcInfo;
292   STARTUPINFO siStartInfo;
293   char *s1=0,*s2=0;
294   const char *s3 = " /c ";
295   int i = GetEnvironmentVariable("COMSPEC",NULL,0);
296   if (i)
297     {
298     char *comshell;
299
300     s1 = (char *)malloc(i);
301     int x = GetEnvironmentVariable("COMSPEC", s1, i);
302     if (!x)
303       {
304       free(s1);
305       return x;
306       }
307
308     /* Explicitly check if we are using COMMAND.COM.  If we are
309      * then use the w9xpopen hack.
310      */
311     comshell = s1 + x;
312     while (comshell >= s1 && *comshell != '\\')
313       --comshell;
314     ++comshell;
315
316     if (GetVersion() < 0x80000000 &&
317         STRICMP(comshell, "command.com") != 0) 
318       {
319       /* NT/2000 and not using command.com. */
320       x = i + (int)strlen(s3) + (int)strlen(cmdstring) + 1;
321       s2 = (char *)malloc(x);
322       ZeroMemory(s2, x);
323       //sprintf(s2, "%s%s%s", s1, s3, cmdstring);
324       sprintf(s2, "%s", cmdstring);
325       }
326     else 
327       {
328       /*
329        * Oh gag, we're on Win9x or using COMMAND.COM. Use
330        * the workaround listed in KB: Q150956
331        */
332       char modulepath[_MAX_PATH];
333       struct stat statinfo;
334       GetModuleFileName(NULL, modulepath, sizeof(modulepath));
335       for (i = x = 0; modulepath[i]; i++)
336         if (modulepath[i] == '\\')
337           x = i+1;
338       modulepath[x] = '\0';
339       /* Create the full-name to w9xpopen, so we can test it exists */
340       strncat(modulepath, 
341               szConsoleSpawn, 
342               (sizeof(modulepath)/sizeof(modulepath[0]))
343               -strlen(modulepath));
344       if (stat(modulepath, &statinfo) != 0) 
345         {
346           /* Eeek - file-not-found - possibly an embedding 
347              situation - see if we can locate it in sys.prefix 
348           */
349         strncpy(modulepath, 
350                 ".", 
351                 sizeof(modulepath)/sizeof(modulepath[0]));
352         if (modulepath[strlen(modulepath)-1] != '\\')
353           strcat(modulepath, "\\");
354         strncat(modulepath, 
355                 szConsoleSpawn, 
356                 (sizeof(modulepath)/sizeof(modulepath[0]))
357                 -strlen(modulepath));
358         /* No where else to look - raise an easily identifiable
359            error, rather than leaving Windows to report
360            "file not found" - as the user is probably blissfully
361            unaware this shim EXE is used, and it will confuse them.
362            (well, it confused me for a while ;-)
363         */
364         if (stat(modulepath, &statinfo) != 0) 
365           {
366           std::cout 
367             << "Can not locate '" << modulepath
368             << "' which is needed "
369             "for popen to work with your shell "
370             "or platform." << std::endl;    
371           free(s1);
372           free(s2);
373           return FALSE;
374           }
375         }
376       x = i + (int)strlen(s3) + (int)strlen(cmdstring) + 1 +
377         (int)strlen(modulepath) + 
378         (int)strlen(szConsoleSpawn) + 1;
379       if(s2)
380         {
381         free(s2);
382         }
383       s2 = (char *)malloc(x);
384       ZeroMemory(s2, x);
385       sprintf(
386         s2,
387         "%s %s%s%s",
388         modulepath,
389         s1,
390         s3,
391         cmdstring);
392       sprintf(
393         s2,
394         "%s %s",
395         modulepath,
396         cmdstring);
397       }
398     }
399
400   /* Could be an else here to try cmd.exe / command.com in the path
401      Now we'll just error out.. */
402   else 
403     {
404     std::cout << "Cannot locate a COMSPEC environment variable to "
405               << "use as the shell" << std::endl; 
406     free(s2);
407     free(s1);
408     return FALSE;
409     }
410   
411   ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
412   siStartInfo.cb = sizeof(STARTUPINFO);
413   siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
414   siStartInfo.hStdInput = hStdin;
415   siStartInfo.hStdOutput = hStdout;
416   siStartInfo.hStdError = hStderr;
417   siStartInfo.wShowWindow = SW_SHOWDEFAULT; 
418   if(hideWindows)
419     {
420     siStartInfo.wShowWindow = SW_HIDE;
421     }
422
423   //std::cout << "Create process: " << s2 << std::endl;
424   if (CreateProcess(NULL,
425                     s2,
426                     NULL,
427                     NULL,
428                     TRUE,
429                     0, //CREATE_NEW_CONSOLE,
430                     NULL,
431                     path,
432                     &siStartInfo,
433                     &piProcInfo) ) 
434     {
435     /* Close the handles now so anyone waiting is woken. */
436     CloseHandle(piProcInfo.hThread);
437     /* Return process handle */
438     *hProcess = piProcInfo.hProcess;
439     //std::cout << "Process created..." << std::endl;
440     free(s2);
441     free(s1);
442     return TRUE;
443     }
444
445   output += "CreateProcessError: ";
446   {
447   /* Format the error message.  */
448   char message[1024];
449   DWORD original = GetLastError();
450   DWORD length = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
451                                FORMAT_MESSAGE_IGNORE_INSERTS, 0, original,
452                                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
453                                message, 1023, 0);
454   if(length < 1)
455     {
456     /* FormatMessage failed.  Use a default message.  */
457     _snprintf(message, 1023,
458               "Process execution failed with error 0x%X.  "
459               "FormatMessage failed with error 0x%X",
460               original, GetLastError());
461     }
462   output += message;
463   }
464   output += "\n";
465   output += "for command: ";
466   output += s2;
467   if(path)
468     {
469     output += "\nin dir: ";
470     output += path;
471     }
472   output += "\n";
473   free(s2);
474   free(s1);
475   return FALSE;
476 }
477
478 /* The following code is based off of KB: Q190351 */
479
480 bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring, 
481                                           const char* path,
482                                           int mode, 
483                                           int n)
484 {
485   HANDLE hProcess;
486
487   SECURITY_ATTRIBUTES saAttr;
488   BOOL fSuccess;
489   int fd1, fd2, fd3;
490   this->hChildStdinRd = 0;
491   this->hChildStdinWr = 0;
492   this->hChildStdoutRd = 0;
493   this->hChildStdoutWr = 0;
494   this->hChildStderrRd = 0;
495   this->hChildStderrWr = 0;
496   this->hChildStdinWrDup = 0;
497   this->hChildStdoutRdDup = 0;
498   this->hChildStderrRdDup = 0;
499   
500   saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
501   saAttr.bInheritHandle = TRUE;
502   saAttr.lpSecurityDescriptor = NULL;
503   
504   fd1 = 0;
505   fd2 = 0;
506   fd3 = 0;
507
508   if (!CreatePipe(&this->hChildStdinRd, &this->hChildStdinWr, &saAttr, 0))
509     {
510     this->Output += "CreatePipeError\n";
511     return false;
512     }
513     
514   /* Create new output read handle and the input write handle. Set
515    * the inheritance properties to FALSE. Otherwise, the child inherits
516    * the these handles; resulting in non-closeable handles to the pipes
517    * being created. */
518   fSuccess = DuplicateHandle(GetCurrentProcess(), this->hChildStdinWr,
519                              GetCurrentProcess(), &this->hChildStdinWrDup, 0,
520                              FALSE,
521                              DUPLICATE_SAME_ACCESS);
522   if (!fSuccess)
523     {
524     this->Output += "DuplicateHandleError\n";
525     return false;
526     }
527
528
529   /* Close the inheritable version of ChildStdin
530      that we're using. */
531   CloseHandle(hChildStdinWr);
532
533   if (!CreatePipe(&this->hChildStdoutRd, &this->hChildStdoutWr, &saAttr, 0))
534     {
535     this->Output += "CreatePipeError\n";
536     return false;
537     }
538
539   fSuccess = DuplicateHandle(GetCurrentProcess(), this->hChildStdoutRd,
540                              GetCurrentProcess(), &this->hChildStdoutRdDup, 0,
541                              FALSE, DUPLICATE_SAME_ACCESS);
542   if (!fSuccess)
543     {
544     this->Output += "DuplicateHandleError\n";
545     return false;
546     }
547
548   /* Close the inheritable version of ChildStdout
549      that we're using. */
550   CloseHandle(hChildStdoutRd);
551
552   if (n != POPEN_4) 
553     {
554     if (!CreatePipe(&this->hChildStderrRd, &this->hChildStderrWr, &saAttr, 0))
555       {
556       this->Output += "CreatePipeError\n";
557       return false;
558       }
559    fSuccess = DuplicateHandle(GetCurrentProcess(),
560                               this->hChildStderrRd,
561                               GetCurrentProcess(),
562                               &this->hChildStderrRdDup, 0,
563                               FALSE, DUPLICATE_SAME_ACCESS);
564     if (!fSuccess)
565       {
566       this->Output += "DuplicateHandleError\n";
567       return false;
568       }
569     /* Close the inheritable version of ChildStdErr that we're using. */
570     CloseHandle(hChildStderrRd);
571
572     }
573           
574   switch (n) 
575     {
576     case POPEN_1:
577       switch (mode & (_O_RDONLY | _O_TEXT | _O_BINARY | _O_WRONLY)) 
578         {
579         case _O_WRONLY | _O_TEXT:
580           /* Case for writing to child Stdin in text mode. */
581           fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup), mode);
582           /* We don't care about these pipes anymore,
583              so close them. */
584           break;
585
586         case _O_RDONLY | _O_TEXT:
587           /* Case for reading from child Stdout in text mode. */
588           fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup), mode);
589           /* We don't care about these pipes anymore,
590              so close them. */
591           break;
592
593         case _O_RDONLY | _O_BINARY:
594           /* Case for readinig from child Stdout in
595              binary mode. */
596           fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup), mode);
597           /* We don't care about these pipes anymore,
598              so close them. */
599           break;
600
601         case _O_WRONLY | _O_BINARY:
602           /* Case for writing to child Stdin in binary mode. */
603           fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup), mode);
604           /* We don't care about these pipes anymore,
605              so close them. */
606           break;
607         }
608       break;
609         
610     case POPEN_2:
611     case POPEN_4: 
612       //if ( 1 ) 
613         {
614         fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup), mode);
615         fd2 = _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup), mode);
616         break;
617         }
618         
619     case POPEN_3:
620       //if ( 1) 
621         {
622         fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup), mode);
623         fd2 = _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup), mode);
624         fd3 = _open_osfhandle(TO_INTPTR(this->hChildStderrRdDup), mode);
625         break;
626         }
627     }
628
629   if (n == POPEN_4) 
630     {
631     if (!RealPopenCreateProcess(cmdstring,
632                                 path,
633                                 this->ConsoleSpawn.c_str(),
634                                 this->hChildStdinRd,
635                                 this->hChildStdoutWr,
636                                 this->hChildStdoutWr,
637                                 &hProcess, this->HideWindows,
638                                 this->Output))
639       {
640       if(fd1 >= 0)
641         {
642         close(fd1);
643         }
644       if(fd2 >= 0)
645         {
646         close(fd2);
647         }
648       if(fd3 >= 0)
649         {
650         close(fd3);
651         }
652       return 0;
653       }
654     }
655   else 
656     {
657     if (!RealPopenCreateProcess(cmdstring,
658                                 path,
659                                 this->ConsoleSpawn.c_str(),
660                                 this->hChildStdinRd,
661                                 this->hChildStdoutWr,
662                                 this->hChildStderrWr,
663                                 &hProcess, this->HideWindows,
664                                 this->Output))
665       {
666       if(fd1 >= 0)
667         {
668         close(fd1);
669         }
670       if(fd2 >= 0)
671         {
672         close(fd2);
673         }
674       if(fd3 >= 0)
675         {
676         close(fd3);
677         }
678       return 0;
679       }
680     }
681
682   /*
683    * Insert the files we've created into the process dictionary
684    * all referencing the list with the process handle and the
685    * initial number of files (see description below in _PyPclose).
686    * Since if _PyPclose later tried to wait on a process when all
687    * handles weren't closed, it could create a deadlock with the
688    * child, we spend some energy here to try to ensure that we
689    * either insert all file handles into the dictionary or none
690    * at all.  It's a little clumsy with the various popen modes
691    * and variable number of files involved.
692    */
693
694   /* Child is launched. Close the parents copy of those pipe
695    * handles that only the child should have open.  You need to
696    * make sure that no handles to the write end of the output pipe
697    * are maintained in this process or else the pipe will not close
698    * when the child process exits and the ReadFile will hang. */
699   this->ProcessHandle = hProcess;
700   if ( fd1 >= 0 )
701     {
702     this->pStdIn = fd1;
703     }
704   if ( fd2 >= 0 )
705     {
706     this->pStdOut = fd2;
707     }
708   if ( fd3 >= 0 )
709     {
710     this->pStdErr = fd3;
711     }
712
713   return true;
714 }
715
716 bool cmWin32ProcessExecution::CloseHandles()
717 {
718   if(this->pStdErr != -1 )
719     {
720     // this will close this as well: this->hChildStderrRdDup
721     _close(this->pStdErr);
722     this->pStdErr = -1;
723     this->hChildStderrRdDup = 0;
724     }
725   if(this->pStdIn != -1 )
726     {
727     // this will close this as well: this->hChildStdinWrDup
728     _close(this->pStdIn);
729     this->pStdIn = -1;
730     this->hChildStdinWrDup = 0;
731     }
732   if(this->pStdOut != -1 )
733     {
734     // this will close this as well: this->hChildStdoutRdDup
735     _close(this->pStdOut);
736     this->pStdOut = -1;
737     this->hChildStdoutRdDup = 0;
738     }
739
740   bool ret = true;
741   if (this->hChildStdinRd && !CloseHandle(this->hChildStdinRd))
742     {
743     ret = false;
744     }
745   this->hChildStdinRd = 0;
746   // now close these two
747   if (this->hChildStdoutWr && !CloseHandle(this->hChildStdoutWr))
748     {
749     ret = false;
750     }
751   this->hChildStdoutWr = 0;
752   if (this->hChildStderrWr && !CloseHandle(this->hChildStderrWr))
753     {
754     ret = false;
755     }
756   this->hChildStderrWr = 0;
757   return ret;
758 }
759 cmWin32ProcessExecution::~cmWin32ProcessExecution()
760 {
761   this->CloseHandles();
762 }
763
764 /*
765  * Wrapper for fclose() to use for popen* files, so we can retrieve the
766  * exit code for the child process and return as a result of the close.
767  *
768  * This function uses the _PyPopenProcs dictionary in order to map the
769  * input file pointer to information about the process that was
770  * originally created by the popen* call that created the file pointer.
771  * The dictionary uses the file pointer as a key (with one entry
772  * inserted for each file returned by the original popen* call) and a
773  * single list object as the value for all files from a single call.
774  * The list object contains the Win32 process handle at [0], and a file
775  * count at [1], which is initialized to the total number of file
776  * handles using that list.
777  *
778  * This function closes whichever handle it is passed, and decrements
779  * the file count in the dictionary for the process handle pointed to
780  * by this file.  On the last close (when the file count reaches zero),
781  * this function will wait for the child process and then return its
782  * exit code as the result of the close() operation.  This permits the
783  * files to be closed in any order - it is always the close() of the
784  * final handle that will return the exit code.
785  */
786
787  /* RED_FLAG 31-Aug-2000 Tim
788   * This is always called (today!) between a pair of
789   * Py_BEGIN_ALLOW_THREADS/ Py_END_ALLOW_THREADS
790   * macros.  So the thread running this has no valid thread state, as
791   * far as Python is concerned.  However, this calls some Python API
792   * functions that cannot be called safely without a valid thread
793   * state, in particular PyDict_GetItem.
794   * As a temporary hack (although it may last for years ...), we
795   * *rely* on not having a valid thread state in this function, in
796   * order to create our own "from scratch".
797   * This will deadlock if _PyPclose is ever called by a thread
798   * holding the global lock.
799   */
800
801 bool cmWin32ProcessExecution::PrivateClose(int /* timeout */)
802 {
803   HANDLE hProcess = this->ProcessHandle;
804
805   int result = -1;
806   DWORD exit_code;
807
808   std::string output = "";
809   bool done = false;
810   while(!done)
811     {
812     Sleep(10);
813     bool have_some = false;
814     struct _stat fsout;
815     struct _stat fserr;
816     int rout = _fstat(this->pStdOut, &fsout);
817     int rerr = _fstat(this->pStdErr, &fserr);
818     if ( rout && rerr )
819       {
820       break;
821       }
822     if (fserr.st_size > 0)
823       {
824       char buffer[1024];
825       int len = read(this->pStdErr, buffer, 1023);
826       buffer[len] = 0;
827       if ( this->Verbose )
828         {
829         cmSystemTools::Stdout(buffer);
830         }
831       output += buffer;
832       have_some = true;
833       }
834     if (fsout.st_size > 0)
835       {
836       char buffer[1024];
837       int len = read(this->pStdOut, buffer, 1023);
838       buffer[len] = 0;
839       if ( this->Verbose )
840         {
841         cmSystemTools::Stdout(buffer);
842         }
843       output += buffer;
844       have_some = true;
845       }
846     unsigned long exitCode;
847     if ( ! have_some )
848       {
849       GetExitCodeProcess(hProcess,&exitCode);
850       if (exitCode != STILL_ACTIVE)
851         {
852         break;
853         }
854       }
855     }  
856
857   
858   if (WaitForSingleObject(hProcess, INFINITE) != WAIT_FAILED &&
859       GetExitCodeProcess(hProcess, &exit_code)) 
860     {
861     result = exit_code;
862     } 
863   else 
864     {
865     /* Indicate failure - this will cause the file object
866      * to raise an I/O error and translate the last Win32
867      * error code from errno.  We do have a problem with
868      * last errors that overlap the normal errno table,
869      * but that's a consistent problem with the file object.
870      */
871     if (result != EOF) 
872       {
873       /* If the error wasn't from the fclose(), then
874        * set errno for the file object error handling.
875        */
876       errno = GetLastError();
877       }
878     result = -1;
879     }
880
881   /* Free up the native handle at this point */
882   CloseHandle(hProcess);
883   this->ExitValue = result;
884   this->Output += output;
885   bool ret = this->CloseHandles();
886   if ( result < 0 || !ret)
887     {
888     return false;
889     }
890   return true;
891 }
892
893 int cmWin32ProcessExecution::Windows9xHack(const char* command)
894 {
895   BOOL bRet;
896   STARTUPINFO si;
897   PROCESS_INFORMATION pi;
898   DWORD exit_code=0;
899
900   if (!command) 
901     {
902     cmSystemTools::Error("Windows9xHack: Command not specified");
903     return 1;
904   }
905
906   /* Make child process use this app's standard files. */
907   ZeroMemory(&si, sizeof si);
908   si.cb = sizeof si;
909   si.dwFlags = STARTF_USESTDHANDLES;
910   si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
911   si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
912   si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
913
914   
915   char * app = 0;
916   char* cmd = new char[ strlen(command) + 1 ];
917   strcpy(cmd, command);
918
919   bRet = CreateProcess(
920     app, cmd,
921     0, 0,
922     TRUE, 0,
923     0, 0,
924     &si, &pi
925     );
926   delete [] cmd;
927
928   if (bRet) 
929     {
930     if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_FAILED) 
931       {
932       GetExitCodeProcess(pi.hProcess, &exit_code);
933       }
934     CloseHandle(pi.hProcess);
935     CloseHandle(pi.hThread);
936     return exit_code;
937     }
938
939   return 1;
940 }