1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
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"
14 #include "cmSystemTools.h"
22 #if defined(__BORLANDC__)
23 # define STRICMP stricmp
24 # define TO_INTPTR(x) ((long)(x))
26 #if defined(_MSC_VER) // Visual studio
27 # if ( _MSC_VER >= 1300 )
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__)
37 # define TO_INTPTR(x) ((intptr_t)(x))
38 # define STRICMP _stricmp
46 #define cmMAX(x,y) (((x)<(y))?(y):(x))
48 void DisplayErrorMessage()
52 FORMAT_MESSAGE_ALLOCATE_BUFFER |
53 FORMAT_MESSAGE_FROM_SYSTEM |
54 FORMAT_MESSAGE_IGNORE_INSERTS,
57 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
62 // Process any inserts in lpMsgBuf.
64 // Display the string.
65 MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
67 LocalFree( lpMsgBuf );
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;
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. */
99 //check if we're running NT
102 osv.dwOSVersionInfoSize = sizeof(osv);
104 return (osv.dwPlatformId == VER_PLATFORM_WIN32_NT);
107 //---------------------------------------------------------------------------
108 bool cmWin32ProcessExecution::BorlandRunCommand(
109 const char* command, const char* dir,
110 std::string& output, int& retVal, bool verbose, int /* timeout */,
114 //std::cerr << std::endl
115 // << "WindowsRunCommand(" << command << ")" << std::endl
117 const int BUFFER_SIZE = 4096;
118 char buf[BUFFER_SIZE];
122 SECURITY_ATTRIBUTES sa;
123 SECURITY_DESCRIPTOR sd;
125 //security information for pipes
126 PROCESS_INFORMATION pi;
127 HANDLE newstdin,newstdout,read_stdout,write_stdin;
131 //initialize security descriptor (Windows NT)
133 InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
134 SetSecurityDescriptorDacl(&sd, true, NULL, false);
135 sa.lpSecurityDescriptor = &sd;
138 else sa.lpSecurityDescriptor = NULL;
139 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
140 sa.bInheritHandle = true;
142 //allow inheritable handles
143 if (!CreatePipe(&newstdin,&write_stdin,&sa,0))
148 if (!CreatePipe(&read_stdout,&newstdout,&sa,0))
151 CloseHandle(newstdin);
152 CloseHandle(write_stdin);
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
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;
171 si.wShowWindow = SW_HIDE;
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,
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;
189 delete [] commandAndArgs;
190 unsigned long exit=0;
192 //process exit code unsigned
195 //bytes read unsigned
199 memset(buf, 0, sizeof(buf));
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);
209 memset(buf, 0, sizeof(buf));
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));
222 cmSystemTools::Stdout(buf);
228 ReadFile(read_stdout,buf,1023,&bread,NULL);
232 cmSystemTools::Stdout(buf);
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);
253 CloseHandle(newstdout);
254 CloseHandle(read_stdout);
255 CloseHandle(write_stdin);
261 bool cmWin32ProcessExecution::StartProcess(
262 const char* cmd, const char* path, bool verbose)
265 this->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);
274 static BOOL RealPopenCreateProcess(const char *cmdstring,
276 const char *szConsoleSpawn,
284 PROCESS_INFORMATION piProcInfo;
285 STARTUPINFO siStartInfo;
287 const char *s3 = " /c ";
288 int i = GetEnvironmentVariable("COMSPEC",NULL,0);
293 s1 = (char *)malloc(i);
294 int x = GetEnvironmentVariable("COMSPEC", s1, i);
301 /* Explicitly check if we are using COMMAND.COM. If we are
302 * then use the w9xpopen hack.
305 while (comshell >= s1 && *comshell != '\\')
309 if (GetVersion() < 0x80000000 &&
310 STRICMP(comshell, "command.com") != 0)
312 /* NT/2000 and not using command.com. */
313 x = i + (int)strlen(s3) + (int)strlen(cmdstring) + 1;
314 s2 = (char *)malloc(x);
316 //sprintf(s2, "%s%s%s", s1, s3, cmdstring);
317 sprintf(s2, "%s", cmdstring);
322 * Oh gag, we're on Win9x or using COMMAND.COM. Use
323 * the workaround listed in KB: Q150956
325 char modulepath[_MAX_PATH];
326 struct stat statinfo;
327 GetModuleFileName(NULL, modulepath, sizeof(modulepath));
328 for (i = x = 0; modulepath[i]; i++)
329 if (modulepath[i] == '\\')
331 modulepath[x] = '\0';
332 /* Create the full-name to w9xpopen, so we can test it exists */
335 (sizeof(modulepath)/sizeof(modulepath[0]))
336 -strlen(modulepath));
337 if (stat(modulepath, &statinfo) != 0)
339 /* Eeek - file-not-found - possibly an embedding
340 situation - see if we can locate it in sys.prefix
344 sizeof(modulepath)/sizeof(modulepath[0]));
345 if (modulepath[strlen(modulepath)-1] != '\\')
346 strcat(modulepath, "\\");
349 (sizeof(modulepath)/sizeof(modulepath[0]))
350 -strlen(modulepath));
351 /* No where else to look - raise an easily identifiable
352 error, rather than leaving Windows to report
353 "file not found" - as the user is probably blissfully
354 unaware this shim EXE is used, and it will confuse them.
355 (well, it confused me for a while ;-)
357 if (stat(modulepath, &statinfo) != 0)
360 << "Can not locate '" << modulepath
361 << "' which is needed "
362 "for popen to work with your shell "
363 "or platform." << std::endl;
369 x = i + (int)strlen(s3) + (int)strlen(cmdstring) + 1 +
370 (int)strlen(modulepath) +
371 (int)strlen(szConsoleSpawn) + 1;
376 s2 = (char *)malloc(x);
393 /* Could be an else here to try cmd.exe / command.com in the path
394 Now we'll just error out.. */
397 std::cout << "Cannot locate a COMSPEC environment variable to "
398 << "use as the shell" << std::endl;
404 ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
405 siStartInfo.cb = sizeof(STARTUPINFO);
406 siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
407 siStartInfo.hStdInput = hStdin;
408 siStartInfo.hStdOutput = hStdout;
409 siStartInfo.hStdError = hStderr;
410 siStartInfo.wShowWindow = SW_SHOWDEFAULT;
413 siStartInfo.wShowWindow = SW_HIDE;
416 //std::cout << "Create process: " << s2 << std::endl;
417 if (CreateProcess(NULL,
422 0, //CREATE_NEW_CONSOLE,
428 /* Close the handles now so anyone waiting is woken. */
429 CloseHandle(piProcInfo.hThread);
430 /* Return process handle */
431 *hProcess = piProcInfo.hProcess;
432 //std::cout << "Process created..." << std::endl;
438 output += "CreateProcessError: ";
440 /* Format the error message. */
442 DWORD original = GetLastError();
443 DWORD length = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
444 FORMAT_MESSAGE_IGNORE_INSERTS, 0, original,
445 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
449 /* FormatMessage failed. Use a default message. */
450 _snprintf(message, 1023,
451 "Process execution failed with error 0x%X. "
452 "FormatMessage failed with error 0x%X",
453 original, GetLastError());
458 output += "for command: ";
462 output += "\nin dir: ";
471 /* The following code is based off of KB: Q190351 */
473 bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring,
480 SECURITY_ATTRIBUTES saAttr;
483 this->hChildStdinRd = 0;
484 this->hChildStdinWr = 0;
485 this->hChildStdoutRd = 0;
486 this->hChildStdoutWr = 0;
487 this->hChildStderrRd = 0;
488 this->hChildStderrWr = 0;
489 this->hChildStdinWrDup = 0;
490 this->hChildStdoutRdDup = 0;
491 this->hChildStderrRdDup = 0;
493 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
494 saAttr.bInheritHandle = TRUE;
495 saAttr.lpSecurityDescriptor = NULL;
501 if (!CreatePipe(&this->hChildStdinRd, &this->hChildStdinWr, &saAttr, 0))
503 this->Output += "CreatePipeError\n";
507 /* Create new output read handle and the input write handle. Set
508 * the inheritance properties to FALSE. Otherwise, the child inherits
509 * these handles; resulting in non-closeable handles to the pipes
511 fSuccess = DuplicateHandle(GetCurrentProcess(), this->hChildStdinWr,
512 GetCurrentProcess(), &this->hChildStdinWrDup, 0,
514 DUPLICATE_SAME_ACCESS);
517 this->Output += "DuplicateHandleError\n";
522 /* Close the inheritable version of ChildStdin
524 CloseHandle(hChildStdinWr);
526 if (!CreatePipe(&this->hChildStdoutRd, &this->hChildStdoutWr, &saAttr, 0))
528 this->Output += "CreatePipeError\n";
532 fSuccess = DuplicateHandle(GetCurrentProcess(), this->hChildStdoutRd,
533 GetCurrentProcess(), &this->hChildStdoutRdDup, 0,
534 FALSE, DUPLICATE_SAME_ACCESS);
537 this->Output += "DuplicateHandleError\n";
541 /* Close the inheritable version of ChildStdout
543 CloseHandle(hChildStdoutRd);
547 if (!CreatePipe(&this->hChildStderrRd, &this->hChildStderrWr, &saAttr, 0))
549 this->Output += "CreatePipeError\n";
552 fSuccess = DuplicateHandle(GetCurrentProcess(),
553 this->hChildStderrRd,
555 &this->hChildStderrRdDup, 0,
556 FALSE, DUPLICATE_SAME_ACCESS);
559 this->Output += "DuplicateHandleError\n";
562 /* Close the inheritable version of ChildStdErr that we're using. */
563 CloseHandle(hChildStderrRd);
570 switch (mode & (_O_RDONLY | _O_TEXT | _O_BINARY | _O_WRONLY))
572 case _O_WRONLY | _O_TEXT:
573 /* Case for writing to child Stdin in text mode. */
574 fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup), mode);
575 /* We don't care about these pipes anymore,
579 case _O_RDONLY | _O_TEXT:
580 /* Case for reading from child Stdout in text mode. */
581 fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup), mode);
582 /* We don't care about these pipes anymore,
586 case _O_RDONLY | _O_BINARY:
587 /* Case for readinig from child Stdout in
589 fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup), mode);
590 /* We don't care about these pipes anymore,
594 case _O_WRONLY | _O_BINARY:
595 /* Case for writing to child Stdin in binary mode. */
596 fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup), mode);
597 /* We don't care about these pipes anymore,
607 fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup), mode);
608 fd2 = _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup), mode);
615 fd1 = _open_osfhandle(TO_INTPTR(this->hChildStdinWrDup), mode);
616 fd2 = _open_osfhandle(TO_INTPTR(this->hChildStdoutRdDup), mode);
617 fd3 = _open_osfhandle(TO_INTPTR(this->hChildStderrRdDup), mode);
624 if (!RealPopenCreateProcess(cmdstring,
626 this->ConsoleSpawn.c_str(),
628 this->hChildStdoutWr,
629 this->hChildStdoutWr,
630 &hProcess, this->HideWindows,
650 if (!RealPopenCreateProcess(cmdstring,
652 this->ConsoleSpawn.c_str(),
654 this->hChildStdoutWr,
655 this->hChildStderrWr,
656 &hProcess, this->HideWindows,
675 /* Child is launched. Close the parents copy of those pipe
676 * handles that only the child should have open. You need to
677 * make sure that no handles to the write end of the output pipe
678 * are maintained in this process or else the pipe will not close
679 * when the child process exits and the ReadFile will hang. */
680 this->ProcessHandle = hProcess;
697 bool cmWin32ProcessExecution::CloseHandles()
699 if(this->pStdErr != -1 )
701 // this will close this as well: this->hChildStderrRdDup
702 _close(this->pStdErr);
704 this->hChildStderrRdDup = 0;
706 if(this->pStdIn != -1 )
708 // this will close this as well: this->hChildStdinWrDup
709 _close(this->pStdIn);
711 this->hChildStdinWrDup = 0;
713 if(this->pStdOut != -1 )
715 // this will close this as well: this->hChildStdoutRdDup
716 _close(this->pStdOut);
718 this->hChildStdoutRdDup = 0;
722 if (this->hChildStdinRd && !CloseHandle(this->hChildStdinRd))
726 this->hChildStdinRd = 0;
727 // now close these two
728 if (this->hChildStdoutWr && !CloseHandle(this->hChildStdoutWr))
732 this->hChildStdoutWr = 0;
733 if (this->hChildStderrWr && !CloseHandle(this->hChildStderrWr))
737 this->hChildStderrWr = 0;
740 cmWin32ProcessExecution::~cmWin32ProcessExecution()
742 this->CloseHandles();
745 bool cmWin32ProcessExecution::PrivateClose(int /* timeout */)
747 HANDLE hProcess = this->ProcessHandle;
752 std::string output = "";
757 bool have_some = false;
760 int rout = _fstat(this->pStdOut, &fsout);
761 int rerr = _fstat(this->pStdErr, &fserr);
766 if (fserr.st_size > 0)
769 int len = read(this->pStdErr, buffer, 1023);
773 cmSystemTools::Stdout(buffer);
778 if (fsout.st_size > 0)
781 int len = read(this->pStdOut, buffer, 1023);
785 cmSystemTools::Stdout(buffer);
790 unsigned long exitCode;
793 GetExitCodeProcess(hProcess,&exitCode);
794 if (exitCode != STILL_ACTIVE)
802 if (WaitForSingleObject(hProcess, INFINITE) != WAIT_FAILED &&
803 GetExitCodeProcess(hProcess, &exit_code))
809 /* Indicate failure - this will cause the file object
810 * to raise an I/O error and translate the last Win32
811 * error code from errno. We do have a problem with
812 * last errors that overlap the normal errno table,
813 * but that's a consistent problem with the file object.
817 /* If the error wasn't from the fclose(), then
818 * set errno for the file object error handling.
820 errno = GetLastError();
825 /* Free up the native handle at this point */
826 CloseHandle(hProcess);
827 this->ExitValue = result;
828 this->Output += output;
829 bool ret = this->CloseHandles();
830 if ( result < 0 || !ret)
837 int cmWin32ProcessExecution::Windows9xHack(const char* command)
841 PROCESS_INFORMATION pi;
846 cmSystemTools::Error("Windows9xHack: Command not specified");
850 /* Make child process use this app's standard files. */
851 ZeroMemory(&si, sizeof si);
853 si.dwFlags = STARTF_USESTDHANDLES;
854 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
855 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
856 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
860 char* cmd = new char[ strlen(command) + 1 ];
861 strcpy(cmd, command);
863 bRet = CreateProcess(
874 if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_FAILED)
876 GetExitCodeProcess(pi.hProcess, &exit_code);
878 CloseHandle(pi.hProcess);
879 CloseHandle(pi.hThread);