static WORD CurrentPsp = SYSTEM_PSP;
static WORD DosLastError = 0;
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 BYTE DosAllocStrategy = DOS_ALLOC_BEST_FIT;
/* PRIVATE FUNCTIONS **********************************************************/
+/* Taken from base/shell/cmd/console.c */
+static BOOL IsConsoleHandle(HANDLE hHandle)
+{
+ DWORD dwMode;
+
+ /* Check whether the handle may be that of a console... */
+ if ((GetFileType(hHandle) & FILE_TYPE_CHAR) == 0) return FALSE;
+
+ /*
+ * It may be. Perform another test... The idea comes from the
+ * MSDN description of the WriteConsole API:
+ *
+ * "WriteConsole fails if it is used with a standard handle
+ * that is redirected to a file. If an application processes
+ * multilingual output that can be redirected, determine whether
+ * the output handle is a console handle (one method is to call
+ * the GetConsoleMode function and check whether it succeeds).
+ * If the handle is a console handle, call WriteConsole. If the
+ * handle is not a console handle, the output is redirected and
+ * you should call WriteFile to perform the I/O."
+ */
+ return GetConsoleMode(hHandle, &dwMode);
+}
+
static VOID DosCombineFreeBlocks(WORD StartBlock)
{
PDOS_MCB CurrentMcb = SEGMENT_TO_MCB(StartBlock), NextMcb;
}
}
-static WORD DosCopyEnvironmentBlock(WORD SourceSegment)
+static WORD DosCopyEnvironmentBlock(WORD SourceSegment, LPCSTR ProgramName)
{
PCHAR Ptr, SourceBuffer, DestBuffer = NULL;
ULONG TotalSize = 0;
}
TotalSize++;
+ /* Add the string buffer size */
+ TotalSize += strlen(ProgramName) + 1;
+
/* Allocate the memory for the environment block */
- DestSegment = DosAllocateMemory((TotalSize + 0x0F) >> 4, NULL);
+ DestSegment = DosAllocateMemory((WORD)((TotalSize + 0x0F) >> 4), NULL);
if (!DestSegment) return 0;
Ptr = SourceBuffer;
strcpy(DestBuffer, Ptr);
/* Advance to the next string */
- Ptr += strlen(Ptr) + 1;
DestBuffer += strlen(Ptr);
+ Ptr += strlen(Ptr) + 1;
/* Put a zero after the string */
*(DestBuffer++) = 0;
}
/* Set the final zero */
- *DestBuffer = 0;
+ *(DestBuffer++) = 0;
+
+ /* Copy the program name after the environment block */
+ strcpy(DestBuffer, ProgramName);
return DestSegment;
}
for (i = 0; i <= 2; i++)
{
/* Set the index in the SFT */
- DestinationTable[i] = i;
+ DestinationTable[i] = (BYTE)i;
/* Increase the reference count */
DosSftRefCount[i]++;
PDOS_MCB CurrentMcb, NextMcb;
BOOLEAN SearchUmb = FALSE;
+ DPRINT("DosAllocateMemory: Size 0x%04X\n", Size);
+
if (DosUmbLinked && (DosAllocStrategy & (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW)))
{
/* Search UMB first */
/* Make sure it's valid */
if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType != 'Z')
{
+ DPRINT("The DOS memory arena is corrupted!\n");
DosLastError = ERROR_ARENA_TRASHED;
return 0;
}
if (FileHandle == INVALID_HANDLE_VALUE)
{
/* Return the error code */
- return GetLastError();
+ return (WORD)GetLastError();
}
/* Open the DOS handle */
if (FileHandle == INVALID_HANDLE_VALUE)
{
/* Return the error code */
- return GetLastError();
+ return (WORD)GetLastError();
}
/* Open the DOS handle */
WORD Result = ERROR_SUCCESS;
DWORD BytesRead32 = 0;
HANDLE Handle = DosGetRealHandle(FileHandle);
+ WORD i;
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))
+ if (IsConsoleHandle(Handle))
+ {
+ for (i = 0; i < Count; i++)
+ {
+ /* Call the BIOS function to read the character */
+ ((LPBYTE)Buffer)[i] = LOBYTE(BiosGetCharacter());
+ BytesRead32++;
+ }
+ }
+ else
{
- /* Store the error code */
- Result = GetLastError();
+ /* 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 */
WORD Result = ERROR_SUCCESS;
DWORD BytesWritten32 = 0;
HANDLE Handle = DosGetRealHandle(FileHandle);
+ WORD i;
DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n",
FileHandle,
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
- /* Write the file */
- if (!WriteFile(Handle, Buffer, Count, &BytesWritten32, NULL))
+ if (IsConsoleHandle(Handle))
+ {
+ for (i = 0; i < Count; i++)
+ {
+ /* Call the BIOS to print the character */
+ BiosPrintCharacter(((LPBYTE)Buffer)[i], DOS_CHAR_ATTRIBUTE, Bda->VideoPage);
+ BytesWritten32++;
+ }
+ }
+ else
{
- /* Store the error code */
- Result = GetLastError();
+ /* 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 */
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 */
+ 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;
+}
+
+BOOLEAN DosDuplicateHandle(WORD OldHandle, WORD NewHandle)
+{
+ BYTE SftIndex;
+ PDOS_PSP PspBlock;
+ LPBYTE HandleTable;
+
+ DPRINT("DosDuplicateHandle: OldHandle 0x%04X, NewHandle 0x%04X\n",
+ OldHandle,
+ NewHandle);
+
+ /* The system PSP has no handle table */
+ if (CurrentPsp == SYSTEM_PSP) return FALSE;
+
+ /* Get a pointer to the handle table */
+ PspBlock = SEGMENT_TO_PSP(CurrentPsp);
+ HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
+
+ /* Make sure the old handle is open */
+ if (HandleTable[OldHandle] == 0xFF) return FALSE;
+
+ /* Check if the new handle is open */
+ if (HandleTable[NewHandle] != 0xFF)
+ {
+ /* Close it */
+ DosCloseHandle(NewHandle);
+ }
+
+ /* Increment the reference count of the SFT entry */
+ SftIndex = HandleTable[OldHandle];
+ DosSftRefCount[SftIndex]++;
+
+ /* Make the new handle point to that SFT entry */
+ HandleTable[NewHandle] = SftIndex;
+
+ /* Return success */
+ return TRUE;
+}
+
BOOLEAN DosCloseHandle(WORD DosHandle)
{
BYTE SftIndex;
DosSystemFileTable[SftIndex] = INVALID_HANDLE_VALUE;
}
+ /* Clear the entry in the JFT */
+ HandleTable[DosHandle] = 0xFF;
+
+ return TRUE;
+}
+
+BOOLEAN DosChangeDrive(BYTE Drive)
+{
+ WCHAR DirectoryPath[DOS_CMDLINE_LENGTH];
+
+ /* Make sure the drive exists */
+ if (Drive > (LastDrive - 'A')) return FALSE;
+
+ /* Find the path to the new current directory */
+ swprintf(DirectoryPath, L"%c\\%S", Drive + 'A', CurrentDirectories[Drive]);
+
+ /* Change the current directory of the process */
+ if (!SetCurrentDirectory(DirectoryPath)) return FALSE;
+
+ /* Set the current drive */
+ CurrentDrive = Drive;
+
+ /* Return success */
+ return TRUE;
+}
+
+BOOLEAN DosChangeDirectory(LPSTR Directory)
+{
+ BYTE DriveNumber;
+ DWORD Attributes;
+ LPSTR Path;
+
+ /* Make sure the directory path is not too long */
+ if (strlen(Directory) >= DOS_DIR_LENGTH)
+ {
+ DosLastError = ERROR_PATH_NOT_FOUND;
+ return FALSE;
+ }
+
+ /* Get the drive number */
+ DriveNumber = Directory[0] - 'A';
+
+ /* Make sure the drive exists */
+ if (DriveNumber > (LastDrive - 'A'))
+ {
+ DosLastError = ERROR_PATH_NOT_FOUND;
+ return FALSE;
+ }
+
+ /* Get the file attributes */
+ Attributes = GetFileAttributesA(Directory);
+
+ /* Make sure the path exists and is a directory */
+ if ((Attributes == INVALID_FILE_ATTRIBUTES)
+ || !(Attributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ DosLastError = ERROR_PATH_NOT_FOUND;
+ return FALSE;
+ }
+
+ /* Check if this is the current drive */
+ if (DriveNumber == CurrentDrive)
+ {
+ /* Change the directory */
+ if (!SetCurrentDirectoryA(Directory))
+ {
+ DosLastError = LOWORD(GetLastError());
+ return FALSE;
+ }
+ }
+
+ /* Get the directory part of the path */
+ Path = strchr(Directory, '\\');
+ if (Path != NULL)
+ {
+ /* Skip the backslash */
+ Path++;
+ }
+
+ /* Set the directory for the drive */
+ if (Path != NULL) strcpy(CurrentDirectories[DriveNumber], Path);
+ else strcpy(CurrentDirectories[DriveNumber], "");
+
+ /* Return success */
return TRUE;
}
PspBlock->FarCall[2] = 0xCB; // retf
/* Set the command line */
- PspBlock->CommandLineSize = strlen(CommandLine);
+ PspBlock->CommandLineSize = (BYTE)min(strlen(CommandLine), DOS_CMDLINE_LENGTH - 1);
RtlCopyMemory(PspBlock->CommandLine, CommandLine, PspBlock->CommandLineSize);
PspBlock->CommandLine[PspBlock->CommandLineSize] = '\r';
}
BOOLEAN Success = FALSE, AllocatedEnvBlock = FALSE;
HANDLE FileHandle = INVALID_HANDLE_VALUE, FileMapping = NULL;
LPBYTE Address = NULL;
- LPSTR ProgramFilePath, Parameters[128];
- CHAR CommandLineCopy[128];
+ LPSTR ProgramFilePath, Parameters[256];
+ CHAR CommandLineCopy[DOS_CMDLINE_LENGTH];
INT ParamCount = 0;
- DWORD Segment = 0;
+ WORD Segment = 0;
WORD MaxAllocSize;
DWORD i, FileSize, ExeSize;
PIMAGE_DOS_HEADER Header;
/* Save a copy of the command line */
strcpy(CommandLineCopy, CommandLine);
+ // FIXME: Improve parsing (especially: "some_path\with spaces\program.exe" options)
+
/* Get the file name of the executable */
ProgramFilePath = strtok(CommandLineCopy, " \t");
/* Load the parameters in the local array */
- while ((ParamCount < 256)
+ while ((ParamCount < sizeof(Parameters)/sizeof(Parameters[0]))
&& ((Parameters[ParamCount] = strtok(NULL, " \t")) != NULL))
{
ParamCount++;
/* No, copy the one from the parent */
EnvBlock = DosCopyEnvironmentBlock((CurrentPsp != SYSTEM_PSP)
? SEGMENT_TO_PSP(CurrentPsp)->EnvBlock
- : SYSTEM_ENV_BLOCK);
+ : SYSTEM_ENV_BLOCK,
+ ProgramFilePath);
}
/* Check if this is an EXE file or a COM file */
for (i = Header->e_maxalloc; i >= Header->e_minalloc; i--, ExeSize--)
{
/* Try to allocate that much memory */
- Segment = DosAllocateMemory(ExeSize, NULL);
+ Segment = DosAllocateMemory((WORD)ExeSize, NULL);
if (Segment != 0) break;
}
/* Initialize the PSP */
DosInitializePsp(Segment,
CommandLine,
- ExeSize,
+ (WORD)ExeSize,
EnvBlock);
/* The process owns its own memory */
DosAllocateMemory(0xFFFF, &MaxAllocSize);
/* Make sure it's enough for the whole program and the PSP */
- if ((MaxAllocSize << 4) < (FileSize + sizeof(DOS_PSP))) goto Cleanup;
+ if (((DWORD)MaxAllocSize << 4) < (FileSize + sizeof(DOS_PSP))) goto Cleanup;
/* Allocate all of it */
Segment = DosAllocateMemory(MaxAllocSize, NULL);
/* Initialize the PSP */
DosInitializePsp(Segment,
CommandLine,
- (FileSize + sizeof(DOS_PSP)) >> 4,
+ (WORD)((FileSize + sizeof(DOS_PSP)) >> 4),
EnvBlock);
/* Set the initial segment registers */
if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType !='Z') break;
/* If this block was allocated by the process, free it */
- if (CurrentMcb->OwnerPsp == Psp) DosFreeMemory(McbSegment);
+ if (CurrentMcb->OwnerPsp == Psp) DosFreeMemory(McbSegment + 1);
/* If this was the last block, quit */
if (CurrentMcb->BlockType == 'Z') break;
DosWriteFile(DOS_OUTPUT_HANDLE, &Character, sizeof(CHAR), &BytesWritten);
}
-VOID DosHandleIoctl(BYTE ControlCode, WORD FileHandle)
+BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle)
{
HANDLE Handle = DosGetRealHandle(FileHandle);
if (Handle == INVALID_HANDLE_VALUE)
{
/* Doesn't exist */
- EmulatorSetFlag(EMULATOR_FLAG_CF);
- EmulatorSetRegister(EMULATOR_REG_AX, ERROR_FILE_NOT_FOUND);
+ DosLastError = ERROR_FILE_NOT_FOUND;
+ return FALSE;
}
switch (ControlCode)
InfoWord |= 1 << 7;
/* Return the device information word */
- EmulatorClearFlag(EMULATOR_FLAG_CF);
EmulatorSetRegister(EMULATOR_REG_DX, InfoWord);
- break;
+ return TRUE;
}
/* Unsupported control code */
{
DPRINT1("Unsupported IOCTL: 0x%02X\n", ControlCode);
- EmulatorSetFlag(EMULATOR_FLAG_CF);
- EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_PARAMETER);
+ DosLastError = ERROR_INVALID_PARAMETER;
+ return FALSE;
}
}
}
-VOID DosInt20h(WORD CodeSegment)
+VOID DosInt20h(LPWORD Stack)
{
/* This is the exit interrupt */
- DosTerminateProcess(CodeSegment, 0);
+ DosTerminateProcess(Stack[STACK_CS], 0);
}
-VOID DosInt21h(WORD CodeSegment)
+VOID DosInt21h(LPWORD Stack)
{
INT i;
CHAR Character;
DWORD Ecx = EmulatorGetRegister(EMULATOR_REG_CX);
DWORD Edx = EmulatorGetRegister(EMULATOR_REG_DX);
DWORD Ebx = EmulatorGetRegister(EMULATOR_REG_BX);
- WORD DataSegment = EmulatorGetRegister(EMULATOR_REG_DS);
- WORD ExtSegment = EmulatorGetRegister(EMULATOR_REG_ES);
+ WORD DataSegment = (WORD)EmulatorGetRegister(EMULATOR_REG_DS);
+ WORD ExtSegment = (WORD)EmulatorGetRegister(EMULATOR_REG_ES);
/* Check the value in the AH register */
switch (HIBYTE(Eax))
/* Terminate Program */
case 0x00:
{
- DosTerminateProcess(CodeSegment, 0);
+ DosTerminateProcess(Stack[STACK_CS], 0);
break;
}
break;
}
+ /* Set Default Drive */
+ case 0x0E:
+ {
+ DosChangeDrive(LOBYTE(Edx));
+ EmulatorSetRegister(EMULATOR_REG_AX,
+ (Eax & 0xFFFFFF00) | (LastDrive - 'A' + 1));
+
+ break;
+ }
+
+ /* Get Default Drive */
+ case 0x19:
+ {
+ EmulatorSetRegister(EMULATOR_REG_AX,
+ (Eax & 0xFFFFFF00) | CurrentDrive);
+
+ break;
+ }
+
/* Set Disk Transfer Area */
case 0x1A:
{
if (CreateDirectoryA(String, NULL))
{
- EmulatorClearFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
- EmulatorSetFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
EmulatorSetRegister(EMULATOR_REG_AX,
(Eax & 0xFFFF0000) | LOWORD(GetLastError()));
}
if (RemoveDirectoryA(String))
{
- EmulatorClearFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
- EmulatorSetFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
EmulatorSetRegister(EMULATOR_REG_AX,
(Eax & 0xFFFF0000) | LOWORD(GetLastError()));
}
String = (PCHAR)((ULONG_PTR)BaseAddress
+ TO_LINEAR(DataSegment, LOWORD(Edx)));
- if (SetCurrentDirectoryA(String))
+ if (DosChangeDirectory(String))
{
- EmulatorClearFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
- EmulatorSetFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
EmulatorSetRegister(EMULATOR_REG_AX,
- (Eax & 0xFFFF0000) | LOWORD(GetLastError()));
+ (Eax & 0xFFFF0000) | DosLastError);
}
break;
if (ErrorCode == 0)
{
/* Clear CF */
- EmulatorClearFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
/* Return the handle in AX */
EmulatorSetRegister(EMULATOR_REG_AX,
else
{
/* Set CF */
- EmulatorSetFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
/* Return the error code in AX */
EmulatorSetRegister(EMULATOR_REG_AX,
case 0x3D:
{
WORD FileHandle;
- WORD ErrorCode = DosCreateFile(&FileHandle,
- (LPCSTR)(ULONG_PTR)BaseAddress
- + TO_LINEAR(DataSegment, LOWORD(Edx)),
- LOBYTE(Eax));
+ WORD ErrorCode = DosOpenFile(&FileHandle,
+ (LPCSTR)(ULONG_PTR)BaseAddress
+ + TO_LINEAR(DataSegment, LOWORD(Edx)),
+ LOBYTE(Eax));
if (ErrorCode == 0)
{
/* Clear CF */
- EmulatorClearFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
/* Return the handle in AX */
EmulatorSetRegister(EMULATOR_REG_AX,
else
{
/* Set CF */
- EmulatorSetFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
/* Return the error code in AX */
EmulatorSetRegister(EMULATOR_REG_AX,
if (DosCloseHandle(LOWORD(Ebx)))
{
/* Clear CF */
- EmulatorClearFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
/* Set CF */
- EmulatorSetFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
/* Return the error code in AX */
EmulatorSetRegister(EMULATOR_REG_AX,
if (ErrorCode == 0)
{
/* Clear CF */
- EmulatorClearFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
/* Return the number of bytes read in AX */
EmulatorSetRegister(EMULATOR_REG_AX,
else
{
/* Set CF */
- EmulatorSetFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
/* Return the error code in AX */
EmulatorSetRegister(EMULATOR_REG_AX,
if (ErrorCode == 0)
{
/* Clear CF */
- EmulatorClearFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
/* Return the number of bytes written in AX */
EmulatorSetRegister(EMULATOR_REG_AX,
else
{
/* Set CF */
- EmulatorSetFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
/* Return the error code in AX */
EmulatorSetRegister(EMULATOR_REG_AX,
break;
}
+ /* Delete File */
+ case 0x41:
+ {
+ LPSTR FileName = (LPSTR)((ULONG_PTR)BaseAddress + TO_LINEAR(DataSegment, Edx));
+
+ /* Call the API function */
+ if (DeleteFileA(FileName)) Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ else
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ EmulatorSetRegister(EMULATOR_REG_AX, GetLastError());
+ }
+
+ break;
+ }
+
+ /* Seek File */
+ case 0x42:
+ {
+ DWORD NewLocation;
+ WORD ErrorCode = DosSeekFile(LOWORD(Ebx),
+ MAKELONG(LOWORD(Edx), LOWORD(Ecx)),
+ LOBYTE(Eax),
+ &NewLocation);
+
+ if (ErrorCode == 0)
+ {
+ /* Clear CF */
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+
+ /* Return the new offset in DX:AX */
+ EmulatorSetRegister(EMULATOR_REG_DX,
+ (Edx & 0xFFFF0000) | HIWORD(NewLocation));
+ EmulatorSetRegister(EMULATOR_REG_AX,
+ (Eax & 0xFFFF0000) | LOWORD(NewLocation));
+ }
+ else
+ {
+ /* Set CF */
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+
+ /* Return the error code in AX */
+ EmulatorSetRegister(EMULATOR_REG_AX,
+ (Eax & 0xFFFF0000) | ErrorCode);
+ }
+
+ break;
+ }
+
+ /* Get/Set File Attributes */
+ case 0x43:
+ {
+ DWORD Attributes;
+ LPSTR FileName = (LPSTR)((ULONG_PTR)BaseAddress + TO_LINEAR(DataSegment, Edx));
+
+ if (LOBYTE(Eax) == 0x00)
+ {
+ /* Get the attributes */
+ Attributes = GetFileAttributesA(FileName);
+
+ /* Check if it failed */
+ if (Attributes == INVALID_FILE_ATTRIBUTES)
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ EmulatorSetRegister(EMULATOR_REG_AX, GetLastError());
+
+ break;
+ }
+
+ /* Return the attributes that DOS can understand */
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ EmulatorSetRegister(EMULATOR_REG_CX,
+ (Ecx & 0xFFFFFF00) | LOBYTE(Attributes));
+ }
+ else if (LOBYTE(Eax) == 0x01)
+ {
+ /* Try to set the attributes */
+ if (SetFileAttributesA(FileName, LOBYTE(Ecx)))
+ {
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ }
+ else
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ EmulatorSetRegister(EMULATOR_REG_AX, GetLastError());
+ }
+ }
+ else
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_FUNCTION);
+ }
+
+ break;
+ }
+
/* IOCTL */
case 0x44:
{
- DosHandleIoctl(LOBYTE(Eax), LOWORD(Ebx));
+ if (DosHandleIoctl(LOBYTE(Eax), LOWORD(Ebx)))
+ {
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ }
+ else
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ EmulatorSetRegister(EMULATOR_REG_AX, DosLastError);
+ }
+
+ break;
+ }
+
+ /* Duplicate Handle */
+ case 0x45:
+ {
+ WORD NewHandle;
+ HANDLE Handle = DosGetRealHandle(LOWORD(Ebx));
+
+ if (Handle != INVALID_HANDLE_VALUE)
+ {
+ /* The handle is invalid */
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_HANDLE);
+
+ break;
+ }
+
+ /* Open a new handle to the same entry */
+ NewHandle = DosOpenHandle(Handle);
+
+ if (NewHandle == INVALID_DOS_HANDLE)
+ {
+ /* Too many files open */
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ EmulatorSetRegister(EMULATOR_REG_AX, ERROR_TOO_MANY_OPEN_FILES);
+
+ break;
+ }
+
+ /* Return the result */
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ EmulatorSetRegister(EMULATOR_REG_AX, NewHandle);
+
+ break;
+ }
+
+ /* Force Duplicate Handle */
+ case 0x46:
+ {
+ if (DosDuplicateHandle(LOWORD(Ebx), LOWORD(Ecx)))
+ {
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ }
+ else
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_HANDLE);
+ }
break;
}
if (Segment != 0)
{
EmulatorSetRegister(EMULATOR_REG_AX, Segment);
- EmulatorClearFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
EmulatorSetRegister(EMULATOR_REG_AX, DosLastError);
EmulatorSetRegister(EMULATOR_REG_BX, MaxAvailable);
- EmulatorSetFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
}
break;
{
if (DosFreeMemory(ExtSegment))
{
- EmulatorClearFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
EmulatorSetRegister(EMULATOR_REG_AX, ERROR_ARENA_TRASHED);
- EmulatorSetFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
}
break;
if (DosResizeMemory(ExtSegment, LOWORD(Ebx), &Size))
{
- EmulatorClearFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
EmulatorSetRegister(EMULATOR_REG_AX, DosLastError);
- EmulatorSetFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
EmulatorSetRegister(EMULATOR_REG_BX, Size);
}
break;
}
+ /* Get Current Process */
+ case 0x51:
+ {
+ EmulatorSetRegister(EMULATOR_REG_BX, CurrentPsp);
+
+ break;
+ }
+
/* Get/Set Memory Management Options */
case 0x58:
{
/* Get allocation strategy */
EmulatorSetRegister(EMULATOR_REG_AX, DosAllocStrategy);
- EmulatorClearFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else if (LOBYTE(Eax) == 0x01)
{
{
/* Can't set both */
EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_PARAMETER);
- EmulatorSetFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
break;
}
{
/* Invalid allocation strategy */
EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_PARAMETER);
- EmulatorSetFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
break;
}
DosAllocStrategy = LOBYTE(Ebx);
- EmulatorClearFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else if (LOBYTE(Eax) == 0x02)
{
Eax &= 0xFFFFFF00;
if (DosUmbLinked) Eax |= 1;
EmulatorSetRegister(EMULATOR_REG_AX, Eax);
- EmulatorClearFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else if (LOBYTE(Eax) == 0x03)
{
if (Ebx) DosLinkUmb();
else DosUnlinkUmb();
- EmulatorClearFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
/* Invalid or unsupported function */
- EmulatorSetFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_FUNCTION);
}
default:
{
DPRINT1("DOS Function INT 0x21, AH = 0x%02X NOT IMPLEMENTED!\n", HIBYTE(Eax));
- EmulatorSetFlag(EMULATOR_FLAG_CF);
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
}
}
}
-VOID DosBreakInterrupt(VOID)
+VOID DosBreakInterrupt(LPWORD Stack)
{
+ UNREFERENCED_PARAMETER(Stack);
+
VdmRunning = FALSE;
}
LPSTR AsciiString;
LPSTR DestPtr = (LPSTR)((ULONG_PTR)BaseAddress + TO_LINEAR(SYSTEM_ENV_BLOCK, 0));
DWORD AsciiSize;
+ CHAR CurrentDirectory[MAX_PATH];
+ CHAR DosDirectory[DOS_DIR_LENGTH];
+ LPSTR Path;
/* Initialize the MCB */
Mcb->BlockType = 'Z';
/* Copy the string into DOS memory */
strcpy(DestPtr, AsciiString);
- /* Free the memory */
- HeapFree(GetProcessHeap(), 0, AsciiString);
-
/* Move to the next string */
SourcePtr += wcslen(SourcePtr) + 1;
DestPtr += strlen(AsciiString);
*(DestPtr++) = 0;
+
+ /* Free the memory */
+ HeapFree(GetProcessHeap(), 0, AsciiString);
}
*DestPtr = 0;
/* Free the memory allocated for environment strings */
FreeEnvironmentStringsW(Environment);
+ /* Clear the current directory buffer */
+ ZeroMemory(CurrentDirectories, sizeof(CurrentDirectories));
+
+ /* Get the current directory */
+ if (!GetCurrentDirectoryA(MAX_PATH, CurrentDirectory))
+ {
+ // TODO: Use some kind of default path?
+ return FALSE;
+ }
+
+ /* Convert that to a DOS path */
+ if (!GetShortPathNameA(CurrentDirectory, DosDirectory, DOS_DIR_LENGTH))
+ {
+ // TODO: Use some kind of default path?
+ return FALSE;
+ }
+
+ /* Set the drive */
+ CurrentDrive = DosDirectory[0] - 'A';
+
+ /* Get the path */
+ Path = strchr(DosDirectory, '\\');
+ if (Path != NULL)
+ {
+ /* Skip the backslash */
+ Path++;
+ }
+
+ /* Set the directory */
+ if (Path != NULL) strcpy(CurrentDirectories[CurrentDrive], Path);
+
/* Read CONFIG.SYS */
Stream = _wfopen(DOS_CONFIG_PATH, L"r");
if (Stream != NULL)