VOID cmdReturnExitCode (VOID) { VDMINFO VDMInfo; PREDIRCOMPLETE_INFO pRdrInfo; VDMInfo.VDMState = RETURN_ON_NO_COMMAND; VDMInfo.EnviornmentSize = 0; VDMInfo.ErrorCode = (ULONG)getDX(); VDMInfo.CmdSize = 0; VDMInfo.TitleLen = 0; VDMInfo.ReservedLen = 0; VDMInfo.DesktopLen = 0; VDMInfo.CurDirectoryLen = 0; CntrlHandlerState = (CntrlHandlerState & ~CNTRL_SHELLCOUNT) | (((WORD)(CntrlHandlerState & CNTRL_SHELLCOUNT))+1); nt_block_event_thread(0); fBlock = TRUE; // a dos program just terminate, inherit its current directories // and tell base too. cmdUpdateCurrentDirectories((BYTE)getAL()); // Check for any copying needed for redirection pRdrInfo = (PREDIRCOMPLETE_INFO) (((ULONG)getBX() << 16) + (ULONG)getCX()); if (cmdCheckCopyForRedirection (pRdrInfo) == FALSE) VDMInfo.ErrorCode = ERROR_NOT_ENOUGH_MEMORY; GetNextVDMCommand (&VDMInfo); if (VDMInfo.CmdSize > 0){ setCF(1); IsRepeatCall = TRUE; } else { setCF(0); setAL((UCHAR)dwExitCode32); nt_resume_event_thread(); nt_std_handle_notification(fSoftpcRedirectionOnShellOut); fBlock = FALSE; } CntrlHandlerState = (CntrlHandlerState & ~CNTRL_SHELLCOUNT) | (((WORD)(CntrlHandlerState & CNTRL_SHELLCOUNT))-1); return; }
DWORD DosStartProcess32(IN LPCSTR ExecutablePath, IN LPCSTR CommandLine, IN LPCSTR Environment OPTIONAL, IN DWORD ReturnAddress OPTIONAL, IN BOOLEAN StartComSpec) { DWORD Result = ERROR_SUCCESS; HANDLE CommandThread; DOS_START_PROC32 DosStartProc32; #ifndef STANDALONE BOOL Success; VDM_COMMAND_INFO CommandInfo; #endif DosStartProc32.ExecutablePath = (LPSTR)ExecutablePath; DosStartProc32.CommandLine = (LPSTR)CommandLine; DosStartProc32.Environment = (LPSTR)Environment; #ifndef STANDALONE DosStartProc32.ComSpecInfo = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*DosStartProc32.ComSpecInfo)); ASSERT(DosStartProc32.ComSpecInfo); DosStartProc32.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); ASSERT(DosStartProc32.hEvent); #endif /* Pause the VM and detach from the console */ EmulatorPause(); DosProcessConsoleDetach(); /* Start the 32-bit process via another thread */ CommandThread = CreateThread(NULL, 0, &CommandThreadProc, &DosStartProc32, 0, NULL); if (CommandThread == NULL) { DisplayMessage(L"FATAL: Failed to create the command processing thread: %d", GetLastError()); Result = GetLastError(); goto Quit; } #ifndef STANDALONE /* Close the thread handle */ CloseHandle(CommandThread); /* Wait for the process to be ready to start */ WaitForSingleObject(DosStartProc32.hEvent, INFINITE); /* Wait for any potential new DOS app started by the 32-bit process */ RtlZeroMemory(&CommandInfo, sizeof(CommandInfo)); Retry: CommandInfo.VDMState = VDM_FLAG_NESTED_TASK | VDM_FLAG_DONT_WAIT; DPRINT1("Calling GetNextVDMCommand 32bit for possible new VDM task...\n"); Success = GetNextVDMCommand(&CommandInfo); DPRINT1("GetNextVDMCommand 32bit awaited, success = %s, last error = %d\n", Success ? "true" : "false", GetLastError()); /* * Check whether we were awaited because the 32-bit process was stopped, * or because it started a new DOS application. */ if (CommandInfo.CmdLen != 0 || CommandInfo.AppLen != 0 || CommandInfo.PifLen != 0) { DPRINT1("GetNextVDMCommand 32bit, this is for a new VDM task - CmdLen = %d, AppLen = %d, PifLen = %d\n", CommandInfo.CmdLen, CommandInfo.AppLen, CommandInfo.PifLen); /* Repeat the request */ Repeat = TRUE; /* * Set 'Reentry' to TRUE or FALSE depending on whether we are going * to reenter with a new COMMAND.COM. See the comment for: * BOP_CMD 0x10 'Get start information' * (dem.c!DosCmdInterpreterBop) for more details. */ Reentry = StartComSpec; /* If needed, start a new command interpreter to handle the possible incoming DOS commands */ if (StartComSpec) { // // DosStartProcess32 was only called by DosCreateProcess, called from INT 21h, // so the caller stack is already prepared for running a new DOS program // (Flags, CS and IP, and the extra interrupt number, are already pushed). // Result = DosStartComSpec(FALSE, Environment, ReturnAddress, &DosStartProc32.ComSpecInfo->ComSpecPsp); if (Result != ERROR_SUCCESS) { DosDisplayMessage("Failed to start a new Command Interpreter (Error: %u).\n", Result); goto Quit; } } else { /* Retrieve the PSP of the COMSPEC (current PSP set by DosLoadExecutable) */ DosStartProc32.ComSpecInfo->ComSpecPsp = Sda->CurrentPsp; Result = ERROR_SUCCESS; } /* Insert the new entry in the list; it will be freed when needed by COMMAND.COM */ InsertComSpecInfo(DosStartProc32.ComSpecInfo); } else { DPRINT1("GetNextVDMCommand 32bit, 32-bit app stopped\n"); /* Check whether this was our 32-bit app which was killed */ if (!DosStartProc32.ComSpecInfo->Terminated) { DPRINT1("Not our 32-bit app, retrying...\n"); goto Retry; } Result = DosStartProc32.ComSpecInfo->dwExitCode; /* Delete the entry */ RtlFreeHeap(RtlGetProcessHeap(), 0, DosStartProc32.ComSpecInfo); } #else /* Wait for the thread to finish */ WaitForSingleObject(CommandThread, INFINITE); GetExitCodeThread(CommandThread, &Result); /* Close the thread handle */ CloseHandle(CommandThread); DPRINT1("32-bit app stopped\n"); #endif Quit: #ifndef STANDALONE CloseHandle(DosStartProc32.hEvent); #endif /* Attach to the console and resume the VM */ DosProcessConsoleAttach(); EmulatorResume(); return Result; }
static DWORD WINAPI CommandThreadProc(LPVOID Parameter) { BOOL Success; PROCESS_INFORMATION ProcessInfo; STARTUPINFOA StartupInfo; DWORD dwExitCode; PDOS_START_PROC32 DosStartProc32 = (PDOS_START_PROC32)Parameter; #ifndef STANDALONE VDM_COMMAND_INFO CommandInfo; PCOMSPEC_INFO ComSpecInfo = DosStartProc32->ComSpecInfo; #endif /* Set up the VDM, startup and process info structures */ #ifndef STANDALONE RtlZeroMemory(&CommandInfo, sizeof(CommandInfo)); #endif RtlZeroMemory(&ProcessInfo, sizeof(ProcessInfo)); RtlZeroMemory(&StartupInfo, sizeof(StartupInfo)); StartupInfo.cb = sizeof(StartupInfo); // FIXME: Build suitable 32-bit environment!! #ifndef STANDALONE /* * Wait for signaling a new VDM task and increment the VDM re-entry count so * that we can handle 16-bit apps that may be possibly started by the 32-bit app. */ CommandInfo.VDMState = VDM_INC_REENTER_COUNT; DPRINT1("Calling GetNextVDMCommand reenter++\n"); Success = GetNextVDMCommand(&CommandInfo); DPRINT1("GetNextVDMCommand reenter++ success = %s, last error = %d\n", Success ? "true" : "false", GetLastError()); ++ReentrancyCount; #endif /* Start the process */ Success = CreateProcessA(NULL, // ProgramName, DosStartProc32->CommandLine, NULL, NULL, TRUE, // Inherit handles CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED, DosStartProc32->Environment, NULL, // lpCurrentDirectory, see "START" command in cmd.exe &StartupInfo, &ProcessInfo); #ifndef STANDALONE /* Signal our caller the process was started */ SetEvent(DosStartProc32->hEvent); // After this point, 'DosStartProc32' is not valid anymore. #endif if (Success) { /* Resume the process */ ResumeThread(ProcessInfo.hThread); /* Wait for the process to finish running and retrieve its exit code */ WaitForSingleObject(ProcessInfo.hProcess, INFINITE); GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode); /* Close the handles */ CloseHandle(ProcessInfo.hThread); CloseHandle(ProcessInfo.hProcess); } else { dwExitCode = GetLastError(); } #ifndef STANDALONE ASSERT(ComSpecInfo); ComSpecInfo->Terminated = TRUE; ComSpecInfo->dwExitCode = dwExitCode; /* Decrement the VDM re-entry count */ CommandInfo.VDMState = VDM_DEC_REENTER_COUNT; DPRINT1("Calling GetNextVDMCommand reenter--\n"); Success = GetNextVDMCommand(&CommandInfo); DPRINT1("GetNextVDMCommand reenter-- success = %s, last error = %d\n", Success ? "true" : "false", GetLastError()); --ReentrancyCount; return 0; #else return dwExitCode; #endif }
static VOID CmdSetExitCode(VOID) { #ifndef STANDALONE BOOL Success; PCOMSPEC_INFO ComSpecInfo; VDM_COMMAND_INFO CommandInfo; #endif /* Pause the VM */ EmulatorPause(); #ifndef STANDALONE /* * Check whether we need to shell out now in case we were started by a 32-bit app, * or we were started alone along with the root 32-bit app. */ ComSpecInfo = FindComSpecInfoByPsp(Sda->CurrentPsp); if ((ComSpecInfo && ComSpecInfo->Terminated) || (ComSpecInfo == &RootCmd && SessionId != 0)) { RemoveComSpecInfo(ComSpecInfo); #endif DPRINT1("Exit DOS from ExitCode (prologue)!\n"); setCF(0); goto Quit; #ifndef STANDALONE } /* Clear the VDM structure */ RtlZeroMemory(&CommandInfo, sizeof(CommandInfo)); Retry: /* Update the VDM state of the task */ // CommandInfo.TaskId = SessionId; CommandInfo.ExitCode = getDX(); CommandInfo.VDMState = VDM_FLAG_DONT_WAIT; DPRINT1("Calling GetNextVDMCommand 32bit end of VDM task\n"); Success = GetNextVDMCommand(&CommandInfo); DPRINT1("GetNextVDMCommand 32bit end of VDM task success = %s, last error = %d\n", Success ? "true" : "false", GetLastError()); /* * Check whether we were awaited because the 32-bit process was stopped, * or because it started a new DOS application. */ if (CommandInfo.CmdLen != 0 || CommandInfo.AppLen != 0 || CommandInfo.PifLen != 0) { DPRINT1("GetNextVDMCommand end-of-app, this is for a new VDM task - CmdLen = %d, AppLen = %d, PifLen = %d\n", CommandInfo.CmdLen, CommandInfo.AppLen, CommandInfo.PifLen); /* Repeat the request */ Repeat = TRUE; setCF(1); } else { DPRINT1("GetNextVDMCommand end-of-app, the app stopped\n"); /* Check whether we need to shell out now in case we were started by a 32-bit app */ ComSpecInfo = FindComSpecInfoByPsp(Sda->CurrentPsp); if (!ComSpecInfo || !ComSpecInfo->Terminated) { DPRINT1("Not our 32-bit app, retrying...\n"); goto Retry; } ASSERT(ComSpecInfo->Terminated == TRUE); /* Record found, remove it and exit now */ RemoveComSpecInfo(ComSpecInfo); DPRINT1("Exit DOS from ExitCode wait!\n"); setCF(0); } #endif // FIXME: Use the retrieved exit code as the value of our exit code // when COMMAND.COM will shell-out ?? Quit: /* Resume the VM */ EmulatorResume(); }
static VOID CmdStartProcess(VOID) { #ifndef STANDALONE PCOMSPEC_INFO ComSpecInfo; #endif SIZE_T CmdLen; PNEXT_CMD DataStruct = (PNEXT_CMD)SEG_OFF_TO_PTR(getDS(), getDX()); DPRINT1("CmdStartProcess -- DS:DX = %04X:%04X (DataStruct = 0x%p)\n", getDS(), getDX(), DataStruct); /* Pause the VM */ EmulatorPause(); #ifndef STANDALONE /* Check whether we need to shell out now in case we were started by a 32-bit app */ ComSpecInfo = FindComSpecInfoByPsp(Sda->CurrentPsp); if (ComSpecInfo && ComSpecInfo->Terminated) { RemoveComSpecInfo(ComSpecInfo); DPRINT1("Exit DOS from start-app BOP\n"); setCF(1); goto Quit; } /* Clear the structure */ RtlZeroMemory(&CommandInfo, sizeof(CommandInfo)); /* Initialize the structure members */ CommandInfo.TaskId = SessionId; CommandInfo.VDMState = VDM_FLAG_DOS; CommandInfo.CmdLine = CmdLine; CommandInfo.CmdLen = sizeof(CmdLine); CommandInfo.AppName = AppName; CommandInfo.AppLen = sizeof(AppName); CommandInfo.PifFile = PifFile; CommandInfo.PifLen = sizeof(PifFile); CommandInfo.CurDirectory = CurDirectory; CommandInfo.CurDirectoryLen = sizeof(CurDirectory); CommandInfo.Desktop = Desktop; CommandInfo.DesktopLen = sizeof(Desktop); CommandInfo.Title = Title; CommandInfo.TitleLen = sizeof(Title); CommandInfo.Env = Env; CommandInfo.EnvLen = EnvSize; if (First) CommandInfo.VDMState |= VDM_FLAG_FIRST_TASK; Command: if (Repeat) CommandInfo.VDMState |= VDM_FLAG_RETRY; Repeat = FALSE; /* Get the VDM command information */ DPRINT1("Calling GetNextVDMCommand in CmdStartProcess: wait for new VDM task...\n"); if (!GetNextVDMCommand(&CommandInfo)) { DPRINT1("CmdStartProcess - GetNextVDMCommand failed, retrying... last error = %d\n", GetLastError()); if (CommandInfo.EnvLen > EnvSize) { /* Expand the environment size */ EnvSize = CommandInfo.EnvLen; CommandInfo.Env = Env = RtlReAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, Env, EnvSize); /* Repeat the request */ Repeat = TRUE; goto Command; } /* Shouldn't happen */ DisplayMessage(L"An unrecoverable failure happened from start-app BOP; exiting DOS."); setCF(1); goto Quit; } // FIXME: What happens if some other 32-bit app is killed while we are waiting there?? DPRINT1("CmdStartProcess - GetNextVDMCommand succeeded, start app...\n"); #else if (!First) { DPRINT1("Exit DOS from start-app BOP\n"); setCF(1); goto Quit; } #endif /* Compute the command line length, not counting the terminating "\r\n" */ CmdLen = strlen(CmdLine); if (CmdLen >= 2 && CmdLine[CmdLen - 2] == '\r') CmdLen -= 2; DPRINT1("Starting '%s' ('%.*s')...\n", AppName, CmdLen, CmdLine); /* Start the process */ // FIXME: Merge 'Env' with the master environment SEG_OFF_TO_PTR(SYSTEM_ENV_BLOCK, 0) // FIXME: Environment RtlCopyMemory(SEG_OFF_TO_PTR(DataStruct->AppNameSeg, DataStruct->AppNameOff), AppName, MAX_PATH); *(PBYTE)(SEG_OFF_TO_PTR(DataStruct->CmdLineSeg, DataStruct->CmdLineOff)) = (BYTE)CmdLen; RtlCopyMemory(SEG_OFF_TO_PTR(DataStruct->CmdLineSeg, DataStruct->CmdLineOff + 1), CmdLine, DOS_CMDLINE_LENGTH); #ifndef STANDALONE /* Update console title if we run in a separate console */ if (SessionId != 0) SetConsoleTitleA(AppName); #endif First = FALSE; setCF(0); DPRINT1("App started!\n"); Quit: /* Resume the VM */ EmulatorResume(); }
static VOID WINAPI DosStart(LPWORD Stack) { BOOLEAN Success; DWORD Result; #ifndef STANDALONE INT i; #endif DPRINT("DosStart\n"); /* * We succeeded, deregister the DOS Starting BOP * so that no app will be able to call us back. */ RegisterBop(BOP_START_DOS, NULL); /* Initialize the callback context */ InitializeContext(&DosContext, BIOS_CODE_SEGMENT, 0x0010); Success = DosBIOSInitialize(); // Success &= DosKRNLInitialize(); if (!Success) { BiosDisplayMessage("DOS32 loading failed (Error: %u). The VDM will shut down.\n", GetLastError()); EmulatorTerminate(); return; } /* Load the mouse driver */ DosMouseInitialize(); #ifndef STANDALONE /* Parse the command line arguments */ for (i = 1; i < NtVdmArgc; i++) { if (wcsncmp(NtVdmArgv[i], L"-i", 2) == 0) { /* This is the session ID (hex format) */ SessionId = wcstoul(NtVdmArgv[i] + 2, NULL, 16); } } /* Initialize Win32-VDM environment */ Env = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, EnvSize); if (Env == NULL) { DosDisplayMessage("Failed to initialize the global environment (Error: %u). The VDM will shut down.\n", GetLastError()); EmulatorTerminate(); return; } /* Clear the structure */ RtlZeroMemory(&CommandInfo, sizeof(CommandInfo)); /* Get the initial information */ CommandInfo.TaskId = SessionId; CommandInfo.VDMState = VDM_GET_FIRST_COMMAND | VDM_FLAG_DOS; GetNextVDMCommand(&CommandInfo); #else /* Retrieve the command to start */ if (NtVdmArgc >= 2) { WideCharToMultiByte(CP_ACP, 0, NtVdmArgv[1], -1, AppName, sizeof(AppName), NULL, NULL); if (NtVdmArgc >= 3) WideCharToMultiByte(CP_ACP, 0, NtVdmArgv[2], -1, CmdLine, sizeof(CmdLine), NULL, NULL); else strcpy(CmdLine, ""); } else { DosDisplayMessage("Invalid DOS command line\n"); EmulatorTerminate(); return; } #endif /* * At this point, CS:IP points to the DOS BIOS exit code. If the * root command interpreter fails to start (or if it exits), DOS * exits and the VDM terminates. */ /* Start the root command interpreter */ // TODO: Really interpret the 'SHELL=' line of CONFIG.NT, and use it! /* * Prepare the stack for DosStartComSpec: * push Flags, CS and IP, and an extra WORD. */ setSP(getSP() - sizeof(WORD)); *((LPWORD)SEG_OFF_TO_PTR(getSS(), getSP())) = (WORD)getEFLAGS(); setSP(getSP() - sizeof(WORD)); *((LPWORD)SEG_OFF_TO_PTR(getSS(), getSP())) = getCS(); setSP(getSP() - sizeof(WORD)); *((LPWORD)SEG_OFF_TO_PTR(getSS(), getSP())) = getIP(); setSP(getSP() - sizeof(WORD)); Result = DosStartComSpec(TRUE, SEG_OFF_TO_PTR(SYSTEM_ENV_BLOCK, 0), MAKELONG(getIP(), getCS()), #ifndef STANDALONE &RootCmd.ComSpecPsp #else NULL #endif ); if (Result != ERROR_SUCCESS) { /* Unprepare the stack for DosStartComSpec */ setSP(getSP() + 4*sizeof(WORD)); DosDisplayMessage("Failed to start the Command Interpreter (Error: %u). The VDM will shut down.\n", Result); EmulatorTerminate(); return; } #ifndef STANDALONE RootCmd.Terminated = FALSE; InsertComSpecInfo(&RootCmd); #endif /**/ /* Attach to the console and resume the VM */ DosProcessConsoleAttach(); EmulatorResume(); /**/ return; }
VOID cmdExec32 (PCHAR pCmd32, PCHAR pEnv) { DWORD dwThreadId; HANDLE hThread; pCommand32 = pCmd32; pEnv32 = pEnv; CntrlHandlerState = (CntrlHandlerState & ~CNTRL_SHELLCOUNT) | (((WORD)(CntrlHandlerState & CNTRL_SHELLCOUNT))+1); nt_block_event_thread(0); fSoftpcRedirectionOnShellOut = fSoftpcRedirection; fBlock = TRUE; if((hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)cmdCreateProcess, NULL, 0, &dwThreadId)) == FALSE) { setCF(0); setAL((UCHAR)GetLastError()); nt_resume_event_thread(); nt_std_handle_notification(fSoftpcRedirectionOnShellOut); fBlock = FALSE; CntrlHandlerState = (CntrlHandlerState & ~CNTRL_SHELLCOUNT) | (((WORD)(CntrlHandlerState & CNTRL_SHELLCOUNT))-1); return; } else CloseHandle (hThread); // Wait for next command to be re-entered VDMInfo.VDMState = NO_PARENT_TO_WAKE | RETURN_ON_NO_COMMAND; VDMInfo.EnviornmentSize = 0; VDMInfo.ErrorCode = 0; VDMInfo.CmdSize = 0; VDMInfo.TitleLen = 0; VDMInfo.ReservedLen = 0; VDMInfo.DesktopLen = 0; VDMInfo.CurDirectoryLen = 0; GetNextVDMCommand (&VDMInfo); if (VDMInfo.CmdSize > 0){ setCF(1); IsRepeatCall = TRUE; } else { setCF(0); setAL((UCHAR)dwExitCode32); nt_resume_event_thread(); nt_std_handle_notification(fSoftpcRedirectionOnShellOut); fBlock = FALSE; } CntrlHandlerState = (CntrlHandlerState & ~CNTRL_SHELLCOUNT) | (((WORD)(CntrlHandlerState & CNTRL_SHELLCOUNT))-1); return; }
VOID cmdCreateProcess ( VOID ) { VDMINFO VDMInfoForCount; STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInformation; HANDLE hStd16In,hStd16Out,hStd16Err; CHAR CurDirVar [] = "=?:"; CHAR Buffer [MAX_DIR]; CHAR *CurDir = Buffer; DWORD dwRet; BOOL Status; NTSTATUS NtStatus; UNICODE_STRING Unicode; OEM_STRING OemString; LPVOID lpNewEnv=NULL; PSTD_HANDLES pStdHandles; ANSI_STRING Env_A; // we have one more 32 executable active Exe32ActiveCount++; // Increment the Re-enterancy count for the VDM VDMInfoForCount.VDMState = INCREMENT_REENTER_COUNT; GetNextVDMCommand (&VDMInfoForCount); RtlZeroMemory((PVOID)&StartupInfo,sizeof(STARTUPINFO)); StartupInfo.cb = sizeof(STARTUPINFO); CurDirVar [1] = chDefaultDrive; dwRet = GetEnvironmentVariable (CurDirVar,Buffer,MAX_DIR); if (dwRet == 0 || dwRet == MAX_DIR) CurDir = NULL; pStdHandles = (PSTD_HANDLES) GetVDMAddr (getSS(), getBP()); if ((hStd16In = (HANDLE) FETCHDWORD(pStdHandles->hStdIn)) != (HANDLE)-1) SetStdHandle (STD_INPUT_HANDLE, hStd16In); if ((hStd16Out = (HANDLE) FETCHDWORD(pStdHandles->hStdOut)) != (HANDLE)-1) SetStdHandle (STD_OUTPUT_HANDLE, hStd16Out); if ((hStd16Err = (HANDLE) FETCHDWORD(pStdHandles->hStdErr)) != (HANDLE)-1) SetStdHandle (STD_ERROR_HANDLE, hStd16Err); /* * Warning, pEnv32 currently points to an ansi environment. * The DOS is using an ANSI env which isn't quite correct. * If the DOS is changed to use an OEM env then we will * have to convert the env back to ansi before spawning * non-dos exes ?!? * 16-Jan-1993 Jonle */ Env_A.Buffer = NULL; RtlInitString((PSTRING)&OemString, pCommand32); NtStatus = RtlOemStringToUnicodeString(&Unicode,&OemString,TRUE); if (NT_SUCCESS(NtStatus)) { NtStatus = RtlUnicodeStringToAnsiString((PANSI_STRING)&OemString, &Unicode, FALSE); RtlFreeUnicodeString( &Unicode ); } if (!NT_SUCCESS(NtStatus)) { SetLastError(RtlNtStatusToDosError(NtStatus)); Status = FALSE; } else { if (pEnv32 != NULL && !cmdXformEnvironment (pEnv32, &Env_A)) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); Status = FALSE; } else { Status = CreateProcess ( NULL, (LPTSTR)pCommand32, NULL, NULL, TRUE, CREATE_SUSPENDED | CREATE_DEFAULT_ERROR_MODE, Env_A.Buffer, (LPTSTR)CurDir, &StartupInfo, &ProcessInformation); } } if (Status == FALSE) dwExitCode32 = GetLastError (); if (hStd16In != (HANDLE)-1) SetStdHandle (STD_INPUT_HANDLE, SCS_hStdIn); if (hStd16Out != (HANDLE)-1) SetStdHandle (STD_OUTPUT_HANDLE, SCS_hStdOut); if (hStd16Err != (HANDLE)-1) SetStdHandle (STD_ERROR_HANDLE, SCS_hStdErr); if (Status) { ResumeThread (ProcessInformation.hThread); WaitForSingleObject(ProcessInformation.hProcess, (DWORD)-1); GetExitCodeProcess (ProcessInformation.hProcess, &dwExitCode32); CloseHandle (ProcessInformation.hProcess); CloseHandle (ProcessInformation.hThread); } if (Env_A.Buffer) RtlFreeAnsiString(&Env_A); // Decrement the Re-enterancy count for the VDM VDMInfoForCount.VDMState = DECREMENT_REENTER_COUNT; GetNextVDMCommand (&VDMInfoForCount); // one less 32 executable active Exe32ActiveCount--; // Kill this thread ExitThread (0); }
static DWORD WINAPI CommandThreadProc(LPVOID Parameter) { BOOLEAN First = TRUE; DWORD Result; VDM_COMMAND_INFO CommandInfo; CHAR CmdLine[MAX_PATH]; CHAR AppName[MAX_PATH]; CHAR PifFile[MAX_PATH]; CHAR Desktop[MAX_PATH]; CHAR Title[MAX_PATH]; ULONG EnvSize = 256; PVOID Env = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, EnvSize); UNREFERENCED_PARAMETER(Parameter); ASSERT(Env != NULL); do { /* Clear the structure */ RtlZeroMemory(&CommandInfo, sizeof(CommandInfo)); /* Initialize the structure members */ CommandInfo.TaskId = SessionId; CommandInfo.VDMState = VDM_FLAG_DOS; CommandInfo.CmdLine = CmdLine; CommandInfo.CmdLen = sizeof(CmdLine); CommandInfo.AppName = AppName; CommandInfo.AppLen = sizeof(AppName); CommandInfo.PifFile = PifFile; CommandInfo.PifLen = sizeof(PifFile); CommandInfo.Desktop = Desktop; CommandInfo.DesktopLen = sizeof(Desktop); CommandInfo.Title = Title; CommandInfo.TitleLen = sizeof(Title); CommandInfo.Env = Env; CommandInfo.EnvLen = EnvSize; if (First) CommandInfo.VDMState |= VDM_FLAG_FIRST_TASK; Command: if (!GetNextVDMCommand(&CommandInfo)) { if (CommandInfo.EnvLen > EnvSize) { /* Expand the environment size */ EnvSize = CommandInfo.EnvLen; Env = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Env, EnvSize); /* Repeat the request */ goto Command; } break; } /* Start the process from the command line */ DPRINT1("Starting '%s' ('%s')...\n", AppName, CmdLine); Result = DosStartProcess(AppName, CmdLine, Env); if (Result != ERROR_SUCCESS) { DisplayMessage(L"Could not start '%S'. Error: %u", AppName, Result); // break; continue; } First = FALSE; } while (AcceptCommands); HeapFree(GetProcessHeap(), 0, Env); return 0; }