PAGE 58,132 ;****************************************************************************** TITLE SAGE - SAGE VxD ;****************************************************************************** ; ; Title: SAGE.ASM - SAGE VxD ; ; Version: 0.060 ; ; Date: 04/18/95 ; ; Author: Bob Eichenlaub ; ;------------------------------------------------------------------------------ ; ; Change log: ; ; DATE REV DESCRIPTION ; ----------- --- ----------------------------------------------------------- ; 04/18/95 Initial version - be ; 07/06/95 serial IRQ detection - be; credit to rjc for the basic approach ; 05/23/97 [darrenmi] major clean-up and support multiple clients ; for IE4 ; ;============================================================================== .386p ;****************************************************************************** ; I N C L U D E S ;****************************************************************************** .XLIST INCLUDE VMM.Inc INCLUDE VWIN32.Inc INCLUDE VPICD.Inc WIN41SERVICES equ 1 ; need _SHELL_Update_User_Activity_Ex service INCLUDE SHELL.Inc INCLUDE VXDLDR.Inc INCLUDE regdef.Inc INCLUDE Debug.Inc INCLUDE Sage.Inc .LIST ;public SAGE_Update_User_Activity ;****************************************************************************** ; V I R T U A L D E V I C E D E C L A R A T I O N ;------------------------------------------------------------------------------ ; The VxD declaration statement defines the VxD name, version number, ; control proc entry point, VxD ID, initialization order, and VM API ; entry points. ; ; - Defined VxD ID: See VXDID.TXT for more information ; - Init order: If serial port detection is enabled then this Vxd MUST loaded ; before VCOMM.VxD and after VPICD.VxD, ; See VMM.INC for the complete ; definition of the init order of the standard devices. ; ;****************************************************************************** Declare_Virtual_Device sage, 1, 0, SAGE_Control, VSageID, UNDEFINED_INIT_ORDER ;****************************************************************************** ; D A T A ;****************************************************************************** ; ; Locked data ; VxD_LOCKED_DATA_SEG Window_List dd 0, 0, 0, 0, 0, 0, 0, 0 cClients dd 0 ; number of valid windows in window list Time_Out_Idle dd 10000 ; the interval between message posts Time_Out_Handle dd 0 ; Handle to the global time out we create PtrSHELL_SUUAE_INFO dd 0 ; pointer to the SHELL_SUUAE_INFO structure PrevActiveDisplay dd 0 ; last screen or user input activity PrevActiveSystem dd 0 ; last system activity Hooked_Proc dd 0 ; shell's user_activity entry that we hooked ; Fake user activity info structure in case on Win95. FakeSUUAE_INFO _SHELL_SUUAE_INFO <0,0,0,0,0> VxD_LOCKED_DATA_ENDS ;****************************************************************************** ; C O D E ;------------------------------------------------------------------------------ ; The 'body' of the VxD is in the standard code segment. ;****************************************************************************** VxD_CODE_SEG BeginProc SAGE_Start_Idle_Timer push esi ; check to see if we've already got a timer mov esi, [Time_Out_Handle] test esi, esi jnz start1 ; get a timer mov eax, [Time_Out_Idle] mov esi, OFFSET32 SAGE_User_Idle_Check VMMCall Set_Global_Time_Out mov [Time_Out_Handle], esi start1: pop esi ret EndProc SAGE_Start_Idle_Timer BeginProc SAGE_Stop_Idle_Timer push esi ; check to see if we have a timer mov esi, [Time_Out_Handle] test esi, esi jz stop1 ; kill it VMMCall Cancel_Time_Out xor esi, esi mov [Time_Out_Handle], esi stop1: pop esi ret EndProc SAGE_Stop_Idle_Timer ;****************************************************************************** ; ; SAGE_Device_IO ; ; DESCRIPTION: ; This is the routine that is called when the CreateFile or ; DeviceIoControl is made ; ; ENTRY: ; ESI = Pointer to args (see VWIN32.INC for struct definition) ; ; EXIT: ; EAX = return value ; ; USES: ; flags ; ;============================================================================== BeginProc SAGE_Device_IO mov ecx, [esi.dwIOControlCode] test ecx, ecx jnz next1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; DIOC_GETVERSION ; ; obtain a pointer to the shell vxd's activity timer info cmp [PtrSHELL_SUUAE_INFO], 0 jne short getver1 VxDCall SHELL_Get_Version cmp eax, 040Ah jae short haveSUUAEX ; Running on Win95 so we don't have SHELL_Update_User_Activty_Ex service, ; hook the shell vxd's activity service to watch activity. mov esi, offset32 SAGE_Update_User_Activity GetVxDServiceOrdinal eax, SHELL_Update_User_Activity VMMCall Hook_Device_Service mov eax, offset32 FakeSUUAE_INFO jmp short setSUUAE_INFO haveSUUAEX: VxDCall _SHELL_Update_User_Activity_Ex, setSUUAE_INFO: mov [PtrSHELL_SUUAE_INFO], eax ; (eax) = ptr to SHELL_SUAAE_INFO structure getver1: xor eax, eax ; success ret next1: cmp ecx,-1 jne next2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; DIOC_CLOSE ; ; see if we have clients to close cmp [cClients], 0 jz close1 ; we do... see if it's the last one... dec [cClients] cmp [cClients], 0 jnz close1 ; last client going away - clean up call SAGE_Stop_Idle_Timer cmp [PtrSHELL_SUUAE_INFO], offset32 FakeSUUAE_INFO jne short close1 ; unhook activity service GetVxDServiceOrdinal eax,SHELL_Update_User_Activity mov esi, offset32 SAGE_Update_User_Activity VMMCall Unhook_Device_Service xor eax, eax mov [PtrSHELL_SUUAE_INFO], eax ; clear pointer close1: xor eax,eax ; success ret next2: cmp ecx,1 jne next3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Set handle and timeout ; mov ebx, [esi.lpvInBuffer] ; Try to find window handle mov eax, [ebx] mov ecx, [cClients] test ecx, ecx jz addtolist ioloop: cmp eax, [Window_List + 4 * ecx - 4] je timeout dec ecx jnz ioloop ; Can't find it - add it to window list mov ecx, [cClients] cmp ecx, 8 jnl timeout addtolist: inc [cClients] mov [Window_List + 4 * ecx], eax timeout: ; update timeout if specified mov eax, [ebx+8] test eax, eax jz config1 mov [Time_Out_Idle], eax config1: call SAGE_Start_Idle_Timer xor eax, eax ; success ret next3: cmp ecx, 2 jne next4 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Query last activity ; mov ebx, [esi.lpvInBuffer] mov edx, [PtrSHELL_SUUAE_INFO] .errnz ssiHoldSystem-ssiHoldDisplay-1 cmp word ptr [edx].ssiHoldDisplay, 0 jne short lact1 ; system or display in "hold" state mov eax, [edx].ssiTimeLastActiveDisplay cmp eax, [edx].ssiTimeLastActiveSystem jae short lact2 mov eax, [edx].ssiTimeLastActiveSystem jmp short lact2 lact1: VMMCall Get_Last_Updated_System_Time lact2: mov [ebx], eax xor eax, eax ret next4: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; some unsupported value... ; mov eax, ERROR_NOT_SUPPORTED ret EndProc SAGE_Device_IO VxD_CODE_ENDS ;****************************************************************************** ; P A G E L O C K E D C O D E ;------------------------------------------------------------------------------ ; Memory is a scarce resource. Use this only where necessary. ;****************************************************************************** VxD_LOCKED_CODE_SEG ;****************************************************************************** ; ; SAGE_Control ; ; DESCRIPTION: ; ; This is a call-back routine to handle the messages that are sent ; to VxD's to control system operation. Every VxD needs this function ; regardless if messages are processed or not. The control proc must ; be in the LOCKED code segment. ; ; The Control_Dispatch macro used in this procedure simplifies ; the handling of messages. To handle a particular message, add ; a Control_Dispatch statement with the message name, followed ; by the procedure that should handle the message. ; ; ENTRY: ; EAX = Message number ; EBX = VM Handle ; ;============================================================================== BeginProc SAGE_Control Control_Dispatch W32_DEVICEIOCONTROL, SAGE_Device_IO clc ret EndProc SAGE_Control BeginDoc ;****************************************************************************** ; ; SAGE_Update_User_Activity ; ; DESCRIPTION: ; ; This service is called by VMD, VKD to tell us that user input occured ; ENTRY: None ; EXIT: None ; USES: NONE ;============================================================================== EndDoc BeginProc SAGE_Update_User_Activity, HOOK_PROC, Hooked_Proc push eax ; save off the time VMMCall Get_Last_Updated_System_Time mov [FakeSUUAE_INFO.ssiTimeLastActiveDisplay], eax pop eax jmp Hooked_Proc EndProc SAGE_Update_User_Activity VxD_LOCKED_CODE_ENDS VxD_PAGEABLE_CODE_SEG ;****************************************************************************** ; ; SAGE_User_Idle_Check ; ; DESCRIPTION: ; ; This checks if key/mouse or serial port (comm) event has occurred. ; ; Entry: ; None ; Exit: ; None ; Uses: ; ALL ;****************************************************************************** BeginProc SAGE_User_Idle_Check,High_Freq,PUBLIC ; ; clear handle ; xor ecx, ecx mov [Time_Out_Handle], ecx ; ; check for idleness ; mov eax, [PtrSHELL_SUUAE_INFO] ; (eax) = ptr to SHELL_SUAAE_INFO structure .errnz ssiHoldSystem-ssiHoldDisplay-1 cmp word ptr [eax].ssiHoldDisplay, 0 jne short holdActive ; system or display in "hold" state mov ecx, [eax].ssiTimeLastActiveDisplay mov edx, [eax].ssiTimeLastActiveSystem cmp ecx, [PrevActiveDisplay] jne notIdle ; display activity changed cmp edx, [PrevActiveSystem] je ResetTimer ; no display or system activity since last time ; ; Not idle so post a message to all clients who want to know ; notIdle: mov [PrevActiveDisplay], ecx ; update idle times for next time mov [PrevActiveSystem], edx holdActive: xor eax, eax mov ecx, [cClients] test ecx, ecx jz ResetTimer loop0: ; get next window mov ebx, [4 * ecx + Window_List - 4] ; skip if it's -1 cmp ebx, -1 je loop1 ; post message push ecx VxDCall _SHELL_PostMessage, pop ecx loop1: dec ecx jnz loop0 ; ; reset the timer so we check again later ; ResetTimer: call SAGE_Start_Idle_Timer ret EndProc SAGE_User_Idle_Check VxD_PAGEABLE_CODE_ENDS ;****************************************************************************** ; R E A L M O D E C O D E ;****************************************************************************** ;****************************************************************************** ; ; Real mode initialization code ; ; DESCRIPTION: ; This code is called when the system is still in real mode, and ; the VxDs are being loaded. ; ; This routine as coded shows how a VxD (with a defined VxD ID) ; could check to see if it was being loaded twice, and abort the ; second without an error message. Note that this would require ; that the VxD have an ID other than Undefined_Device_ID. See ; the file VXDID.TXT more details. ; ; ENTRY: ; AX = VMM Version ; BX = Flags ; Bit 0: duplicate device ID already loaded ; Bit 1: duplicate ID was from the INT 2F device list ; Bit 2: this device is from the INT 2F device list ; EDX = Reference data from INT 2F response, or 0 ; SI = Environment segment, passed from MS-DOS ; ; EXIT: ; BX = ptr to list of pages to exclude (0, if none) ; SI = ptr to list of instance data items (0, if none) ; EDX = DWORD of reference data to be passed to protect mode init ; ;============================================================================== VxD_REAL_INIT_SEG BeginProc SAGE_Real_Init_Proc test bx, Duplicate_Device_ID ; check for already loaded jnz short duplicate ; jump if so xor bx, bx ; no exclusion table xor si, si ; no instance data table xor edx, edx ; no reference data mov ax, Device_Load_Ok ret duplicate: mov ax, Abort_Device_Load + No_Fail_Message ret EndProc SAGE_Real_Init_Proc VxD_REAL_INIT_ENDS END