CVS resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / cmWin32ProcessExecution.cxx
blob479e1139db475f21485427a6f8c18be79f149f16
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmWin32ProcessExecution.cxx,v $
5 Language: C++
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"
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 _close(this->pStdErr);
719 this->pStdErr = -1;
721 if(this->pStdIn != -1 )
723 _close(this->pStdIn);
724 this->pStdIn = -1;
726 if(this->pStdOut != -1 )
728 _close(this->pStdOut);
729 this->pStdOut = -1;
732 bool ret = true;
733 if (this->hChildStdinRd && !CloseHandle(this->hChildStdinRd))
735 ret = false;
737 this->hChildStdinRd = 0;
738 if(this->hChildStdoutRdDup && !CloseHandle(this->hChildStdoutRdDup))
740 ret = false;
742 this->hChildStdoutRdDup = 0;
743 if(this->hChildStderrRdDup && !CloseHandle(this->hChildStderrRdDup))
745 ret = false;
747 this->hChildStderrRdDup = 0;
748 if(this->hChildStdinWrDup && !CloseHandle(this->hChildStdinWrDup))
750 ret = false;
752 this->hChildStdinWrDup = 0;
753 if (this->hChildStdoutWr && !CloseHandle(this->hChildStdoutWr))
755 ret = false;
757 this->hChildStdoutWr = 0;
758 if (this->hChildStderrWr && !CloseHandle(this->hChildStderrWr))
760 ret = false;
762 this->hChildStderrWr = 0;
763 return ret;
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;
811 int result = -1;
812 DWORD exit_code;
814 std::string output = "";
815 bool done = false;
816 while(!done)
818 Sleep(10);
819 bool have_some = false;
820 struct _stat fsout;
821 struct _stat fserr;
822 int rout = _fstat(this->pStdOut, &fsout);
823 int rerr = _fstat(this->pStdErr, &fserr);
824 if ( rout && rerr )
826 break;
828 if (fserr.st_size > 0)
830 char buffer[1024];
831 int len = read(this->pStdErr, buffer, 1023);
832 buffer[len] = 0;
833 if ( this->Verbose )
835 cmSystemTools::Stdout(buffer);
837 output += buffer;
838 have_some = true;
840 if (fsout.st_size > 0)
842 char buffer[1024];
843 int len = read(this->pStdOut, buffer, 1023);
844 buffer[len] = 0;
845 if ( this->Verbose )
847 cmSystemTools::Stdout(buffer);
849 output += buffer;
850 have_some = true;
852 unsigned long exitCode;
853 if ( ! have_some )
855 GetExitCodeProcess(hProcess,&exitCode);
856 if (exitCode != STILL_ACTIVE)
858 break;
864 if (WaitForSingleObject(hProcess, INFINITE) != WAIT_FAILED &&
865 GetExitCodeProcess(hProcess, &exit_code))
867 result = exit_code;
869 else
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.
877 if (result != EOF)
879 /* If the error wasn't from the fclose(), then
880 * set errno for the file object error handling.
882 errno = GetLastError();
884 result = -1;
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)
894 return false;
896 return true;
899 int cmWin32ProcessExecution::Windows9xHack(const char* command)
901 BOOL bRet;
902 STARTUPINFO si;
903 PROCESS_INFORMATION pi;
904 DWORD exit_code=0;
906 if (!command)
908 cmSystemTools::Error("Windows9xHack: Command not specified");
909 return 1;
912 /* Make child process use this app's standard files. */
913 ZeroMemory(&si, sizeof si);
914 si.cb = 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);
921 char * app = 0;
922 char* cmd = new char[ strlen(command) + 1 ];
923 strcpy(cmd, command);
925 bRet = CreateProcess(
926 app, cmd,
927 0, 0,
928 TRUE, 0,
929 0, 0,
930 &si, &pi
932 delete [] cmd;
934 if (bRet)
936 if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_FAILED)
938 GetExitCodeProcess(pi.hProcess, &exit_code);
940 CloseHandle(pi.hProcess);
941 CloseHandle(pi.hThread);
942 return exit_code;
945 return 1;