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