cmWin32ProcessExecution.cxx 27 KB

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