windows-nt/Source/XPSP1/NT/shell/ext/msidle/sage/sage.asm
2020-09-26 16:20:57 +08:00

525 lines
16 KiB
NASM

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, <SUUAE_CONTINUOUS OR SUUAE_CONTINUOUS_CHECK>
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, <ebx, WM_SAGE_MSG, eax, eax, eax, eax>
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