/* Allocate stack space for the registers */
StackPointer -= sizeof(DOS_REGISTER_STATE);
State = SEG_OFF_TO_PTR(getSS(), StackPointer);
+ setSP(StackPointer);
/* Save */
State->EAX = getEAX();
static inline VOID DosRestoreState(VOID)
{
PDOS_REGISTER_STATE State;
- WORD StackPointer = getSP();
- /* SS:SP points to the stack on the last entry to INT 21h */
- StackPointer -= (STACK_FLAGS + 1) * 2; /* Interrupt parameters */
- StackPointer -= sizeof(DOS_REGISTER_STATE); /* Pushed state structure */
- State = SEG_OFF_TO_PTR(getSS(), StackPointer);
+ /* Pop the state structure from the stack */
+ State = SEG_OFF_TO_PTR(getSS(), getSP());
+ setSP(getSP() + sizeof(DOS_REGISTER_STATE));
/* Restore */
setEAX(State->EAX);
IN LPCSTR ExecutablePath,
IN PDOS_EXEC_PARAM_BLOCK Parameters,
IN LPCSTR CommandLine OPTIONAL,
- IN LPCSTR Environment OPTIONAL,
- IN DWORD ReturnAddress OPTIONAL)
+ IN LPCSTR Environment OPTIONAL)
{
DWORD Result = ERROR_SUCCESS;
HANDLE FileHandle = INVALID_HANDLE_VALUE, FileMapping = NULL;
/* Buffer for command line conversion: 1 byte for size; 127 bytes for contents */
CHAR CmdLineBuffer[1 + DOS_CMDLINE_LENGTH];
- DPRINT1("DosLoadExecutable(%d, %s, 0x%08X, 0x%08X)\n",
+ DPRINT1("DosLoadExecutable(%d, '%s', 0x%08X, 0x%08X, 0x%08X)\n",
LoadType,
ExecutablePath,
Parameters,
- ReturnAddress);
+ CommandLine,
+ Environment);
/* Try to get the full path to the executable */
if (GetFullPathNameA(ExecutablePath, sizeof(FullPath), FullPath, NULL))
Header = (PIMAGE_DOS_HEADER)Address;
/* Get the base size of the file, in paragraphs (rounded up) */
- BaseSize = (((Header->e_cp - 1) * 512) + Header->e_cblp + 0x0F) >> 4;
+ BaseSize = ((((Header->e_cp - (Header->e_cblp != 0)) * 512)
+ + Header->e_cblp + 0x0F) >> 4) - Header->e_cparhdr;
if (LoadType != DOS_LOAD_OVERLAY)
{
DosChangeMemoryOwner(Segment, Segment);
DosChangeMemoryOwner(EnvBlock, Segment);
- /* Set INT 22h to the return address */
- ((PULONG)BaseAddress)[0x22] = ReturnAddress;
+ /* Set INT 22h to the current CS:IP */
+ ((PULONG)BaseAddress)[0x22] = MAKELONG(getIP(), getCS());
/* Create the PSP */
DosCreatePsp(Segment, (WORD)TotalSize);
if (LoadType == DOS_LOAD_AND_EXECUTE)
{
/* Save the program state */
- if (CurrentPsp != SYSTEM_PSP) DosSaveState();
+ if (CurrentPsp != SYSTEM_PSP)
+ {
+ /* Push the task state */
+ DosSaveState();
+
+ /* Update the last stack in the PSP */
+ SEGMENT_TO_PSP(CurrentPsp)->LastStack = MAKELONG(getSP(), getSS());
+ }
/* Set the initial segment registers */
setDS(Segment);
DosChangeMemoryOwner(Segment, Segment);
DosChangeMemoryOwner(EnvBlock, Segment);
- /* Set INT 22h to the return address */
- ((PULONG)BaseAddress)[0x22] = ReturnAddress;
+ /* Set INT 22h to the current CS:IP */
+ ((PULONG)BaseAddress)[0x22] = MAKELONG(getIP(), getCS());
/* Create the PSP */
DosCreatePsp(Segment, MaxAllocSize);
if (LoadType == DOS_LOAD_AND_EXECUTE)
{
+ /* Save the program state */
+ if (CurrentPsp != SYSTEM_PSP)
+ {
+ /* Push the task state */
+ DosSaveState();
+
+ /* Update the last stack in the PSP */
+ SEGMENT_TO_PSP(CurrentPsp)->LastStack = MAKELONG(getSP(), getSS());
+ }
+
/* Set the initial segment registers */
setDS(Segment);
setES(Segment);
IN LPCSTR Environment OPTIONAL)
{
DWORD Result;
- LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
+
+ SIZE_T CmdLen = strlen(CommandLine);
+ DPRINT1("Starting '%s' ('%.*s')...\n",
+ ExecutablePath,
+ /* Display the command line without the terminating 0d 0a (and skip the terminating NULL) */
+ CmdLen >= 2 ? (CommandLine[CmdLen - 2] == '\r' ? CmdLen - 2
+ : CmdLen)
+ : CmdLen,
+ CommandLine);
Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
ExecutablePath,
NULL,
CommandLine,
- Environment,
- IntVecTable[0x20]);
+ Environment);
if (Result != ERROR_SUCCESS) goto Quit;
+#ifndef STANDALONE
+ /* Update console title if we run in a separate console */
+ if (SessionId != 0)
+ SetConsoleTitleA(ExecutablePath);
+#endif
+
/* Attach to the console */
ConsoleAttach();
VidBiosAttachToConsole();
- // HACK: Simulate a ENTER key release scancode on the PS/2 port because
- // some apps expect to read a key release scancode (> 0x80) when they
- // are started.
- // (hbelusca 2 May 2015: I'm not sure it's really useful. See r65012)
- // IOWriteB(PS2_CONTROL_PORT, 0xD2); // Next write is for the first PS/2 port
- // IOWriteB(PS2_DATA_PORT, 0x80 | 0x1C); // ENTER key release
-
/* Start simulation */
SetEvent(VdmTaskEvent);
CpuSimulate();
#ifndef STANDALONE
WORD DosCreateProcess(LPCSTR ProgramName,
- PDOS_EXEC_PARAM_BLOCK Parameters,
- DWORD ReturnAddress)
+ PDOS_EXEC_PARAM_BLOCK Parameters)
{
DWORD Result;
DWORD BinaryType;
LPVOID Environment = NULL;
VDM_COMMAND_INFO CommandInfo;
- CHAR CmdLine[MAX_PATH]; // DOS_CMDLINE_LENGTH + 1
+ CHAR CmdLine[MAX_PATH + DOS_CMDLINE_LENGTH + 1];
CHAR AppName[MAX_PATH];
CHAR PifFile[MAX_PATH];
CHAR Desktop[MAX_PATH];
StartupInfo.cb = sizeof(StartupInfo);
/*
- * Convert the DOS command line to Win32-compatible format.
+ * Convert the DOS command line to Win32-compatible format, by concatenating
+ * the program name with the converted command line.
* Format of the DOS command line: 1 byte for size; 127 bytes for contents.
*/
+ CmdLinePtr = CmdLine;
+ strncpy(CmdLinePtr, ProgramName, MAX_PATH); // Concatenate the program name
+ CmdLinePtr += strlen(CmdLinePtr);
+ *CmdLinePtr++ = ' '; // Add separating space
+
CmdLineSize = min(*(PBYTE)FAR_POINTER(Parameters->CommandLine), DOS_CMDLINE_LENGTH);
- RtlCopyMemory(CmdLine,
+ RtlCopyMemory(CmdLinePtr,
(LPSTR)FAR_POINTER(Parameters->CommandLine) + 1,
CmdLineSize);
/* NULL-terminate it */
- CmdLine[CmdLineSize] = '\0';
+ CmdLinePtr[CmdLineSize] = '\0';
/* Remove any trailing return carriage character and NULL-terminate the command line */
- CmdLinePtr = CmdLine;
while (*CmdLinePtr && *CmdLinePtr != '\r' && *CmdLinePtr != '\n') CmdLinePtr++;
*CmdLinePtr = '\0';
AppName,
Parameters,
CmdLine,
- Env,
- ReturnAddress);
+ Env);
if (Result == ERROR_SUCCESS)
{
/* Increment the re-entry count */
setSS(HIWORD(SEGMENT_TO_PSP(CurrentPsp)->LastStack));
setSP(LOWORD(SEGMENT_TO_PSP(CurrentPsp)->LastStack));
- /* Restore the program state */
- DosRestoreState();
+ /* Are we returning to DOS code? */
+ if (HIWORD(PspBlock->TerminateAddress) == DOS_CODE_SEGMENT)
+ {
+ /* Pop the task state */
+ DosRestoreState();
+ }
/* Return control to the parent process */
CpuExecute(HIWORD(PspBlock->TerminateAddress),