cmWin32ProcessExecution.cxx 23 KB

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