mirror of
https://github.com/reactos/reactos.git
synced 2024-07-01 18:24:24 +00:00
[NTVDM]
- 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:
parent
5c08d6b6c5
commit
cdfa735cd1
|
@ -21,6 +21,7 @@ list(APPEND SOURCE
|
|||
hardware/vga.c
|
||||
dos/dos32krnl/bios.c
|
||||
dos/dos32krnl/dos.c
|
||||
dos/dos32krnl/dosfiles.c
|
||||
dos/dem.c
|
||||
bop.c
|
||||
callback.c
|
||||
|
|
|
@ -91,22 +91,13 @@ static WORD BiosPeekCharacter(VOID)
|
|||
else return 0xFFFF;
|
||||
}
|
||||
|
||||
WORD BiosGetCharacter(VOID)
|
||||
static WORD BiosGetCharacter(VOID)
|
||||
{
|
||||
WORD CharacterData = 0;
|
||||
|
||||
/* Check if there is a key available */
|
||||
if (BiosKbdBufferTop(&CharacterData))
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
/* Check if there is a key available, and if so, remove it from the queue */
|
||||
if (BiosKbdBufferTop(&CharacterData)) BiosKbdBufferPop();
|
||||
else CharacterData = 0xFFFF;
|
||||
|
||||
return CharacterData;
|
||||
}
|
||||
|
@ -121,7 +112,17 @@ static VOID WINAPI BiosKeyboardService(LPWORD Stack)
|
|||
case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
@ -130,13 +131,13 @@ static VOID WINAPI BiosKeyboardService(LPWORD Stack)
|
|||
/* Get extended keystroke status */
|
||||
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 */
|
||||
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
|
||||
setAX(Data);
|
||||
setAX(Character);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
WORD BiosGetCharacter(VOID);
|
||||
|
||||
BOOLEAN KbdBiosInitialize(VOID);
|
||||
VOID KbdBiosCleanup(VOID);
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
/* Some interrupts are in fact addresses to tables */
|
||||
|
@ -1541,6 +1572,15 @@ BOOLEAN VidBiosInitialize(VOID)
|
|||
((PULONG)BaseAddress)[0x43] = (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 */
|
||||
VidBiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE);
|
||||
|
||||
|
|
|
@ -37,9 +37,12 @@ enum
|
|||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID VidBiosSyncCursorPosition(VOID);
|
||||
|
||||
VOID WINAPI VidBiosVideoService(LPWORD Stack);
|
||||
|
||||
VOID VidBiosSyncCursorPosition(VOID);
|
||||
VOID VidBiosDetachFromConsole(VOID);
|
||||
VOID VidBiosAttachToConsole(VOID);
|
||||
|
||||
BOOLEAN VidBiosInitialize(VOID);
|
||||
VOID VidBiosCleanup(VOID);
|
||||
|
|
|
@ -44,6 +44,13 @@ do { \
|
|||
#define CALL16_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 */
|
||||
BYTE Int16To32[] =
|
||||
{
|
||||
|
@ -52,12 +59,6 @@ BYTE Int16To32[] =
|
|||
/* Push the value of the interrupt to be called */
|
||||
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 */
|
||||
// BOP_SEQ:
|
||||
0xF8, // clc
|
||||
|
@ -74,7 +75,8 @@ BYTE Int16To32[] =
|
|||
0xEB, 0xF5, // jmp BOP_SEQ (offset -11)
|
||||
|
||||
// EXIT:
|
||||
0x83, 0xC4, 0x08, // add sp, 8
|
||||
// 0x44, 0x44, // inc sp, inc sp
|
||||
0x83, 0xC4, 0x02, // add sp, 2
|
||||
0xCF, // iret
|
||||
};
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "bop.h"
|
||||
|
||||
#include "bios/bios.h"
|
||||
#include "hardware/vga.h"
|
||||
|
||||
/* Extra PSDK/NDK Headers */
|
||||
#include <ndk/obtypes.h>
|
||||
|
@ -138,8 +137,7 @@ static VOID WINAPI DosCmdInterpreterBop(LPWORD Stack)
|
|||
|
||||
StartupInfo.cb = sizeof(StartupInfo);
|
||||
|
||||
VgaRefreshDisplay();
|
||||
VgaDetachFromConsole(FALSE);
|
||||
VidBiosDetachFromConsole();
|
||||
|
||||
Result = CreateProcessA(NULL,
|
||||
CommandLine,
|
||||
|
@ -171,9 +169,7 @@ static VOID WINAPI DosCmdInterpreterBop(LPWORD Stack)
|
|||
dwExitCode = GetLastError();
|
||||
}
|
||||
|
||||
VgaAttachToConsole();
|
||||
VgaRefreshDisplay();
|
||||
VidBiosSyncCursorPosition();
|
||||
VidBiosAttachToConsole();
|
||||
|
||||
setAL((UCHAR)dwExitCode);
|
||||
|
||||
|
|
|
@ -24,65 +24,15 @@
|
|||
|
||||
/* 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 ***********************************************************/
|
||||
|
||||
CHAR DosReadCharacter(VOID)
|
||||
CHAR DosReadCharacter(WORD FileHandle)
|
||||
{
|
||||
CHAR Character = '\0';
|
||||
WORD BytesRead;
|
||||
|
||||
if (IsConsoleHandle(DosGetRealHandle(DOS_INPUT_HANDLE)))
|
||||
{
|
||||
/* Call the BIOS */
|
||||
Character = LOBYTE(BiosGetCharacter());
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use the file reading function */
|
||||
DosReadFile(DOS_INPUT_HANDLE, &Character, sizeof(CHAR), &BytesRead);
|
||||
}
|
||||
/* Use the file reading function */
|
||||
DosReadFile(FileHandle, &Character, 1, &BytesRead);
|
||||
|
||||
return Character;
|
||||
}
|
||||
|
@ -117,12 +67,12 @@ BOOLEAN DosCheckInput(VOID)
|
|||
}
|
||||
}
|
||||
|
||||
VOID DosPrintCharacter(CHAR Character)
|
||||
VOID DosPrintCharacter(WORD FileHandle, CHAR Character)
|
||||
{
|
||||
WORD BytesWritten;
|
||||
|
||||
/* Use the file writing function */
|
||||
DosWriteFile(DOS_OUTPUT_HANDLE, &Character, sizeof(CHAR), &BytesWritten);
|
||||
DosWriteFile(FileHandle, &Character, 1, &BytesWritten);
|
||||
}
|
||||
|
||||
BOOLEAN DosBIOSInitialize(VOID)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: dos.c
|
||||
* FILE: dos/dos32krnl/dos.c
|
||||
* PURPOSE: VDM DOS Kernel
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
@ -29,8 +29,13 @@ static DWORD DiskTransferArea;
|
|||
/*static*/ BYTE CurrentDrive;
|
||||
static CHAR LastDrive = 'E';
|
||||
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 BOOLEAN DosUmbLinked = FALSE;
|
||||
static WORD DosErrorLevel = 0x0000;
|
||||
|
@ -431,6 +436,11 @@ static WORD DosCopyEnvironmentBlock(LPCVOID Environment, LPCSTR ProgramName)
|
|||
return DestSegment;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Taken from base/shell/cmd/console.c */
|
||||
BOOL IsConsoleHandle(HANDLE hHandle)
|
||||
{
|
||||
|
@ -455,7 +465,7 @@ BOOL IsConsoleHandle(HANDLE hHandle)
|
|||
return GetConsoleMode(hHandle, &dwMode);
|
||||
}
|
||||
|
||||
static WORD DosOpenHandle(HANDLE Handle)
|
||||
WORD DosOpenHandle(HANDLE Handle)
|
||||
{
|
||||
BYTE i;
|
||||
WORD DosHandle;
|
||||
|
@ -482,10 +492,10 @@ static WORD DosOpenHandle(HANDLE Handle)
|
|||
for (i = 0; i < DOS_SFT_SIZE; i++)
|
||||
{
|
||||
/* Check if this is the same handle */
|
||||
if (DosSystemFileTable[i] != Handle) continue;
|
||||
if (DosSystemFileTable[i].Handle != Handle) continue;
|
||||
|
||||
/* Already in the table, reference it */
|
||||
DosSftRefCount[i]++;
|
||||
DosSystemFileTable[i].RefCount++;
|
||||
|
||||
/* Set the JFT entry to that SFT index */
|
||||
HandleTable[DosHandle] = i;
|
||||
|
@ -498,11 +508,11 @@ static WORD DosOpenHandle(HANDLE Handle)
|
|||
for (i = 0; i < DOS_SFT_SIZE; i++)
|
||||
{
|
||||
/* 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 */
|
||||
DosSystemFileTable[i] = Handle;
|
||||
DosSftRefCount[i] = 1;
|
||||
DosSystemFileTable[i].Handle = Handle;
|
||||
DosSystemFileTable[i].RefCount = 1;
|
||||
|
||||
/* Set the JFT entry to that SFT index */
|
||||
HandleTable[DosHandle] = i;
|
||||
|
@ -531,7 +541,7 @@ HANDLE DosGetRealHandle(WORD DosHandle)
|
|||
if (HandleTable[DosHandle] == 0xFF) return INVALID_HANDLE_VALUE;
|
||||
|
||||
/* Return the Win32 handle */
|
||||
return DosSystemFileTable[HandleTable[DosHandle]];
|
||||
return DosSystemFileTable[HandleTable[DosHandle]].Handle;
|
||||
}
|
||||
|
||||
static VOID DosCopyHandleTable(LPBYTE DestinationTable)
|
||||
|
@ -553,7 +563,7 @@ static VOID DosCopyHandleTable(LPBYTE DestinationTable)
|
|||
DestinationTable[i] = (BYTE)i;
|
||||
|
||||
/* Increase the reference count */
|
||||
DosSftRefCount[i]++;
|
||||
DosSystemFileTable[i].RefCount++;
|
||||
}
|
||||
|
||||
/* Done */
|
||||
|
@ -570,7 +580,7 @@ static VOID DosCopyHandleTable(LPBYTE DestinationTable)
|
|||
DestinationTable[i] = SourceTable[i];
|
||||
|
||||
/* 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 */
|
||||
SftIndex = HandleTable[DosHandle];
|
||||
DosSftRefCount[SftIndex]--;
|
||||
DosSystemFileTable[SftIndex].RefCount--;
|
||||
|
||||
/* Check if the reference count fell to zero */
|
||||
if (!DosSftRefCount[SftIndex])
|
||||
if (!DosSystemFileTable[SftIndex].RefCount)
|
||||
{
|
||||
/* Close the file, it's no longer needed */
|
||||
CloseHandle(DosSystemFileTable[SftIndex]);
|
||||
CloseHandle(DosSystemFileTable[SftIndex].Handle);
|
||||
|
||||
/* Clear the handle */
|
||||
DosSystemFileTable[SftIndex] = INVALID_HANDLE_VALUE;
|
||||
DosSystemFileTable[SftIndex].Handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
SftIndex = HandleTable[OldHandle];
|
||||
DosSftRefCount[SftIndex]++;
|
||||
DosSystemFileTable[SftIndex].RefCount++;
|
||||
|
||||
/* Make the new handle point to that SFT entry */
|
||||
HandleTable[NewHandle] = SftIndex;
|
||||
|
@ -650,260 +660,11 @@ static BOOLEAN DosDuplicateHandle(WORD OldHandle, WORD NewHandle)
|
|||
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)
|
||||
{
|
||||
|
@ -1279,6 +1040,36 @@ Cleanup:
|
|||
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,
|
||||
LPCSTR ProgramName,
|
||||
PDOS_EXEC_PARAM_BLOCK Parameters)
|
||||
|
@ -1363,16 +1154,17 @@ WORD DosCreateProcess(DOS_EXEC_TYPE LoadType,
|
|||
GetNextVDMCommand(&CommandInfo);
|
||||
|
||||
/* Load the executable */
|
||||
Result= DosLoadExecutable(LoadType,
|
||||
AppName,
|
||||
CmdLine,
|
||||
Env,
|
||||
&Parameters->StackLocation,
|
||||
&Parameters->EntryPoint);
|
||||
Result = DosLoadExecutable(LoadType,
|
||||
AppName,
|
||||
CmdLine,
|
||||
Env,
|
||||
&Parameters->StackLocation,
|
||||
&Parameters->EntryPoint);
|
||||
if (Result != ERROR_SUCCESS)
|
||||
{
|
||||
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;
|
||||
|
@ -1392,6 +1184,7 @@ WORD DosCreateProcess(DOS_EXEC_TYPE LoadType,
|
|||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode)
|
||||
{
|
||||
|
@ -1400,7 +1193,6 @@ VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode)
|
|||
PDOS_MCB CurrentMcb;
|
||||
LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
|
||||
PDOS_PSP PspBlock = SEGMENT_TO_PSP(Psp);
|
||||
VDM_COMMAND_INFO CommandInfo;
|
||||
|
||||
DPRINT("DosTerminateProcess: Psp 0x%04X, ReturnCode 0x%02X\n",
|
||||
Psp,
|
||||
|
@ -1451,10 +1243,13 @@ Done:
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef STANDALONE
|
||||
// FIXME: This is probably not the best way to do it
|
||||
/* Check if this was a nested DOS task */
|
||||
if (CurrentPsp != SYSTEM_PSP)
|
||||
{
|
||||
VDM_COMMAND_INFO CommandInfo;
|
||||
|
||||
/* Decrement the re-entry count */
|
||||
CommandInfo.TaskId = SessionId;
|
||||
CommandInfo.VDMState = VDM_DEC_REENTER_COUNT;
|
||||
|
@ -1468,6 +1263,7 @@ Done:
|
|||
CommandInfo.VDMState = VDM_FLAG_DONT_WAIT;
|
||||
GetNextVDMCommand(&CommandInfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Save the return code - Normal termination */
|
||||
DosErrorLevel = MAKEWORD(ReturnCode, 0x00);
|
||||
|
@ -1500,12 +1296,12 @@ BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle)
|
|||
* for a list of possible flags.
|
||||
*/
|
||||
|
||||
if (Handle == DosSystemFileTable[0])
|
||||
if (Handle == DosSystemFileTable[DOS_INPUT_HANDLE].Handle)
|
||||
{
|
||||
/* Console input */
|
||||
InfoWord |= 1 << 0;
|
||||
}
|
||||
else if (Handle == DosSystemFileTable[1])
|
||||
else if (Handle == DosSystemFileTable[DOS_OUTPUT_HANDLE].Handle)
|
||||
{
|
||||
/* Console output */
|
||||
InfoWord |= 1 << 1;
|
||||
|
@ -1556,11 +1352,12 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
/* Read Character from STDIN with Echo */
|
||||
case 0x01:
|
||||
{
|
||||
Character = DosReadCharacter();
|
||||
DosPrintCharacter(Character);
|
||||
// FIXME: Under DOS 2+, input / output handle may be redirected!!!!
|
||||
Character = DosReadCharacter(DOS_INPUT_HANDLE);
|
||||
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
|
||||
|
||||
/* Let the BOP repeat if needed */
|
||||
if (getCF()) break;
|
||||
// /* Let the BOP repeat if needed */
|
||||
// if (getCF()) break;
|
||||
|
||||
setAL(Character);
|
||||
break;
|
||||
|
@ -1569,8 +1366,9 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
/* Write Character to STDOUT */
|
||||
case 0x02:
|
||||
{
|
||||
// FIXME: Under DOS 2+, output handle may be redirected!!!!
|
||||
Character = getDL();
|
||||
DosPrintCharacter(Character);
|
||||
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
|
||||
|
||||
/*
|
||||
* We return the output character (DOS 2.1+).
|
||||
|
@ -1588,7 +1386,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
{
|
||||
// FIXME: Really read it from STDAUX!
|
||||
DPRINT1("INT 16h, 03h: Read character from STDAUX is HALFPLEMENTED\n");
|
||||
setAL(DosReadCharacter());
|
||||
// setAL(DosReadCharacter());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1597,7 +1395,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
{
|
||||
// FIXME: Really write it to STDAUX!
|
||||
DPRINT1("INT 16h, 04h: Write character to STDAUX is HALFPLEMENTED\n");
|
||||
DosPrintCharacter(getDL());
|
||||
// DosPrintCharacter(getDL());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1616,10 +1414,12 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
{
|
||||
Character = getDL();
|
||||
|
||||
// FIXME: Under DOS 2+, output handle may be redirected!!!!
|
||||
|
||||
if (Character != 0xFF)
|
||||
{
|
||||
/* Output */
|
||||
DosPrintCharacter(Character);
|
||||
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
|
||||
|
||||
/*
|
||||
* We return the output character (DOS 2.1+).
|
||||
|
@ -1634,7 +1434,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
if (DosCheckInput())
|
||||
{
|
||||
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
|
||||
setAL(DosReadCharacter());
|
||||
setAL(DosReadCharacter(DOS_INPUT_HANDLE));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1651,10 +1451,15 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
case 0x07:
|
||||
case 0x08:
|
||||
{
|
||||
Character = DosReadCharacter();
|
||||
// FIXME: Under DOS 2+, input handle may be redirected!!!!
|
||||
Character = DosReadCharacter(DOS_INPUT_HANDLE);
|
||||
|
||||
/* Let the BOP repeat if needed */
|
||||
if (getCF()) break;
|
||||
// FIXME: For 0x07, do not check Ctrl-C/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);
|
||||
break;
|
||||
|
@ -1667,7 +1472,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
|
||||
while (*String != '$')
|
||||
{
|
||||
DosPrintCharacter(*String);
|
||||
DosPrintCharacter(DOS_OUTPUT_HANDLE, *String);
|
||||
String++;
|
||||
}
|
||||
|
||||
|
@ -1683,26 +1488,27 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
/* Read Buffered Input */
|
||||
case 0x0A:
|
||||
{
|
||||
WORD Count = 0;
|
||||
InputBuffer = (PDOS_INPUT_BUFFER)SEG_OFF_TO_PTR(getDS(), getDX());
|
||||
|
||||
while (Stack[STACK_COUNTER] < InputBuffer->MaxLength)
|
||||
{
|
||||
/* Try to read a character */
|
||||
Character = DosReadCharacter();
|
||||
DPRINT1("Read Buffered Input\n");
|
||||
|
||||
/* If it's not ready yet, let the BOP repeat */
|
||||
if (getCF()) break;
|
||||
while (Count < InputBuffer->MaxLength)
|
||||
{
|
||||
/* Try to read a character (wait) */
|
||||
Character = DosReadCharacter(DOS_INPUT_HANDLE);
|
||||
|
||||
/* Echo the character and append it to the buffer */
|
||||
DosPrintCharacter(Character);
|
||||
InputBuffer->Buffer[Stack[STACK_COUNTER]] = Character;
|
||||
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
|
||||
InputBuffer->Buffer[Count] = Character;
|
||||
|
||||
if (Character == '\r') break;
|
||||
Stack[STACK_COUNTER]++;
|
||||
Count++;
|
||||
}
|
||||
|
||||
/* Update the length */
|
||||
InputBuffer->Length = Stack[STACK_COUNTER];
|
||||
InputBuffer->Length = Count;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1719,7 +1525,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
BYTE InputFunction = getAL();
|
||||
|
||||
/* 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.
|
||||
|
@ -2163,47 +1969,11 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
/* Read from File or Device */
|
||||
case 0x3F:
|
||||
{
|
||||
WORD Handle = getBX();
|
||||
LPBYTE Buffer = (LPBYTE)SEG_OFF_TO_PTR(getDS(), getDX());
|
||||
WORD Count = getCX();
|
||||
WORD BytesRead = 0;
|
||||
WORD ErrorCode = ERROR_SUCCESS;
|
||||
CHAR Character;
|
||||
|
||||
if (IsConsoleHandle(DosGetRealHandle(Handle)))
|
||||
{
|
||||
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);
|
||||
}
|
||||
WORD ErrorCode = DosReadFile(getBX(),
|
||||
SEG_OFF_TO_PTR(getDS(), getDX()),
|
||||
getCX(),
|
||||
&BytesRead);
|
||||
|
||||
if (ErrorCode == ERROR_SUCCESS)
|
||||
{
|
||||
|
@ -2215,6 +1985,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
|
||||
setAX(ErrorCode);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2358,7 +2129,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
WORD NewHandle;
|
||||
HANDLE Handle = DosGetRealHandle(getBX());
|
||||
|
||||
if (Handle != INVALID_HANDLE_VALUE)
|
||||
if (Handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
/* The handle is invalid */
|
||||
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
|
||||
|
@ -2491,6 +2262,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
break;
|
||||
}
|
||||
|
||||
#ifndef STANDALONE
|
||||
/* Execute */
|
||||
case 0x4B:
|
||||
{
|
||||
|
@ -2511,6 +2283,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Terminate With Return Code */
|
||||
case 0x4C:
|
||||
|
@ -2540,8 +2313,11 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
getCX());
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -2552,8 +2328,11 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
WORD Result = (WORD)demFileFindNext(FAR_POINTER(DiskTransferArea));
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -2581,6 +2360,23 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
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 */
|
||||
case 0x58:
|
||||
{
|
||||
|
@ -2666,32 +2462,6 @@ VOID WINAPI DosFastConOut(LPWORD Stack)
|
|||
* 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 */
|
||||
USHORT AX = getAX();
|
||||
USHORT BX = getBX();
|
||||
|
@ -2707,12 +2477,11 @@ VOID WINAPI DosFastConOut(LPWORD Stack)
|
|||
/* Restore AX and BX */
|
||||
setBX(BX);
|
||||
setAX(AX);
|
||||
#endif
|
||||
}
|
||||
|
||||
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());
|
||||
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
|
||||
}
|
||||
|
@ -2778,17 +2547,19 @@ BOOLEAN DosKRNLInitialize(VOID)
|
|||
/* Initialize the SFT */
|
||||
for (i = 0; i < DOS_SFT_SIZE; i++)
|
||||
{
|
||||
DosSystemFileTable[i] = INVALID_HANDLE_VALUE;
|
||||
DosSftRefCount[i] = 0;
|
||||
DosSystemFileTable[i].Handle = INVALID_HANDLE_VALUE;
|
||||
DosSystemFileTable[i].RefCount = 0;
|
||||
}
|
||||
|
||||
/* Get handles to standard I/O devices */
|
||||
DosSystemFileTable[0] = GetStdHandle(STD_INPUT_HANDLE);
|
||||
DosSystemFileTable[1] = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DosSystemFileTable[2] = GetStdHandle(STD_ERROR_HANDLE);
|
||||
DosSystemFileTable[0].Handle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
DosSystemFileTable[1].Handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DosSystemFileTable[2].Handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
/* Initialize the reference counts */
|
||||
DosSftRefCount[0] = DosSftRefCount[1] = DosSftRefCount[2] = 1;
|
||||
DosSystemFileTable[0].RefCount =
|
||||
DosSystemFileTable[1].RefCount =
|
||||
DosSystemFileTable[2].RefCount = 1;
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -30,10 +30,12 @@
|
|||
#define USER_MEMORY_SIZE 0x8FFE
|
||||
#define SYSTEM_PSP 0x08
|
||||
#define SYSTEM_ENV_BLOCK 0x800
|
||||
#define INVALID_DOS_HANDLE 0xFFFF
|
||||
#define DOS_INPUT_HANDLE 0
|
||||
#define DOS_OUTPUT_HANDLE 1
|
||||
#define DOS_ERROR_HANDLE 2
|
||||
|
||||
#define INVALID_DOS_HANDLE 0xFFFF
|
||||
#define DOS_INPUT_HANDLE 0
|
||||
#define DOS_OUTPUT_HANDLE 1
|
||||
#define DOS_ERROR_HANDLE 2
|
||||
|
||||
#define DOS_SFT_SIZE 255
|
||||
#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)))
|
||||
|
@ -172,9 +174,9 @@ do { \
|
|||
* DOS BIOS Functions
|
||||
* See bios.c
|
||||
*/
|
||||
CHAR DosReadCharacter(VOID);
|
||||
CHAR DosReadCharacter(WORD FileHandle);
|
||||
BOOLEAN DosCheckInput(VOID);
|
||||
VOID DosPrintCharacter(CHAR Character);
|
||||
VOID DosPrintCharacter(WORD FileHandle, CHAR Character);
|
||||
|
||||
BOOLEAN DosBIOSInitialize(VOID);
|
||||
|
||||
|
@ -184,9 +186,15 @@ BOOLEAN DosBIOSInitialize(VOID);
|
|||
* See dos.c
|
||||
*/
|
||||
BOOL IsConsoleHandle(HANDLE hHandle);
|
||||
WORD DosOpenHandle(HANDLE Handle);
|
||||
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 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);
|
||||
DWORD DosLoadExecutable(
|
||||
|
@ -202,6 +210,9 @@ WORD DosCreateProcess(
|
|||
LPCSTR ProgramName,
|
||||
PDOS_EXEC_PARAM_BLOCK Parameters
|
||||
);
|
||||
DWORD DosStartProcess(IN LPCSTR ExecutablePath,
|
||||
IN LPCSTR CommandLine,
|
||||
IN PVOID Environment);
|
||||
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode);
|
||||
BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle);
|
||||
|
||||
|
|
331
reactos/subsystems/ntvdm/dos/dos32krnl/dosfiles.c
Normal file
331
reactos/subsystems/ntvdm/dos/dos32krnl/dosfiles.c
Normal 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);
|
||||
}
|
|
@ -395,13 +395,22 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
|
|||
/* Initialize the PS2 port */
|
||||
PS2Initialize(ConsoleInput);
|
||||
|
||||
/**************** ATTACH INPUT WITH CONSOLE *****************/
|
||||
/* Start the input thread */
|
||||
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 */
|
||||
// if (!VgaInitialize(ConsoleOutput)) return FALSE;
|
||||
VgaInitialize(ConsoleOutput);
|
||||
if (!VgaInitialize(ConsoleOutput))
|
||||
{
|
||||
DisplayMessage(L"Failed to initialize VGA support.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Initialize the software callback system and register the emulator BOPs */
|
||||
InitializeCallbacks();
|
||||
|
|
|
@ -34,13 +34,15 @@
|
|||
#define EMULATOR_FLAG_VIP (1 << 20)
|
||||
#define EMULATOR_FLAG_ID (1 << 21)
|
||||
|
||||
#define STACK_VAR_B 0
|
||||
#define STACK_VAR_A 1
|
||||
#define STACK_COUNTER 2
|
||||
#define STACK_INT_NUM 3
|
||||
#define STACK_IP 4
|
||||
#define STACK_CS 5
|
||||
#define STACK_FLAGS 6
|
||||
//
|
||||
// WARNING WARNING!!
|
||||
// If you're changing the indices here, you then need to
|
||||
// also fix the BOP code in callback.c !!!!!!!!!!!!!!!!!
|
||||
//
|
||||
#define STACK_INT_NUM 0
|
||||
#define STACK_IP 1
|
||||
#define STACK_CS 2
|
||||
#define STACK_FLAGS 3
|
||||
|
||||
|
||||
/* Basic Memory Management */
|
||||
|
|
|
@ -421,7 +421,7 @@ static VOID VgaUpdateCursorPosition(VOID)
|
|||
VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG] = LOBYTE(Offset);
|
||||
VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG] = HIBYTE(Offset);
|
||||
|
||||
VidBiosSyncCursorPosition();
|
||||
// VidBiosSyncCursorPosition();
|
||||
VgaUpdateTextCursor();
|
||||
}
|
||||
|
||||
|
@ -538,61 +538,6 @@ static BOOL VgaAttachToConsoleInternal(PCOORD Resolution)
|
|||
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)
|
||||
{
|
||||
DWORD dwMode;
|
||||
|
@ -1038,7 +983,10 @@ static BOOL VgaEnterTextMode(PCOORD Resolution)
|
|||
return FALSE;
|
||||
}
|
||||
}
|
||||
else VgaUpdateCursorPosition();
|
||||
else
|
||||
{
|
||||
VgaUpdateCursorPosition();
|
||||
}
|
||||
|
||||
/* The active framebuffer is now the text framebuffer */
|
||||
ConsoleFramebuffer = TextFramebuffer;
|
||||
|
@ -1886,6 +1834,71 @@ VOID VgaResetPalette(VOID)
|
|||
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)
|
||||
{
|
||||
/* Save the default text-mode console output handle */
|
||||
|
|
|
@ -58,6 +58,13 @@ VOID WINAPI ControlBop(LPWORD Stack)
|
|||
|
||||
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;
|
||||
LPBYTE BiosCode = (LPBYTE)SEG_OFF_TO_PTR(BiosSegment, 0);
|
||||
USHORT i;
|
||||
|
@ -74,15 +81,6 @@ VOID InitializeInt32(WORD BiosSegment)
|
|||
BiosCode[Offset++] = 0x6A; // push 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);
|
||||
|
||||
BiosCode[Offset++] = 0xE9; // jmp near BOP_SEQ
|
||||
|
@ -113,9 +111,11 @@ VOID InitializeInt32(WORD BiosSegment)
|
|||
BiosCode[Offset++] = 0xF5;
|
||||
|
||||
// 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++] = 0x08;
|
||||
BiosCode[Offset++] = 0x02;
|
||||
|
||||
BiosCode[Offset++] = 0xCF; // iret
|
||||
|
||||
|
|
|
@ -21,12 +21,6 @@
|
|||
|
||||
#include "resource.h"
|
||||
|
||||
/*
|
||||
* Activate this line if you want to run NTVDM in standalone mode with:
|
||||
* ntvdm.exe <program>
|
||||
*/
|
||||
// #define STANDALONE
|
||||
|
||||
/* VARIABLES ******************************************************************/
|
||||
|
||||
static HANDLE ConsoleInput = INVALID_HANDLE_VALUE;
|
||||
|
@ -39,7 +33,10 @@ static HMENU hConsoleMenu = NULL;
|
|||
static INT VdmMenuPos = -1;
|
||||
static BOOLEAN ShowPointer = FALSE;
|
||||
|
||||
#ifndef STANDALONE
|
||||
ULONG SessionId = 0;
|
||||
#endif
|
||||
|
||||
HANDLE VdmTaskEvent = NULL;
|
||||
|
||||
/*
|
||||
|
@ -124,7 +121,7 @@ AppendMenuItems(HMENU hMenu,
|
|||
static VOID
|
||||
CreateVdmMenu(HANDLE ConOutHandle)
|
||||
{
|
||||
hConsoleMenu = ConsoleMenuControl(ConsoleOutput,
|
||||
hConsoleMenu = ConsoleMenuControl(ConOutHandle,
|
||||
ID_SHOWHIDE_MOUSE,
|
||||
ID_VDM_QUIT);
|
||||
if (hConsoleMenu == NULL) return;
|
||||
|
@ -176,7 +173,8 @@ static VOID ShowHideMousePointer(HANDLE ConOutHandle, BOOLEAN ShowPtr)
|
|||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID DisplayMessage(LPCWSTR Format, ...)
|
||||
VOID
|
||||
DisplayMessage(LPCWSTR Format, ...)
|
||||
{
|
||||
WCHAR Buffer[256];
|
||||
va_list Parameters;
|
||||
|
@ -188,7 +186,9 @@ VOID DisplayMessage(LPCWSTR Format, ...)
|
|||
va_end(Parameters);
|
||||
}
|
||||
|
||||
BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
|
||||
static BOOL
|
||||
WINAPI
|
||||
ConsoleCtrlHandler(DWORD ControlType)
|
||||
{
|
||||
switch (ControlType)
|
||||
{
|
||||
|
@ -224,12 +224,14 @@ BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
VOID ConsoleInitUI(VOID)
|
||||
static VOID
|
||||
ConsoleInitUI(VOID)
|
||||
{
|
||||
CreateVdmMenu(ConsoleOutput);
|
||||
}
|
||||
|
||||
VOID ConsoleCleanupUI(VOID)
|
||||
static VOID
|
||||
ConsoleCleanupUI(VOID)
|
||||
{
|
||||
/* Display again properly the mouse pointer */
|
||||
if (ShowPointer) ShowHideMousePointer(ConsoleOutput, ShowPointer);
|
||||
|
@ -237,7 +239,97 @@ VOID ConsoleCleanupUI(VOID)
|
|||
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;
|
||||
INPUT_RECORD InputRecord;
|
||||
|
@ -296,74 +388,10 @@ DWORD WINAPI PumpConsoleInput(LPVOID Parameter)
|
|||
return 0;
|
||||
}
|
||||
|
||||
BOOL ConsoleInit(VOID)
|
||||
{
|
||||
/* Set the handler routine */
|
||||
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
|
||||
|
||||
/* 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)
|
||||
#ifndef STANDALONE
|
||||
static DWORD
|
||||
WINAPI
|
||||
CommandThreadProc(LPVOID Parameter)
|
||||
{
|
||||
BOOLEAN First = TRUE;
|
||||
DWORD Result;
|
||||
|
@ -404,39 +432,25 @@ DWORD WINAPI CommandThreadProc(LPVOID Parameter)
|
|||
if (!GetNextVDMCommand(&CommandInfo)) break;
|
||||
|
||||
/* Start the process from the command line */
|
||||
DPRINT1("Starting '%s'...\n", AppName);
|
||||
|
||||
Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE, AppName, CmdLine, Env, NULL, NULL);
|
||||
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;
|
||||
// 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;
|
||||
}
|
||||
while (AcceptCommands);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
INT wmain(INT argc, WCHAR *argv[])
|
||||
INT
|
||||
wmain(INT argc, WCHAR *argv[])
|
||||
{
|
||||
#ifdef STANDALONE
|
||||
|
||||
|
@ -459,6 +473,7 @@ INT wmain(INT argc, WCHAR *argv[])
|
|||
}
|
||||
|
||||
#else
|
||||
|
||||
INT i;
|
||||
WCHAR *endptr;
|
||||
|
||||
|
@ -530,27 +545,16 @@ INT wmain(INT argc, WCHAR *argv[])
|
|||
#else
|
||||
|
||||
/* Start the process from the command line */
|
||||
DPRINT1("Starting '%s'...\n", ApplicationName);
|
||||
|
||||
Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
|
||||
ApplicationName,
|
||||
CommandLine,
|
||||
GetEnvironmentStrings(),
|
||||
NULL,
|
||||
NULL);
|
||||
DPRINT1("Starting '%s' ('%s')...\n", ApplicationName, CommandLine);
|
||||
Result = DosStartProcess(ApplicationName,
|
||||
CommandLine,
|
||||
GetEnvironmentStrings());
|
||||
if (Result != ERROR_SUCCESS)
|
||||
{
|
||||
DisplayMessage(L"Could not start '%S'. Error: %u", ApplicationName, Result);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Start simulation */
|
||||
SetEvent(VdmTaskEvent);
|
||||
EmulatorSimulate();
|
||||
|
||||
/* Perform another screen refresh */
|
||||
VgaRefreshDisplay();
|
||||
|
||||
#endif
|
||||
|
||||
Cleanup:
|
||||
|
|
|
@ -28,13 +28,22 @@
|
|||
|
||||
#include <vddsvc.h>
|
||||
|
||||
DWORD WINAPI SetLastConsoleEventActive(VOID);
|
||||
|
||||
#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 ******************************************************************/
|
||||
|
||||
#ifndef STANDALONE
|
||||
extern ULONG SessionId;
|
||||
#endif
|
||||
|
||||
extern HANDLE VdmTaskEvent;
|
||||
|
||||
VOID DisplayMessage(LPCWSTR Format, ...);
|
||||
|
|
Loading…
Reference in a new issue