cmWin32ProcessExecution.cxx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  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. bool cmWin32ProcessExecution::StartProcess(
  40. const char* cmd, const char* path, bool verbose)
  41. {
  42. this->Initialize();
  43. this->m_Verbose = verbose;
  44. return this->PrivateOpen(cmd, path, _O_RDONLY | _O_TEXT, POPEN_3);
  45. }
  46. bool cmWin32ProcessExecution::Wait(int timeout)
  47. {
  48. return this->PrivateClose(timeout);
  49. }
  50. #define PERROR(str) //::ErrorMessage(__LINE__, str)
  51. static void ErrorMessage(int line, char *str) //display detailed error info
  52. {
  53. DWORD lastmsg = GetLastError();
  54. LPVOID msg;
  55. FormatMessage(
  56. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  57. NULL,
  58. lastmsg,
  59. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  60. (LPTSTR) &msg,
  61. 0,
  62. NULL
  63. );
  64. printf("%d - %s: %s (%d)\n",line,str,msg, lastmsg);
  65. LocalFree(msg);
  66. ::SetLastError(ERROR_SUCCESS);
  67. }
  68. /*
  69. * Internal dictionary mapping popen* file pointers to process handles,
  70. * for use when retrieving the process exit code. See _PyPclose() below
  71. * for more information on this dictionary's use.
  72. */
  73. static void *_PyPopenProcs = NULL;
  74. static BOOL RealPopenCreateProcess(const char *cmdstring,
  75. const char *path,
  76. const char *szConsoleSpawn,
  77. HANDLE hStdin,
  78. HANDLE hStdout,
  79. HANDLE hStderr,
  80. HANDLE *hProcess)
  81. {
  82. PERROR("Start");
  83. //std::cout << "Run: " << cmdstring << std::endl;
  84. PERROR("Start");
  85. PROCESS_INFORMATION piProcInfo;
  86. PERROR("PROCESS_INFORMATION");
  87. STARTUPINFO siStartInfo;
  88. PERROR("STARTUPINFO");
  89. char *s1,*s2, *s3 = " /c ";
  90. int i;
  91. int x;
  92. if (i = GetEnvironmentVariable("COMSPEC",NULL,0))
  93. {
  94. PERROR("GetEnvironmentVariable");
  95. char *comshell;
  96. s1 = (char *)_alloca(i);
  97. if (!(x = GetEnvironmentVariable("COMSPEC", s1, i)))
  98. {
  99. PERROR("GetEnvironmentVariable");
  100. return x;
  101. }
  102. /* Explicitly check if we are using COMMAND.COM. If we are
  103. * then use the w9xpopen hack.
  104. */
  105. comshell = s1 + x;
  106. while (comshell >= s1 && *comshell != '\\')
  107. --comshell;
  108. ++comshell;
  109. if (GetVersion() < 0x80000000 &&
  110. STRICMP(comshell, "command.com") != 0)
  111. {
  112. /* NT/2000 and not using command.com. */
  113. x = i + (int)strlen(s3) + (int)strlen(cmdstring) + 1;
  114. s2 = (char *)_alloca(x);
  115. ZeroMemory(s2, x);
  116. sprintf(s2, "%s%s%s", s1, s3, cmdstring);
  117. //std::cout << "s1: " << s1 << " s2: " << s2 << " s3: " << s3
  118. // << std::endl;
  119. }
  120. else
  121. {
  122. /*
  123. * Oh gag, we're on Win9x or using COMMAND.COM. Use
  124. * the workaround listed in KB: Q150956
  125. */
  126. char modulepath[_MAX_PATH];
  127. struct stat statinfo;
  128. GetModuleFileName(NULL, modulepath, sizeof(modulepath));
  129. for (i = x = 0; modulepath[i]; i++)
  130. if (modulepath[i] == '\\')
  131. x = i+1;
  132. modulepath[x] = '\0';
  133. /* Create the full-name to w9xpopen, so we can test it exists */
  134. strncat(modulepath,
  135. szConsoleSpawn,
  136. (sizeof(modulepath)/sizeof(modulepath[0]))
  137. -strlen(modulepath));
  138. if (stat(modulepath, &statinfo) != 0)
  139. {
  140. /* Eeek - file-not-found - possibly an embedding
  141. situation - see if we can locate it in sys.prefix
  142. */
  143. strncpy(modulepath,
  144. ".",
  145. sizeof(modulepath)/sizeof(modulepath[0]));
  146. if (modulepath[strlen(modulepath)-1] != '\\')
  147. strcat(modulepath, "\\");
  148. strncat(modulepath,
  149. szConsoleSpawn,
  150. (sizeof(modulepath)/sizeof(modulepath[0]))
  151. -strlen(modulepath));
  152. /* No where else to look - raise an easily identifiable
  153. error, rather than leaving Windows to report
  154. "file not found" - as the user is probably blissfully
  155. unaware this shim EXE is used, and it will confuse them.
  156. (well, it confused me for a while ;-)
  157. */
  158. if (stat(modulepath, &statinfo) != 0)
  159. {
  160. std::cout
  161. << "Can not locate '" << szConsoleSpawn
  162. << "' which is needed "
  163. "for popen to work with your shell "
  164. "or platform." << std::endl;
  165. return FALSE;
  166. }
  167. }
  168. x = i + (int)strlen(s3) + (int)strlen(cmdstring) + 1 +
  169. (int)strlen(modulepath) +
  170. (int)strlen(szConsoleSpawn) + 1;
  171. s2 = (char *)_alloca(x);
  172. ZeroMemory(s2, x);
  173. sprintf(
  174. s2,
  175. "%s \"%s%s%s\"",
  176. modulepath,
  177. s1,
  178. s3,
  179. cmdstring);
  180. }
  181. }
  182. /* Could be an else here to try cmd.exe / command.com in the path
  183. Now we'll just error out.. */
  184. else
  185. {
  186. std::cout << "Cannot locate a COMSPEC environment variable to "
  187. << "use as the shell" << std::endl;
  188. return FALSE;
  189. }
  190. ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
  191. siStartInfo.cb = sizeof(STARTUPINFO);
  192. siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
  193. siStartInfo.hStdInput = hStdin;
  194. siStartInfo.hStdOutput = hStdout;
  195. siStartInfo.hStdError = hStderr;
  196. siStartInfo.wShowWindow = SW_HIDE;
  197. if (CreateProcess(NULL,
  198. s2,
  199. NULL,
  200. NULL,
  201. TRUE,
  202. CREATE_NEW_CONSOLE,
  203. NULL,
  204. path,
  205. &siStartInfo,
  206. &piProcInfo) )
  207. {
  208. PERROR("CreateProcess");
  209. /* Close the handles now so anyone waiting is woken. */
  210. CloseHandle(piProcInfo.hThread);
  211. PERROR("Close Handle");
  212. /* Return process handle */
  213. *hProcess = piProcInfo.hProcess;
  214. //std::cout << "Process created..." << std::endl;
  215. return TRUE;
  216. }
  217. win32_error("CreateProcess", s2);
  218. return FALSE;
  219. }
  220. /* The following code is based off of KB: Q190351 */
  221. bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring,
  222. const char* path,
  223. int mode,
  224. int n)
  225. {
  226. HANDLE hChildStdinRd, hChildStdinWr, hChildStdoutRd, hChildStdoutWr,
  227. hChildStderrRd, hChildStderrWr, hChildStdinWrDup, hChildStdoutRdDup,
  228. hChildStderrRdDup, hProcess; /* hChildStdoutWrDup; */
  229. SECURITY_ATTRIBUTES saAttr;
  230. BOOL fSuccess;
  231. int fd1, fd2, fd3;
  232. //FILE *f1, *f2, *f3;
  233. saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
  234. saAttr.bInheritHandle = TRUE;
  235. saAttr.lpSecurityDescriptor = NULL;
  236. if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
  237. {
  238. return win32_error("CreatePipe", NULL);
  239. }
  240. PERROR("CreatePipe");
  241. /* Create new output read handle and the input write handle. Set
  242. * the inheritance properties to FALSE. Otherwise, the child inherits
  243. * the these handles; resulting in non-closeable handles to the pipes
  244. * being created. */
  245. fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
  246. GetCurrentProcess(), &hChildStdinWrDup, 0,
  247. FALSE,
  248. DUPLICATE_SAME_ACCESS);
  249. if (!fSuccess)
  250. return win32_error("DuplicateHandle", NULL);
  251. PERROR("DuplicateHandle");
  252. /* Close the inheritable version of ChildStdin
  253. that we're using. */
  254. CloseHandle(hChildStdinWr);
  255. PERROR("CloseHandle");
  256. if (!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
  257. return win32_error("CreatePipe", NULL);
  258. fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
  259. GetCurrentProcess(), &hChildStdoutRdDup, 0,
  260. FALSE, DUPLICATE_SAME_ACCESS);
  261. if (!fSuccess)
  262. return win32_error("DuplicateHandle", NULL);
  263. PERROR("DuplicateHandle");
  264. /* Close the inheritable version of ChildStdout
  265. that we're using. */
  266. CloseHandle(hChildStdoutRd);
  267. PERROR("CloseHandle");
  268. if (n != POPEN_4)
  269. {
  270. if (!CreatePipe(&hChildStderrRd, &hChildStderrWr, &saAttr, 0))
  271. return win32_error("CreatePipe", NULL);
  272. PERROR("CreatePipe");
  273. fSuccess = DuplicateHandle(GetCurrentProcess(),
  274. hChildStderrRd,
  275. GetCurrentProcess(),
  276. &hChildStderrRdDup, 0,
  277. FALSE, DUPLICATE_SAME_ACCESS);
  278. if (!fSuccess)
  279. return win32_error("DuplicateHandle", NULL);
  280. PERROR("DuplicateHandle");
  281. /* Close the inheritable version of ChildStdErr that we're using. */
  282. CloseHandle(hChildStderrRd);
  283. PERROR("CloseHandle");
  284. }
  285. switch (n)
  286. {
  287. case POPEN_1:
  288. switch (mode & (_O_RDONLY | _O_TEXT | _O_BINARY | _O_WRONLY))
  289. {
  290. case _O_WRONLY | _O_TEXT:
  291. /* Case for writing to child Stdin in text mode. */
  292. fd1 = _open_osfhandle(TO_INTPTR(hChildStdinWrDup), mode);
  293. //f1 = _fdopen(fd1, "w");
  294. /* We don't care about these pipes anymore,
  295. so close them. */
  296. CloseHandle(hChildStdoutRdDup);
  297. CloseHandle(hChildStderrRdDup);
  298. PERROR("CloseHandle");
  299. break;
  300. case _O_RDONLY | _O_TEXT:
  301. /* Case for reading from child Stdout in text mode. */
  302. fd1 = _open_osfhandle(TO_INTPTR(hChildStdoutRdDup), mode);
  303. //f1 = _fdopen(fd1, "r");
  304. /* We don't care about these pipes anymore,
  305. so close them. */
  306. CloseHandle(hChildStdinWrDup);
  307. CloseHandle(hChildStderrRdDup);
  308. PERROR("CloseHandle");
  309. break;
  310. case _O_RDONLY | _O_BINARY:
  311. /* Case for readinig from child Stdout in
  312. binary mode. */
  313. fd1 = _open_osfhandle(TO_INTPTR(hChildStdoutRdDup), mode);
  314. //f1 = _fdopen(fd1, "rb");
  315. /* We don't care about these pipes anymore,
  316. so close them. */
  317. CloseHandle(hChildStdinWrDup);
  318. CloseHandle(hChildStderrRdDup);
  319. PERROR("CloseHandle");
  320. break;
  321. case _O_WRONLY | _O_BINARY:
  322. /* Case for writing to child Stdin in binary mode. */
  323. fd1 = _open_osfhandle(TO_INTPTR(hChildStdinWrDup), mode);
  324. //f1 = _fdopen(fd1, "wb");
  325. /* We don't care about these pipes anymore,
  326. so close them. */
  327. CloseHandle(hChildStdoutRdDup);
  328. CloseHandle(hChildStderrRdDup);
  329. PERROR("CloseHandle");
  330. break;
  331. }
  332. break;
  333. case POPEN_2:
  334. case POPEN_4:
  335. if ( 1 )
  336. {
  337. // Comment this out. Maybe we will need it in the future.
  338. // file IO access to the process might be cool.
  339. //char *m1, *m2;
  340. //if (mode && _O_TEXT)
  341. // {
  342. // m1 = "r";
  343. // m2 = "w";
  344. // }
  345. //else
  346. // {
  347. // m1 = "rb";
  348. // m2 = "wb";
  349. // }
  350. fd1 = _open_osfhandle(TO_INTPTR(hChildStdinWrDup), mode);
  351. //f1 = _fdopen(fd1, m2);
  352. fd2 = _open_osfhandle(TO_INTPTR(hChildStdoutRdDup), mode);
  353. //f2 = _fdopen(fd2, m1);
  354. PERROR("_open_osfhandle");
  355. if (n != 4)
  356. {
  357. CloseHandle(hChildStderrRdDup);
  358. PERROR("CloseHandle");
  359. }
  360. break;
  361. }
  362. case POPEN_3:
  363. if ( 1)
  364. {
  365. // Comment this out. Maybe we will need it in the future.
  366. // file IO access to the process might be cool.
  367. //char *m1, *m2;
  368. //if (mode && _O_TEXT)
  369. // {
  370. // m1 = "r";
  371. // m2 = "w";
  372. // }
  373. //else
  374. // {
  375. // m1 = "rb";
  376. // m2 = "wb";
  377. // }
  378. fd1 = _open_osfhandle(TO_INTPTR(hChildStdinWrDup), mode);
  379. //f1 = _fdopen(fd1, m2);
  380. fd2 = _open_osfhandle(TO_INTPTR(hChildStdoutRdDup), mode);
  381. //f2 = _fdopen(fd2, m1);
  382. fd3 = _open_osfhandle(TO_INTPTR(hChildStderrRdDup), mode);
  383. //f3 = _fdopen(fd3, m1);
  384. PERROR("_open_osfhandle");
  385. break;
  386. }
  387. }
  388. if (n == POPEN_4)
  389. {
  390. if (!RealPopenCreateProcess(cmdstring,
  391. path,
  392. this->m_ConsoleSpawn.c_str(),
  393. hChildStdinRd,
  394. hChildStdoutWr,
  395. hChildStdoutWr,
  396. &hProcess))
  397. return NULL;
  398. }
  399. else
  400. {
  401. if (!RealPopenCreateProcess(cmdstring,
  402. path,
  403. this->m_ConsoleSpawn.c_str(),
  404. hChildStdinRd,
  405. hChildStdoutWr,
  406. hChildStderrWr,
  407. &hProcess))
  408. return NULL;
  409. }
  410. /*
  411. * Insert the files we've created into the process dictionary
  412. * all referencing the list with the process handle and the
  413. * initial number of files (see description below in _PyPclose).
  414. * Since if _PyPclose later tried to wait on a process when all
  415. * handles weren't closed, it could create a deadlock with the
  416. * child, we spend some energy here to try to ensure that we
  417. * either insert all file handles into the dictionary or none
  418. * at all. It's a little clumsy with the various popen modes
  419. * and variable number of files involved.
  420. */
  421. /* Child is launched. Close the parents copy of those pipe
  422. * handles that only the child should have open. You need to
  423. * make sure that no handles to the write end of the output pipe
  424. * are maintained in this process or else the pipe will not close
  425. * when the child process exits and the ReadFile will hang. */
  426. if (!CloseHandle(hChildStdinRd))
  427. return win32_error("CloseHandle", NULL);
  428. PERROR("CloseHandle");
  429. if (!CloseHandle(hChildStdoutWr))
  430. return win32_error("CloseHandle", NULL);
  431. PERROR("CloseHandle");
  432. if ((n != 4) && (!CloseHandle(hChildStderrWr)))
  433. return win32_error("CloseHandle", NULL);
  434. PERROR("CloseHandle");
  435. this->m_ProcessHandle = hProcess;
  436. if ( fd1 >= 0 )
  437. {
  438. // this->m_StdIn = f1;
  439. this->m_pStdIn = fd1;
  440. }
  441. if ( fd2 >= 0 )
  442. {
  443. // this->m_StdOut = f2;
  444. this->m_pStdOut = fd2;
  445. }
  446. if ( fd3 >= 0 )
  447. {
  448. // this->m_StdErr = f3;
  449. this->m_pStdErr = fd3;
  450. }
  451. //std::cout << "Process created for real..." << std::endl;
  452. //std::cout << fd1 << " " << fd2 << " " << fd3 << std::endl;
  453. return true;
  454. }
  455. /*
  456. * Wrapper for fclose() to use for popen* files, so we can retrieve the
  457. * exit code for the child process and return as a result of the close.
  458. *
  459. * This function uses the _PyPopenProcs dictionary in order to map the
  460. * input file pointer to information about the process that was
  461. * originally created by the popen* call that created the file pointer.
  462. * The dictionary uses the file pointer as a key (with one entry
  463. * inserted for each file returned by the original popen* call) and a
  464. * single list object as the value for all files from a single call.
  465. * The list object contains the Win32 process handle at [0], and a file
  466. * count at [1], which is initialized to the total number of file
  467. * handles using that list.
  468. *
  469. * This function closes whichever handle it is passed, and decrements
  470. * the file count in the dictionary for the process handle pointed to
  471. * by this file. On the last close (when the file count reaches zero),
  472. * this function will wait for the child process and then return its
  473. * exit code as the result of the close() operation. This permits the
  474. * files to be closed in any order - it is always the close() of the
  475. * final handle that will return the exit code.
  476. */
  477. /* RED_FLAG 31-Aug-2000 Tim
  478. * This is always called (today!) between a pair of
  479. * Py_BEGIN_ALLOW_THREADS/ Py_END_ALLOW_THREADS
  480. * macros. So the thread running this has no valid thread state, as
  481. * far as Python is concerned. However, this calls some Python API
  482. * functions that cannot be called safely without a valid thread
  483. * state, in particular PyDict_GetItem.
  484. * As a temporary hack (although it may last for years ...), we
  485. * *rely* on not having a valid thread state in this function, in
  486. * order to create our own "from scratch".
  487. * This will deadlock if _PyPclose is ever called by a thread
  488. * holding the global lock.
  489. */
  490. bool cmWin32ProcessExecution::PrivateClose(int timeout)
  491. {
  492. HANDLE hProcess = this->m_ProcessHandle;
  493. int result = -1;
  494. DWORD exit_code;
  495. std::string output = "";
  496. bool done = false;
  497. while(!done)
  498. {
  499. Sleep(10);
  500. bool have_some = false;
  501. struct _stat fsout;
  502. struct _stat fserr;
  503. int rout = _fstat(this->m_pStdOut, &fsout);
  504. int rerr = _fstat(this->m_pStdErr, &fserr);
  505. if ( rout && rerr )
  506. {
  507. break;
  508. }
  509. if (fserr.st_size > 0)
  510. {
  511. //std::cout << "Some error" << std::endl;
  512. char buffer[1023];
  513. int len = read(this->m_pStdErr, buffer, 1023);
  514. buffer[len] = 0;
  515. if ( this->m_Verbose )
  516. {
  517. std::cout << buffer << std::flush;
  518. }
  519. output += buffer;
  520. have_some = true;
  521. }
  522. if (fsout.st_size > 0)
  523. {
  524. //std::cout << "Some output" << std::endl;
  525. char buffer[1023];
  526. int len = read(this->m_pStdOut, buffer, 1023);
  527. buffer[len] = 0;
  528. if ( this->m_Verbose )
  529. {
  530. std::cout << buffer << std::flush;
  531. }
  532. output += buffer;
  533. have_some = true;
  534. }
  535. unsigned long exitCode;
  536. if ( ! have_some )
  537. {
  538. GetExitCodeProcess(hProcess,&exitCode);
  539. if (exitCode != STILL_ACTIVE)
  540. {
  541. //std::cout << "STILL_ACTIVE = " << STILL_ACTIVE << std::endl;
  542. //std::cout << "Process is not active any more: " << exitCode << std::endl;
  543. break;
  544. }
  545. }
  546. }
  547. //std::cout << "Waiting for process to close" << std::endl;
  548. if (WaitForSingleObject(hProcess, INFINITE) != WAIT_FAILED &&
  549. GetExitCodeProcess(hProcess, &exit_code))
  550. {
  551. result = exit_code;
  552. }
  553. else
  554. {
  555. /* Indicate failure - this will cause the file object
  556. * to raise an I/O error and translate the last Win32
  557. * error code from errno. We do have a problem with
  558. * last errors that overlap the normal errno table,
  559. * but that's a consistent problem with the file object.
  560. */
  561. if (result != EOF)
  562. {
  563. /* If the error wasn't from the fclose(), then
  564. * set errno for the file object error handling.
  565. */
  566. errno = GetLastError();
  567. }
  568. result = -1;
  569. }
  570. //std::cout << "Process closed with error code: " << result << std::endl;
  571. /* Free up the native handle at this point */
  572. CloseHandle(hProcess);
  573. this->m_ExitValue = result;
  574. this->m_Output = output;
  575. if ( result < 0 )
  576. {
  577. return false;
  578. }
  579. return true;
  580. }
  581. int cmWin32ProcessExecution::Windows9xHack(const char* command)
  582. {
  583. BOOL bRet;
  584. STARTUPINFO si;
  585. PROCESS_INFORMATION pi;
  586. DWORD exit_code=0;
  587. if (!command)
  588. {
  589. cmSystemTools::Error("Windows9xHack: Command not specified");
  590. return 1;
  591. }
  592. /* Make child process use this app's standard files. */
  593. ZeroMemory(&si, sizeof si);
  594. si.cb = sizeof si;
  595. si.dwFlags = STARTF_USESTDHANDLES;
  596. si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
  597. si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  598. si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
  599. char* cmd = new char[ strlen(command) + 1 ];
  600. strcpy(cmd, command);
  601. bRet = CreateProcess(
  602. NULL, cmd,
  603. NULL, NULL,
  604. TRUE, 0,
  605. NULL, NULL,
  606. &si, &pi
  607. );
  608. delete [] cmd;
  609. if (bRet)
  610. {
  611. if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_FAILED)
  612. {
  613. GetExitCodeProcess(pi.hProcess, &exit_code);
  614. }
  615. CloseHandle(pi.hProcess);
  616. CloseHandle(pi.hThread);
  617. return exit_code;
  618. }
  619. return 1;
  620. }