- Continue to work on VGA attach/detach from console;
- Stick more #if(n)def STANDALONE to portions of code that are useful (or not) in standalone (i.e. not in OS-integrated) mode;
- Isolate the Dos***File functions in a new source file;
- Get rid of STACK_COUNTER, STACK_VAR_A and STACK_VAR_B since we now use 32-->16 bit callbacks (and therefore adjust the callback/INT32 trampoline stubs accordingly).

svn path=/trunk/; revision=63238
This commit is contained in:
Hermès Bélusca-Maïto 2014-05-11 19:25:09 +00:00
parent 5c08d6b6c5
commit cdfa735cd1
17 changed files with 809 additions and 668 deletions

View file

@ -21,6 +21,7 @@ list(APPEND SOURCE
hardware/vga.c hardware/vga.c
dos/dos32krnl/bios.c dos/dos32krnl/bios.c
dos/dos32krnl/dos.c dos/dos32krnl/dos.c
dos/dos32krnl/dosfiles.c
dos/dem.c dos/dem.c
bop.c bop.c
callback.c callback.c

View file

@ -91,22 +91,13 @@ static WORD BiosPeekCharacter(VOID)
else return 0xFFFF; else return 0xFFFF;
} }
WORD BiosGetCharacter(VOID) static WORD BiosGetCharacter(VOID)
{ {
WORD CharacterData = 0; WORD CharacterData = 0;
/* Check if there is a key available */ /* Check if there is a key available, and if so, remove it from the queue */
if (BiosKbdBufferTop(&CharacterData)) if (BiosKbdBufferTop(&CharacterData)) BiosKbdBufferPop();
{ else CharacterData = 0xFFFF;
/* A key was available, remove it from the queue */
BiosKbdBufferPop();
}
else
{
/* No key available. Set the handler CF to repeat the BOP */
setCF(1);
// CharacterData = 0xFFFF;
}
return CharacterData; return CharacterData;
} }
@ -121,7 +112,17 @@ static VOID WINAPI BiosKeyboardService(LPWORD Stack)
case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h
{ {
/* Read the character (and wait if necessary) */ /* Read the character (and wait if necessary) */
setAX(BiosGetCharacter()); WORD Character = BiosGetCharacter();
if (Character == 0xFFFF)
{
/* No key available. Set the handler CF to repeat the BOP */
setCF(1);
break;
}
setAX(Character);
break; break;
} }
@ -130,13 +131,13 @@ static VOID WINAPI BiosKeyboardService(LPWORD Stack)
/* Get extended keystroke status */ /* Get extended keystroke status */
case 0x11: // FIXME: Temporarily do the same as INT 16h, 01h case 0x11: // FIXME: Temporarily do the same as INT 16h, 01h
{ {
WORD Data = BiosPeekCharacter(); WORD Character = BiosPeekCharacter();
if (Data != 0xFFFF) if (Character != 0xFFFF)
{ {
/* There is a character, clear ZF and return it */ /* There is a character, clear ZF and return it */
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF; Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
setAX(Data); setAX(Character);
} }
else else
{ {

View file

@ -21,8 +21,6 @@
/* FUNCTIONS ******************************************************************/ /* FUNCTIONS ******************************************************************/
WORD BiosGetCharacter(VOID);
BOOLEAN KbdBiosInitialize(VOID); BOOLEAN KbdBiosInitialize(VOID);
VOID KbdBiosCleanup(VOID); VOID KbdBiosCleanup(VOID);

View file

@ -1532,6 +1532,37 @@ VOID WINAPI VidBiosVideoService(LPWORD Stack)
} }
} }
/*
* Those attach / detach functions are work-in-progress
*/
static BOOL Attached = TRUE;
VOID VidBiosAttachToConsole(VOID)
{
// VgaRefreshDisplay();
if (!Attached)
{
VgaAttachToConsole();
Attached = TRUE;
}
VgaRefreshDisplay();
VidBiosSyncCursorPosition();
}
VOID VidBiosDetachFromConsole(VOID)
{
/* Perform another screen refresh */
VgaRefreshDisplay();
/* Detach from the console */
VgaDetachFromConsole(FALSE);
Attached = FALSE;
}
BOOLEAN VidBiosInitialize(VOID) BOOLEAN VidBiosInitialize(VOID)
{ {
/* Some interrupts are in fact addresses to tables */ /* Some interrupts are in fact addresses to tables */
@ -1541,6 +1572,15 @@ BOOLEAN VidBiosInitialize(VOID)
((PULONG)BaseAddress)[0x43] = (ULONG)NULL; ((PULONG)BaseAddress)[0x43] = (ULONG)NULL;
((PULONG)BaseAddress)[0x44] = (ULONG)NULL; ((PULONG)BaseAddress)[0x44] = (ULONG)NULL;
//
// FIXME: At the moment we always set a VGA mode. In the future,
// we should set this mode **only** when:
// - an app starts to use directly the video memory
// (that should be done in emulator.c)
// - or starts to use non-stream I/O interrupts
// (that should be done here, or maybe in VGA ??)
//
/* Set the default video mode */ /* Set the default video mode */
VidBiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE); VidBiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE);

View file

@ -37,9 +37,12 @@ enum
/* FUNCTIONS ******************************************************************/ /* FUNCTIONS ******************************************************************/
VOID VidBiosSyncCursorPosition(VOID);
VOID WINAPI VidBiosVideoService(LPWORD Stack); VOID WINAPI VidBiosVideoService(LPWORD Stack);
VOID VidBiosSyncCursorPosition(VOID); VOID VidBiosDetachFromConsole(VOID);
VOID VidBiosAttachToConsole(VOID);
BOOLEAN VidBiosInitialize(VOID); BOOLEAN VidBiosInitialize(VOID);
VOID VidBiosCleanup(VOID); VOID VidBiosCleanup(VOID);

View file

@ -44,6 +44,13 @@ do { \
#define CALL16_TRAMPOLINE_SIZE (1 * sizeof(ULONGLONG)) #define CALL16_TRAMPOLINE_SIZE (1 * sizeof(ULONGLONG))
#define INT16_TRAMPOLINE_SIZE (1 * sizeof(ULONGLONG)) #define INT16_TRAMPOLINE_SIZE (1 * sizeof(ULONGLONG))
//
// WARNING WARNING!!
//
// If you modify the code stubs here, think also
// about updating them in int32.c too!!
//
/* 16-bit generic interrupt code for calling a 32-bit interrupt handler */ /* 16-bit generic interrupt code for calling a 32-bit interrupt handler */
BYTE Int16To32[] = BYTE Int16To32[] =
{ {
@ -52,12 +59,6 @@ BYTE Int16To32[] =
/* Push the value of the interrupt to be called */ /* Push the value of the interrupt to be called */
0x6A, 0xFF, // push i (patchable to 0x6A, 0xIntNum) 0x6A, 0xFF, // push i (patchable to 0x6A, 0xIntNum)
/* The counter variable (initialized to 0) */
0x6A, 0x00, // push 0
/* Stack variables */
0x83, 0xEC, 0x04, // sub sp, 4
/* The BOP Sequence */ /* The BOP Sequence */
// BOP_SEQ: // BOP_SEQ:
0xF8, // clc 0xF8, // clc
@ -74,7 +75,8 @@ BYTE Int16To32[] =
0xEB, 0xF5, // jmp BOP_SEQ (offset -11) 0xEB, 0xF5, // jmp BOP_SEQ (offset -11)
// EXIT: // EXIT:
0x83, 0xC4, 0x08, // add sp, 8 // 0x44, 0x44, // inc sp, inc sp
0x83, 0xC4, 0x02, // add sp, 2
0xCF, // iret 0xCF, // iret
}; };

View file

@ -21,7 +21,6 @@
#include "bop.h" #include "bop.h"
#include "bios/bios.h" #include "bios/bios.h"
#include "hardware/vga.h"
/* Extra PSDK/NDK Headers */ /* Extra PSDK/NDK Headers */
#include <ndk/obtypes.h> #include <ndk/obtypes.h>
@ -138,8 +137,7 @@ static VOID WINAPI DosCmdInterpreterBop(LPWORD Stack)
StartupInfo.cb = sizeof(StartupInfo); StartupInfo.cb = sizeof(StartupInfo);
VgaRefreshDisplay(); VidBiosDetachFromConsole();
VgaDetachFromConsole(FALSE);
Result = CreateProcessA(NULL, Result = CreateProcessA(NULL,
CommandLine, CommandLine,
@ -171,9 +169,7 @@ static VOID WINAPI DosCmdInterpreterBop(LPWORD Stack)
dwExitCode = GetLastError(); dwExitCode = GetLastError();
} }
VgaAttachToConsole(); VidBiosAttachToConsole();
VgaRefreshDisplay();
VidBiosSyncCursorPosition();
setAL((UCHAR)dwExitCode); setAL((UCHAR)dwExitCode);

View file

@ -24,65 +24,15 @@
/* PRIVATE FUNCTIONS **********************************************************/ /* PRIVATE FUNCTIONS **********************************************************/
#if 0
static WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten)
{
WORD Result = ERROR_SUCCESS;
DWORD BytesWritten32 = 0;
HANDLE Handle = DosGetRealHandle(FileHandle);
WORD i;
DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n",
FileHandle,
Count);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
if (IsConsoleHandle(Handle))
{
for (i = 0; i < Count; i++)
{
/* Call the BIOS to print the character */
VidBiosPrintCharacter(((LPBYTE)Buffer)[i], DOS_CHAR_ATTRIBUTE, Bda->VideoPage);
BytesWritten32++;
}
}
else
{
/* Write the file */
if (!WriteFile(Handle, Buffer, Count, &BytesWritten32, NULL))
{
/* Store the error code */
Result = (WORD)GetLastError();
}
}
/* The number of bytes written is always 16-bit */
*BytesWritten = LOWORD(BytesWritten32);
/* Return the error code */
return Result;
}
#endif
/* PUBLIC FUNCTIONS ***********************************************************/ /* PUBLIC FUNCTIONS ***********************************************************/
CHAR DosReadCharacter(VOID) CHAR DosReadCharacter(WORD FileHandle)
{ {
CHAR Character = '\0'; CHAR Character = '\0';
WORD BytesRead; WORD BytesRead;
if (IsConsoleHandle(DosGetRealHandle(DOS_INPUT_HANDLE))) /* Use the file reading function */
{ DosReadFile(FileHandle, &Character, 1, &BytesRead);
/* Call the BIOS */
Character = LOBYTE(BiosGetCharacter());
}
else
{
/* Use the file reading function */
DosReadFile(DOS_INPUT_HANDLE, &Character, sizeof(CHAR), &BytesRead);
}
return Character; return Character;
} }
@ -117,12 +67,12 @@ BOOLEAN DosCheckInput(VOID)
} }
} }
VOID DosPrintCharacter(CHAR Character) VOID DosPrintCharacter(WORD FileHandle, CHAR Character)
{ {
WORD BytesWritten; WORD BytesWritten;
/* Use the file writing function */ /* Use the file writing function */
DosWriteFile(DOS_OUTPUT_HANDLE, &Character, sizeof(CHAR), &BytesWritten); DosWriteFile(FileHandle, &Character, 1, &BytesWritten);
} }
BOOLEAN DosBIOSInitialize(VOID) BOOLEAN DosBIOSInitialize(VOID)

View file

@ -1,7 +1,7 @@
/* /*
* COPYRIGHT: GPL - See COPYING in the top level directory * COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine * PROJECT: ReactOS Virtual DOS Machine
* FILE: dos.c * FILE: dos/dos32krnl/dos.c
* PURPOSE: VDM DOS Kernel * PURPOSE: VDM DOS Kernel
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/ */
@ -29,8 +29,13 @@ static DWORD DiskTransferArea;
/*static*/ BYTE CurrentDrive; /*static*/ BYTE CurrentDrive;
static CHAR LastDrive = 'E'; static CHAR LastDrive = 'E';
static CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH]; static CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH];
static HANDLE DosSystemFileTable[DOS_SFT_SIZE];
static WORD DosSftRefCount[DOS_SFT_SIZE]; static struct
{
HANDLE Handle;
WORD RefCount;
} DosSystemFileTable[DOS_SFT_SIZE];
static BYTE DosAllocStrategy = DOS_ALLOC_BEST_FIT; static BYTE DosAllocStrategy = DOS_ALLOC_BEST_FIT;
static BOOLEAN DosUmbLinked = FALSE; static BOOLEAN DosUmbLinked = FALSE;
static WORD DosErrorLevel = 0x0000; static WORD DosErrorLevel = 0x0000;
@ -431,6 +436,11 @@ static WORD DosCopyEnvironmentBlock(LPCVOID Environment, LPCSTR ProgramName)
return DestSegment; return DestSegment;
} }
/* Taken from base/shell/cmd/console.c */ /* Taken from base/shell/cmd/console.c */
BOOL IsConsoleHandle(HANDLE hHandle) BOOL IsConsoleHandle(HANDLE hHandle)
{ {
@ -455,7 +465,7 @@ BOOL IsConsoleHandle(HANDLE hHandle)
return GetConsoleMode(hHandle, &dwMode); return GetConsoleMode(hHandle, &dwMode);
} }
static WORD DosOpenHandle(HANDLE Handle) WORD DosOpenHandle(HANDLE Handle)
{ {
BYTE i; BYTE i;
WORD DosHandle; WORD DosHandle;
@ -482,10 +492,10 @@ static WORD DosOpenHandle(HANDLE Handle)
for (i = 0; i < DOS_SFT_SIZE; i++) for (i = 0; i < DOS_SFT_SIZE; i++)
{ {
/* Check if this is the same handle */ /* Check if this is the same handle */
if (DosSystemFileTable[i] != Handle) continue; if (DosSystemFileTable[i].Handle != Handle) continue;
/* Already in the table, reference it */ /* Already in the table, reference it */
DosSftRefCount[i]++; DosSystemFileTable[i].RefCount++;
/* Set the JFT entry to that SFT index */ /* Set the JFT entry to that SFT index */
HandleTable[DosHandle] = i; HandleTable[DosHandle] = i;
@ -498,11 +508,11 @@ static WORD DosOpenHandle(HANDLE Handle)
for (i = 0; i < DOS_SFT_SIZE; i++) for (i = 0; i < DOS_SFT_SIZE; i++)
{ {
/* Make sure this is an empty table entry */ /* Make sure this is an empty table entry */
if (DosSystemFileTable[i] != INVALID_HANDLE_VALUE) continue; if (DosSystemFileTable[i].Handle != INVALID_HANDLE_VALUE) continue;
/* Initialize the empty table entry */ /* Initialize the empty table entry */
DosSystemFileTable[i] = Handle; DosSystemFileTable[i].Handle = Handle;
DosSftRefCount[i] = 1; DosSystemFileTable[i].RefCount = 1;
/* Set the JFT entry to that SFT index */ /* Set the JFT entry to that SFT index */
HandleTable[DosHandle] = i; HandleTable[DosHandle] = i;
@ -531,7 +541,7 @@ HANDLE DosGetRealHandle(WORD DosHandle)
if (HandleTable[DosHandle] == 0xFF) return INVALID_HANDLE_VALUE; if (HandleTable[DosHandle] == 0xFF) return INVALID_HANDLE_VALUE;
/* Return the Win32 handle */ /* Return the Win32 handle */
return DosSystemFileTable[HandleTable[DosHandle]]; return DosSystemFileTable[HandleTable[DosHandle]].Handle;
} }
static VOID DosCopyHandleTable(LPBYTE DestinationTable) static VOID DosCopyHandleTable(LPBYTE DestinationTable)
@ -553,7 +563,7 @@ static VOID DosCopyHandleTable(LPBYTE DestinationTable)
DestinationTable[i] = (BYTE)i; DestinationTable[i] = (BYTE)i;
/* Increase the reference count */ /* Increase the reference count */
DosSftRefCount[i]++; DosSystemFileTable[i].RefCount++;
} }
/* Done */ /* Done */
@ -570,7 +580,7 @@ static VOID DosCopyHandleTable(LPBYTE DestinationTable)
DestinationTable[i] = SourceTable[i]; DestinationTable[i] = SourceTable[i];
/* Increase the reference count */ /* Increase the reference count */
DosSftRefCount[SourceTable[i]]++; DosSystemFileTable[SourceTable[i]].RefCount++;
} }
} }
@ -594,16 +604,16 @@ static BOOLEAN DosCloseHandle(WORD DosHandle)
/* Decrement the reference count of the SFT entry */ /* Decrement the reference count of the SFT entry */
SftIndex = HandleTable[DosHandle]; SftIndex = HandleTable[DosHandle];
DosSftRefCount[SftIndex]--; DosSystemFileTable[SftIndex].RefCount--;
/* Check if the reference count fell to zero */ /* Check if the reference count fell to zero */
if (!DosSftRefCount[SftIndex]) if (!DosSystemFileTable[SftIndex].RefCount)
{ {
/* Close the file, it's no longer needed */ /* Close the file, it's no longer needed */
CloseHandle(DosSystemFileTable[SftIndex]); CloseHandle(DosSystemFileTable[SftIndex].Handle);
/* Clear the handle */ /* Clear the handle */
DosSystemFileTable[SftIndex] = INVALID_HANDLE_VALUE; DosSystemFileTable[SftIndex].Handle = INVALID_HANDLE_VALUE;
} }
/* Clear the entry in the JFT */ /* Clear the entry in the JFT */
@ -641,7 +651,7 @@ static BOOLEAN DosDuplicateHandle(WORD OldHandle, WORD NewHandle)
/* Increment the reference count of the SFT entry */ /* Increment the reference count of the SFT entry */
SftIndex = HandleTable[OldHandle]; SftIndex = HandleTable[OldHandle];
DosSftRefCount[SftIndex]++; DosSystemFileTable[SftIndex].RefCount++;
/* Make the new handle point to that SFT entry */ /* Make the new handle point to that SFT entry */
HandleTable[NewHandle] = SftIndex; HandleTable[NewHandle] = SftIndex;
@ -650,260 +660,11 @@ static BOOLEAN DosDuplicateHandle(WORD OldHandle, WORD NewHandle)
return TRUE; return TRUE;
} }
static WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes)
{
HANDLE FileHandle;
WORD DosHandle;
DPRINT("DosCreateFile: FilePath \"%s\", Attributes 0x%04X\n",
FilePath,
Attributes);
/* Create the file */
FileHandle = CreateFileA(FilePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
CREATE_ALWAYS,
Attributes,
NULL);
if (FileHandle == INVALID_HANDLE_VALUE)
{
/* Return the error code */
return (WORD)GetLastError();
}
/* Open the DOS handle */
DosHandle = DosOpenHandle(FileHandle);
if (DosHandle == INVALID_DOS_HANDLE)
{
/* Close the handle */
CloseHandle(FileHandle);
/* Return the error code */
return ERROR_TOO_MANY_OPEN_FILES;
}
/* It was successful */
*Handle = DosHandle;
return ERROR_SUCCESS;
}
static WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode)
{
HANDLE FileHandle;
ACCESS_MASK Access = 0;
WORD DosHandle;
DPRINT("DosOpenFile: FilePath \"%s\", AccessMode 0x%04X\n",
FilePath,
AccessMode);
/* Parse the access mode */
switch (AccessMode & 3)
{
case 0:
{
/* Read-only */
Access = GENERIC_READ;
break;
}
case 1:
{
/* Write only */
Access = GENERIC_WRITE;
break;
}
case 2:
{
/* Read and write */
Access = GENERIC_READ | GENERIC_WRITE;
break;
}
default:
{
/* Invalid */
return ERROR_INVALID_PARAMETER;
}
}
/* Open the file */
FileHandle = CreateFileA(FilePath,
Access,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (FileHandle == INVALID_HANDLE_VALUE)
{
/* Return the error code */
return (WORD)GetLastError();
}
/* Open the DOS handle */
DosHandle = DosOpenHandle(FileHandle);
if (DosHandle == INVALID_DOS_HANDLE)
{
/* Close the handle */
CloseHandle(FileHandle);
/* Return the error code */
return ERROR_TOO_MANY_OPEN_FILES;
}
/* It was successful */
*Handle = DosHandle;
return ERROR_SUCCESS;
}
WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead)
{
WORD Result = ERROR_SUCCESS;
DWORD BytesRead32 = 0;
HANDLE Handle = DosGetRealHandle(FileHandle);
DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
/* Read the file */
if (!ReadFile(Handle, Buffer, Count, &BytesRead32, NULL))
{
/* Store the error code */
Result = (WORD)GetLastError();
}
/* The number of bytes read is always 16-bit */
*BytesRead = LOWORD(BytesRead32);
/* Return the error code */
return Result;
}
WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten)
{
WORD Result = ERROR_SUCCESS;
DWORD BytesWritten32 = 0;
HANDLE Handle = DosGetRealHandle(FileHandle);
WORD i;
DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n",
FileHandle,
Count);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
if (IsConsoleHandle(Handle))
{
for (i = 0; i < Count; i++)
{
/* Save AX and BX */
USHORT AX = getAX();
USHORT BX = getBX();
/* Set the parameters */
setAL(((PCHAR)Buffer)[i]);
setBL(DOS_CHAR_ATTRIBUTE);
setBH(Bda->VideoPage);
/* Call the BIOS INT 10h, AH=0Eh "Teletype Output" */
setAH(0x0E);
Int32Call(&DosContext, BIOS_VIDEO_INTERRUPT);
/* Restore AX and BX */
setBX(BX);
setAX(AX);
BytesWritten32++;
}
}
else
{
/* Write the file */
if (!WriteFile(Handle, Buffer, Count, &BytesWritten32, NULL))
{
/* Store the error code */
Result = (WORD)GetLastError();
}
}
/* The number of bytes written is always 16-bit */
*BytesWritten = LOWORD(BytesWritten32);
/* Return the error code */
return Result;
}
static WORD DosSeekFile(WORD FileHandle, LONG Offset, BYTE Origin, LPDWORD NewOffset)
{
WORD Result = ERROR_SUCCESS;
DWORD FilePointer;
HANDLE Handle = DosGetRealHandle(FileHandle);
DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
FileHandle,
Offset,
Origin);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
/* Check if the origin is valid */
if (Origin != FILE_BEGIN && Origin != FILE_CURRENT && Origin != FILE_END)
{
return ERROR_INVALID_FUNCTION;
}
/* Move the file pointer */
FilePointer = SetFilePointer(Handle, Offset, NULL, Origin);
/* Check if there's a possibility the operation failed */
if (FilePointer == INVALID_SET_FILE_POINTER)
{
/* Get the real error code */
Result = (WORD)GetLastError();
}
if (Result != ERROR_SUCCESS)
{
/* The operation did fail */
return Result;
}
/* Return the file pointer, if requested */
if (NewOffset) *NewOffset = FilePointer;
/* Return success */
return ERROR_SUCCESS;
}
static BOOLEAN DosFlushFileBuffers(WORD FileHandle)
{
HANDLE Handle = DosGetRealHandle(FileHandle);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return FALSE;
/*
* No need to check whether the handle is a console handle since
* FlushFileBuffers() automatically does this check and calls
* FlushConsoleInputBuffer() for us.
*/
// if (IsConsoleHandle(Handle))
// return (BOOLEAN)FlushConsoleInputBuffer(Handle);
// else
return (BOOLEAN)FlushFileBuffers(Handle);
}
static BOOLEAN DosChangeDrive(BYTE Drive) static BOOLEAN DosChangeDrive(BYTE Drive)
{ {
@ -1279,6 +1040,36 @@ Cleanup:
return Result; return Result;
} }
DWORD DosStartProcess(IN LPCSTR ExecutablePath,
IN LPCSTR CommandLine,
IN PVOID Environment)
{
DWORD Result;
Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
ExecutablePath,
CommandLine,
Environment,
NULL,
NULL);
if (Result != ERROR_SUCCESS) goto Quit;
/* Attach to the console */
VidBiosAttachToConsole(); // FIXME: And in fact, attach the full NTVDM UI to the console
/* Start simulation */
SetEvent(VdmTaskEvent);
EmulatorSimulate();
/* Detach from the console */
VidBiosDetachFromConsole(); // FIXME: And in fact, detach the full NTVDM UI from the console
Quit:
return Result;
}
#ifndef STANDALONE
WORD DosCreateProcess(DOS_EXEC_TYPE LoadType, WORD DosCreateProcess(DOS_EXEC_TYPE LoadType,
LPCSTR ProgramName, LPCSTR ProgramName,
PDOS_EXEC_PARAM_BLOCK Parameters) PDOS_EXEC_PARAM_BLOCK Parameters)
@ -1363,16 +1154,17 @@ WORD DosCreateProcess(DOS_EXEC_TYPE LoadType,
GetNextVDMCommand(&CommandInfo); GetNextVDMCommand(&CommandInfo);
/* Load the executable */ /* Load the executable */
Result= DosLoadExecutable(LoadType, Result = DosLoadExecutable(LoadType,
AppName, AppName,
CmdLine, CmdLine,
Env, Env,
&Parameters->StackLocation, &Parameters->StackLocation,
&Parameters->EntryPoint); &Parameters->EntryPoint);
if (Result != ERROR_SUCCESS) if (Result != ERROR_SUCCESS)
{ {
DisplayMessage(L"Could not load '%S'. Error: %u", AppName, Result); DisplayMessage(L"Could not load '%S'. Error: %u", AppName, Result);
break; // FIXME: Decrement the reenter count. Or, instead, just increment
// the VDM reenter count *only* if this call succeeds...
} }
break; break;
@ -1392,6 +1184,7 @@ WORD DosCreateProcess(DOS_EXEC_TYPE LoadType,
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
#endif
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode) VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode)
{ {
@ -1400,7 +1193,6 @@ VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode)
PDOS_MCB CurrentMcb; PDOS_MCB CurrentMcb;
LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress); LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
PDOS_PSP PspBlock = SEGMENT_TO_PSP(Psp); PDOS_PSP PspBlock = SEGMENT_TO_PSP(Psp);
VDM_COMMAND_INFO CommandInfo;
DPRINT("DosTerminateProcess: Psp 0x%04X, ReturnCode 0x%02X\n", DPRINT("DosTerminateProcess: Psp 0x%04X, ReturnCode 0x%02X\n",
Psp, Psp,
@ -1451,10 +1243,13 @@ Done:
} }
} }
#ifndef STANDALONE
// FIXME: This is probably not the best way to do it // FIXME: This is probably not the best way to do it
/* Check if this was a nested DOS task */ /* Check if this was a nested DOS task */
if (CurrentPsp != SYSTEM_PSP) if (CurrentPsp != SYSTEM_PSP)
{ {
VDM_COMMAND_INFO CommandInfo;
/* Decrement the re-entry count */ /* Decrement the re-entry count */
CommandInfo.TaskId = SessionId; CommandInfo.TaskId = SessionId;
CommandInfo.VDMState = VDM_DEC_REENTER_COUNT; CommandInfo.VDMState = VDM_DEC_REENTER_COUNT;
@ -1468,6 +1263,7 @@ Done:
CommandInfo.VDMState = VDM_FLAG_DONT_WAIT; CommandInfo.VDMState = VDM_FLAG_DONT_WAIT;
GetNextVDMCommand(&CommandInfo); GetNextVDMCommand(&CommandInfo);
} }
#endif
/* Save the return code - Normal termination */ /* Save the return code - Normal termination */
DosErrorLevel = MAKEWORD(ReturnCode, 0x00); DosErrorLevel = MAKEWORD(ReturnCode, 0x00);
@ -1500,12 +1296,12 @@ BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle)
* for a list of possible flags. * for a list of possible flags.
*/ */
if (Handle == DosSystemFileTable[0]) if (Handle == DosSystemFileTable[DOS_INPUT_HANDLE].Handle)
{ {
/* Console input */ /* Console input */
InfoWord |= 1 << 0; InfoWord |= 1 << 0;
} }
else if (Handle == DosSystemFileTable[1]) else if (Handle == DosSystemFileTable[DOS_OUTPUT_HANDLE].Handle)
{ {
/* Console output */ /* Console output */
InfoWord |= 1 << 1; InfoWord |= 1 << 1;
@ -1556,11 +1352,12 @@ VOID WINAPI DosInt21h(LPWORD Stack)
/* Read Character from STDIN with Echo */ /* Read Character from STDIN with Echo */
case 0x01: case 0x01:
{ {
Character = DosReadCharacter(); // FIXME: Under DOS 2+, input / output handle may be redirected!!!!
DosPrintCharacter(Character); Character = DosReadCharacter(DOS_INPUT_HANDLE);
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
/* Let the BOP repeat if needed */ // /* Let the BOP repeat if needed */
if (getCF()) break; // if (getCF()) break;
setAL(Character); setAL(Character);
break; break;
@ -1569,8 +1366,9 @@ VOID WINAPI DosInt21h(LPWORD Stack)
/* Write Character to STDOUT */ /* Write Character to STDOUT */
case 0x02: case 0x02:
{ {
// FIXME: Under DOS 2+, output handle may be redirected!!!!
Character = getDL(); Character = getDL();
DosPrintCharacter(Character); DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
/* /*
* We return the output character (DOS 2.1+). * We return the output character (DOS 2.1+).
@ -1588,7 +1386,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
{ {
// FIXME: Really read it from STDAUX! // FIXME: Really read it from STDAUX!
DPRINT1("INT 16h, 03h: Read character from STDAUX is HALFPLEMENTED\n"); DPRINT1("INT 16h, 03h: Read character from STDAUX is HALFPLEMENTED\n");
setAL(DosReadCharacter()); // setAL(DosReadCharacter());
break; break;
} }
@ -1597,7 +1395,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
{ {
// FIXME: Really write it to STDAUX! // FIXME: Really write it to STDAUX!
DPRINT1("INT 16h, 04h: Write character to STDAUX is HALFPLEMENTED\n"); DPRINT1("INT 16h, 04h: Write character to STDAUX is HALFPLEMENTED\n");
DosPrintCharacter(getDL()); // DosPrintCharacter(getDL());
break; break;
} }
@ -1616,10 +1414,12 @@ VOID WINAPI DosInt21h(LPWORD Stack)
{ {
Character = getDL(); Character = getDL();
// FIXME: Under DOS 2+, output handle may be redirected!!!!
if (Character != 0xFF) if (Character != 0xFF)
{ {
/* Output */ /* Output */
DosPrintCharacter(Character); DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
/* /*
* We return the output character (DOS 2.1+). * We return the output character (DOS 2.1+).
@ -1634,7 +1434,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
if (DosCheckInput()) if (DosCheckInput())
{ {
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF; Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
setAL(DosReadCharacter()); setAL(DosReadCharacter(DOS_INPUT_HANDLE));
} }
else else
{ {
@ -1651,10 +1451,15 @@ VOID WINAPI DosInt21h(LPWORD Stack)
case 0x07: case 0x07:
case 0x08: case 0x08:
{ {
Character = DosReadCharacter(); // FIXME: Under DOS 2+, input handle may be redirected!!!!
Character = DosReadCharacter(DOS_INPUT_HANDLE);
/* Let the BOP repeat if needed */ // FIXME: For 0x07, do not check Ctrl-C/Break.
if (getCF()) break; // For 0x08, do check those control sequences and if needed,
// call INT 0x23.
// /* Let the BOP repeat if needed */
// if (getCF()) break;
setAL(Character); setAL(Character);
break; break;
@ -1667,7 +1472,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
while (*String != '$') while (*String != '$')
{ {
DosPrintCharacter(*String); DosPrintCharacter(DOS_OUTPUT_HANDLE, *String);
String++; String++;
} }
@ -1683,26 +1488,27 @@ VOID WINAPI DosInt21h(LPWORD Stack)
/* Read Buffered Input */ /* Read Buffered Input */
case 0x0A: case 0x0A:
{ {
WORD Count = 0;
InputBuffer = (PDOS_INPUT_BUFFER)SEG_OFF_TO_PTR(getDS(), getDX()); InputBuffer = (PDOS_INPUT_BUFFER)SEG_OFF_TO_PTR(getDS(), getDX());
while (Stack[STACK_COUNTER] < InputBuffer->MaxLength) DPRINT1("Read Buffered Input\n");
{
/* Try to read a character */
Character = DosReadCharacter();
/* If it's not ready yet, let the BOP repeat */ while (Count < InputBuffer->MaxLength)
if (getCF()) break; {
/* Try to read a character (wait) */
Character = DosReadCharacter(DOS_INPUT_HANDLE);
/* Echo the character and append it to the buffer */ /* Echo the character and append it to the buffer */
DosPrintCharacter(Character); DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
InputBuffer->Buffer[Stack[STACK_COUNTER]] = Character; InputBuffer->Buffer[Count] = Character;
if (Character == '\r') break; if (Character == '\r') break;
Stack[STACK_COUNTER]++; Count++;
} }
/* Update the length */ /* Update the length */
InputBuffer->Length = Stack[STACK_COUNTER]; InputBuffer->Length = Count;
break; break;
} }
@ -1719,7 +1525,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
BYTE InputFunction = getAL(); BYTE InputFunction = getAL();
/* Flush STDIN buffer */ /* Flush STDIN buffer */
DosFlushFileBuffers(DOS_INPUT_HANDLE); // Maybe just create a DosFlushInputBuffer... DosFlushFileBuffers(DOS_INPUT_HANDLE);
/* /*
* If the input function number contained in AL is valid, i.e. * If the input function number contained in AL is valid, i.e.
@ -2163,47 +1969,11 @@ VOID WINAPI DosInt21h(LPWORD Stack)
/* Read from File or Device */ /* Read from File or Device */
case 0x3F: case 0x3F:
{ {
WORD Handle = getBX();
LPBYTE Buffer = (LPBYTE)SEG_OFF_TO_PTR(getDS(), getDX());
WORD Count = getCX();
WORD BytesRead = 0; WORD BytesRead = 0;
WORD ErrorCode = ERROR_SUCCESS; WORD ErrorCode = DosReadFile(getBX(),
CHAR Character; SEG_OFF_TO_PTR(getDS(), getDX()),
getCX(),
if (IsConsoleHandle(DosGetRealHandle(Handle))) &BytesRead);
{
while (Stack[STACK_COUNTER] < Count)
{
/* Read a character from the BIOS */
Character = LOBYTE(BiosGetCharacter());
/* Stop if the BOP needs to be repeated */
if (getCF()) break;
// FIXME: Security checks!
DosPrintCharacter(Character);
Buffer[Stack[STACK_COUNTER]++] = Character;
if (Character == '\r')
{
/* Stop on first carriage return */
DosPrintCharacter('\n');
break;
}
}
if (Character != '\r')
{
if (Stack[STACK_COUNTER] < Count) ErrorCode = ERROR_NOT_READY;
else BytesRead = Count;
}
else BytesRead = Stack[STACK_COUNTER];
}
else
{
/* Use the file reading function */
ErrorCode = DosReadFile(Handle, Buffer, Count, &BytesRead);
}
if (ErrorCode == ERROR_SUCCESS) if (ErrorCode == ERROR_SUCCESS)
{ {
@ -2215,6 +1985,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
setAX(ErrorCode); setAX(ErrorCode);
} }
break; break;
} }
@ -2358,7 +2129,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
WORD NewHandle; WORD NewHandle;
HANDLE Handle = DosGetRealHandle(getBX()); HANDLE Handle = DosGetRealHandle(getBX());
if (Handle != INVALID_HANDLE_VALUE) if (Handle == INVALID_HANDLE_VALUE)
{ {
/* The handle is invalid */ /* The handle is invalid */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
@ -2491,6 +2262,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
break; break;
} }
#ifndef STANDALONE
/* Execute */ /* Execute */
case 0x4B: case 0x4B:
{ {
@ -2511,6 +2283,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
break; break;
} }
#endif
/* Terminate With Return Code */ /* Terminate With Return Code */
case 0x4C: case 0x4C:
@ -2540,8 +2313,11 @@ VOID WINAPI DosInt21h(LPWORD Stack)
getCX()); getCX());
setAX(Result); setAX(Result);
if (Result == ERROR_SUCCESS) Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
else Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; if (Result == ERROR_SUCCESS)
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
else
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
break; break;
} }
@ -2552,8 +2328,11 @@ VOID WINAPI DosInt21h(LPWORD Stack)
WORD Result = (WORD)demFileFindNext(FAR_POINTER(DiskTransferArea)); WORD Result = (WORD)demFileFindNext(FAR_POINTER(DiskTransferArea));
setAX(Result); setAX(Result);
if (Result == ERROR_SUCCESS) Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
else Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; if (Result == ERROR_SUCCESS)
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
else
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
break; break;
} }
@ -2581,6 +2360,23 @@ VOID WINAPI DosInt21h(LPWORD Stack)
break; break;
} }
/* Internal - Get "List of lists" (SYSVARS) */
case 0x52:
{
/*
* On return, ES points at the DOS data segment (see also INT 2F/AX=1203h).
* See Ralf Brown: http://www.ctyme.com/intr/rb-2983.htm
* for more information.
*/
/* Return the DOS "list of lists" in ES:BX */
setES(0x0000);
setBX(0x0000);
DisplayMessage(L"Required for AARD code, do you remember? :P");
break;
}
/* Get/Set Memory Management Options */ /* Get/Set Memory Management Options */
case 0x58: case 0x58:
{ {
@ -2666,32 +2462,6 @@ VOID WINAPI DosFastConOut(LPWORD Stack)
* for more information. * for more information.
*/ */
#if 0
if (Stack[STACK_COUNTER] == 0)
{
Stack[STACK_COUNTER]++;
/* Save AX and BX */
Stack[STACK_VAR_A] = getAX();
Stack[STACK_VAR_B] = getBX();
/* Rewind the BOP manually, we can't use CF because the interrupt could modify it */
EmulatorExecute(getCS(), getIP() - 4);
/* Call INT 0x10, AH = 0x0E */
setAH(0x0E);
setBL(DOS_CHAR_ATTRIBUTE);
setBH(Bda->VideoPage);
EmulatorInterrupt(0x10);
}
else
{
/* Restore AX and BX */
setAX(Stack[STACK_VAR_A]);
setBX(Stack[STACK_VAR_B]);
}
#else
/* Save AX and BX */ /* Save AX and BX */
USHORT AX = getAX(); USHORT AX = getAX();
USHORT BX = getBX(); USHORT BX = getBX();
@ -2707,12 +2477,11 @@ VOID WINAPI DosFastConOut(LPWORD Stack)
/* Restore AX and BX */ /* Restore AX and BX */
setBX(BX); setBX(BX);
setAX(AX); setAX(AX);
#endif
} }
VOID WINAPI DosInt2Fh(LPWORD Stack) VOID WINAPI DosInt2Fh(LPWORD Stack)
{ {
DPRINT1("DOS System Function INT 0x2F, AH = %xh, AL = %xh NOT IMPLEMENTED!\n", DPRINT1("DOS Internal System Function INT 0x2F, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
getAH(), getAL()); getAH(), getAL());
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
} }
@ -2778,17 +2547,19 @@ BOOLEAN DosKRNLInitialize(VOID)
/* Initialize the SFT */ /* Initialize the SFT */
for (i = 0; i < DOS_SFT_SIZE; i++) for (i = 0; i < DOS_SFT_SIZE; i++)
{ {
DosSystemFileTable[i] = INVALID_HANDLE_VALUE; DosSystemFileTable[i].Handle = INVALID_HANDLE_VALUE;
DosSftRefCount[i] = 0; DosSystemFileTable[i].RefCount = 0;
} }
/* Get handles to standard I/O devices */ /* Get handles to standard I/O devices */
DosSystemFileTable[0] = GetStdHandle(STD_INPUT_HANDLE); DosSystemFileTable[0].Handle = GetStdHandle(STD_INPUT_HANDLE);
DosSystemFileTable[1] = GetStdHandle(STD_OUTPUT_HANDLE); DosSystemFileTable[1].Handle = GetStdHandle(STD_OUTPUT_HANDLE);
DosSystemFileTable[2] = GetStdHandle(STD_ERROR_HANDLE); DosSystemFileTable[2].Handle = GetStdHandle(STD_ERROR_HANDLE);
/* Initialize the reference counts */ /* Initialize the reference counts */
DosSftRefCount[0] = DosSftRefCount[1] = DosSftRefCount[2] = 1; DosSystemFileTable[0].RefCount =
DosSystemFileTable[1].RefCount =
DosSystemFileTable[2].RefCount = 1;
#endif #endif

View file

@ -30,10 +30,12 @@
#define USER_MEMORY_SIZE 0x8FFE #define USER_MEMORY_SIZE 0x8FFE
#define SYSTEM_PSP 0x08 #define SYSTEM_PSP 0x08
#define SYSTEM_ENV_BLOCK 0x800 #define SYSTEM_ENV_BLOCK 0x800
#define INVALID_DOS_HANDLE 0xFFFF
#define DOS_INPUT_HANDLE 0 #define INVALID_DOS_HANDLE 0xFFFF
#define DOS_OUTPUT_HANDLE 1 #define DOS_INPUT_HANDLE 0
#define DOS_ERROR_HANDLE 2 #define DOS_OUTPUT_HANDLE 1
#define DOS_ERROR_HANDLE 2
#define DOS_SFT_SIZE 255 #define DOS_SFT_SIZE 255
#define SEGMENT_TO_MCB(seg) ((PDOS_MCB)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0))) #define SEGMENT_TO_MCB(seg) ((PDOS_MCB)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
#define SEGMENT_TO_PSP(seg) ((PDOS_PSP)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0))) #define SEGMENT_TO_PSP(seg) ((PDOS_PSP)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
@ -172,9 +174,9 @@ do { \
* DOS BIOS Functions * DOS BIOS Functions
* See bios.c * See bios.c
*/ */
CHAR DosReadCharacter(VOID); CHAR DosReadCharacter(WORD FileHandle);
BOOLEAN DosCheckInput(VOID); BOOLEAN DosCheckInput(VOID);
VOID DosPrintCharacter(CHAR Character); VOID DosPrintCharacter(WORD FileHandle, CHAR Character);
BOOLEAN DosBIOSInitialize(VOID); BOOLEAN DosBIOSInitialize(VOID);
@ -184,9 +186,15 @@ BOOLEAN DosBIOSInitialize(VOID);
* See dos.c * See dos.c
*/ */
BOOL IsConsoleHandle(HANDLE hHandle); BOOL IsConsoleHandle(HANDLE hHandle);
WORD DosOpenHandle(HANDLE Handle);
HANDLE DosGetRealHandle(WORD DosHandle); HANDLE DosGetRealHandle(WORD DosHandle);
WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes);
WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode);
WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead); WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead);
WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten); WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten);
WORD DosSeekFile(WORD FileHandle, LONG Offset, BYTE Origin, LPDWORD NewOffset);
BOOL DosFlushFileBuffers(WORD FileHandle);
VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, WORD Environment); VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, WORD Environment);
DWORD DosLoadExecutable( DWORD DosLoadExecutable(
@ -202,6 +210,9 @@ WORD DosCreateProcess(
LPCSTR ProgramName, LPCSTR ProgramName,
PDOS_EXEC_PARAM_BLOCK Parameters PDOS_EXEC_PARAM_BLOCK Parameters
); );
DWORD DosStartProcess(IN LPCSTR ExecutablePath,
IN LPCSTR CommandLine,
IN PVOID Environment);
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode); VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode);
BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle); BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle);

View file

@ -0,0 +1,331 @@
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: dos/dos32krnl/dosfiles.c
* PURPOSE: DOS Files
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
/* INCLUDES *******************************************************************/
#define NDEBUG
#include "emulator.h"
// #include "callback.h"
#include "dos.h"
#include "dos/dem.h"
#include "bios/bios.h"
/* PRIVATE VARIABLES **********************************************************/
/* PUBLIC FUNCTIONS ***********************************************************/
WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes)
{
HANDLE FileHandle;
WORD DosHandle;
DPRINT("DosCreateFile: FilePath \"%s\", Attributes 0x%04X\n",
FilePath,
Attributes);
/* Create the file */
FileHandle = CreateFileA(FilePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
CREATE_ALWAYS,
Attributes,
NULL);
if (FileHandle == INVALID_HANDLE_VALUE)
{
/* Return the error code */
return (WORD)GetLastError();
}
/* Open the DOS handle */
DosHandle = DosOpenHandle(FileHandle);
if (DosHandle == INVALID_DOS_HANDLE)
{
/* Close the handle */
CloseHandle(FileHandle);
/* Return the error code */
return ERROR_TOO_MANY_OPEN_FILES;
}
/* It was successful */
*Handle = DosHandle;
return ERROR_SUCCESS;
}
WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode)
{
HANDLE FileHandle;
ACCESS_MASK Access = 0;
WORD DosHandle;
DPRINT("DosOpenFile: FilePath \"%s\", AccessMode 0x%04X\n",
FilePath,
AccessMode);
/* Parse the access mode */
switch (AccessMode & 3)
{
case 0:
{
/* Read-only */
Access = GENERIC_READ;
break;
}
case 1:
{
/* Write only */
Access = GENERIC_WRITE;
break;
}
case 2:
{
/* Read and write */
Access = GENERIC_READ | GENERIC_WRITE;
break;
}
default:
{
/* Invalid */
return ERROR_INVALID_PARAMETER;
}
}
/* Open the file */
FileHandle = CreateFileA(FilePath,
Access,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (FileHandle == INVALID_HANDLE_VALUE)
{
/* Return the error code */
return (WORD)GetLastError();
}
/* Open the DOS handle */
DosHandle = DosOpenHandle(FileHandle);
if (DosHandle == INVALID_DOS_HANDLE)
{
/* Close the handle */
CloseHandle(FileHandle);
/* Return the error code */
return ERROR_TOO_MANY_OPEN_FILES;
}
/* It was successful */
*Handle = DosHandle;
return ERROR_SUCCESS;
}
WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead)
{
WORD Result = ERROR_SUCCESS;
DWORD BytesRead32 = 0;
HANDLE Handle = DosGetRealHandle(FileHandle);
DPRINT1("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
if (IsConsoleHandle(Handle))
{
CHAR Character;
/*
* Use BIOS Get Keystroke function
*/
/* Save AX */
USHORT AX = getAX();
for (BytesRead32 = 0; BytesRead32 < Count; BytesRead32++)
{
/* Call the BIOS INT 16h, AH=00h "Get Keystroke" */
setAH(0x00);
Int32Call(&DosContext, BIOS_KBD_INTERRUPT);
/* Retrieve the character in AL (scan code is in AH) */
Character = getAL();
// FIXME: Sometimes we need echo, some other times not.
// DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
((PCHAR)Buffer)[BytesRead32] = Character;
/* Stop on first carriage return */
if (Character == '\r')
{
// DosPrintCharacter(DOS_OUTPUT_HANDLE, '\n');
break;
}
// BytesRead32++;
}
/* Restore AX */
setAX(AX);
}
else
{
/* Read the file */
if (!ReadFile(Handle, Buffer, Count /* * sizeof(CHAR) */, &BytesRead32, NULL))
{
/* Store the error code */
Result = (WORD)GetLastError();
}
}
/* The number of bytes read is always 16-bit */
*BytesRead = LOWORD(BytesRead32);
/* Return the error code */
return Result;
}
WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten)
{
WORD Result = ERROR_SUCCESS;
DWORD BytesWritten32 = 0;
HANDLE Handle = DosGetRealHandle(FileHandle);
DPRINT1("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n",
FileHandle,
Count);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
if (IsConsoleHandle(Handle))
{
/*
* Use BIOS Teletype function
*/
/* Save AX and BX */
USHORT AX = getAX();
USHORT BX = getBX();
// FIXME: Use BIOS Write String function INT 10h, AH=13h ??
for (BytesWritten32 = 0; BytesWritten32 < Count; BytesWritten32++)
{
/* Set the parameters */
setAL(((PCHAR)Buffer)[BytesWritten32]);
setBL(DOS_CHAR_ATTRIBUTE);
setBH(Bda->VideoPage);
/* Call the BIOS INT 10h, AH=0Eh "Teletype Output" */
setAH(0x0E);
Int32Call(&DosContext, BIOS_VIDEO_INTERRUPT);
// BytesWritten32++;
}
/* Restore AX and BX */
setBX(BX);
setAX(AX);
}
else
{
/* Write the file */
if (!WriteFile(Handle, Buffer, Count /* * sizeof(CHAR) */, &BytesWritten32, NULL))
{
/* Store the error code */
Result = (WORD)GetLastError();
}
}
/* The number of bytes written is always 16-bit */
*BytesWritten = LOWORD(BytesWritten32);
/* Return the error code */
return Result;
}
WORD DosSeekFile(WORD FileHandle, LONG Offset, BYTE Origin, LPDWORD NewOffset)
{
WORD Result = ERROR_SUCCESS;
DWORD FilePointer;
HANDLE Handle = DosGetRealHandle(FileHandle);
DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
FileHandle,
Offset,
Origin);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
/* Check if the origin is valid */
if (Origin != FILE_BEGIN && Origin != FILE_CURRENT && Origin != FILE_END)
{
return ERROR_INVALID_FUNCTION;
}
/* Move the file pointer */
if (IsConsoleHandle(Handle))
{
/* Always succeeds when seeking a console handle */
FilePointer = 0;
Result = ERROR_SUCCESS;
}
else
{
FilePointer = SetFilePointer(Handle, Offset, NULL, Origin);
}
/* Check if there's a possibility the operation failed */
if (FilePointer == INVALID_SET_FILE_POINTER)
{
/* Get the real error code */
Result = (WORD)GetLastError();
}
if (Result != ERROR_SUCCESS)
{
/* The operation did fail */
return Result;
}
/* Return the file pointer, if requested */
if (NewOffset) *NewOffset = FilePointer;
/* Return success */
return ERROR_SUCCESS;
}
// This function is almost exclusively used as a DosFlushInputBuffer
BOOL DosFlushFileBuffers(WORD FileHandle)
{
HANDLE Handle = DosGetRealHandle(FileHandle);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return FALSE;
/*
* No need to check whether the handle is a console handle since
* FlushFileBuffers() automatically does this check and calls
* FlushConsoleInputBuffer() for us.
*/
return FlushFileBuffers(Handle);
}

View file

@ -395,13 +395,22 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
/* Initialize the PS2 port */ /* Initialize the PS2 port */
PS2Initialize(ConsoleInput); PS2Initialize(ConsoleInput);
/**************** ATTACH INPUT WITH CONSOLE *****************/
/* Start the input thread */ /* Start the input thread */
InputThread = CreateThread(NULL, 0, &PumpConsoleInput, ConsoleInput, 0, NULL); InputThread = CreateThread(NULL, 0, &PumpConsoleInput, ConsoleInput, 0, NULL);
// if (InputThread == NULL) return FALSE; if (InputThread == NULL)
{
DisplayMessage(L"Failed to create the console input thread.");
return FALSE;
}
/************************************************************/
/* Initialize the VGA */ /* Initialize the VGA */
// if (!VgaInitialize(ConsoleOutput)) return FALSE; if (!VgaInitialize(ConsoleOutput))
VgaInitialize(ConsoleOutput); {
DisplayMessage(L"Failed to initialize VGA support.");
return FALSE;
}
/* Initialize the software callback system and register the emulator BOPs */ /* Initialize the software callback system and register the emulator BOPs */
InitializeCallbacks(); InitializeCallbacks();

View file

@ -34,13 +34,15 @@
#define EMULATOR_FLAG_VIP (1 << 20) #define EMULATOR_FLAG_VIP (1 << 20)
#define EMULATOR_FLAG_ID (1 << 21) #define EMULATOR_FLAG_ID (1 << 21)
#define STACK_VAR_B 0 //
#define STACK_VAR_A 1 // WARNING WARNING!!
#define STACK_COUNTER 2 // If you're changing the indices here, you then need to
#define STACK_INT_NUM 3 // also fix the BOP code in callback.c !!!!!!!!!!!!!!!!!
#define STACK_IP 4 //
#define STACK_CS 5 #define STACK_INT_NUM 0
#define STACK_FLAGS 6 #define STACK_IP 1
#define STACK_CS 2
#define STACK_FLAGS 3
/* Basic Memory Management */ /* Basic Memory Management */

View file

@ -421,7 +421,7 @@ static VOID VgaUpdateCursorPosition(VOID)
VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG] = LOBYTE(Offset); VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG] = LOBYTE(Offset);
VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG] = HIBYTE(Offset); VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG] = HIBYTE(Offset);
VidBiosSyncCursorPosition(); // VidBiosSyncCursorPosition();
VgaUpdateTextCursor(); VgaUpdateTextCursor();
} }
@ -538,61 +538,6 @@ static BOOL VgaAttachToConsoleInternal(PCOORD Resolution)
return TRUE; return TRUE;
} }
BOOL VgaAttachToConsole(VOID)
{
if (TextResolution.X == 0 || TextResolution.Y == 0)
DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
if (TextResolution.X == 0) TextResolution.X = 80;
if (TextResolution.Y == 0) TextResolution.Y = 25;
return VgaAttachToConsoleInternal(&TextResolution);
}
VOID VgaDetachFromConsole(BOOL ChangingMode)
{
ULONG dummyLength;
PVOID dummyPtr;
COORD dummySize = {0};
__RegisterConsoleVDM(0,
NULL,
NULL,
NULL,
0,
&dummyLength,
&dummyPtr,
NULL,
0,
dummySize,
(PCHAR*)&dummyPtr);
TextFramebuffer = NULL;
if (!ChangingMode)
{
SMALL_RECT ConRect;
/* Restore the old screen buffer */
SetConsoleActiveScreenBuffer(TextConsoleBuffer);
/* Restore the original console size */
ConRect.Left = 0;
ConRect.Top = 0;
ConRect.Right = ConRect.Left + OrgConsoleBufferInfo.srWindow.Right - OrgConsoleBufferInfo.srWindow.Left;
ConRect.Bottom = ConRect.Top + OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top ;
/*
* See the following trick explanation in VgaAttachToConsoleInternal.
*/
SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
/* Restore the original cursor shape */
SetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo);
}
}
static BOOL IsConsoleHandle(HANDLE hHandle) static BOOL IsConsoleHandle(HANDLE hHandle)
{ {
DWORD dwMode; DWORD dwMode;
@ -1038,7 +983,10 @@ static BOOL VgaEnterTextMode(PCOORD Resolution)
return FALSE; return FALSE;
} }
} }
else VgaUpdateCursorPosition(); else
{
VgaUpdateCursorPosition();
}
/* The active framebuffer is now the text framebuffer */ /* The active framebuffer is now the text framebuffer */
ConsoleFramebuffer = TextFramebuffer; ConsoleFramebuffer = TextFramebuffer;
@ -1886,6 +1834,71 @@ VOID VgaResetPalette(VOID)
PaletteChanged = TRUE; PaletteChanged = TRUE;
} }
BOOL VgaAttachToConsole(VOID)
{
//
// FIXME: We should go back to the saved screen state
//
if (TextResolution.X == 0 || TextResolution.Y == 0)
DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
if (TextResolution.X == 0) TextResolution.X = 80;
if (TextResolution.Y == 0) TextResolution.Y = 25;
return VgaAttachToConsoleInternal(&TextResolution);
}
VOID VgaDetachFromConsole(BOOL ChangingMode)
{
ULONG dummyLength;
PVOID dummyPtr;
COORD dummySize = {0};
//
// FIXME: We should save the screen state
//
__RegisterConsoleVDM(0,
NULL,
NULL,
NULL,
0,
&dummyLength,
&dummyPtr,
NULL,
0,
dummySize,
(PCHAR*)&dummyPtr);
TextFramebuffer = NULL;
if (!ChangingMode)
{
SMALL_RECT ConRect;
/* Restore the old screen buffer */
SetConsoleActiveScreenBuffer(TextConsoleBuffer);
/* Restore the original console size */
ConRect.Left = 0;
ConRect.Top = 0;
ConRect.Right = ConRect.Left + OrgConsoleBufferInfo.srWindow.Right - OrgConsoleBufferInfo.srWindow.Left;
ConRect.Bottom = ConRect.Top + OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top ;
/*
* See the following trick explanation in VgaAttachToConsoleInternal.
*/
SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
/* Restore the original cursor shape */
SetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo);
}
}
BOOLEAN VgaInitialize(HANDLE TextHandle) BOOLEAN VgaInitialize(HANDLE TextHandle)
{ {
/* Save the default text-mode console output handle */ /* Save the default text-mode console output handle */

View file

@ -58,6 +58,13 @@ VOID WINAPI ControlBop(LPWORD Stack)
VOID InitializeInt32(WORD BiosSegment) VOID InitializeInt32(WORD BiosSegment)
{ {
//
// WARNING WARNING!!
//
// If you modify the code stubs here, think also
// about updating them in callback.c too!!
//
LPDWORD IntVecTable = (LPDWORD)BaseAddress; LPDWORD IntVecTable = (LPDWORD)BaseAddress;
LPBYTE BiosCode = (LPBYTE)SEG_OFF_TO_PTR(BiosSegment, 0); LPBYTE BiosCode = (LPBYTE)SEG_OFF_TO_PTR(BiosSegment, 0);
USHORT i; USHORT i;
@ -74,15 +81,6 @@ VOID InitializeInt32(WORD BiosSegment)
BiosCode[Offset++] = 0x6A; // push i BiosCode[Offset++] = 0x6A; // push i
BiosCode[Offset++] = (UCHAR)i; BiosCode[Offset++] = (UCHAR)i;
/* The counter variable (initialized to 0) */
BiosCode[Offset++] = 0x6A; // push 0
BiosCode[Offset++] = 0x00;
/* Stack variables */
BiosCode[Offset++] = 0x83; // sub sp, 4
BiosCode[Offset++] = 0xEC;
BiosCode[Offset++] = 0x04;
BopSeqOffset = COMMON_STUB_OFFSET - (Offset + 3); BopSeqOffset = COMMON_STUB_OFFSET - (Offset + 3);
BiosCode[Offset++] = 0xE9; // jmp near BOP_SEQ BiosCode[Offset++] = 0xE9; // jmp near BOP_SEQ
@ -113,9 +111,11 @@ VOID InitializeInt32(WORD BiosSegment)
BiosCode[Offset++] = 0xF5; BiosCode[Offset++] = 0xF5;
// EXIT: // EXIT:
BiosCode[Offset++] = 0x83; // add sp, 8 // BiosCode[Offset++] = 0x44; // inc sp
// BiosCode[Offset++] = 0x44; // inc sp
BiosCode[Offset++] = 0x83; // add sp, 2
BiosCode[Offset++] = 0xC4; BiosCode[Offset++] = 0xC4;
BiosCode[Offset++] = 0x08; BiosCode[Offset++] = 0x02;
BiosCode[Offset++] = 0xCF; // iret BiosCode[Offset++] = 0xCF; // iret

View file

@ -21,12 +21,6 @@
#include "resource.h" #include "resource.h"
/*
* Activate this line if you want to run NTVDM in standalone mode with:
* ntvdm.exe <program>
*/
// #define STANDALONE
/* VARIABLES ******************************************************************/ /* VARIABLES ******************************************************************/
static HANDLE ConsoleInput = INVALID_HANDLE_VALUE; static HANDLE ConsoleInput = INVALID_HANDLE_VALUE;
@ -39,7 +33,10 @@ static HMENU hConsoleMenu = NULL;
static INT VdmMenuPos = -1; static INT VdmMenuPos = -1;
static BOOLEAN ShowPointer = FALSE; static BOOLEAN ShowPointer = FALSE;
#ifndef STANDALONE
ULONG SessionId = 0; ULONG SessionId = 0;
#endif
HANDLE VdmTaskEvent = NULL; HANDLE VdmTaskEvent = NULL;
/* /*
@ -124,7 +121,7 @@ AppendMenuItems(HMENU hMenu,
static VOID static VOID
CreateVdmMenu(HANDLE ConOutHandle) CreateVdmMenu(HANDLE ConOutHandle)
{ {
hConsoleMenu = ConsoleMenuControl(ConsoleOutput, hConsoleMenu = ConsoleMenuControl(ConOutHandle,
ID_SHOWHIDE_MOUSE, ID_SHOWHIDE_MOUSE,
ID_VDM_QUIT); ID_VDM_QUIT);
if (hConsoleMenu == NULL) return; if (hConsoleMenu == NULL) return;
@ -176,7 +173,8 @@ static VOID ShowHideMousePointer(HANDLE ConOutHandle, BOOLEAN ShowPtr)
/* PUBLIC FUNCTIONS ***********************************************************/ /* PUBLIC FUNCTIONS ***********************************************************/
VOID DisplayMessage(LPCWSTR Format, ...) VOID
DisplayMessage(LPCWSTR Format, ...)
{ {
WCHAR Buffer[256]; WCHAR Buffer[256];
va_list Parameters; va_list Parameters;
@ -188,7 +186,9 @@ VOID DisplayMessage(LPCWSTR Format, ...)
va_end(Parameters); va_end(Parameters);
} }
BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType) static BOOL
WINAPI
ConsoleCtrlHandler(DWORD ControlType)
{ {
switch (ControlType) switch (ControlType)
{ {
@ -224,12 +224,14 @@ BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
return TRUE; return TRUE;
} }
VOID ConsoleInitUI(VOID) static VOID
ConsoleInitUI(VOID)
{ {
CreateVdmMenu(ConsoleOutput); CreateVdmMenu(ConsoleOutput);
} }
VOID ConsoleCleanupUI(VOID) static VOID
ConsoleCleanupUI(VOID)
{ {
/* Display again properly the mouse pointer */ /* Display again properly the mouse pointer */
if (ShowPointer) ShowHideMousePointer(ConsoleOutput, ShowPointer); if (ShowPointer) ShowHideMousePointer(ConsoleOutput, ShowPointer);
@ -237,7 +239,97 @@ VOID ConsoleCleanupUI(VOID)
DestroyVdmMenu(); DestroyVdmMenu();
} }
DWORD WINAPI PumpConsoleInput(LPVOID Parameter) static BOOL
ConsoleAttach(VOID)
{
/* Save the original input and output console modes */
if (!GetConsoleMode(ConsoleInput , &OrgConsoleInputMode ) ||
!GetConsoleMode(ConsoleOutput, &OrgConsoleOutputMode))
{
CloseHandle(ConsoleOutput);
CloseHandle(ConsoleInput);
wprintf(L"FATAL: Cannot save console in/out modes\n");
// return FALSE;
}
/* Initialize the UI */
ConsoleInitUI();
return TRUE;
}
static VOID
ConsoleDetach(VOID)
{
/* Restore the original input and output console modes */
SetConsoleMode(ConsoleOutput, OrgConsoleOutputMode);
SetConsoleMode(ConsoleInput , OrgConsoleInputMode );
/* Cleanup the UI */
ConsoleCleanupUI();
}
static BOOL
ConsoleInit(VOID)
{
/* Set the handler routine */
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
/* Enable the CTRL_LAST_CLOSE_EVENT */
SetLastConsoleEventActive();
/*
* NOTE: The CONIN$ and CONOUT$ "virtual" files
* always point to non-redirected console handles.
*/
/* Get the input handle to the real console, and check for success */
ConsoleInput = CreateFileW(L"CONIN$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (ConsoleInput == INVALID_HANDLE_VALUE)
{
wprintf(L"FATAL: Cannot retrieve a handle to the console input\n");
return FALSE;
}
/* Get the output handle to the real console, and check for success */
ConsoleOutput = CreateFileW(L"CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (ConsoleOutput == INVALID_HANDLE_VALUE)
{
CloseHandle(ConsoleInput);
wprintf(L"FATAL: Cannot retrieve a handle to the console output\n");
return FALSE;
}
/* Effectively attach to the console */
return ConsoleAttach();
}
static VOID
ConsoleCleanup(VOID)
{
/* Detach from the console */
ConsoleDetach();
/* Close the console handles */
if (ConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleOutput);
if (ConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleInput);
}
DWORD
WINAPI
PumpConsoleInput(LPVOID Parameter)
{ {
HANDLE ConsoleInput = (HANDLE)Parameter; HANDLE ConsoleInput = (HANDLE)Parameter;
INPUT_RECORD InputRecord; INPUT_RECORD InputRecord;
@ -296,74 +388,10 @@ DWORD WINAPI PumpConsoleInput(LPVOID Parameter)
return 0; return 0;
} }
BOOL ConsoleInit(VOID) #ifndef STANDALONE
{ static DWORD
/* Set the handler routine */ WINAPI
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE); CommandThreadProc(LPVOID Parameter)
/* Enable the CTRL_LAST_CLOSE_EVENT */
SetLastConsoleEventActive();
/* Get the input handle to the real console, and check for success */
ConsoleInput = CreateFileW(L"CONIN$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (ConsoleInput == INVALID_HANDLE_VALUE)
{
wprintf(L"FATAL: Cannot retrieve a handle to the console input\n");
return FALSE;
}
/* Get the output handle to the real console, and check for success */
ConsoleOutput = CreateFileW(L"CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (ConsoleOutput == INVALID_HANDLE_VALUE)
{
CloseHandle(ConsoleInput);
wprintf(L"FATAL: Cannot retrieve a handle to the console output\n");
return FALSE;
}
/* Save the original input and output console modes */
if (!GetConsoleMode(ConsoleInput , &OrgConsoleInputMode ) ||
!GetConsoleMode(ConsoleOutput, &OrgConsoleOutputMode))
{
CloseHandle(ConsoleOutput);
CloseHandle(ConsoleInput);
wprintf(L"FATAL: Cannot save console in/out modes\n");
return FALSE;
}
/* Initialize the UI */
ConsoleInitUI();
return TRUE;
}
VOID ConsoleCleanup(VOID)
{
/* Restore the original input and output console modes */
SetConsoleMode(ConsoleOutput, OrgConsoleOutputMode);
SetConsoleMode(ConsoleInput , OrgConsoleInputMode );
/* Cleanup the UI */
ConsoleCleanupUI();
/* Close the console handles */
if (ConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleOutput);
if (ConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleInput);
}
DWORD WINAPI CommandThreadProc(LPVOID Parameter)
{ {
BOOLEAN First = TRUE; BOOLEAN First = TRUE;
DWORD Result; DWORD Result;
@ -404,39 +432,25 @@ DWORD WINAPI CommandThreadProc(LPVOID Parameter)
if (!GetNextVDMCommand(&CommandInfo)) break; if (!GetNextVDMCommand(&CommandInfo)) break;
/* Start the process from the command line */ /* Start the process from the command line */
DPRINT1("Starting '%s'...\n", AppName); DPRINT1("Starting '%s' ('%s')...\n", AppName, CmdLine);
Result = DosStartProcess(AppName, CmdLine, Env);
Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE, AppName, CmdLine, Env, NULL, NULL);
if (Result != ERROR_SUCCESS) if (Result != ERROR_SUCCESS)
{ {
DisplayMessage(L"Could not start '%S'. Error: %u", AppName, Result); DisplayMessage(L"Could not start '%S'. Error: %u", AppName, Result);
break; // break;
continue;
} }
/* Attach to the console */
if (!First) VgaAttachToConsole();
/* Perform a screen refresh */
VgaRefreshDisplay();
/* Start simulation */
SetEvent(VdmTaskEvent);
EmulatorSimulate();
/* Perform another screen refresh */
VgaRefreshDisplay();
/* Detach from the console */
VgaDetachFromConsole(FALSE);
First = FALSE; First = FALSE;
} }
while (AcceptCommands); while (AcceptCommands);
return 0; return 0;
} }
#endif
INT wmain(INT argc, WCHAR *argv[]) INT
wmain(INT argc, WCHAR *argv[])
{ {
#ifdef STANDALONE #ifdef STANDALONE
@ -459,6 +473,7 @@ INT wmain(INT argc, WCHAR *argv[])
} }
#else #else
INT i; INT i;
WCHAR *endptr; WCHAR *endptr;
@ -530,27 +545,16 @@ INT wmain(INT argc, WCHAR *argv[])
#else #else
/* Start the process from the command line */ /* Start the process from the command line */
DPRINT1("Starting '%s'...\n", ApplicationName); DPRINT1("Starting '%s' ('%s')...\n", ApplicationName, CommandLine);
Result = DosStartProcess(ApplicationName,
Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE, CommandLine,
ApplicationName, GetEnvironmentStrings());
CommandLine,
GetEnvironmentStrings(),
NULL,
NULL);
if (Result != ERROR_SUCCESS) if (Result != ERROR_SUCCESS)
{ {
DisplayMessage(L"Could not start '%S'. Error: %u", ApplicationName, Result); DisplayMessage(L"Could not start '%S'. Error: %u", ApplicationName, Result);
goto Cleanup; goto Cleanup;
} }
/* Start simulation */
SetEvent(VdmTaskEvent);
EmulatorSimulate();
/* Perform another screen refresh */
VgaRefreshDisplay();
#endif #endif
Cleanup: Cleanup:

View file

@ -28,13 +28,22 @@
#include <vddsvc.h> #include <vddsvc.h>
DWORD WINAPI SetLastConsoleEventActive(VOID);
#include <debug.h> #include <debug.h>
DWORD WINAPI SetLastConsoleEventActive(VOID); /*
* Activate this line if you want to run NTVDM in standalone mode with:
* ntvdm.exe <program>
*/
#define STANDALONE
/* FUNCTIONS ******************************************************************/ /* FUNCTIONS ******************************************************************/
#ifndef STANDALONE
extern ULONG SessionId; extern ULONG SessionId;
#endif
extern HANDLE VdmTaskEvent; extern HANDLE VdmTaskEvent;
VOID DisplayMessage(LPCWSTR Format, ...); VOID DisplayMessage(LPCWSTR Format, ...);