/*++ Copyright (c) 1992 Microsoft Corporation Module Name: Int21Map.c Abstract: This module performs int 21 API translation for dpmi Author: Dave Hastings (daveh) 23-Nov-1992 Revision History: Neil Sandlin (neilsa) 31-Jul-1995 - Updates for the 486 emulator --*/ #include "precomp.h" #pragma hdrstop #include "int21map.h" #include "softpc.h" #include "xlathlp.h" // // Local constants // //#define Verbose 1 #define MAX_SUPPORTED_DOS_CALL 0x6d #define DosxTranslated NULL typedef VOID (*APIXLATFUNCTION)(VOID); APIXLATFUNCTION ApiXlatTable[MAX_SUPPORTED_DOS_CALL] = { DosxTranslated , // 00h - Terminate process NoTranslation , // 01h - Char input with echo NoTranslation , // 02h - Character output NoTranslation , // 03h - Auxiliary input NoTranslation , // 04h - Auxiliary output NoTranslation , // 05h - Print character NoTranslation , // 06h - Direct console I/O NoTranslation , // 07h - Unfiltered char input NoTranslation , // 08h - Char input w/o echo DisplayString , // 09h - Display "$" term string BufferedKeyboardInput , // 0Ah - Buffered keyboard input NoTranslation , // 0Bh - Check keyboard status FlushBuffReadKbd , // 0Ch - Flush buff, Read kbd NoTranslation , // 0Dh - Disk reset NoTranslation , // 0Eh - Select disk NotSupportedFCB , // 0Fh * Open file with FCB NotSupportedFCB , // 10h * Close file with FCB FindFileFCB , // 11h - Find First File FindFileFCB , // 12h - Find Next File MapFCB , // 13h - Delete File NotSupportedFCB , // 14h * Sequential Read NotSupportedFCB , // 15h * Sequential Write NotSupportedFCB , // 16h * Create File With FCB RenameFCB , // 17h - Rename File With FCB NoTranslation , // 18h - UNUSED NoTranslation , // 19h - Get Current Disk SetDTA , // 1Ah - Set DTA Address GetDriveData , // 1Bh - Get Default Drive Data GetDriveData , // 1Ch - Get Drive Data NoTranslation , // 1Dh - UNUSED NoTranslation , // 1Eh - UNUSED GetDriveData , // 1Fh - Get Drive Parameter Blk NoTranslation , // 20h - UNUSED NotSupportedFCB , // 21h * Random Read NotSupportedFCB , // 22h * Random Write NotSupportedFCB , // 23h * Get File Size NotSupportedFCB , // 24h * Set Relative Record SetVector , // 25h - Set interrupt vector CreatePSP , // 26h - Create PSP NotSupportedFCB , // 27h * Random block read NotSupportedFCB , // 28h * Random block write ParseFilename , // 29h - Parse filename GetDate , // 2Ah - Get date NoTranslation , // 2Bh - Set date NoTranslation , // 2Ch - Get time NoTranslation , // 2Dh - Set time NoTranslation , // 2Eh - Set/Reset verify flag GetDTA , // 2Fh - Get DTA address NoTranslation , // 30h - Get DOS version TSR , // 31h - Terminate and Stay Res GetDevParamBlock , // 32h - Get device parameter blk NoTranslation , // 33h - Get/Set Control-C Flag ReturnESBX , // 34h - Get Address of InDOS GetVector , // 35h - Get Interrupt Vector NoTranslation , // 36h - Get Disk Free Space NoTranslation , // 37h - Char Oper GetSetCountry , // 38h - Get/Set Current Country MapASCIIZDSDX , // 39h - Create Directory MapASCIIZDSDX , // 3Ah - Remove Directory MapASCIIZDSDX , // 3Bh - Change Current Directory MapASCIIZDSDX , // 3Ch - Create File with Handle MapASCIIZDSDX , // 3Dh - Open File with Handle NoTranslation , // 3Eh - Close File with Handle ReadWriteFile , // 3Fh - Read File or Device ReadWriteFile , // 40h - Write File or Device MapASCIIZDSDX , // 41h - Delete File NoTranslation , // 42h - Move file pointer MapASCIIZDSDX , // 43h - Get/Set File Attributes IOCTL , // 44h - IOCTL NoTranslation , // 45h - Duplicate File Handle NoTranslation , // 46h - Force Duplicate Handle GetCurDir , // 47h - Get Current Directory AllocateMemoryBlock , // 48h - Allocate Memory Block FreeMemoryBlock , // 49h - Free Memory Block ResizeMemoryBlock , // 4Ah - Resize Memory Block LoadExec , // 4Bh - Load and Exec Program DosxTranslated , // 4Ch - Terminate with Ret Code NoTranslation , // 4Dh - Get Ret Code Child Proc FindFirstFileHandle , // 4Eh - Find First File FindNextFileHandle , // 4Fh - Find Next File SetPSP , // 50h - Set PSP Segment GetPSP , // 51h - Get PSP Segment ReturnESBX , // 52h - Get List of Lists (invars) TranslateBPB , // 53h - Translate BPB NoTranslation , // 54h - Get Verify Flag CreatePSP , // 55h - Create PSP RenameFile , // 56h - Rename File NoTranslation , // 57h - Get/Set Date/Time File NoTranslation , // 58h - Get/Set Alloc Strategy NoTranslation , // 59h - Get Extended Error Info CreateTempFile , // 5Ah - Create Temporary File MapASCIIZDSDX , // 5Bh - Create New File NoTranslation , // 5Ch - Lock/Unlock File Region Func5Dh , // 5Dh - Server DOS call Func5Eh , // 5Eh - Net Name/Printer Setup Func5Fh , // 5Fh - Network redir stuff NotSupportedBad , // 60h - NameTrans NoTranslation , // 61h - UNUSED GetPSP , // 62h - Get PSP Address #ifdef DBCS ReturnDSSI , // 63h - Get DBCS Vector #else NotSupportedBetter , // 63h - Hangool call #endif NotSupportedBad , // 64h - Set Prn Flag GetExtendedCountryInfo , // 65h - Get Extended Country Info NoTranslation , // 66h - Get/Set Global Code Page NoTranslation , // 67h - Set Handle Count NoTranslation , // 68h - Commit File NoTranslation , // 69h - NoTranslation , // 6Ah - NoTranslation , // 6Bh - MapASCIIZDSSI // 6Ch - Extended open }; VOID DpmiXlatInt21Call( VOID ) /*++ Routine Description: This routine dispatches to the appropriate routine to perform the actual translation of the api Arguments: None Return Value: None. --*/ { DECLARE_LocalVdmContext; ULONG DosMajorCode; PUCHAR StackPointer; // // Pop ds from stack // StackPointer = Sim32GetVDMPointer( ((ULONG)getSS() << 16), 1, TRUE ); StackPointer += (*GetSPRegister)(); setDS(*(PWORD16)StackPointer); (*SetSPRegister)((*GetSPRegister)() + 2); DosMajorCode = getAH(); if (DosMajorCode >= MAX_SUPPORTED_DOS_CALL) { return; } if (ApiXlatTable[DosMajorCode]) { ULONG Eip, Esp; USHORT Cs, Ss; Eip = getEIP(); Esp = getESP(); Cs = getCS(); Ss = getSS(); (*ApiXlatTable[DosMajorCode])(); setEIP(Eip); setESP(Esp); setCS(Cs); setSS(Ss); SimulateIret(PASS_CARRY_FLAG_16); } // put this back in after beta 2.5 DpmiFreeAllBuffers(); } VOID NoTranslation( VOID ) /*++ Routine Description: This routine handles int 21 functions which don't need any translation. It simply executes the int 21 in real/v86 mode Arguments: None Return Value: None. --*/ { DECLARE_LocalVdmContext; DpmiSwitchToRealMode(); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); } VOID DisplayString( VOID ) /*++ Routine Description: This routine translates the int 21 display string function. N.B. Win 3.1 does this by calling int 21 function 2 repeatedly. We do it this way because Win 3.1 does. If this function is frequently used, we should actually buffer the string and call the dos display string function. Arguments: None Return Value: None. --*/ { PUCHAR String; DECLARE_LocalVdmContext; USHORT ClientAX, ClientDX; USHORT ClientDS = getDS(); DpmiSwitchToRealMode(); String = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetDXRegister)(); // // Repeatedly call int 21 function 2 to display the characters // ClientAX = getAX(); ClientDX = getDX(); setAH(2); while (*(String) != '$') { setDL(*(String)); DPMI_EXEC_INT(0x21); String++; } setAX(ClientAX); setDX(ClientDX); DpmiSwitchToProtectedMode(); } VOID BufferedKeyboardInput( VOID ) /*++ Routine Description: This routine performs the tranlation for the int 21 function Ah Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; PUCHAR PmInputBuffer, RmInputBuffer; USHORT BufferSeg, BufferOff, BufferLen; USHORT ClientDX; USHORT ClientDS = getDS(); DpmiSwitchToRealMode(); ClientDX = getDX(); // // Get a pointer to the PM buffer // PmInputBuffer = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetDXRegister)(); // // Get the buffer length (there are two bytes in addition to the // buffer) // BufferLen = *PmInputBuffer + 2; // // Move the buffer to low memory // RmInputBuffer = DpmiMapAndCopyBuffer(PmInputBuffer, BufferLen); // // Set up the registers for the int 21 call // DPMI_FLAT_TO_SEGMENTED(RmInputBuffer, &BufferSeg, &BufferOff); setDS(BufferSeg); setDX(BufferOff); DPMI_EXEC_INT(0x21); // // Copy the data back // DpmiUnmapAndCopyBuffer(PmInputBuffer, RmInputBuffer, BufferLen); setDX(ClientDX); DpmiSwitchToProtectedMode(); setDS(ClientDS); } VOID FlushBuffReadKbd( VOID ) /*++ Routine Description: This routine performs translation for the flush keyboard routines. It calls the appropriate xlat routine. Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; if (getAL() == 0x0a) { BufferedKeyboardInput(); } else { NoTranslation(); } } VOID NotSupportedFCB( VOID ) /*++ Routine Description: This routine does not do any translation. It prints a warning to the debugger Arguments: None. Return Value: None. --*/ { #if DBG DECLARE_LocalVdmContext; DbgPrint( "WARNING: DOS INT 21 call AH = %x will not be translated.\n", getAH()); DbgPrint( " Protected mode applications should not be using\n"); DbgPrint( " this type of FCB call. Convert this application\n"); DbgPrint( " to use the handle calls.\n" ); #endif NoTranslation(); } VOID FindFileFCB( VOID ) /*++ Routine Description: This function translates the find first/find next FCB calls. Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; PUCHAR FcbAddress, FcbBufferedAddress; USHORT FcbSegment, FcbOffset; USHORT ClientDX; USHORT FcbLength; USHORT ClientDS = getDS(); DpmiSwitchToRealMode(); SetDTAPointers(); ClientDX = getDX(); FcbAddress = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetDXRegister)(); // // Calculate the size of the FCB // FcbLength = DpmiCalcFcbLength(FcbAddress); // // Buffer the FCB // FcbBufferedAddress = DpmiMapAndCopyBuffer(FcbAddress, FcbLength); // // Check to see if we need to set the real dta // if (CurrentDosDta != CurrentDta) SetDosDTA(); // // Make the int 21 call // DPMI_FLAT_TO_SEGMENTED(FcbBufferedAddress, &FcbSegment, &FcbOffset); setDS(FcbSegment); setDX(FcbOffset); DPMI_EXEC_INT(0x21); // // If the call was successful and the PM dta is in high memory // copy the dta to high memory // if ((getAL() == 0) && (CurrentPmDtaAddress != CurrentDta)) { MoveMemory(CurrentPmDtaAddress, CurrentDta, FcbLength); DpmiUnmapAndCopyBuffer(FcbAddress, FcbBufferedAddress, FcbLength); } else { DpmiUnmapBuffer(FcbBufferedAddress, FcbLength); } setDX(ClientDX); DpmiSwitchToProtectedMode(); setDS(ClientDS); } VOID MapFCB( VOID ) /*++ Routine Description: This routine translates the delete file fcb int 21 call Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT FcbLength, FcbSegment, FcbOffset; PUCHAR FcbAddress, FcbBufferedAddress; USHORT ClientDX; USHORT ClientDS = getDS(); DpmiSwitchToRealMode(); ClientDX = getDX(); FcbAddress = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetDXRegister)(); // // Get the length of the FCB // FcbLength = DpmiCalcFcbLength(FcbAddress); // // Copy the FCB // FcbBufferedAddress = DpmiMapAndCopyBuffer(FcbAddress, FcbLength); // // Make the int 21 call // DPMI_FLAT_TO_SEGMENTED(FcbBufferedAddress, &FcbSegment, &FcbOffset); setDS(FcbSegment); setDX(FcbOffset); DPMI_EXEC_INT(0x21); // // Copy the FCB back // DpmiUnmapAndCopyBuffer(FcbAddress, FcbBufferedAddress, FcbLength); // // Clean up // setDX(ClientDX); DpmiSwitchToProtectedMode(); setDS(ClientDS); } VOID RenameFCB( VOID ) /*++ Routine Description: This routine translates the rename fcb int 21 function Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT FcbSegment, FcbOffset; PUCHAR FcbAddress, FcbBufferedAddress; USHORT ClientDX; USHORT ClientDS = getDS(); DpmiSwitchToRealMode(); ClientDX = getDX(); FcbAddress = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetDXRegister)(); // // Copy the FCB (The fcb for rename is a special format, fixed size) // FcbBufferedAddress = DpmiMapAndCopyBuffer(FcbAddress, 0x25); // // Make the int 21 call // DPMI_FLAT_TO_SEGMENTED(FcbBufferedAddress, &FcbSegment, &FcbOffset); setDS(FcbSegment); setDX(FcbOffset); DPMI_EXEC_INT(0x21); // // Copy the FCB back // DpmiUnmapAndCopyBuffer(FcbAddress, FcbAddress, 0x25); // // Clean up // setDX(ClientDX); DpmiSwitchToProtectedMode(); setDS(ClientDS); } VOID GetDriveData( VOID ) /*++ Routine Description: Translates the drive data int 21 calls Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT Selector; DpmiSwitchToRealMode(); DPMI_EXEC_INT(0x21); Selector = getDS(); DpmiSwitchToProtectedMode(); setDS(SegmentToSelector(Selector, STD_DATA)); (*SetBXRegister)((ULONG)getBX()); } VOID SetVector( VOID ) /*++ Routine Description: This function translates int 21 function 25 Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; SetProtectedModeInterrupt(getAL(), getDS(), (*GetDXRegister)(), (USHORT)(Frame32 ? VDM_INT_32 : VDM_INT_16)); } VOID CreatePSP( VOID ) /*++ Routine Description: This routine translates the selector to a segment and reflects the calls Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; ULONG Segment; USHORT ClientDX; DpmiSwitchToRealMode(); ClientDX = getDX(); Segment = SELECTOR_TO_INTEL_LINEAR_ADDRESS(ClientDX); if (Segment > ONE_MB) { // // Create PSP doesn't do anything on error // } else { setDX((USHORT) (Segment >> 4)); DPMI_EXEC_INT(0x21); } setDX(ClientDX); DpmiSwitchToProtectedMode(); } VOID ParseFilename( VOID ) /*++ Routine Description: This routine translates the int 21 parse filename api Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT ClientSI, ClientDI, FcbLength, StringOff, Seg, Off; PUCHAR Fcb, BufferedFcb, String, BufferedString; USHORT ClientDS = getDS(); USHORT ClientES = getES(); DpmiSwitchToRealMode(); ClientSI = getSI(); ClientDI = getDI(); Fcb = Sim32GetVDMPointer(((ULONG)ClientES << 16), 1, TRUE) + (*GetDIRegister)(); FcbLength = DpmiCalcFcbLength(Fcb); BufferedFcb = DpmiMapAndCopyBuffer(Fcb, FcbLength); String = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetSIRegister)(); BufferedString = DpmiMapAndCopyBuffer(String, 20); DPMI_FLAT_TO_SEGMENTED(BufferedFcb, &Seg, &Off); setES(Seg); setDI(Off); DPMI_FLAT_TO_SEGMENTED(BufferedString, &Seg, &StringOff); setDS(Seg); setSI(StringOff); DPMI_EXEC_INT(0x21); DpmiUnmapAndCopyBuffer(Fcb, BufferedFcb, FcbLength); DpmiUnmapAndCopyBuffer(String, BufferedString, 20); setDI(ClientDI); setSI(ClientSI + (getSI() - StringOff)); DpmiSwitchToProtectedMode(); setDS(ClientDS); setES(ClientES); } VOID GetDTA( VOID ) /*++ Routine Description: This routine returns the current DTA. Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; // // Win31 compatibility: // // Some hosebag programs set the DTA to a selector that they later free! // This test makes sure that this does not cause us to crash. // if (!SEGMENT_IS_WRITABLE(CurrentDtaSelector)) { CurrentDtaSelector = 0; CurrentDtaOffset = 0; } setES(CurrentDtaSelector); setBX(CurrentDtaOffset); setCF(0); } VOID SetDTA( VOID ) /*++ Routine Description: This routine sets the PM dta address. If the buffer is usable directly, CurrentDta is set to the translated address. Otherwise, it is set to the dosx dta. N.B. The Set Dta call is not actually reflected to Dos until a function call is made that actually uses the Dta, e.g. the Find First/Next functions. This techique was implemented to match what is done in Win 3.1. Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT ClientDX; ClientDX = getDX(); CurrentDtaOffset = ClientDX; CurrentDtaSelector = getDS(); // // Make sure real DTA is updated later // CurrentDosDta = (PUCHAR) NULL; } VOID SetDTAPointers( VOID ) /*++ Routine Description: This routine sets up the flat address values used elsewhere to reference the current DTA. N.B. This must be done on every entry to handle function calls because the PM dta may have been GlobalRealloc'd. This may change the base address of the PM selector (which invalidates the flat addresses), but not the selector/offset itself. Arguments: None. Return Value: None. --*/ { PUCHAR NewDta; NewDta = Sim32GetVDMPointer( (CurrentDtaSelector << 16), 1, TRUE ); NewDta += CurrentDtaOffset; CurrentPmDtaAddress = NewDta; // // If the new dta is not accessible in v86 mode, use the one // supplied by Dosx // if ((ULONG)(NewDta + 128 - IntelBase) > MAX_V86_ADDRESS) { NewDta = DosxDtaBuffer; } // // Update Current DTA information // CurrentDta = NewDta; } VOID SetDosDTA( VOID ) /*++ Routine Description: This routine is called internally by other functions in this module to reflect a Set Dta call to Dos. WARNING: The client must be in REAL mode Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT ClientAX, ClientDX, ClientDS, NewDtaSegment, NewDtaOffset; ASSERT((getMSW() & MSW_PE) == 0); ClientAX = getAX(); ClientDX = getDX(); ClientDS = getDS(); DPMI_FLAT_TO_SEGMENTED(CurrentDta, &NewDtaSegment, &NewDtaOffset); setDS(NewDtaSegment); setDX(NewDtaOffset); setAH(0x1a); DPMI_EXEC_INT(0x21); setAX(ClientAX); setDX(ClientDX); setDS(ClientDS); CurrentDosDta = CurrentDta; } VOID TSR( VOID ) /*++ Routine Description: This function translates int 21h tsr. Win 3.1 does some magic here. We didn't before and it worked fine. Maybe we will later. Arguments: None. Return Value: None. --*/ { NoTranslation(); } VOID GetDevParamBlock( VOID ) /*++ Routine Description: This routine translates the Device Parameter Block apis Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT Selector; DpmiSwitchToRealMode(); DPMI_EXEC_INT(0x21); Selector = getDS(); DpmiSwitchToProtectedMode(); setDS(SegmentToSelector(Selector, STD_DATA)); (*SetBXRegister)((ULONG)getBX()); } VOID ReturnESBX( VOID ) /*++ Routine Description: This function translates api that return information in es:bx Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT Selector; DpmiSwitchToRealMode(); DPMI_EXEC_INT(0x21); Selector = getES(); DpmiSwitchToProtectedMode(); (*SetBXRegister)((ULONG)getBX()); setES(SegmentToSelector(Selector, STD_DATA)); } VOID GetVector( VOID ) /*++ Routine Description: This function translates int 21 function 35 Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; PVDM_INTERRUPTHANDLER Handlers = DpmiInterruptHandlers; USHORT IntNumber = getAL(); setES(Handlers[IntNumber].CsSelector); (*SetBXRegister)(Handlers[IntNumber].Eip); } VOID GetSetCountry( VOID ) /*++ Routine Description: This function translates int 21 function 38 Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; if (getDX() == 0xFFFF) { NoTranslation(); } else { USHORT ClientDX, Seg, Off; PUCHAR Country, BufferedCountry; USHORT ClientDS = getDS(); DpmiSwitchToRealMode(); ClientDX = getDX(); Country = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetDXRegister)(); BufferedCountry = DpmiMapAndCopyBuffer(Country, 34); DPMI_FLAT_TO_SEGMENTED(BufferedCountry, &Seg, &Off); setDS(Seg); setDX(Off); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); DpmiUnmapAndCopyBuffer(Country, BufferedCountry, 34); setDX(ClientDX); setDS(ClientDS); } } VOID MapASCIIZDSDX( VOID ) /*++ Routine Description: This routine maps the int 21 functions that pass file names in ds:dx Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; PUCHAR BufferedString; USHORT ClientDX, StringSeg, StringOff, Length; USHORT ClientDS = getDS(); BufferedString = DpmiMapString(ClientDS, (GetDXRegister)(), &Length); if (BufferedString == NULL) { setCF(1); setAX(3); } else { DpmiSwitchToRealMode(); ClientDX = getDX(); DPMI_FLAT_TO_SEGMENTED(BufferedString, &StringSeg, &StringOff); setDS(StringSeg); setDX(StringOff); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); DpmiUnmapString(BufferedString, Length); setDX(ClientDX); setDS(ClientDS); } } VOID ReadWriteFile( VOID ) /*++ Routine Description: This routine translates the read/write file int 21 calls. Large reads are broken down into 4k chunks. Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT ClientCX, ClientDX, ClientAX, Function, DataSeg, DataOff, BytesToRead; ULONG BytesRead, TotalBytesToRead; PUCHAR ReadWriteData, BufferedData; USHORT ClientDS = getDS(); DpmiSwitchToRealMode(); ClientCX = getCX(); ClientDX = getDX(); Function = getAH(); ClientAX = getAX(); TotalBytesToRead = (*GetCXRegister)(); BytesRead = 0; ReadWriteData = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetDXRegister)(); // while (TotalBytesToRead != BytesRead) { do { if ((TotalBytesToRead - BytesRead) > 1024 * 4) { BytesToRead = 4 * 1024; } else { BytesToRead = (USHORT)(TotalBytesToRead - BytesRead); } BufferedData = DpmiMapAndCopyBuffer(ReadWriteData, BytesToRead); DPMI_FLAT_TO_SEGMENTED(BufferedData, &DataSeg, &DataOff); setDS(DataSeg); setDX(DataOff); setCX(BytesToRead); setAX(ClientAX); DPMI_EXEC_INT(0x21); if (getCF()) { DpmiUnmapBuffer(BufferedData, BytesToRead); break; } if (getAX() == 0) { DpmiUnmapBuffer(BufferedData, BytesToRead); break; } else if (getAX() < BytesToRead) { CopyMemory(ReadWriteData, BufferedData, getAX()); DpmiUnmapBuffer(BufferedData, BytesToRead); BytesRead += getAX(); break; } else { DpmiUnmapAndCopyBuffer( ReadWriteData, BufferedData, BytesToRead ); } ReadWriteData += getAX(); BytesRead += getAX(); // } } while (TotalBytesToRead != BytesRead); setDX(ClientDX); setCX(ClientCX); if (!getCF()) { (*SetAXRegister)(BytesRead); } DpmiSwitchToProtectedMode(); setDS(ClientDS); } #define MAX_SUPPORTED_DOS_IOCTL_CALL 0x10 // // Note: The translations here differ from those in the windows dpmi vxd, // because we do not have to lock memory, and we don't support block // device drivers. // APIXLATFUNCTION IOCTLXlatTable[MAX_SUPPORTED_DOS_IOCTL_CALL] = { NoTranslation , // 00 - Get Device Data NoTranslation , // 01 - Set Device Data MapDSDXLenCX , // 02 - Receive Ctrl Chr Data MapDSDXLenCX , // 03 - Send Ctrl Chr Data MapDSDXLenCX , // 04 - Receive Ctrl Block Data MapDSDXLenCX , // 05 - Send Ctrl Block Data NoTranslation , // 06 - Check Input Status NoTranslation , // 07 - Check Output Status NoTranslation , // 08 - Check Block Dev Removable NoTranslation , // 09 - Check Block Dev Remote NoTranslation , // 0A - Check if Handle Remote NoTranslation , // 0B - Change sharing retry cnt IOCTLMap2Bytes , // 0C - MAP DS:DX LENGTH 2! IOCTLBlockDevs , // 0D - Generic IOCTL to blk dev NoTranslation , // 0E - Get Logical Drive Map NoTranslation // 0F - Set Logical Drive Map }; VOID IOCTL( VOID ) /*++ Routine Description: This function translates the int 21 ioctl function. Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT IoctlMinor; IoctlMinor = getAL(); if (IoctlMinor >= MAX_SUPPORTED_DOS_IOCTL_CALL) { #if DBG OutputDebugString("DPMI: IOCTL DOS CALL NOT SUPPORTED\n"); #endif NoTranslation(); return; } (*IOCTLXlatTable[IoctlMinor])(); } VOID GetCurDir( VOID ) /*++ Routine Description: This routine translates the get current directory call Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; PUCHAR DirInfo, BufferedDirInfo; USHORT ClientSI, Seg, Off; USHORT ClientDS = getDS(); DpmiSwitchToRealMode(); ClientSI = getSI(); DirInfo = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetSIRegister)(); BufferedDirInfo = DpmiMapAndCopyBuffer(DirInfo, 64); DPMI_FLAT_TO_SEGMENTED(BufferedDirInfo, &Seg, &Off); setDS(Seg); setSI(Off); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); DpmiUnmapAndCopyBuffer(DirInfo, BufferedDirInfo, 64); setSI(ClientSI); setDS(ClientDS); } VOID AllocateMemoryBlock( VOID ) /*++ Routine Description: This routine translates the AllocateMemory Int 21 api Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; PMEM_DPMI pMem; ULONG MemSize = ((ULONG)getBX()) << 4; pMem = DpmiAllocateXmem(MemSize); if (pMem) { pMem->SelCount = (USHORT) ((MemSize>>16) + 1); pMem->Sel = ALLOCATE_SELECTORS(pMem->SelCount); if (!pMem->Sel) { pMem->SelCount = 0; DpmiFreeXmem(pMem); pMem = NULL; } else { SetDescriptorArray(pMem->Sel, (ULONG)pMem->Address, MemSize); } } if (!pMem) { setCF(1); setAX(8); setBX(0); } else { setCF(0); setAX(pMem->Sel); } } VOID FreeMemoryBlock( VOID ) /*++ Routine Description: This routine translates the ResizeMemory Int 21 api Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; PMEM_DPMI pMem; USHORT Sel = getES(); if (pMem = DpmiFindXmem(Sel)) { while(pMem->SelCount--) { FreeSelector(Sel); Sel+=8; } DpmiFreeXmem(pMem); setCF(0); } else { setCF(1); setAX(9); } } VOID ResizeMemoryBlock( VOID ) /*++ Routine Description: This routine translates the ResizeMemory int 21 api Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; PMEM_DPMI pMem; ULONG MemSize = ((ULONG)getBX()) << 4; USHORT Sel = getES(); if (pMem = DpmiFindXmem(Sel)) { if (DpmiReallocateXmem(pMem, MemSize)) { SetDescriptorArray(pMem->Sel, (ULONG)pMem->Address, MemSize); setCF(0); } else { // not enough memory setCF(1); setAX(8); } } else { // invalid block setCF(1); setAX(9); } } VOID LoadExec( VOID ) /*++ Routine Description: This function translates the int 21 load exec function. Load overlay is not supported. The child always inherits the environment, and the fcbs in the parameter block are ignored. (win 3.1 does this) Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; PUCHAR CommandTail, BufferedString, Environment; USHORT ClientDX, ClientBX, Seg, Off, Length, i, EnvironmentSel; USHORT ClientDS = getDS(); USHORT ClientES = getES(); DpmiSwitchToRealMode(); ClientDX = getDX(); ClientBX = getBX(); if (getAL() == 3) { setCF(1); setAX(1); } else { // // Map the command string // BufferedString = DpmiMapString(ClientDS, (*GetDXRegister)(), &Length); if (BufferedString == NULL) { setCF(1); setAX(3); } else { // // Make sure real DTA is updated later // CurrentDosDta = (PUCHAR) NULL; // // Set up the Parameter block // // We use the large xlat buffer. The parameter block comes // first, and we fill in the command tail after // ZeroMemory(LargeXlatBuffer, 512); // // The environment segment address is now set // // // Set the command tail address, and copy the command tail (all // 128 bytes // DPMI_FLAT_TO_SEGMENTED((LargeXlatBuffer + 0x10), &Seg, &Off) *(PWORD16)(LargeXlatBuffer + 2) = Off; *(PWORD16)(LargeXlatBuffer + 4) = Seg; // // CommandTail = FLAT(es:bx) // CommandTail = Sim32GetVDMPointer(((ULONG)ClientES << 16), 1, TRUE) + (*GetBXRegister)(); if (CurrentAppFlags & DPMI_32BIT) { // // CommandTail -> string // CommandTail = Sim32GetVDMPointer((*(PWORD16)(CommandTail + 4)) << 16, 1, TRUE) + *(PDWORD16)(CommandTail); } else { // // CommandTail -> string // CommandTail = Sim32GetVDMPointer(*(PDWORD16)(CommandTail + 2), 1, TRUE); } CopyMemory((LargeXlatBuffer + 0x10), CommandTail, 128); // // Set FCB pointers and put spaces in the file names // DPMI_FLAT_TO_SEGMENTED((LargeXlatBuffer + 144), &Seg, &Off) *(PWORD16)(LargeXlatBuffer + 6) = Off; *(PWORD16)(LargeXlatBuffer + 8) = Seg; for (i = 0; i < 11; i++) { (LargeXlatBuffer + 144 + 1)[i] = ' '; } DPMI_FLAT_TO_SEGMENTED((LargeXlatBuffer + 188), &Seg, &Off) *(PWORD16)(LargeXlatBuffer + 0xA) = Off; *(PWORD16)(LargeXlatBuffer + 0xC) = Seg; for (i = 0; i < 11; i++) { (LargeXlatBuffer + 188 + 1)[i] = ' '; } // // Save the environment selector, and make it a segment // Environment = Sim32GetVDMPointer(((ULONG)CurrentPSPSelector << 16) | 0x2C, 1, TRUE); EnvironmentSel = *(PWORD16)Environment; *(PWORD16)Environment = (USHORT)(SELECTOR_TO_INTEL_LINEAR_ADDRESS(EnvironmentSel) >> 4); // // Set up registers for the exec // DPMI_FLAT_TO_SEGMENTED(BufferedString, &Seg, &Off); setDS(Seg); setDX(Off); DPMI_FLAT_TO_SEGMENTED(LargeXlatBuffer, &Seg, &Off); setES(Seg); setBX(Off); DPMI_EXEC_INT(0x21); // // Restore the environment selector // Environment = Sim32GetVDMPointer(((ULONG)CurrentPSPSelector << 16) | 0x2C, 1, TRUE); *(PWORD16)Environment = EnvironmentSel; // // Free translation buffer // DpmiUnmapString(BufferedString, Length); } } setDX(ClientDX); setBX(ClientBX); DpmiSwitchToProtectedMode(); setES(ClientES); setDS(ClientDS); } VOID Terminate( VOID ) /*++ Routine Description: description-of-function. Arguments: argument-name - Supplies | Returns description of argument. . . Return Value: return-value - Description of conditions needed to return value. - or - None. --*/ { // bugbug We're currently mapping this one in the dos extender } VOID FindFirstFileHandle( VOID ) /*++ Routine Description: This routine translates the find first api. Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT ClientDX, Seg, Off, StringLength; PUCHAR BufferedString; USHORT ClientDS = getDS(); // // map the string // BufferedString = DpmiMapString(ClientDS, (GetDXRegister)(), &StringLength); if (BufferedString == NULL) { setCF(1); setAX(3); } else { DpmiSwitchToRealMode(); SetDTAPointers(); ClientDX = getDX(); // // Copy the DTA (if necessary) // if (CurrentDta != CurrentPmDtaAddress) { CopyMemory(CurrentDta, CurrentPmDtaAddress, 43); } // // Check to see if we need to set the real dta // if (CurrentDosDta != CurrentDta) SetDosDTA(); DPMI_FLAT_TO_SEGMENTED(BufferedString, &Seg, &Off); setDS(Seg); setDX(Off); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); setDS(ClientDS); DpmiUnmapString(BufferedString, StringLength); // // Copy the DTA back (if necessary) // if (CurrentDta != CurrentPmDtaAddress) { CopyMemory(CurrentPmDtaAddress, CurrentDta, 43); } setDX(ClientDX); } } VOID FindNextFileHandle( VOID ) /*++ Routine Description: This routine translates the find next api Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; DpmiSwitchToRealMode(); SetDTAPointers(); // // Copy the DTA (if necessary) // if (CurrentDta != CurrentPmDtaAddress) { CopyMemory(CurrentDta, CurrentPmDtaAddress, 43); } // // Check to see if we need to set the real dta // if (CurrentDosDta != CurrentDta) SetDosDTA(); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); // // Copy the DTA back (if necessary) // if (CurrentDta != CurrentPmDtaAddress) { CopyMemory(CurrentPmDtaAddress, CurrentDta, 43); } } VOID SetPSP( VOID ) /*++ Routine Description: This routine translates the set psp api. This is substantially the same as CreatePSP, except that this can fail (and return carry). It also remembers the PSP selector, so we can return it on request. Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; ULONG Segment; USHORT ClientBX; DpmiSwitchToRealMode(); ClientBX = getBX(); if (ClientBX == 0) { CurrentPSPSelector = ClientBX; } else { Segment = SELECTOR_TO_INTEL_LINEAR_ADDRESS(ClientBX); if (Segment > ONE_MB) { setCF(1); } else { setBX((USHORT) (Segment >> 4)); DPMI_EXEC_INT(0x21); CurrentPSPSelector = ClientBX; } } setBX(ClientBX); DpmiSwitchToProtectedMode(); } VOID GetPSP( VOID ) /*++ Routine Description: This routine returns the current PSP selector Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; DpmiSwitchToRealMode(); // // Get the current psp segment to see if it changed // DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); // // If it changed get a new selector for the psp // if (getBX() != (USHORT)(SELECTOR_TO_INTEL_LINEAR_ADDRESS(CurrentPSPSelector) >> 4) ){ CurrentPSPSelector = SegmentToSelector(getBX(), STD_DATA); } setBX(CurrentPSPSelector); setCF(0); } VOID TranslateBPB( VOID ) /*++ Routine Description: This function fails and returns. On NT we do not support this dos call. Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; #if DBG OutputDebugString("DPMI: Int 21 function 53 is not supported\n"); #endif setCF(1); } VOID RenameFile( VOID ) /*++ Routine Description: This routine translates the rename int 21 api Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; PUCHAR SourceString, DestinationString; USHORT ClientDX, ClientDI, Seg, Off, SourceLength, DestinationLength; USHORT ClientDS = getDS(); USHORT ClientES = getES(); SourceString = DpmiMapString(ClientDS, (*GetDXRegister)(), &SourceLength); if (SourceString == NULL) { setCF(1); setAX(3); } else { DestinationString = DpmiMapString(ClientES, (*GetDIRegister)(), &DestinationLength); if (DestinationString == NULL) { setCF(1); setAX(3); DpmiUnmapString(SourceString, SourceLength); } else { DpmiSwitchToRealMode(); ClientDX = getDX(); ClientDI = getDI(); DPMI_FLAT_TO_SEGMENTED(SourceString, &Seg, &Off); setDX(Off); setDS(Seg); DPMI_FLAT_TO_SEGMENTED(DestinationString, &Seg, &Off); setDI(Off); setES(Seg); DPMI_EXEC_INT(0x21); setDX(ClientDX); setDI(ClientDI); DpmiSwitchToProtectedMode(); setDS(ClientDS); setES(ClientES); DpmiUnmapString(SourceString, SourceLength); DpmiUnmapString(DestinationString, DestinationLength); } } } VOID CreateTempFile( VOID ) /*++ Routine Description: This function maps the int 21 create temp file api Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; PUCHAR String, BufferedString; USHORT ClientDX, Seg, Off, Length; USHORT ClientDS = getDS(); DpmiSwitchToRealMode(); ClientDX = getDX(); String = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetDXRegister)(); Length = 0; while (String[Length] != '\0') { Length++; } Length += 13; BufferedString = DpmiMapAndCopyBuffer(String, Length); DPMI_FLAT_TO_SEGMENTED(BufferedString, &Seg, &Off); setDS(Seg); setDX(Off); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); DpmiUnmapAndCopyBuffer(String, BufferedString, Length); setDX(ClientDX); setDS(ClientDS); } #define MAX_SUPPORTED_DOS_5D_CALL 12 APIXLATFUNCTION Func5DXlatTable[MAX_SUPPORTED_DOS_5D_CALL] = { NotSupportedBad , // 0 MapDPL , // 1 NotSupportedBad , // 2 MapDPL , // 3 MapDPL , // 4 NotSupportedBad , // 5 NotSupportedBad , // 6 NoTranslation , // 7 NoTranslation , // 8 NoTranslation , // 9 MapDPL , // 10 NotSupportedBad // 11 }; VOID Func5Dh( VOID ) /*++ Routine Description: This function translates dos call 5d Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT Func5DhMinor; Func5DhMinor = getAL(); if (Func5DhMinor >= MAX_SUPPORTED_DOS_5D_CALL) { #if DBG OutputDebugString("DPMI: DOS FUNCTION 5D UNSUPPORTED\n"); #endif NoTranslation(); return; } (*Func5DXlatTable[Func5DhMinor])(); } #define MAX_SUPPORTED_DOS_5E_CALL 4 APIXLATFUNCTION Func5EXlatTable[MAX_SUPPORTED_DOS_5E_CALL] = { GetMachineName, MapASCIIZDSDX, GetPrinterSetup, SetPrinterSetup }; VOID Func5Eh( VOID ) /*++ Routine Description: description-of-function. Arguments: argument-name - Supplies | Returns description of argument. . . Return Value: return-value - Description of conditions needed to return value. - or - None. --*/ { DECLARE_LocalVdmContext; USHORT Func5EhMinor; Func5EhMinor = getAL(); if (Func5EhMinor >= MAX_SUPPORTED_DOS_5E_CALL) { #if DBG OutputDebugString("DPMI: DOS FUNCTION 5E UNSUPPORTED\n"); #endif NoTranslation(); return; } (*Func5EXlatTable[Func5EhMinor])(); } VOID Func5Fh( VOID ) /*++ Routine Description: description-of-function. Arguments: argument-name - Supplies | Returns description of argument. . . Return Value: return-value - Description of conditions needed to return value. - or - None. --*/ { DECLARE_LocalVdmContext; USHORT Func5FMinor; Func5FMinor = getAL(); if (Func5FMinor == 4) { MapASCIIZDSSI(); return; } else if ((Func5FMinor == 2) || (Func5FMinor == 3) || (Func5FMinor == 5) ){ USHORT ClientSI, ClientDI, DataOff, DataSeg; PUCHAR Data16, BufferedData16, Data128, BufferedData128; USHORT ClientDS = getDS(); USHORT ClientES = getES(); DpmiSwitchToRealMode(); ClientDI = getDI(); ClientSI = getSI(); Data16 = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetSIRegister)(); BufferedData16 = DpmiMapAndCopyBuffer(Data16, 16); Data128 = Sim32GetVDMPointer(((ULONG)ClientES << 16), 1, TRUE) + (*GetDIRegister)(); BufferedData128 = DpmiMapAndCopyBuffer(Data128, 128); DPMI_FLAT_TO_SEGMENTED(BufferedData16, &DataSeg, &DataOff); setDS(DataSeg); setSI(DataOff); DPMI_FLAT_TO_SEGMENTED(BufferedData128, &DataSeg, &DataOff); setES(DataSeg); setDI(DataOff); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); DpmiUnmapAndCopyBuffer(Data16, BufferedData16, 16); DpmiUnmapAndCopyBuffer(Data128, BufferedData128, 128); setDS(ClientDS); setES(ClientES); setSI(ClientSI); setDI(ClientDI); } else { #if DBG OutputDebugString("DPMI: UNSUPPORTED INT 21 FUNCTION 5F\n"); #endif NoTranslation(); } } VOID NotSupportedBad( VOID ) /*++ Routine Description: description-of-function. Arguments: argument-name - Supplies | Returns description of argument. . . Return Value: return-value - Description of conditions needed to return value. - or - None. --*/ { #if DBG DECLARE_LocalVdmContext; DbgPrint("WARNING: DOS INT 21 call AX= %x will not be translated.\n", getAH()); DbgPrint(" Use of this call is not supported from Prot\n"); DbgPrint(" mode applications.\n"); #endif NoTranslation(); } VOID ReturnDSSI( VOID ) /*++ Routine Description: This function translates api that return information in ds:si Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT Selector; DpmiSwitchToRealMode(); DPMI_EXEC_INT(0x21); Selector = getDS(); DpmiSwitchToProtectedMode(); (*SetSIRegister)((ULONG)getSI()); setDS(SegmentToSelector(Selector, STD_DATA)); } VOID NotSupportedBetter( VOID ) /*++ Routine Description: description-of-function. Arguments: argument-name - Supplies | Returns description of argument. . . Return Value: return-value - Description of conditions needed to return value. - or - None. --*/ { #if DBG DECLARE_LocalVdmContext; DbgPrint("WARNING: DOS INT 21 call AX= %x will not be translated.", getAH()); DbgPrint(" Use of this call by a Prot Mode app is not"); DbgPrint(" appropriate. There is a better INT 21 call, or a"); DbgPrint(" Windows call which should be used instead of this."); #endif NoTranslation(); } VOID GetExtendedCountryInfo( VOID ) /*++ Routine Description: This routine translates the get extended country info int 21 api Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; PUCHAR Country, BufferedCountry; USHORT ClientDI, Seg, Off, Length; USHORT ClientES = getES(); DpmiSwitchToRealMode(); ClientDI = getDI(); Length = getCX(); Country = Sim32GetVDMPointer(((ULONG)ClientES << 16), 1, TRUE) + (*GetDIRegister)(); BufferedCountry = DpmiMapAndCopyBuffer(Country, Length); DPMI_FLAT_TO_SEGMENTED(BufferedCountry, &Seg, &Off); setES(Seg); setDI(Off); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); setES(ClientES); DpmiUnmapAndCopyBuffer(Country, BufferedCountry, Length); setDI(ClientDI); } VOID MapASCIIZDSSI( VOID ) /*++ Routine Description: This function translates the int 21 extended open call Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; PUCHAR BufferedString; USHORT ClientSI, StringSeg, StringOff, Length; USHORT ClientDS = getDS(); BufferedString = DpmiMapString(ClientDS, (*GetSIRegister)(), &Length); if (BufferedString == NULL) { setCF(1); setAX(3); } else { DpmiSwitchToRealMode(); ClientSI = getSI(); DPMI_FLAT_TO_SEGMENTED(BufferedString, &StringSeg, &StringOff); setDS(StringSeg); setSI(StringOff); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); DpmiUnmapString(BufferedString, Length); setSI(ClientSI); setDS(ClientDS); } } VOID MapDSDXLenCX( VOID ) /*++ Routine Description: This function maps the ioctl calls that pass data in DS:DX, with length in cx Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT ClientDX, ClientCX, DataSeg, DataOff; PUCHAR Data, BufferedData; USHORT ClientDS = getDS(); DpmiSwitchToRealMode(); ClientDX = getDX(); ClientCX = getCX(); Data = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetDXRegister)(); BufferedData = DpmiMapAndCopyBuffer(Data, ClientCX); DPMI_FLAT_TO_SEGMENTED(BufferedData, &DataSeg, &DataOff); setDS(DataSeg); setDX(DataOff); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); DpmiUnmapAndCopyBuffer(Data, BufferedData, ClientCX); setDS(ClientDS); setDX(ClientDX); } VOID IOCTLMap2Bytes( VOID ) /*++ Routine Description: description-of-function. Arguments: argument-name - Supplies | Returns description of argument. . . Return Value: return-value - Description of conditions needed to return value. - or - None. --*/ { DECLARE_LocalVdmContext; USHORT ClientDX, DataSeg, DataOff; PUCHAR Data, BufferedData; USHORT ClientDS = getDS(); DpmiSwitchToRealMode(); ClientDX = getDX(); Data = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetDXRegister)(); BufferedData = DpmiMapAndCopyBuffer(Data, 2); DPMI_FLAT_TO_SEGMENTED(BufferedData, &DataSeg, &DataOff); setDS(DataSeg); setDX(DataOff); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); DpmiUnmapAndCopyBuffer(Data, BufferedData, 2); setDS(ClientDS); setDX(ClientDX); } VOID IOCTLBlockDevs( VOID ) /*++ Routine Description: This function fails the block device ioctls Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT IoctlSubFunction, Seg, Off, ClientDX; PUCHAR Data, BufferedData; USHORT Length; USHORT ClientDS = getDS(); IoctlSubFunction = getCL(); if ((IoctlSubFunction < 0x40) || (IoctlSubFunction > 0x42) && (IoctlSubFunction < 0x60) || (IoctlSubFunction > 0x62) && (IoctlSubFunction != 0x68) ) { #if DBG OutputDebugString("DPMI: IOCTL DOS CALL NOT SUPPORTED\n"); #endif NoTranslation(); return; } // // Read and write track are special (and a pain) // if ((IoctlSubFunction == 0x41) || (IoctlSubFunction == 0x61)) { IoctlReadWriteTrack(); return; } DpmiSwitchToRealMode(); ClientDX = getDX(); Data = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetDXRegister)(); switch (IoctlSubFunction) { case 0x40: // // Map set device params // Length = (*(PWORD16)(Data + 0x26)); Length <<= 2; Length += 0x28; break; case 0x60: // // Map get device params // Length = 38; break; case 0x62: // // Map format verify // Length = 5; break; case 0x68: // // Map Media sense // Length = 4; break; } BufferedData = DpmiMapAndCopyBuffer(Data, Length); DPMI_FLAT_TO_SEGMENTED(BufferedData, &Seg, &Off); setDS(Seg); setDX(Off); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); DpmiUnmapAndCopyBuffer(Data, BufferedData, Length); setDS(ClientDS); setDX(ClientDX); } VOID IoctlReadWriteTrack( VOID ) /*++ Routine Description: This routine maps the read/write track ioctl. Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT ClientDX, ClientDS, ClientCX, ClientAX; USHORT Seg, Off, NumberOfSectors, BytesPerSector; USHORT SectorsRead, SectorsToRead; PUCHAR ParameterBlock, BufferedPBlock, Data, BufferedData; ClientAX = getAX(); ClientDX = getDX(); ClientCX = getCX(); ClientDS = getDS(); DpmiSwitchToRealMode(); // // Find out how many bytes/sector // BufferedData = DpmiAllocateBuffer(0x40); DPMI_FLAT_TO_SEGMENTED(BufferedData, &Seg, &Off); setDS(Seg); setDX(Off); setAX(0x440D); setCX(0x860); DPMI_EXEC_INT(0x21); if (getCF()) { // // Failed, we don't know how much data to buffer, // so fail read/write track // DpmiFreeBuffer(BufferedData, 0x40); setDX(ClientDX); setCX(ClientCX); DpmiSwitchToProtectedMode(); setDS(ClientDS); return; } // // Get the number of bytes/sector // BytesPerSector = *(PWORD16)(BufferedData + 0x7); DpmiFreeBuffer(BufferedData, 0x40); setDX(ClientDX); // // First map the parameter block // ParameterBlock = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetDXRegister)(); BufferedPBlock = DpmiMapAndCopyBuffer(ParameterBlock, 13); // // Get the segment and offset of the parameter block // DPMI_FLAT_TO_SEGMENTED(BufferedPBlock, &Seg, &Off); setDS(Seg); setDX(Off); if (CurrentAppFlags & DPMI_32BIT) { Data = Sim32GetVDMPointer( (*((PWORD16)(BufferedPBlock + 0xd)) << 16), 1, TRUE ); Data += *((PDWORD16)(BufferedPBlock + 0x9)); } else { Data = Sim32GetVDMPointer( (*((PWORD16)(BufferedPBlock + 0xb)) << 16), 1, TRUE ); Data += *((PWORD16)(BufferedPBlock + 0x9)); } NumberOfSectors = *((PWORD16)(BufferedPBlock + 7)); SectorsRead = 0; while (NumberOfSectors != SectorsRead) { if ((NumberOfSectors - SectorsRead) * BytesPerSector > 1024 * 4) { SectorsToRead = 4 * 1024 / BytesPerSector; } else { SectorsToRead = (USHORT)(NumberOfSectors - SectorsRead); } BufferedData = DpmiMapAndCopyBuffer( Data, (USHORT) (SectorsToRead * BytesPerSector) ); DPMI_FLAT_TO_SEGMENTED(BufferedData, &Seg, &Off); *((PWORD16)(BufferedPBlock + 9)) = Off; *((PWORD16)(BufferedPBlock + 11)) = Seg; *((PWORD16)(BufferedPBlock + 7)) = SectorsToRead; setAX(ClientAX); setCX(ClientCX); DPMI_EXEC_INT(0x21); if (getCF()) { DpmiUnmapBuffer( BufferedData, (USHORT) (SectorsToRead * BytesPerSector) ); break; } DpmiUnmapAndCopyBuffer( Data, BufferedData, (USHORT) (SectorsToRead * BytesPerSector) ); Data += SectorsToRead * BytesPerSector; *((PWORD16)(BufferedPBlock + 5)) += SectorsToRead; SectorsRead += SectorsToRead; } DpmiUnmapBuffer(BufferedPBlock,13); setDX(ClientDX); DpmiSwitchToProtectedMode(); setDS(ClientDS); } VOID MapDPL( VOID ) /*++ Routine Description: This routine maps a DPL for the server call Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT ClientDX, DataSeg, DataOff; PUCHAR Data, BufferedData; USHORT ClientDS = getDS(); DpmiSwitchToRealMode(); ClientDX = getDX(); Data = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetDXRegister)(); BufferedData = DpmiMapAndCopyBuffer(Data, 22); DPMI_FLAT_TO_SEGMENTED(BufferedData, &DataSeg, &DataOff); setDS(DataSeg); setDX(DataOff); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); DpmiUnmapAndCopyBuffer(Data, BufferedData, 22); setDX(ClientDX); setDS(ClientDS); } VOID GetMachineName( VOID ) /*++ Routine Description: This routine maps a machine name for int 21 function 5e Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT ClientDX, DataSeg, DataOff; PUCHAR Data, BufferedData; USHORT ClientDS = getDS(); DpmiSwitchToRealMode(); ClientDX = getDX(); Data = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetDXRegister)(); BufferedData = DpmiMapAndCopyBuffer(Data, 16); DPMI_FLAT_TO_SEGMENTED(BufferedData, &DataSeg, &DataOff); setDS(DataSeg); setDX(DataOff); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); DpmiUnmapAndCopyBuffer(Data, BufferedData, 16); setDX(ClientDX); setDS(ClientDS); } VOID GetPrinterSetup( VOID ) /*++ Routine Description: This routine maps printer setup data for int 21 function 5e Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT ClientSI, ClientCX, DataSeg, DataOff; PUCHAR Data, BufferedData; USHORT ClientDS = getDS(); DpmiSwitchToRealMode(); ClientSI = getSI(); ClientCX = getCX(); Data = Sim32GetVDMPointer(((ULONG)ClientDS << 16), 1, TRUE) + (*GetSIRegister)(); BufferedData = DpmiMapAndCopyBuffer(Data, ClientCX); DPMI_FLAT_TO_SEGMENTED(BufferedData, &DataSeg, &DataOff); setDS(DataSeg); setSI(DataOff); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); DpmiUnmapAndCopyBuffer(Data, BufferedData, ClientCX); setSI(ClientSI); setDS(ClientDS); } VOID SetPrinterSetup( VOID ) /*++ Routine Description: This routine maps printer setup data for int 21 function 5e Arguments: None. Return Value: None. --*/ { DECLARE_LocalVdmContext; USHORT ClientDI, DataSeg, DataOff; PUCHAR Data, BufferedData; USHORT ClientES = getES(); DpmiSwitchToRealMode(); ClientDI = getDI(); Data = Sim32GetVDMPointer(((ULONG)ClientES << 16), 1, TRUE) + (*GetDIRegister)(); BufferedData = DpmiMapAndCopyBuffer(Data, 64); DPMI_FLAT_TO_SEGMENTED(BufferedData, &DataSeg, &DataOff); setES(DataSeg); setDI(DataOff); DPMI_EXEC_INT(0x21); DpmiSwitchToProtectedMode(); setES(ClientES); DpmiUnmapAndCopyBuffer(Data, BufferedData, 64); setDI(ClientDI); } VOID GetDate( VOID ) /*++ Routine Description: This routine maps int21 func 2A GetDate Arguments: None. Return Value: Client (DH) - month Client (DL) - Day Client (CX) - Year Client (AL) - WeekDay --*/ { DECLARE_LocalVdmContext; SYSTEMTIME TimeDate; GetLocalTime(&TimeDate); setDH((UCHAR)TimeDate.wMonth); setDL((UCHAR)TimeDate.wDay); setCX(TimeDate.wYear); setAL((UCHAR)TimeDate.wDayOfWeek); }