cmWin32ProcessExecution.cxx 26 KB

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