[NTVDM]: Commit some local changes that can be committed now:
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Mon, 13 Jul 2015 01:21:46 +0000 (01:21 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Mon, 13 Jul 2015 01:21:46 +0000 (01:21 +0000)
- Whitespace fixes.
- Improve some DPRINTs.
- hardcoded_values--;
- Fix DisplayMessage() for NULL-terminated strings.
- Free the allocated block of memory in the mouse driver cleanup procedure.
- Properly inherit the parent process environment block if needed.
- Return the correct last error if DosCopyEnvironmentBlock fails.
- Big ifs turned into switch.
- Implement some INT 2Fh DOS multiplex functions (AX=1200h "Installation check", AX=1203h "Get DOS data segment", AX=1214h "Compare FAR pointers", AX=122Fh "Set DOS version to return"); remove the DPRINT for AX=1680h "Release Current Virtual Machine Time-slice".
- Stubplement INT 2Ah "DOS critical sections / network" (it just monitors calls to itself at the moment).
- Use the boot drive root path as the current directory if we failed retrieving a valid one.
- Offsetize the DOS_SYSVARS members (so that I don't have to compute by head the offsets, especially when some of the members is a structure from which I don't know in advance its size); add some C_ASSERTs on the size of DOS standard structures.
- Move the NullDriverRoutine buffer outside the sysvars buffer (because it has nothing to do inside it).
- In ConDrvReadInput: do not echo the first part of an extended character.
- Add basic support for changing the reported DosVersion.

svn path=/trunk/; revision=68395

13 files changed:
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/country.c
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.h
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.c
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.h
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c
reactos/subsystems/mvdm/ntvdm/dos/mouse32.c
reactos/subsystems/mvdm/ntvdm/hardware/cmos.c
reactos/subsystems/mvdm/ntvdm/ntvdm.c
reactos/subsystems/mvdm/ntvdm/ntvdm.h

index f384cd1..689b7cf 100644 (file)
@@ -32,9 +32,6 @@
 
 /* PRIVATE VARIABLES **********************************************************/
 
-// static BYTE CurrentDrive;
-// static CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH];
-
 /* PRIVATE FUNCTIONS **********************************************************/
 
 /* PUBLIC FUNCTIONS ***********************************************************/
@@ -105,7 +102,13 @@ BOOLEAN DosBuildSysEnvBlock(VOID)
     LPSTR SourcePtr, Environment;
     LPSTR DestPtr = (LPSTR)SEG_OFF_TO_PTR(SYSTEM_ENV_BLOCK, 0);
 
-    /* Get the environment strings */
+    /*
+     * Get the environment strings
+     *
+     * NOTE: On non-STANDALONE builds, this corresponds to the VDM environment
+     * as created by BaseVDM for NTVDM. On STANDALONE builds this is the Win32
+     * environment. In this last case we need to convert it to a proper VDM env.
+     */
     SourcePtr = Environment = GetEnvironmentStrings();
     if (Environment == NULL) return FALSE;
 
@@ -231,10 +234,6 @@ BOOLEAN DosBIOSInitialize(VOID)
 
 #endif
 
-
-    /* Register the DOS 32-bit Interrupts */
-    // RegisterDosInt32(0x20, DosInt20h);
-
     /* Initialize the DOS kernel */
     return DosKRNLInitialize();
 }
index fe9908b..7901779 100644 (file)
@@ -61,9 +61,11 @@ WORD NTAPI ConDrvReadInput(PDOS_DEVICE_NODE Device, DWORD Buffer, PWORD Length)
         /* Check if this is a special character */
         if (Character == 0) ExtendedCode = getAH();
 
-        if (DoEcho) DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
         Pointer[BytesRead++] = Character;
 
+        if (Character != 0 && DoEcho)
+            DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
+
         /* Stop on first carriage return */
         if (Character == '\r')
         {
index 921bac0..b47bab9 100644 (file)
@@ -98,30 +98,30 @@ DosGetCountryInfo(IN OUT PWORD CountryId,
                             (LPSTR)&CountryInfo->DecimalSep,
                             sizeof(CountryInfo->DecimalSep));
     if (Return == 0) return LOWORD(GetLastError());
-    
+
     Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDATE,
                             (LPSTR)&CountryInfo->DateSep,
                             sizeof(CountryInfo->DateSep));
     if (Return == 0) return LOWORD(GetLastError());
-    
+
     Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STIME,
                             (LPSTR)&CountryInfo->TimeSep,
                             sizeof(CountryInfo->TimeSep));
     if (Return == 0) return LOWORD(GetLastError());
-    
+
     // NOTE: '4: Symbol replace decimal separator' is unsupported.
     Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY | LOCALE_RETURN_NUMBER,
                             (LPSTR)&NumVal,
                             sizeof(NumVal));
     if (Return == 0) return LOWORD(GetLastError());
     CountryInfo->CurrencyFormat = (BYTE)NumVal;
-    
+
     Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS | LOCALE_RETURN_NUMBER, // LOCALE_IDIGITS | LOCALE_RETURN_NUMBER
                             (LPSTR)&NumVal,
                             sizeof(NumVal));
     if (Return == 0) return LOWORD(GetLastError());
     CountryInfo->CurrencyDigitsNum = (BYTE)NumVal;
-    
+
     Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ITIME | LOCALE_RETURN_NUMBER,
                             (LPSTR)&NumVal,
                             sizeof(NumVal));
@@ -129,7 +129,7 @@ DosGetCountryInfo(IN OUT PWORD CountryId,
     CountryInfo->TimeFormat = (BYTE)NumVal;
 
     CountryInfo->CaseMapPtr = MAKELONG(FIELD_OFFSET(COUNTRY_DATA, CaseMapRoutine), CountryDataSegment);
-    
+
     // CountryInfo->DataListSep;
 
     return ERROR_SUCCESS;
@@ -240,7 +240,7 @@ BOOLEAN DosCountryInitialize(VOID)
     CountryDataSegment = DosAllocateMemory(sizeof(COUNTRY_DATA), NULL);
     if (CountryDataSegment == 0) return FALSE;
     CountryData = (PCOUNTRY_DATA)SEG_OFF_TO_PTR(CountryDataSegment, 0x0000);
-    
+
     RtlMoveMemory(CountryData->CaseMapRoutine,
                   CaseMapRoutine,
                   sizeof(CaseMapRoutine));
index 9f163b9..c125b1a 100644 (file)
@@ -123,6 +123,7 @@ typedef struct _DOS_DRIVER
         };
     };
 } DOS_DRIVER, *PDOS_DRIVER;
+C_ASSERT(sizeof(DOS_DRIVER) == 0x12);
 
 typedef struct _DOS_REQUEST_HEADER
 {
index 99354e4..efa1ea6 100644 (file)
@@ -91,7 +91,7 @@ static BOOLEAN DosChangeDirectory(LPSTR Directory)
         return FALSE;
     }
 
-    /* Check whether the directory string is of format "?:..." */
+    /* Check whether the directory string is of format "X:..." */
     if (strlen(Directory) >= 2 && Directory[1] == ':')
     {
         /* Get the drive number */
@@ -114,8 +114,8 @@ static BOOLEAN DosChangeDirectory(LPSTR Directory)
     Attributes = GetFileAttributesA(Directory);
 
     /* Make sure the path exists and is a directory */
-    if ((Attributes == INVALID_FILE_ATTRIBUTES)
-        || !(Attributes & FILE_ATTRIBUTE_DIRECTORY))
+    if ((Attributes == INVALID_FILE_ATTRIBUTES) ||
+       !(Attributes & FILE_ATTRIBUTE_DIRECTORY))
     {
         Sda->LastErrorCode = ERROR_PATH_NOT_FOUND;
         return FALSE;
@@ -146,17 +146,11 @@ static BOOLEAN DosChangeDirectory(LPSTR Directory)
         return FALSE;
     }
 
-    /* Get the directory part of the path */
+    /* Get the directory part of the path and set the current directory for the drive */
     Path = strchr(DosDirectory, '\\');
     if (Path != NULL)
     {
-        /* Skip the backslash */
-        Path++;
-    }
-
-    /* Set the directory for the drive */
-    if (Path != NULL)
-    {
+        Path++; // Skip the backslash
         strncpy(DosData->CurrentDirectories[DriveNumber], Path, DOS_DIR_LENGTH);
     }
     else
@@ -829,8 +823,10 @@ VOID WINAPI DosInt21h(LPWORD Stack)
             DWORD NumberOfFreeClusters;
             DWORD TotalNumberOfClusters;
 
-            if (getDL() == 0x00) RootPath[0] = 'A' + Sda->CurrentDrive;
-            else RootPath[0] = 'A' + getDL() - 1;
+            if (getDL() == 0x00)
+                RootPath[0] = 'A' + Sda->CurrentDrive;
+            else
+                RootPath[0] = 'A' + getDL() - 1;
 
             if (GetDiskFreeSpaceA(RootPath,
                                   &SectorsPerCluster,
@@ -914,7 +910,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
         {
             WORD CountryId = getAL() < 0xFF ? getAL() : getBX();
             WORD ErrorCode;
-            
+
             ErrorCode = DosGetCountryInfo(&CountryId,
                                           (PDOS_COUNTRY_INFO)SEG_OFF_TO_PTR(getDS(), getDX()));
 
@@ -1110,7 +1106,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
                  * See Ralf Brown: http://www.ctyme.com/intr/rb-2797.htm
                  * "AX destroyed (DOS 3.3) AL seems to be drive of deleted file."
                  */
-                setAL(FileName[0] - 'A');
+                setAL(RtlUpperChar(FileName[0]) - 'A');
             }
             else
             {
@@ -1519,54 +1515,68 @@ VOID WINAPI DosInt21h(LPWORD Stack)
         /* Get/Set Memory Management Options */
         case 0x58:
         {
-            if (getAL() == 0x00)
+            switch (getAL())
             {
                 /* Get allocation strategy */
-                Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
-                setAX(Sda->AllocStrategy);
-            }
-            else if (getAL() == 0x01)
-            {
-                /* Set allocation strategy */
-
-                if ((getBL() & (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
-                    == (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
+                case 0x00:
                 {
-                    /* Can't set both */
-                    Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
-                    setAX(ERROR_INVALID_PARAMETER);
+                    Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+                    setAX(Sda->AllocStrategy);
                     break;
                 }
 
-                if ((getBL() & 0x3F) > DOS_ALLOC_LAST_FIT)
+                /* Set allocation strategy */
+                case 0x01:
                 {
-                    /* Invalid allocation strategy */
-                    Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
-                    setAX(ERROR_INVALID_PARAMETER);
+                    if ((getBL() & (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
+                        == (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
+                    {
+                        /* Can't set both */
+                        Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+                        setAX(ERROR_INVALID_PARAMETER);
+                        break;
+                    }
+
+                    if ((getBL() & ~(DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
+                        > DOS_ALLOC_LAST_FIT)
+                    {
+                        /* Invalid allocation strategy */
+                        Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+                        setAX(ERROR_INVALID_PARAMETER);
+                        break;
+                    }
+
+                    Sda->AllocStrategy = getBL();
+                    Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
                     break;
                 }
 
-                Sda->AllocStrategy = getBL();
-                Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
-            }
-            else if (getAL() == 0x02)
-            {
                 /* Get UMB link state */
-                Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
-                setAL(DosUmbLinked ? 0x01 : 0x00);
-            }
-            else if (getAL() == 0x03)
-            {
+                case 0x02:
+                {
+                    Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+                    setAL(DosUmbLinked ? 0x01 : 0x00);
+                    break;
+                }
+
                 /* Set UMB link state */
-                if (getBX()) DosLinkUmb();
-                else DosUnlinkUmb();
-                Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
-            }
-            else
-            {
+                case 0x03:
+                {
+                    if (getBX())
+                        DosLinkUmb();
+                    else
+                        DosUnlinkUmb();
+
+                    Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+                    break;
+                }
+
                 /* Invalid or unsupported function */
-                Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
-                setAX(ERROR_INVALID_FUNCTION);
+                default:
+                {
+                    Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+                    setAX(ERROR_INVALID_FUNCTION);
+                }
             }
 
             break;
@@ -2021,10 +2031,77 @@ VOID WINAPI DosFastConOut(LPWORD Stack)
     setAX(AX);
 }
 
+VOID WINAPI DosInt2Ah(LPWORD Stack)
+{
+    DPRINT1("INT 2Ah, AX=%4xh called\n", getAX());
+}
+
 VOID WINAPI DosInt2Fh(LPWORD Stack)
 {
     switch (getAH())
     {
+        /* DOS 3+ Internal Utility Functions */
+        case 0x12:
+        {
+            DPRINT1("INT 2Fh, AX=%4xh DOS Internal Utility Function called\n", getAX());
+
+            switch (getAL())
+            {
+                /* Installation Check */
+                case 0x00:
+                {
+                    setAL(0xFF);
+                    break;
+                }
+
+                /* Get DOS Data Segment */
+                case 0x03:
+                {
+                    setDS(DOS_DATA_SEGMENT);
+                    break;
+                }
+
+                /* Compare FAR Pointers */
+                case 0x14:
+                {
+                    PVOID PointerFromFarPointer1 = SEG_OFF_TO_PTR(getDS(), getSI());
+                    PVOID PointerFromFarPointer2 = SEG_OFF_TO_PTR(getES(), getDI());
+                    BOOLEAN AreEqual = (PointerFromFarPointer1 == PointerFromFarPointer2);
+
+                    setZF(AreEqual);
+                    setCF(!AreEqual);
+                    break;
+                }
+
+                /* Set DOS Version Number to return */
+                case 0x2F:
+                {
+                    WORD DosVersion = getDX();
+
+                    // Special case: return the true DOS version when DX=00h
+                    if (DosVersion == 0x0000)
+                        DosData->DosVersion = DOS_VERSION;
+                    else
+                        DosData->DosVersion = DosVersion;
+
+                    break;
+                }
+            }
+
+            break;
+        }
+
+        /* Mostly Windows 2.x/3.x/9x support */
+        case 0x16:
+        {
+            /*
+             * AL=80h is DOS/Windows/DPMI "Release Current Virtual Machine Time-slice"
+             * Just do nothing in this case.
+             */
+            if (getAL() != 0x80) goto Default;
+            break;
+        }
+
         /* Extended Memory Specification */
         case 0x43:
         {
@@ -2057,7 +2134,7 @@ VOID WINAPI DosInt2Fh(LPWORD Stack)
             break;
         }
 
-        default:
+        default: Default:
         {
             DPRINT1("DOS Internal System Function INT 0x2F, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
                     getAH(), getAL());
@@ -2073,6 +2150,8 @@ BOOLEAN DosKRNLInitialize(VOID)
     UCHAR i;
     PDOS_SFT Sft;
     LPSTR Path;
+    BOOLEAN Success = TRUE;
+    DWORD dwRet;
     CHAR CurrentDirectory[MAX_PATH];
     CHAR DosDirectory[DOS_DIR_LENGTH];
 
@@ -2103,59 +2182,88 @@ BOOLEAN DosKRNLInitialize(VOID)
     SysVars->FirstSft = MAKELONG(DOS_DATA_OFFSET(Sft), DOS_DATA_SEGMENT);
     SysVars->CurrentDirs = MAKELONG(DOS_DATA_OFFSET(CurrentDirectories),
                                     DOS_DATA_SEGMENT);
-    /* The last drive can be redefined with the LASTDRIVE command. At the moment, set the real maximum possible, 'Z'. */
-    SysVars->NumLocalDrives = 'Z' - 'A' + 1;
+    /*
+     * The last drive can be redefined with the LASTDRIVE command.
+     * At the moment, set the real maximum possible, 'Z'.
+     */
+    SysVars->NumLocalDrives = 'Z' - 'A' + 1; // See #define NUM_DRIVES in dos.h
 
     /* The boot drive is initialized to the %SYSTEMDRIVE% value */
     // NOTE: Using the NtSystemRoot system variable might be OS-specific...
-    SysVars->BootDrive = SharedUserData->NtSystemRoot[0] - 'A' + 1;
+    SysVars->BootDrive = RtlUpcaseUnicodeChar(SharedUserData->NtSystemRoot[0]) - 'A' + 1;
 
     /* Initialize the NUL device driver */
     SysVars->NullDevice.Link = 0xFFFFFFFF;
     SysVars->NullDevice.DeviceAttributes = DOS_DEVATTR_NUL | DOS_DEVATTR_CHARACTER;
-    SysVars->NullDevice.StrategyRoutine = FIELD_OFFSET(DOS_SYSVARS, NullDriverRoutine);
+    // Offset from within the DOS data segment
+    SysVars->NullDevice.StrategyRoutine  = DOS_DATA_OFFSET(NullDriverRoutine);
+    // Hardcoded to the RETF inside StrategyRoutine
     SysVars->NullDevice.InterruptRoutine = SysVars->NullDevice.StrategyRoutine + 6;
     RtlFillMemory(SysVars->NullDevice.DeviceName,
                   sizeof(SysVars->NullDevice.DeviceName),
                   ' ');
     RtlCopyMemory(SysVars->NullDevice.DeviceName, "NUL", strlen("NUL"));
-    RtlCopyMemory(SysVars->NullDriverRoutine,
+    RtlCopyMemory(DosData->NullDriverRoutine,
                   NullDriverRoutine,
                   sizeof(NullDriverRoutine));
 
+    /* Default DOS version to report */
+    DosData->DosVersion = DOS_VERSION;
+
     /* Initialize the swappable data area */
     Sda = &DosData->Sda;
     RtlZeroMemory(Sda, sizeof(*Sda));
 
-    /* Get the current directory */
-    if (!GetCurrentDirectoryA(sizeof(CurrentDirectory), CurrentDirectory))
+    /* Get the current directory and convert it to a DOS path */
+    dwRet = GetCurrentDirectoryA(sizeof(CurrentDirectory), CurrentDirectory);
+    if (dwRet == 0)
     {
-        // TODO: Use some kind of default path?
-        return FALSE;
+        Success = FALSE;
+        DPRINT1("GetCurrentDirectoryA failed (Error: %u)\n", GetLastError());
+    }
+    else if (dwRet > sizeof(CurrentDirectory))
+    {
+        Success = FALSE;
+        DPRINT1("Current directory too long (%d > MAX_PATH) for GetCurrentDirectoryA\n", dwRet);
     }
 
-    /* Convert it to a DOS path */
-    if (!GetShortPathNameA(CurrentDirectory, DosDirectory, sizeof(DosDirectory)))
+    if (Success)
     {
-        // TODO: Use some kind of default path?
-        return FALSE;
+        dwRet = GetShortPathNameA(CurrentDirectory, DosDirectory, sizeof(DosDirectory));
+        if (dwRet == 0)
+        {
+            Success = FALSE;
+            DPRINT1("GetShortPathNameA failed (Error: %u)\n", GetLastError());
+        }
+        else if (dwRet > sizeof(DosDirectory))
+        {
+            Success = FALSE;
+            DPRINT1("Short path too long (%d > DOS_DIR_LENGTH) for GetShortPathNameA\n", dwRet);
+        }
+    }
+
+    if (!Success)
+    {
+        /* We failed, use the boot drive instead */
+        DosDirectory[0] = SysVars->BootDrive + 'A' - 1;
+        DosDirectory[1] = ':';
+        DosDirectory[2] = '\\';
+        DosDirectory[3] = '\0';
     }
 
-    /* Set the drive */
+    /* Set the current drive */
     Sda->CurrentDrive = RtlUpperChar(DosDirectory[0]) - 'A';
 
-    /* Get the directory part of the path */
+    /* Get the directory part of the path and set the current directory */
     Path = strchr(DosDirectory, '\\');
     if (Path != NULL)
     {
-        /* Skip the backslash */
-        Path++;
+        Path++; // Skip the backslash
+        strncpy(DosData->CurrentDirectories[Sda->CurrentDrive], Path, DOS_DIR_LENGTH);
     }
-
-    /* Set the directory */
-    if (Path != NULL)
+    else
     {
-        strncpy(DosData->CurrentDirectories[Sda->CurrentDrive], Path, DOS_DIR_LENGTH);
+        DosData->CurrentDirectories[Sda->CurrentDrive][0] = '\0';
     }
 
     /* Set the current PSP to the system PSP */
@@ -2205,7 +2313,13 @@ BOOLEAN DosKRNLInitialize(VOID)
     RegisterDosInt32(0x2F, DosInt2Fh        ); // Multiplex Interrupt
 
     /* Unimplemented DOS interrupts */
-    RegisterDosInt32(0x2A, NULL); // Network - Installation Check
+    RegisterDosInt32(0x2A, DosInt2Ah); // DOS Critical Sections / Network
+//  RegisterDosInt32(0x2E, NULL); // COMMAND.COM "Reload Transient"
+
+    /* Reserved DOS interrupts */
+    RegisterDosInt32(0x2B, NULL);
+    RegisterDosInt32(0x2C, NULL);
+    RegisterDosInt32(0x2D, NULL);
 
     /* Initialize country data */
     DosCountryInitialize();
index 84cd42e..964b6b6 100644 (file)
@@ -80,21 +80,25 @@ typedef struct _DOS_SYSVARS
     WORD FirstMcb;
 
     /* This is where the SYSVARS really start */
-    DWORD FirstDpb;
-    DWORD FirstSft;
-    DWORD ActiveClock;
-    DWORD ActiveCon;
-    BYTE Reserved0[6];
-    DWORD CurrentDirs;
-    BYTE Reserved1[6];
-    BYTE NumBlockDevices;
-    BYTE NumLocalDrives; // Set by LASTDRIVE
-    DOS_DRIVER NullDevice;
-    BYTE NullDriverRoutine[7];
-    BYTE Reserved2[8];
-    BYTE BootDrive;
-    BYTE UseDwordMoves;
-    WORD ExtMemSize;
+    DWORD FirstDpb;                             // 0x00
+    DWORD FirstSft;                             // 0x04
+    DWORD ActiveClock;                          // 0x08
+    DWORD ActiveCon;                            // 0x0c
+    BYTE Reserved0[6];                          // 0x10
+    DWORD CurrentDirs;                          // 0x16
+    BYTE Reserved1[6];                          // 0x1a
+    BYTE NumBlockDevices;                       // 0x20
+    BYTE NumLocalDrives;                        // 0x21 - Set by LASTDRIVE
+    DOS_DRIVER NullDevice;                      // 0x22
+    BYTE Reserved2;                             // 0x34
+    WORD ProgramVersionTable;                   // 0x35
+    DWORD SetVerTable;                          // 0x37
+    WORD Reserved3[2];                          // 0x3b
+    WORD BuffersNumber;                         // 0x3f - 'x' parameter in "BUFFERS=x,y" command
+    WORD BuffersLookaheadNumber;                // 0x41 - 'y' parameter in "BUFFERS=x,y" command
+    BYTE BootDrive;                             // 0x43
+    BYTE UseDwordMoves;                         // 0x44
+    WORD ExtMemSize;                            // 0x45
 } DOS_SYSVARS, *PDOS_SYSVARS;
 
 typedef struct _DOS_CLOCK_TRANSFER_RECORD
@@ -232,6 +236,8 @@ typedef struct _DOS_SDA
 typedef struct _DOS_DATA
 {
     DOS_SYSVARS SysVars;
+    BYTE NullDriverRoutine[7];
+    WORD DosVersion; // DOS version to report to programs (can be different from the true one)
     DOS_SDA Sda;
     CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH];
     BYTE Sft[ANYSIZE_ARRAY];
@@ -242,8 +248,7 @@ typedef struct _DOS_DATA
 /* VARIABLES ******************************************************************/
 
 extern BOOLEAN DoEcho;
-extern WORD DosErrorLevel;
-extern WORD DosLastError;
+extern PDOS_DATA DosData;
 extern PDOS_SYSVARS SysVars;
 extern PDOS_SDA Sda;
 
index 1e31b2f..5b8c1cb 100644 (file)
@@ -77,7 +77,7 @@ WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable)
         /* Make sure it's valid */
         if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType != 'Z')
         {
-            DPRINT("The DOS memory arena is corrupted!\n");
+            DPRINT1("The DOS memory arena is corrupted!\n");
             Sda->LastErrorCode = ERROR_ARENA_TRASHED;
             return 0;
         }
@@ -94,7 +94,7 @@ WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable)
         /* Check if this block is big enough */
         if (CurrentMcb->Size < Size) goto Next;
 
-        switch (Sda->AllocStrategy & 0x3F)
+        switch (Sda->AllocStrategy & ~(DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
         {
             case DOS_ALLOC_FIRST_FIT:
             {
@@ -159,7 +159,7 @@ Done:
     if (CurrentMcb->Size > Size)
     {
         /* It is, split it into two blocks */
-        if ((Sda->AllocStrategy & 0x3F) != DOS_ALLOC_LAST_FIT)
+        if ((Sda->AllocStrategy & ~(DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW)) != DOS_ALLOC_LAST_FIT)
         {
             PDOS_MCB NextMcb = SEGMENT_TO_MCB(Result + Size + 1);
 
index bf3e61a..76ac6e2 100644 (file)
@@ -29,6 +29,7 @@ typedef struct _DOS_MCB
     BYTE Unused[3];
     CHAR Name[8];
 } DOS_MCB, *PDOS_MCB;
+C_ASSERT(sizeof(DOS_MCB) == 0x10);
 #pragma pack(pop)
 
 /* VARIABLES ******************************************************************/
index 1a25742..46c77c6 100644 (file)
@@ -166,7 +166,7 @@ VOID DosClonePsp(WORD DestSegment, WORD SourceSegment)
     LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
 
     /* Literally copy the PSP first */
-    RtlCopyMemory(DestPsp, SourcePsp, sizeof(DOS_PSP));
+    RtlCopyMemory(DestPsp, SourcePsp, sizeof(*DestPsp));
 
     /* Save the interrupt vectors */
     DestPsp->TerminateAddress = IntVecTable[0x22];
@@ -222,7 +222,8 @@ VOID DosCreatePsp(WORD Segment, WORD ProgramSize)
     PspBlock->HandleTablePtr  = MAKELONG(0x18, Segment);
 
     /* Set the DOS version */
-    PspBlock->DosVersion = DOS_VERSION;
+    // FIXME: This is here that SETVER stuff enters into action!
+    PspBlock->DosVersion = DosData->DosVersion;
 
     /* Set the far call opcodes */
     PspBlock->FarCall[0] = 0xCD; // int 0x21
@@ -377,16 +378,20 @@ DWORD DosLoadExecutable(IN DOS_EXEC_TYPE LoadType,
         /* If no optional environment is given... */
         if (Environment == NULL)
         {
-            /* ... get the one from the parameter block */
             ASSERT(Parameters);
-            Environment = (LPCSTR)SEG_OFF_TO_PTR(Parameters->Environment, 0);
+            /* ... get the one from the parameter block (if not NULL)... */
+            if (Parameters->Environment)
+                Environment = (LPCSTR)SEG_OFF_TO_PTR(Parameters->Environment, 0);
+            /* ... or the one from the parent (otherwise) */
+            else
+                Environment = (LPCSTR)SEG_OFF_TO_PTR(SEGMENT_TO_PSP(Sda->CurrentPsp)->EnvBlock, 0);
         }
 
         /* Copy the environment block to DOS memory */
         EnvBlock = DosCopyEnvironmentBlock(Environment, ExecutablePath);
         if (EnvBlock == 0)
         {
-            Result = ERROR_NOT_ENOUGH_MEMORY;
+            Result = Sda->LastErrorCode;
             goto Cleanup;
         }
     }
@@ -431,7 +436,6 @@ DWORD DosLoadExecutable(IN DOS_EXEC_TYPE LoadType,
 
             /* Try to allocate that much memory */
             Segment = DosAllocateMemory((WORD)TotalSize, &MaxAllocSize);
-
             if (Segment == 0)
             {
                 /* Check if there's at least enough memory for the minimum size */
@@ -460,8 +464,10 @@ DWORD DosLoadExecutable(IN DOS_EXEC_TYPE LoadType,
             SEGMENT_TO_PSP(Segment)->EnvBlock = EnvBlock;
 
             /* Calculate the segment where the program should be loaded */
-            if (!LoadHigh) LoadSegment = Segment + (sizeof(DOS_PSP) >> 4);
-            else LoadSegment = Segment + TotalSize - BaseSize;
+            if (!LoadHigh)
+                LoadSegment = Segment + (sizeof(DOS_PSP) >> 4);
+            else
+                LoadSegment = Segment + TotalSize - BaseSize;
 
             RelocFactor = LoadSegment;
         }
index 9e8e081..7f8580b 100644 (file)
@@ -1025,11 +1025,15 @@ BOOLEAN DosMouseInitialize(VOID)
 
 VOID DosMouseCleanup(VOID)
 {
+    if (DriverState.ShowCount > 0) EraseMouseCursor();
+    DosMouseDisable();
+
     /* Restore the old mouse service interrupt handler */
     ((PDWORD)BaseAddress)[DOS_MOUSE_INTERRUPT] = OldIntHandler;
 
-    if (DriverState.ShowCount > 0) EraseMouseCursor();
-    DosMouseDisable();
+    DosFreeMemory(MouseDataSegment);
+    MouseDataSegment = 0;
+    MouseData = 0;
 }
 
 /* EOF */
index ed72a50..390c1d2 100644 (file)
@@ -454,7 +454,7 @@ VOID CmosInitialize(VOID)
                            OPEN_ALWAYS,
                            FILE_ATTRIBUTE_NORMAL,
                            NULL);
-    DPRINT1("CMOS opening %s ; GetLastError() = %u\n", hCmosRam != INVALID_HANDLE_VALUE ? "succeeded" : "failed", GetLastError());
+    DPRINT1("CMOS opening %s (Error: %u)\n", hCmosRam != INVALID_HANDLE_VALUE ? "succeeded" : "failed", GetLastError());
 
     if (hCmosRam != INVALID_HANDLE_VALUE)
     {
@@ -469,7 +469,7 @@ VOID CmosInitialize(VOID)
             DPRINT1("Invalid CMOS file, read bytes %u, expected bytes %u\n", CmosSize, sizeof(CmosMemory));
             RtlZeroMemory(&CmosMemory, sizeof(CmosMemory));
         }
-        DPRINT1("CMOS loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
+        DPRINT1("CMOS loading %s (Error: %u)\n", Success ? "succeeded" : "failed", GetLastError());
         SetFilePointer(hCmosRam, 0, NULL, FILE_BEGIN);
     }
 
index 7a00543..ac247db 100644 (file)
@@ -127,7 +127,7 @@ VdmMenuExists(HMENU hConsoleMenu)
     {
         if (GetMenuItemID(hConsoleMenu, i) == ID_SHOWHIDE_MOUSE)
         {
-            /* set VdmMenuPos to the position of the existing menu */
+            /* Set VdmMenuPos to the position of the existing menu */
             VdmMenuPos = i - 1;
             return TRUE;
         }
@@ -225,7 +225,7 @@ static VOID EnableExtraHardware(HANDLE ConsoleInput)
 /* PUBLIC FUNCTIONS ***********************************************************/
 
 VOID
-DisplayMessage(LPCWSTR Format, ...)
+DisplayMessage(IN LPCWSTR Format, ...)
 {
 #ifndef WIN2K_COMPLIANT
     WCHAR  StaticBuffer[256];
@@ -242,11 +242,12 @@ DisplayMessage(LPCWSTR Format, ...)
     /*
      * Retrieve the message length and if it is too long, allocate
      * an auxiliary buffer; otherwise use the static buffer.
+     * The string is built to be NULL-terminated.
      */
-    MsgLen = _vscwprintf(Format, Parameters) + 1; // NULL-terminated
-    if (MsgLen > ARRAYSIZE(StaticBuffer))
+    MsgLen = _vscwprintf(Format, Parameters);
+    if (MsgLen >= ARRAYSIZE(StaticBuffer))
     {
-        Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, MsgLen * sizeof(WCHAR));
+        Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, (MsgLen + 1) * sizeof(WCHAR));
         if (Buffer == NULL)
         {
             /* Allocation failed, use the static buffer and display a suitable error message */
@@ -256,11 +257,15 @@ DisplayMessage(LPCWSTR Format, ...)
         }
     }
 #else
-    MsgLen = ARRAYSIZE(Buffer);
+    MsgLen = ARRAYSIZE(Buffer) - 1;
 #endif
 
-    /* Display the message */
+    RtlZeroMemory(Buffer, (MsgLen + 1) * sizeof(WCHAR));
     _vsnwprintf(Buffer, MsgLen, Format, Parameters);
+
+    va_end(Parameters);
+
+    /* Display the message */
     DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer);
     MessageBoxW(NULL, Buffer, L"NTVDM Subsystem", MB_OK);
 
@@ -268,8 +273,6 @@ DisplayMessage(LPCWSTR Format, ...)
     /* Free the buffer if needed */
     if (Buffer != StaticBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
 #endif
-
-    va_end(Parameters);
 }
 
 static BOOL
index f5f774d..08044dd 100644 (file)
@@ -75,7 +75,7 @@ extern WCHAR** NtVdmArgv;
 /*
  * Interface functions
  */
-VOID DisplayMessage(LPCWSTR Format, ...);
+VOID DisplayMessage(IN LPCWSTR Format, ...);
 
 /*static*/ VOID
 CreateVdmMenu(HANDLE ConOutHandle);