home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / dospawn.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  7KB  |  225 lines

  1. /***
  2. *dospawn.c - spawn a child process
  3. *
  4. *       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       defines _dospawn - spawn a child process
  8. *
  9. *******************************************************************************/
  10.  
  11. #include <cruntime.h>
  12. #include <oscalls.h>
  13. #include <internal.h>
  14. #include <msdos.h>
  15. #include <process.h>
  16. #include <string.h>
  17. #include <errno.h>
  18. #include <stdlib.h>
  19. #include <tchar.h>
  20. #include <dbgint.h>
  21.  
  22. #ifndef WPRFLAG
  23. int _p_overlay = 2;
  24. #endif  /* WPRFLAG */
  25.  
  26. /***
  27. *int _dospawn(mode, name, cmdblk, envblk) - spawn a child process
  28. *
  29. *Purpose:
  30. *       Spawns a child process
  31. *
  32. *Entry:
  33. *       int mode     - _P_WAIT, _P_NOWAIT, _P_NOWAITO, _P_OVERLAY, or _P_DETACH
  34. *       _TSCHAR *name   - name of program to execute
  35. *       _TSCHAR *cmdblk - parameter block
  36. *       _TSCHAR *envblk - environment block
  37. *
  38. *Exit:
  39. *       _P_OVERLAY: -1 = error, otherwise doesn't return
  40. *       _P_WAIT:    termination code << 8 + result code
  41. *       _P_DETACH: -1 = error, 0 = success
  42. *       others:    PID of process
  43. *
  44. *Exceptions:
  45. *
  46. *******************************************************************************/
  47.  
  48. #ifdef WPRFLAG
  49. int __cdecl _wdospawn (
  50. #else  /* WPRFLAG */
  51. int __cdecl _dospawn (
  52. #endif  /* WPRFLAG */
  53.         int mode,
  54.         const _TSCHAR *name,
  55.         _TSCHAR *cmdblk,
  56.         _TSCHAR *envblk
  57.         )
  58. {
  59.         char syncexec, asyncresult, background;
  60.         LPTSTR CommandLine;
  61.         STARTUPINFO StartupInfo;
  62.         PROCESS_INFORMATION ProcessInformation;
  63.         BOOL CreateProcessStatus;
  64.         ULONG dosretval;                /* OS return value */
  65.         DWORD retval;
  66.         DWORD fdwCreate = 0;            /* flags for CreateProcess */
  67.         int i;
  68.         ioinfo *pio;
  69.         char *posfile;
  70.         UNALIGNED long *posfhnd;
  71.         int nh;                         /* number of file handles to be
  72.                                            passed to the child */
  73.  
  74.         /* translate input mode value to individual flags */
  75.         syncexec = asyncresult = background = 0;
  76.         switch (mode) {
  77.         case _P_WAIT:    syncexec=1;    break;  /* synchronous execution */
  78.         case 2: /* _P_OVERLAY */
  79.         case _P_NOWAITO: break;                 /* asynchronous execution */
  80.         case _P_NOWAIT:  asyncresult=1; break;  /* asynch + remember result */
  81.         case _P_DETACH:  background=1;  break;  /* detached in null scrn grp */
  82.         default:
  83.             /* invalid mode */
  84.             errno = EINVAL;
  85.             _doserrno = 0;              /* not a Dos error */
  86.             return -1;
  87.         }
  88.  
  89.         /*
  90.          * Loop over null separate arguments, and replace null separators
  91.          * with spaces to turn it back into a single null terminated
  92.          * command line.
  93.          */
  94.         CommandLine = cmdblk;
  95.         while (*cmdblk) {
  96.             while (*cmdblk) {
  97.                 cmdblk++;
  98.             }
  99.  
  100.             /*
  101.              * If not last argument, turn null separator into a space.
  102.              */
  103.             if (cmdblk[1] != _T('\0')) {
  104.                 *cmdblk++ = _T(' ');
  105.             }
  106.         }
  107.  
  108.         memset(&StartupInfo,0,sizeof(StartupInfo));
  109.         StartupInfo.cb = sizeof(StartupInfo);
  110.  
  111.         for ( nh = _nhandle ;
  112.               nh && !_osfile(nh - 1) ;
  113.               nh-- ) ;
  114.  
  115.         StartupInfo.cbReserved2 = (WORD)(sizeof( int ) + (nh *
  116.                                   (sizeof( char ) + sizeof( long ))));
  117.  
  118.         StartupInfo.lpReserved2 = _calloc_crt( StartupInfo.cbReserved2, 1 );
  119.  
  120.         *((UNALIGNED int *)(StartupInfo.lpReserved2)) = nh;
  121.  
  122.         posfile = (char *)(StartupInfo.lpReserved2 + sizeof( int ));
  123.  
  124.         posfhnd = (UNALIGNED long *)(StartupInfo.lpReserved2 + sizeof( int ) +
  125.                   (nh * sizeof( char )));
  126.  
  127.         for ( i = 0,
  128.               posfile = (char *)(StartupInfo.lpReserved2 + sizeof( int )),
  129.               posfhnd = (UNALIGNED long *)(StartupInfo.lpReserved2 +
  130.                         sizeof( int ) + (nh * sizeof( char ))) ;
  131.               i < nh ;
  132.               i++, posfile++, posfhnd++ )
  133.         {
  134.             pio = _pioinfo(i);
  135.             if ( (pio->osfile & FNOINHERIT) == 0 ) {
  136.                 *posfile = pio->osfile;
  137.                 *posfhnd = pio->osfhnd;
  138.             }
  139.             else {
  140.                 *posfile = 0;
  141.                 *posfhnd = (long)INVALID_HANDLE_VALUE;
  142.             }
  143.         }
  144.  
  145.         /*
  146.          * if the child process is detached, it cannot access the console, so
  147.          * we must nuke the information passed for the first three handles.
  148.          */
  149.         if ( background ) {
  150.  
  151.             for ( i = 0,
  152.                   posfile = (char *)(StartupInfo.lpReserved2 + sizeof( int )),
  153.                   posfhnd = (UNALIGNED long *)(StartupInfo.lpReserved2 + sizeof( int )
  154.                             + (nh * sizeof( char ))) ;
  155.                   i < __min( nh, 3 ) ;
  156.                   i++, posfile++, posfhnd++ )
  157.             {
  158.                 *posfile = 0;
  159.                 *posfhnd = (long)INVALID_HANDLE_VALUE;
  160.             }
  161.  
  162.             fdwCreate |= DETACHED_PROCESS;
  163.         }
  164.  
  165.         /**
  166.          * Set errno to 0 to distinguish a child process
  167.          * which returns -1L from an error in the spawning
  168.          * (which will set errno to something non-zero
  169.         **/
  170.  
  171.         _doserrno = errno = 0 ;
  172.  
  173. #ifdef WPRFLAG
  174.         /* indicate to CreateProcess that environment block is wide */
  175.         fdwCreate |= CREATE_UNICODE_ENVIRONMENT;
  176. #endif  /* WPRFLAG */
  177.  
  178.         CreateProcessStatus = CreateProcess( (LPTSTR)name,
  179.                                              CommandLine,
  180.                                              NULL,
  181.                                              NULL,
  182.                                              TRUE,
  183.                                              fdwCreate,
  184.                                              envblk,
  185.                                              NULL,
  186.                                              &StartupInfo,
  187.                                              &ProcessInformation
  188.                                            );
  189.  
  190.         dosretval = GetLastError();
  191.         _free_crt( StartupInfo.lpReserved2 );
  192.  
  193.         if (!CreateProcessStatus) {
  194.             _dosmaperr(dosretval);
  195.             return -1;
  196.         }
  197.  
  198.         if (mode == 2 /* _P_OVERLAY */) {
  199.             /* destroy ourselves */
  200.             _exit(0);
  201.         }
  202.         else if (mode == _P_WAIT) {
  203.             WaitForSingleObject(ProcessInformation.hProcess, (DWORD)(-1L));
  204.  
  205.             /* return termination code and exit code -- note we return
  206.                the full exit code */
  207.             GetExitCodeProcess(ProcessInformation.hProcess, &retval);
  208.  
  209.             CloseHandle(ProcessInformation.hProcess);
  210.         }
  211.         else if (mode == _P_DETACH) {
  212.             /* like totally detached asynchronous spawn, dude,
  213.                close process handle, return 0 for success */
  214.             CloseHandle(ProcessInformation.hProcess);
  215.             retval = (DWORD)0;
  216.         }
  217.         else {
  218.             /* asynchronous spawn -- return PID */
  219.             retval = (DWORD)ProcessInformation.hProcess;
  220.         }
  221.  
  222.         CloseHandle(ProcessInformation.hThread);
  223.         return retval;
  224. }
  225.