Пример #1
0
static VOID WINAPI DosCmdInterpreterBop(LPWORD Stack)
{
    /* Get the Function Number and skip it */
    BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
    setIP(getIP() + 1);

    switch (FuncNum)
    {
        /* Kill the VDM */
        case 0x00:
        {
            /* Stop the VDM */
            EmulatorTerminate();
            return;
        }

        /*
         * Get a new app to start
         *
         * Input
         *     DS:DX : Data block.
         *
         * Output
         *     CF    : 0: Success; 1: Failure.
         */
        case 0x01:
        {
            CmdStartProcess();
            break;
        }

        /*
         * Check binary format
         *
         * Input
         *     DS:DX : Program to check.
         *
         * Output
         *     CF    : 0: Success; 1: Failure.
         *     AX    : Error code.
         */
        case 0x07:
        {
            DWORD BinaryType;
            LPSTR ProgramName = (LPSTR)SEG_OFF_TO_PTR(getDS(), getDX());

            if (!GetBinaryTypeA(ProgramName, &BinaryType))
            {
                /* An error happened, bail out */
                setCF(1);
                setAX(LOWORD(GetLastError()));
                break;
            }

            // FIXME: We only support DOS binaries for now...
            ASSERT(BinaryType == SCS_DOS_BINARY);
            if (BinaryType != SCS_DOS_BINARY)
            {
                /* An error happened, bail out */
                setCF(1);
                setAX(LOWORD(ERROR_BAD_EXE_FORMAT));
                break;
            }

            /* Return success: DOS application */
            setCF(0);
            break;
        }

        /*
         * Start an external command
         *
         * Input
         *     DS:SI : Command to start.
         *     ES    : Environment block segment.
         *     AL    : Current drive number.
         *     AH    : 0: Directly start the command;
         *             1: Use "cmd.exe /c" to start the command.
         *
         * Output
         *     CF    : 0: Shell-out; 1: Continue.
         *     AL    : Error/Exit code.
         */
        case 0x08:
        {
            CmdStartExternalCommand();
            break;
        }

        /*
         * Start the default 32-bit command interpreter (COMSPEC)
         *
         * Input
         *     ES    : Environment block segment.
         *     AL    : Current drive number.
         *
         * Output
         *     CF    : 0: Shell-out; 1: Continue.
         *     AL    : Error/Exit code.
         */
        case 0x0A:
        {
            CmdStartComSpec32();
            break;
        }

        /*
         * Set exit code
         *
         * Input
         *     DX    : Exit code
         *
         * Output
         *     CF    : 0: Shell-out; 1: Continue.
         */
        case 0x0B:
        {
            CmdSetExitCode();
            break;
        }

        /*
         * Get start information
         *
         * Output
         *     AL    : 0 (resp. 1): Started from (resp. without) an existing console.
         */
        case 0x10:
        {
#ifndef STANDALONE
            /*
             * When a new instance of our (internal) COMMAND.COM is started,
             * we check whether we need to run a 32-bit COMSPEC. This goes by
             * checking whether we were started in a new console (no parent
             * console process) or from an existing one.
             *
             * However COMMAND.COM can also be started in the case where a
             * 32-bit process (started by a 16-bit parent) wants to start a new
             * 16-bit process: to ensure DOS reentry we need to start a new
             * instance of COMMAND.COM. On Windows the COMMAND.COM is started
             * just before the 32-bit process (in fact, it is this COMMAND.COM
             * which starts the 32-bit process via an undocumented command-line
             * switch '/z', which syntax is:
             *     COMMAND.COM /z\bAPPNAME.EXE
             * notice the '\b' character inserted in-between. Then COMMAND.COM
             * issues a BOP_CMD 08h with AH=00h to start the process).
             *
             * Instead, we do the reverse, i.e. we start the 32-bit process,
             * and *only* if needed, i.e. if this process wants to start a
             * new 16-bit process, we start our COMMAND.COM.
             *
             * The problem we then face is that our COMMAND.COM will possibly
             * want to start a new COMSPEC, however we do not want this.
             * The chosen solution is to flag this case -- done with the 'Reentry'
             * boolean -- so that COMMAND.COM will not attempt to start COMSPEC
             * but instead will directly try to start the 16-bit process.
             */
            // setAL(SessionId != 0);
            setAL((SessionId != 0) && !Reentry);
            /* Reset 'Reentry' */
            Reentry = FALSE;
#else
            setAL(0);
#endif
            break;
        }

        default:
        {
            DPRINT1("Unknown DOS CMD Interpreter BOP Function: 0x%02X\n", FuncNum);
            // setCF(1); // Disable, otherwise we enter an infinite loop
            break;
        }
    }
}
Пример #2
0
/***********************************************************************
 *		MZ_Exec
 *
 * this may only be called from existing DOS processes
 */
BOOL WINAPI MZ_Exec( CONTEXT86 *context, LPCSTR filename, BYTE func, LPVOID paramblk )
{
  DWORD binType;
  STARTUPINFOA st;
  PROCESS_INFORMATION pe;
  HANDLE hFile;

  BOOL ret = FALSE;

  if(!GetBinaryTypeA(filename, &binType))   /* determine what kind of binary this is */
  {
    return FALSE; /* binary is not an executable */
  }

  /* handle non-dos executables */
  if(binType != SCS_DOS_BINARY)
  {
    if(func == 0) /* load and execute */
    {
      LPSTR fullCmdLine;
      WORD fullCmdLength;
      LPBYTE psp_start = (LPBYTE)((DWORD)DOSVM_psp << 4);
      PDB16 *psp = (PDB16 *)psp_start;
      ExecBlock *blk = (ExecBlock *)paramblk;
      LPBYTE cmdline = PTR_REAL_TO_LIN(SELECTOROF(blk->cmdline),OFFSETOF(blk->cmdline));
      LPBYTE envblock = PTR_REAL_TO_LIN(psp->environment, 0);
      int    cmdLength = cmdline[0];

      /*
       * If cmdLength is 127, command tail is truncated and environment 
       * variable CMDLINE should contain full command line 
       * (this includes filename).
       */
      if (cmdLength == 127)
      {
          FIXME( "CMDLINE argument passing is unimplemented.\n" );
          cmdLength = 126; /* FIXME */
      }

      fullCmdLength = (strlen(filename) + 1) + cmdLength + 1; /* filename + space + cmdline + terminating null character */

      fullCmdLine = HeapAlloc(GetProcessHeap(), 0, fullCmdLength);
      if(!fullCmdLine) return FALSE; /* return false on memory alloc failure */

      /* build the full command line from the executable file and the command line being passed in */
      snprintf(fullCmdLine, fullCmdLength, "%s ", filename); /* start off with the executable filename and a space */
      memcpy(fullCmdLine + strlen(fullCmdLine), cmdline + 1, cmdLength); /* append cmdline onto the end */
      fullCmdLine[fullCmdLength - 1] = 0; /* null terminate string */

      ZeroMemory (&st, sizeof(STARTUPINFOA));
      st.cb = sizeof(STARTUPINFOA);
      ret = CreateProcessA (NULL, fullCmdLine, NULL, NULL, TRUE, 0, envblock, NULL, &st, &pe);

      /* wait for the app to finish and clean up PROCESS_INFORMATION handles */
      if(ret)
      {
        WaitForSingleObject(pe.hProcess, INFINITE);  /* wait here until the child process is complete */
        CloseHandle(pe.hProcess);
        CloseHandle(pe.hThread);
      }

      HeapFree(GetProcessHeap(), 0, fullCmdLine);  /* free the memory we allocated */
    }
    else
    {
      FIXME("EXEC type of %d not implemented for non-dos executables\n", func);
      ret = FALSE;
    }

    return ret;
  } /* if(binType != SCS_DOS_BINARY) */


  /* handle dos executables */

  hFile = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ,
			     NULL, OPEN_EXISTING, 0, 0);
  if (hFile == INVALID_HANDLE_VALUE) return FALSE;

  switch (func) {
  case 0: /* load and execute */
  case 1: /* load but don't execute */
    {
      /* save current process's return SS:SP now */
      LPBYTE psp_start = (LPBYTE)((DWORD)DOSVM_psp << 4);
      PDB16 *psp = (PDB16 *)psp_start;
      psp->saveStack = (DWORD)MAKESEGPTR(context->SegSs, LOWORD(context->Esp));
    }
    ret = MZ_DoLoadImage( hFile, filename, NULL, ((ExecBlock *)paramblk)->env_seg );
    if (ret) {
      /* MZ_LoadImage created a new PSP and loaded new values into it,
       * let's work on the new values now */
      LPBYTE psp_start = (LPBYTE)((DWORD)DOSVM_psp << 4);
      ExecBlock *blk = (ExecBlock *)paramblk;
      LPBYTE cmdline = PTR_REAL_TO_LIN(SELECTOROF(blk->cmdline),OFFSETOF(blk->cmdline));

      /* First character contains the length of the command line. */
      MZ_FillPSP(psp_start, (LPSTR)cmdline + 1, cmdline[0]);

      /* the lame MS-DOS engineers decided that the return address should be in int22 */
      DOSVM_SetRMHandler(0x22, (FARPROC16)MAKESEGPTR(context->SegCs, LOWORD(context->Eip)));
      if (func) {
	/* don't execute, just return startup state */
        /*
         * From Ralph Brown:
         *  For function 01h, the AX value to be passed to the child program 
         *  is put on top of the child's stack
         */
        LPBYTE stack;
        init_sp -= 2;
        stack = (LPBYTE) CTX_SEG_OFF_TO_LIN(context, init_ss, init_sp);
        /* FIXME: push AX correctly */
        stack[0] = 0x00;    /* push AL */
        stack[1] = 0x00;    /* push AH */
	
	blk->init_cs = init_cs;
	blk->init_ip = init_ip;
	blk->init_ss = init_ss;
	blk->init_sp = init_sp;
      } else {
	/* execute by making us return to new process */
	context->SegCs = init_cs;
	context->Eip   = init_ip;
	context->SegSs = init_ss;
	context->Esp   = init_sp;
	context->SegDs = DOSVM_psp;
	context->SegEs = DOSVM_psp;
	context->Eax   = 0;
      }
    }
    break;
  case 3: /* load overlay */
    {
      OverlayBlock *blk = (OverlayBlock *)paramblk;
      ret = MZ_DoLoadImage( hFile, filename, blk, 0);
    }
    break;
  default:
    FIXME("EXEC load type %d not implemented\n", func);
    SetLastError(ERROR_INVALID_FUNCTION);
    break;
  }
  CloseHandle(hFile);
  return ret;
}