From cdfa735cd1cd410278da902ee26b61dcd5ed547d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Sun, 11 May 2014 19:25:09 +0000 Subject: [PATCH] [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 --- reactos/subsystems/ntvdm/CMakeLists.txt | 1 + .../subsystems/ntvdm/bios/bios32/kbdbios32.c | 35 +- reactos/subsystems/ntvdm/bios/kbdbios.h | 2 - reactos/subsystems/ntvdm/bios/vidbios.c | 40 ++ reactos/subsystems/ntvdm/bios/vidbios.h | 5 +- reactos/subsystems/ntvdm/callback.c | 16 +- reactos/subsystems/ntvdm/dos/dem.c | 8 +- reactos/subsystems/ntvdm/dos/dos32krnl/bios.c | 60 +- reactos/subsystems/ntvdm/dos/dos32krnl/dos.c | 529 +++++------------- reactos/subsystems/ntvdm/dos/dos32krnl/dos.h | 23 +- .../subsystems/ntvdm/dos/dos32krnl/dosfiles.c | 331 +++++++++++ reactos/subsystems/ntvdm/emulator.c | 15 +- reactos/subsystems/ntvdm/emulator.h | 16 +- reactos/subsystems/ntvdm/hardware/vga.c | 127 +++-- reactos/subsystems/ntvdm/int32.c | 22 +- reactos/subsystems/ntvdm/ntvdm.c | 236 ++++---- reactos/subsystems/ntvdm/ntvdm.h | 11 +- 17 files changed, 809 insertions(+), 668 deletions(-) create mode 100644 reactos/subsystems/ntvdm/dos/dos32krnl/dosfiles.c diff --git a/reactos/subsystems/ntvdm/CMakeLists.txt b/reactos/subsystems/ntvdm/CMakeLists.txt index 80ab3e92e41..2ee9f55eaad 100644 --- a/reactos/subsystems/ntvdm/CMakeLists.txt +++ b/reactos/subsystems/ntvdm/CMakeLists.txt @@ -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 diff --git a/reactos/subsystems/ntvdm/bios/bios32/kbdbios32.c b/reactos/subsystems/ntvdm/bios/bios32/kbdbios32.c index 9d95ccd368b..716af1f50d7 100644 --- a/reactos/subsystems/ntvdm/bios/bios32/kbdbios32.c +++ b/reactos/subsystems/ntvdm/bios/bios32/kbdbios32.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 { diff --git a/reactos/subsystems/ntvdm/bios/kbdbios.h b/reactos/subsystems/ntvdm/bios/kbdbios.h index 46486785b2b..1d8798ac763 100644 --- a/reactos/subsystems/ntvdm/bios/kbdbios.h +++ b/reactos/subsystems/ntvdm/bios/kbdbios.h @@ -21,8 +21,6 @@ /* FUNCTIONS ******************************************************************/ -WORD BiosGetCharacter(VOID); - BOOLEAN KbdBiosInitialize(VOID); VOID KbdBiosCleanup(VOID); diff --git a/reactos/subsystems/ntvdm/bios/vidbios.c b/reactos/subsystems/ntvdm/bios/vidbios.c index cec5a7060e2..41d22d3b1a6 100644 --- a/reactos/subsystems/ntvdm/bios/vidbios.c +++ b/reactos/subsystems/ntvdm/bios/vidbios.c @@ -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); diff --git a/reactos/subsystems/ntvdm/bios/vidbios.h b/reactos/subsystems/ntvdm/bios/vidbios.h index 70b3e54606e..5e291471115 100644 --- a/reactos/subsystems/ntvdm/bios/vidbios.h +++ b/reactos/subsystems/ntvdm/bios/vidbios.h @@ -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); diff --git a/reactos/subsystems/ntvdm/callback.c b/reactos/subsystems/ntvdm/callback.c index 34c0bcc7824..feed3d80270 100644 --- a/reactos/subsystems/ntvdm/callback.c +++ b/reactos/subsystems/ntvdm/callback.c @@ -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 }; diff --git a/reactos/subsystems/ntvdm/dos/dem.c b/reactos/subsystems/ntvdm/dos/dem.c index f78dab86a3a..f0b251d2e03 100644 --- a/reactos/subsystems/ntvdm/dos/dem.c +++ b/reactos/subsystems/ntvdm/dos/dem.c @@ -21,7 +21,6 @@ #include "bop.h" #include "bios/bios.h" -#include "hardware/vga.h" /* Extra PSDK/NDK Headers */ #include @@ -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); diff --git a/reactos/subsystems/ntvdm/dos/dos32krnl/bios.c b/reactos/subsystems/ntvdm/dos/dos32krnl/bios.c index b7ce9d313e5..32057e51f4b 100644 --- a/reactos/subsystems/ntvdm/dos/dos32krnl/bios.c +++ b/reactos/subsystems/ntvdm/dos/dos32krnl/bios.c @@ -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) diff --git a/reactos/subsystems/ntvdm/dos/dos32krnl/dos.c b/reactos/subsystems/ntvdm/dos/dos32krnl/dos.c index f1f9fffd70b..6ce7e3faf76 100644 --- a/reactos/subsystems/ntvdm/dos/dos32krnl/dos.c +++ b/reactos/subsystems/ntvdm/dos/dos32krnl/dos.c @@ -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 */ @@ -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 diff --git a/reactos/subsystems/ntvdm/dos/dos32krnl/dos.h b/reactos/subsystems/ntvdm/dos/dos32krnl/dos.h index 18e0b14cd07..f3e9140fec3 100644 --- a/reactos/subsystems/ntvdm/dos/dos32krnl/dos.h +++ b/reactos/subsystems/ntvdm/dos/dos32krnl/dos.h @@ -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); diff --git a/reactos/subsystems/ntvdm/dos/dos32krnl/dosfiles.c b/reactos/subsystems/ntvdm/dos/dos32krnl/dosfiles.c new file mode 100644 index 00000000000..03a5df83847 --- /dev/null +++ b/reactos/subsystems/ntvdm/dos/dos32krnl/dosfiles.c @@ -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 + */ + +/* 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); +} diff --git a/reactos/subsystems/ntvdm/emulator.c b/reactos/subsystems/ntvdm/emulator.c index cbe3e1eb01c..094d156df7d 100644 --- a/reactos/subsystems/ntvdm/emulator.c +++ b/reactos/subsystems/ntvdm/emulator.c @@ -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(); diff --git a/reactos/subsystems/ntvdm/emulator.h b/reactos/subsystems/ntvdm/emulator.h index 20e9a07a98c..1b1337f3726 100644 --- a/reactos/subsystems/ntvdm/emulator.h +++ b/reactos/subsystems/ntvdm/emulator.h @@ -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 */ diff --git a/reactos/subsystems/ntvdm/hardware/vga.c b/reactos/subsystems/ntvdm/hardware/vga.c index 7c4665dc401..590ff058407 100644 --- a/reactos/subsystems/ntvdm/hardware/vga.c +++ b/reactos/subsystems/ntvdm/hardware/vga.c @@ -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 */ diff --git a/reactos/subsystems/ntvdm/int32.c b/reactos/subsystems/ntvdm/int32.c index b89eb137e03..2e9631df2e1 100644 --- a/reactos/subsystems/ntvdm/int32.c +++ b/reactos/subsystems/ntvdm/int32.c @@ -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 diff --git a/reactos/subsystems/ntvdm/ntvdm.c b/reactos/subsystems/ntvdm/ntvdm.c index 813a8858f0a..1239defc765 100644 --- a/reactos/subsystems/ntvdm/ntvdm.c +++ b/reactos/subsystems/ntvdm/ntvdm.c @@ -21,12 +21,6 @@ #include "resource.h" -/* - * Activate this line if you want to run NTVDM in standalone mode with: - * ntvdm.exe - */ -// #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: diff --git a/reactos/subsystems/ntvdm/ntvdm.h b/reactos/subsystems/ntvdm/ntvdm.h index 3555ce41d6b..d6a2569729e 100644 --- a/reactos/subsystems/ntvdm/ntvdm.h +++ b/reactos/subsystems/ntvdm/ntvdm.h @@ -28,13 +28,22 @@ #include +DWORD WINAPI SetLastConsoleEventActive(VOID); + #include -DWORD WINAPI SetLastConsoleEventActive(VOID); +/* + * Activate this line if you want to run NTVDM in standalone mode with: + * ntvdm.exe + */ +#define STANDALONE /* FUNCTIONS ******************************************************************/ +#ifndef STANDALONE extern ULONG SessionId; +#endif + extern HANDLE VdmTaskEvent; VOID DisplayMessage(LPCWSTR Format, ...); -- 2.17.1