home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / msysjour / vol07 / 01 / tsr / template.asm
Assembly Source File  |  1991-12-31  |  70KB  |  1,473 lines

  1.                 page    66,132
  2. ;=============================================================================
  3. ; TEMPLATE - A template for a Terminate and stay resident program
  4. ;
  5. ; Written by Douglas Boling
  6. ;
  7. ; Revision History
  8. ;
  9. ;    1.0   Initial Release
  10. ;
  11. ;=============================================================================
  12. ;----------------------------------------------------------------------------
  13. ; BIOS Data segment
  14. ;----------------------------------------------------------------------------
  15. bios_data       segment at 40h
  16.                 org     17h
  17. shift_state     db      ?                       ;State of keyboard shift keys
  18.                 org     4Eh
  19. video_buffoff   dw      ?                       ;Offset of video buffer
  20.                 org     63h
  21. video_ioregs    dw      ?                       ;I/O addr of video controller
  22.                 org     84h
  23. video_rows      db      ?                       ;Number of rows on the screen
  24. bios_data       ends
  25. ;----------------------------------------------------------------------------
  26. ; CODE segment
  27. ;----------------------------------------------------------------------------
  28. code            segment para public 'code'
  29.                 assume  cs:code
  30.  
  31. POPTIME         EQU     18                      ;Ticks allowed until popup
  32. RESSTACKSIZE    EQU     512                     ;Size of resident stack
  33.  
  34.                 org     80h
  35. command_tail    db      ?
  36.                 org     100h
  37. begin:          jmp     initialize
  38.  
  39. program         db      "Template 1.0 (c) 1992 Douglas Boling",13,10
  40.                 db      "Written by Douglas Boling$",26
  41. ;-----------------------------------------------------------------------------
  42. ; Memory locations required for system overhead.
  43. ;-----------------------------------------------------------------------------
  44. hotshift        db      0ah                     ;Shift combination for TSR
  45.                                                 ;  <Alt> <Left shift>
  46.                                                 ; bit      key
  47.                                                 ;  0       R Shift
  48.                                                 ;  1       L Shift
  49.                                                 ;  2       Ctrl
  50.                                                 ;  3       Alt
  51. dos_version     dw      0                       ;DOS version number
  52. mouse_flag      db      0                       ;Mouse driver present
  53. resident_sp     dw      0                       ;Resident stack pointer
  54.  
  55. ems_flag        db      0                       ;Use expanded memory
  56. ems_segment     dw      0                       ;EMS page frame segment
  57. ems_version     db      0                       ;Version of EMS manager
  58.  
  59. ems_handle      dw      0                       ;EMS handle used
  60.  
  61. xms_flag        db      0                       ;Extended memory available
  62. xms_service     dd      -1                      ;Entry pt for XMS manager
  63. xms_version     db      0                       ;Version of XMS manager
  64.  
  65. indos_ptr       dd      -1                      ;Pointer to INDOS flag
  66. criterr_ptr     dd      -1                      ;Pointer to DOS crit err flag
  67.  
  68. int08h          dd      -1                      ;Int 2f vector (Timer)
  69. int09h          dd      -1                      ;Int 09 vector (Keyboard HW)
  70. int10h          dd      -1                      ;Int 10 vector (Video BIOS)
  71. int13h          dd      -1                      ;Int 13 vector (Disk BIOS)
  72. int16h          dd      -1                      ;Int 16 vector (BIOS Keyboard)
  73. int28h          dd      -1                      ;Int 28 vector (DOS Idle)
  74. int2Fh          dd      -1                      ;Int 2F vector (DOS Multiplex)
  75.  
  76. int08_active    db      0                       ;Interrupt active flag
  77. int09_active    db      0                       ;Interrupt active flag
  78. int10_active    db      0                       ;Interrupt active flag
  79. int13_active    db      0                       ;Interrupt active flag
  80. int16_active    db      0                       ;Interrupt active flag
  81. int28_active    db      0                       ;Interrupt active flag
  82. int2F_active    db      0                       ;Interrupt active flag
  83.  
  84. SWNotifyJT      dw      offset SWNInit          ;Jump table used by switcher
  85.                 dw      offset SWNQSuspend      ;  notification routine.
  86.                 dw      offset SWNSuspend
  87.                 dw      offset SWNActivate
  88.                 dw      offset SWNActive
  89.                 dw      offset SWNCSession
  90.                 dw      offset SWNDSession
  91.                 dw      offset SWNExit
  92. ;----------------------------------------------------------------------------
  93. ;Switcher global data structures
  94. ;----------------------------------------------------------------------------
  95. StartupInfo     =       $
  96.  sisVersion     dw      3                       ;Switcher structure ID
  97.  sisNextDev     dd      0                       ;Ptr to prev startup structure
  98.  sisVirtDevFile dd      0                       ;Ptr to name of opt dev drvr
  99.  sisReferenceData dd    0                       ;Data for Win dev drivr
  100.  sisInstData    dd      0                       ;Ptr to instance mem list
  101.  
  102. InstItem1       dd      0                       ;Ptr to instance data
  103. InstSize1       dw      0                       ;Size of instance data
  104. InstItem2       dd      0                       ;Ptr to instance stack
  105. InstSize2       dw      0                       ;Size of instance stack
  106.                 dd      0                       ;Ptr to next block = 0 to
  107.                 dw      0                       ;  terminate list
  108. ;============================================================================
  109. ;Instance data
  110. ;============================================================================
  111. TSRInstData     =       $
  112. ;----------------------------------------------------------------------------
  113. ;Switcher instance data structures
  114. ;----------------------------------------------------------------------------
  115. SWService       dd      0                       ;Ptr to switcher service rtn
  116.  
  117. CallbackInfo    =       $
  118.  scbiNext       dd      0                       ;Ptr to prev callback struc
  119.  scbiEntryPoint dd      0                       ;Ptr to local callback proc
  120.  scbiReserved   dd      0                       ;Reserved
  121.  scbiAPI        dd      0                       ;Ptr to info structures
  122.  
  123. SwapInfo        =       $
  124.                 dw      0                       ;Zero swapinfo structure
  125.                 dw      0                       ;  since no API support
  126.                 dw      0                       ;  implimented by the TSR
  127.                 dw      0
  128.                 dw      0
  129.  
  130. ;----------------------------------------------------------------------------
  131. ;DOS State information
  132. ;----------------------------------------------------------------------------
  133. saved_dta       dd      0                       ;saved pointer to curr DTA
  134. saved_psp       dw      0                       ;saved segment of curr PSP
  135. ss_register     dw      0                       ;SS register
  136. sp_register     dw      0                       ;SP register
  137.  
  138. shift_save      db      0                       ;Keyboard shift lock state
  139. A20_state       dw      0                       ;Saved state of A20 line
  140.  
  141. mem_alloc       dw      0                       ;DOS memory allocation strat
  142. linkflag        db      0                       ;DOS UMB link flag
  143.  
  144. curr_disk       db      0                       ;Default disk at popup
  145. curr_dir        db      64 dup (0)              ;Default directory at popup
  146.  
  147. errinfoarray:
  148. errAX           dw      0                       ;Saved extended error info
  149. errBX           dw      0
  150. errCX           dw      0
  151. errDX           dw      0
  152. errSI           dw      0
  153. errDI           dw      0
  154. errDS           dw      0
  155. errES           dw      0
  156.                 dw      3 dup (0)               ;Reserved error table bytes
  157.  
  158. vector1bh       dd      0                       ;int 1Bh vector (Break)
  159. vector23h       dd      0                       ;int 23h vector (Ctrl-C)
  160. vector24h       dd      0                       ;int 24h vector (Crit err)
  161.  
  162. ;----------------------------------------------------------------------------
  163. ;TSR State information
  164. ;----------------------------------------------------------------------------
  165. popflag         db      0                       ;Request flag/timer
  166. main_active     db      0                       ;TSR active flag
  167. no_switch       dw      0                       ;Flag indicating switch OK
  168. ret_addr        dw      0                       ;Saved return addr for calls
  169. win_enhanced    db      0                       ;Enhanced mode windows flag
  170. TSRInstDataEnd  =       $
  171.  
  172. ;============================================================================
  173. ; VIDEOINT processes BIOS video services interrupt (Int 10h)
  174. ;============================================================================
  175. videoint        proc    far
  176.                 assume  cs:code,ds:nothing,es:nothing
  177.                 inc     cs:int10_active
  178.                 pushf
  179.                 call    cs:[int10h]             ;Call old int
  180.                 dec     cs:int10_active
  181.                 iret                            ;Return
  182. videoint        endp
  183.  
  184. ;=============================================================================
  185. ; DISKINT receives control when an interrupt 13h is generated.
  186. ;=============================================================================
  187. diskint         proc    far
  188.                 assume  cs:code,ds:nothing,es:nothing
  189.                 pushf                           ;save flags register
  190.                 inc     cs:int13_active         ;set disk access flag
  191.                 call    cs:[int13h]
  192.                 pushf                           ;save flags again
  193.                 dec     cs:int13_active         ;reset disk access flag
  194.                 popf                            ;restore flags
  195.                 ret     2                       ;exit with flags intact
  196. diskint         endp
  197.  
  198. ;============================================================================
  199. ; BIOSKEYINT processes the BIOS keyboard services
  200. ;============================================================================
  201. bioskeyint      proc    far
  202.                 assume  cs:code,ds:nothing,es:nothing
  203.                 pushf                           ;save flags register
  204.                 inc     cs:int16_active         ;set keyboard active flag
  205.                 call    cs:[int16h]
  206.                 pushf                           ;save flags again
  207.                 dec     cs:int16_active         ;reset keyborard avtive flag
  208.                 popf                            ;restore flags
  209.                 ret     2                       ;exit with flags intact
  210. bioskeyint      endp
  211.  
  212. ;============================================================================
  213. ; TIMERINT processes timer interrupt (Int 08h)
  214. ;============================================================================
  215. timerint        proc    far
  216.                 assume  cs:code,ds:nothing,es:nothing
  217.                 pushf
  218.                 call    cs:[int08h]             ;Call old int 8
  219.  
  220.                 cmp     cs:int08_active,0       ;See if we are in this
  221.                 jne     timerint_exit           ;  routine already
  222.  
  223.                 cmp     cs:popflag,0            ;See if we need to try to
  224.                 jne     timer_check             ;  pop up
  225. timerint_exit:
  226.                 iret                            ;Return
  227. timer_check:
  228.                 push    ax
  229.                 inc     cs:int08_active         ;Set int active flag
  230.  
  231.                 call    check_system            ;See if system OK to pop up
  232.                 or      ax,ax
  233.                 jne     timerint_dec
  234.                 call    main                    ;Call the TSR
  235.                 mov     cs:popflag,1
  236. timerint_dec:
  237.                 dec     cs:popflag
  238.                 dec     cs:int08_active         ;Clear int active flag
  239.                 pop     ax
  240.                 jmp     short timerint_exit
  241. timerint        endp
  242.  
  243. ;============================================================================
  244. ; KEYINT processes keyboard interrupts (Int 09h)
  245. ;============================================================================
  246. keyint          proc    far
  247.                 assume  cs:code,ds:nothing,es:nothing
  248.                 pushf
  249.                 call    cs:[int09h]             ;Call old int 9
  250.  
  251.                 push    ax
  252.                 push    ds
  253.                 mov     ax,40h
  254.                 mov     ds,ax                   ;Set ES to bios data segment
  255.                 assume  ds:bios_data
  256.                 mov     al,ds:[shift_state]
  257.                 and     al,0fh                  ;Mask lock bits
  258.                 cmp     al,cs:[hotshift]
  259.                 pop     ds
  260.                 pop     ax
  261.                 je      keyint_hotkey
  262. keyint_exit:
  263.                 iret                            ;Return
  264. keyint_hotkey:
  265.                 mov     cs:popflag,POPTIME      ;Set timer to pop up
  266.                 jmp     short keyint_exit
  267. keyint          endp
  268.  
  269. ;============================================================================
  270. ; IDLEINT processes DOS Idle interrupt (Int 28h)
  271. ;============================================================================
  272. idleint         proc    far
  273.                 assume  cs:code,ds:nothing,es:nothing
  274.                 pushf
  275.                 call    cs:[int28h]             ;Call old int
  276.  
  277.                 cmp     cs:int28_active,0       ;See if we are in this
  278.                 jne     idleint_exit            ;  routine already
  279.                 cmp     cs:popflag,0            ;See if we need to try to
  280.                 jne     idle_check              ;  pop up
  281. idleint_exit:
  282.                 iret                            ;Return
  283. idle_check:
  284.                 push    ax
  285.                 inc     cs:int28_active         ;Set int active flag
  286.                 call    check_system            ;See if OK to pop up.  Ignore
  287.                 or      al,al                   ;  INDOS since in idle.
  288.                 jne     idleint_exit1
  289.                 mov     cs:popflag,0            ;Clear popup flag
  290.                 call    main                    ;Call the TSR
  291. idleint_exit1:
  292.                 dec     cs:int28_active         ;Clear int active flag
  293.                 pop     ax
  294.                 jmp     short idleint_exit
  295. idleint         endp
  296.  
  297. ;============================================================================
  298. ; MUXINT processes the DOS Multiplex interrupt
  299. ;============================================================================
  300. muxint          proc    far
  301.                 assume  cs:code,ds:nothing,es:nothing
  302.  
  303.                 cmp     ax,1605h                ;See if Windows start
  304.                 je      init_win
  305.                 cmp     ax,4b05h                ;See if switcher get instance
  306.                 je      init_instance           ;  data.
  307.                 cmp     ax,4b01h                ;See if switcher build chain
  308.                 je      chain_init
  309. muxint_jmp:
  310.                 jmp     cs:[int2fh]             ;Call old int
  311. close_win:
  312.                 test    dx,01h                  ;See if enhanced mode Windows
  313.                 jne     muxint_jmp
  314.                 dec     cs:win_enhanced         ;Clear enhanced mode flag
  315.                 jmp     short muxint_jmp
  316. init_win:
  317.                 test    dx,01h                  ;See if enhanced mode Windows
  318.                 jne     init_instance
  319.                 inc     cs:win_enhanced
  320. init_instance:
  321.                 pushf
  322.                 call    cs:[int2fh]             ;Call old int
  323.                 mov     word ptr cs:[sisNextDev],bx
  324.                 mov     word ptr cs:[sisNextDev+2],es
  325.                 push    cs                      ;ES:BX point to switcher struc
  326.                 pop     es
  327.                 mov     bx,offset StartupInfo
  328.                 jmp     short muxint_exit
  329. chain_init:
  330.                 pushf
  331.                 call    cs:[int2fh]             ;Call old int
  332.                 mov     word ptr cs:[scbiNext],bx
  333.                 mov     word ptr cs:[scbiNext+2],es
  334.                 push    cs                      ;ES:BX point to switcher struc
  335.                 pop     es
  336.                 mov     bx,offset CallbackInfo
  337. muxint_exit:
  338.                 iret
  339. muxint          endp
  340.  
  341. ;---------------------------------------------------------------------------
  342. ; Check System Determines if the system is in a state compatible with TSRs
  343. ; Exit: CF - Clear if OK to pop up
  344. ;---------------------------------------------------------------------------
  345. check_system    proc    near
  346.                 assume  cs:code,ds:nothing,es:nothing
  347.                 push    bx
  348.                 push    ds
  349.                 xor     ax,ax
  350.                 or      al,cs:int10_active      ;Check BIOS video int
  351.                 or      al,cs:int13_active      ;Check BIOS disk int
  352.                 or      al,cs:int16_active      ;Check BIOS keyboard int
  353.                 lds     bx,cs:criterr_ptr       ;Check DOS critical error
  354.                 or      al,byte ptr ds:[bx]     ;  flag
  355.                 lds     bx,cs:indos_ptr         ;Check INDOS flag
  356.                 mov     ah,byte ptr ds:[bx]
  357. check_sys_exit:
  358.                 pop     ds
  359.                 pop     bx
  360.                 ret
  361. check_system    endp
  362.  
  363. ;=============================================================================
  364. ; CRITICALERR receives control when an interrupt 24h is generated.
  365. ;=============================================================================
  366. criticalerr     proc    far
  367.                 assume  cs:code,ds:nothing,es:nothing
  368.                 xor     al,al                   ;Default to ignore
  369.                 cmp     cs:dos_version,30ah     ;See if before DOS 3.1
  370.                 jl      critical1
  371.                 add     al,3
  372. critical1:
  373.                 iret
  374. criticalerr     endp
  375.  
  376. ;=============================================================================
  377. ; MAIN
  378. ;=============================================================================
  379. main            proc    near
  380.                 assume  cs:code,ds:nothing,es:nothing
  381.                 cli
  382.                 inc     cs:no_switch            ;Don't allow switch
  383.                 inc     cs:[main_active]        ;set program status flag
  384.                 mov     cs:ss_register,ss       ;save SS and SP registers
  385.                 mov     cs:sp_register,sp
  386.                 mov     ax,cs                   ;switch to internal stack
  387.                 mov     bx,resident_sp
  388.                 mov     ss,ax
  389.                 mov     sp,bx
  390.                 dec     cs:no_switch
  391.                 sti                             ;enable interrupts
  392.                 call    save_regs               ;save all registers
  393.                 assume  ds:code,es:nothing
  394. ;-----------------------------------------------------------------------------
  395. ;Point the interrupt 1Bh, 23h, and 24h vectors to internal handlers.
  396. ;-----------------------------------------------------------------------------
  397.                 mov     ax,351bh                ;get and save 1Bh vector
  398.                 int     21h
  399.                 mov     word ptr vector1bh,bx
  400.                 mov     word ptr vector1bh[2],es
  401.                 mov     ax,251bh                ;point interrupt to IRET
  402.                 mov     dx,offset idleint_exit
  403.                 int     21h
  404.  
  405.                 mov     ax,3523h                ;get and save 23h vector
  406.                 int     21h
  407.                 mov     word ptr vector23h,bx
  408.                 mov     word ptr vector23h[2],es
  409.                 mov     ax,2523h                ;Set to IRET
  410.                 mov     dx,offset idleint_exit
  411.                 int     21h
  412.  
  413.                 mov     ax,3524h                ;get and save 24h vector
  414.                 int     21h
  415.                 mov     word ptr vector24h,bx
  416.                 mov     word ptr vector24h[2],es
  417.                 mov     ax,2524h                ;point interrupt to internal
  418.                 mov     dx,offset criticalerr   ;  critical error handler
  419.                 int     21h
  420. ;-----------------------------------------------------------------------------
  421. ;Save and switch to internal PSP
  422. ;-----------------------------------------------------------------------------
  423.                 mov     ah,51h                  ;Get current PSP
  424.                 call    dospspcall              ;Beware DOS 2.0 - 3.0
  425.                 mov     saved_psp,bx            ;save it
  426.                 push    cs
  427.                 pop     bx
  428.                 mov     ah,50h                  ;Set internal PSP
  429.                 call    dospspcall
  430. ;-----------------------------------------------------------------------------
  431. ;Save and switch to internal DTA
  432. ;-----------------------------------------------------------------------------
  433.                 mov     ah,2fh
  434.                 int     21h                     ;Get current DTA
  435.                 mov     word ptr saved_dta,bx   ;save it
  436.                 mov     word ptr saved_dta[2],es
  437.                 mov     dx,offset command_tail  ;use PSP for DTA
  438.                 mov     ah,1ah                  ;Set DTA
  439.                 int     21h
  440. ;-----------------------------------------------------------------------------
  441. ;If DOS  3.x, save extended error information.
  442. ;-----------------------------------------------------------------------------
  443.                 cmp     word ptr dos_version,030ah
  444.                 jb      skip_err_save
  445.                 push    ds                      ;save DS
  446.                 xor     ax,ax                   ;Clear regs
  447.                 mov     bx,ax
  448.                 mov     cx,ax
  449.                 mov     dx,ax
  450.                 mov     di,ax
  451.                 mov     si,ax
  452.                 mov     ah,59h                  ;Extended error info
  453.                 int     21h                     ;Call DOS
  454.                 mov     cs:[errDS],ds           ;save returned DS
  455.                 pop     ds                      ;Restore DS
  456.                 push    bx
  457.                 mov     bx,offset errinfoarray  ;Save data in registers
  458.                 mov     [bx],ax                 ;  in this specific order.
  459.                 pop     [bx+2]
  460.                 mov     [bx+4],cx
  461.                 mov     [bx+6],dx
  462.                 mov     [bx+8],si
  463.                 mov     [bx+10],di
  464.                 mov     [bx+14],es
  465. skip_err_save:
  466. ;-----------------------------------------------------------------------------
  467. ;If using EMS memory, save EMS mapping context and map our page.
  468. ;-----------------------------------------------------------------------------
  469.                 cmp     ems_flag,0
  470.                 je      skip_ems_save
  471.                 mov     ah,47h                  ;Save mapping context
  472.                 mov     dx,ems_handle
  473.                 int     67h
  474.                 or      ah,ah
  475.                 jne     clean_up
  476.                 xor     ax,ax
  477.                 mov     bx,ax
  478.                 call    map_emsmem              ;Map page
  479.                 jne     clean_up
  480. skip_ems_save:
  481. ;-----------------------------------------------------------------------------
  482. ;Save default directory and drive
  483. ;-----------------------------------------------------------------------------
  484.                 mov     ah,19h                  ;Get current disk
  485.                 int     21h
  486.                 mov     curr_disk,al
  487.                 mov     ah,47h                  ;Get current directory
  488.                 xor     dl,dl
  489.                 mov     si,offset curr_dir
  490.                 int     21h
  491. ;-----------------------------------------------------------------------------
  492. ;Save state of A20 line.
  493. ;-----------------------------------------------------------------------------
  494.                 cmp     xms_flag,0
  495.                 je      skip_xms_save
  496.                 mov     ah,7                    ;Get state of A20 line
  497.                 call    [xms_service]
  498.                 mov     A20_state,ax
  499. skip_xms_save:
  500. ;-----------------------------------------------------------------------------
  501. ;Save UMB link and mem allocaton state. If DOS 5, link UMBs
  502. ;-----------------------------------------------------------------------------
  503.                 mov     ax,5800h                ;Get DOS mem alloc strategy
  504.                 int     21h
  505.                 mov     mem_alloc,ax
  506.                 cmp     dos_version,500h        ;If DOS 5, save UMB link
  507.                 jb      skip_umblink            ;  state.  Then link UMBs
  508.                 mov     ax,5802h
  509.                 int     21h
  510.                 mov     linkflag,al             ;Save UMB link state
  511.                 mov     ax,5803h
  512.                 mov     bx,1                    ;Link UMBs
  513.                 int     21h
  514. skip_umblink:
  515. ;-----------------------------------------------------------------------------
  516. ;Save Mouse state
  517. ;-----------------------------------------------------------------------------
  518.                 cmp     mouse_flag,0
  519.                 je      skip_mouse_save
  520.                 mov     ax,17h
  521.                 mov     dx,offset ResCodeEnd    ;Save mouse state
  522.                 push    cs
  523.                 pop     es
  524.                 int     33h
  525. skip_mouse_save:
  526. ;-----------------------------------------------------------------------------
  527. ;Save Keyboard shift state
  528. ;-----------------------------------------------------------------------------
  529.                 mov     ah,2                    ;Get keyboard shift state
  530.                 int     16h
  531.                 mov     shift_save,al
  532.  
  533. ;=============================================================================
  534. ;Do work here
  535. ;=============================================================================
  536.                 mov     ax,0e07h                ;Beep the speaker
  537.                 int     10h
  538. work_1:
  539.                 mov     ah,01                   ;See if key available
  540.                 int     16h
  541.                 jne     work_2
  542.                 call    TSR_idle                ;Indicate TSR idle
  543.                 jmp     short work_1
  544. work_2:
  545.                 xor     ah,ah
  546.                 int     16h
  547.                 cmp     al,27                   ;See if <Esc> key
  548.                 jne     work_1                  ;No, continue to wait
  549.  
  550.                 mov     ax,0e07h                ;Beep the speaker again
  551.                 int     10h
  552.  
  553. ;-----------------------------------------------------------------------------
  554. ;Clean up DOS for return to forground task.
  555. ;-----------------------------------------------------------------------------
  556. clean_up:
  557.                 push    cs
  558.                 pop     ds
  559.                 assume  ds:code,es:nothing
  560. ;-----------------------------------------------------------------------------
  561. ;Restore Keyboard shift state
  562. ;-----------------------------------------------------------------------------
  563.                 mov     ax,bios_data            ;Point ES to BIOS data seg
  564.                 mov     es,ax
  565.                 assume  es:bios_data
  566.                 mov     al,shift_save
  567.                 and     al,0f0h                 ;Look only at lock bits
  568.                 mov     es:[shift_state],al
  569.                 push    cs
  570.                 pop     es
  571.                 assume  es:code
  572. ;-----------------------------------------------------------------------------
  573. ;Restore Mouse state
  574. ;-----------------------------------------------------------------------------
  575.                 cmp     mouse_flag,0
  576.                 je      skip_mouse_restore
  577.                 mov     ax,17h
  578.                 mov     dx,offset ResCodeEnd    ;Restore mouse state
  579.                 int     33h
  580. skip_mouse_restore:
  581. ;-----------------------------------------------------------------------------
  582. ;Restore UMB link state, link and allocation strat
  583. ;-----------------------------------------------------------------------------
  584.                 mov     ax,5801h                ;Set DOS mem alloc strategy
  585.                 mov     bx,mem_alloc
  586.                 int     21h
  587.  
  588.                 cmp     dos_version,500h        ;If DOS 5, restore UMB link
  589.                 jb      skip_umblink_restore    ;  state.
  590.                 mov     ax,5803h                ;Set UMB link state
  591.                 xor     bh,bh
  592.                 mov     bl,linkflag
  593.                 int     21h
  594. skip_umblink_restore:
  595. ;-----------------------------------------------------------------------------
  596. ;Restore A20 line
  597. ;-----------------------------------------------------------------------------
  598.                 cmp     xms_flag,0
  599.                 je      skip_xms_restore
  600.                 mov     ah,5                    ;Assume local disable A20
  601.                 cmp     A20_state,0
  602.                 je      xms_restore_1
  603.                 inc     ah                      ;Change to local enable A20
  604. xms_restore_1:
  605.                 call    [xms_service]           ;Restore A20 line state
  606.                 mov     A20_state,ax
  607. skip_xms_restore:
  608. ;-----------------------------------------------------------------------------
  609. ;If using EMS memory, restore EMS mapping context.
  610. ;-----------------------------------------------------------------------------
  611.                 cmp     ems_flag,0
  612.                 je      ems_restore_skip
  613.                 mov     ah,48h                  ;Restore mapping context
  614.                 mov     dx,ems_handle
  615.                 int     67h
  616. ems_restore_skip:
  617. ;-----------------------------------------------------------------------------
  618. ;Restore default directory and drive
  619. ;-----------------------------------------------------------------------------
  620.                 mov     ah,0eh                  ;Set default disk
  621.                 mov     dl,curr_disk
  622.                 int     21h
  623.                 mov     ah,3bh                  ;Set current directory
  624.                 mov     dx,offset curr_dir
  625.                 int     21h
  626. ;-----------------------------------------------------------------------------
  627. ;Restore extended error info.
  628. ;-----------------------------------------------------------------------------
  629.                 cmp     word ptr dos_version,30ah ;DOS 3.1 and up
  630.                 jb      skip_err_restore
  631.                 mov     ax,5d0ah                ;Restore ext error info
  632.                 mov     dx,offset errinfoarray  ;point to Saved info
  633.                 int     21h
  634. skip_err_restore:
  635. ;-----------------------------------------------------------------------------
  636. ;Restore PSP and DTA
  637. ;-----------------------------------------------------------------------------
  638.                 mov     bx,saved_psp            ;Get old PSP
  639.                 mov     ah,50h                  ;Restore PSP
  640.                 call    dospspcall
  641.                 push    ds
  642.                 lds     dx,[saved_dta]
  643.                 mov     ah,1ah                  ;Restore DTA
  644.                 int     21h
  645. ;-----------------------------------------------------------------------------
  646. ;Reset the displaced interrupt 1Bh, 23h, and 24h vectors.
  647. ;-----------------------------------------------------------------------------
  648.                 mov     ax,2524h                ;reset int 24h vector
  649.                 lds     dx,cs:[vector24h]
  650.                 int     21h
  651.                 mov     ax,2523h                ;reset int 24h vector
  652.                 lds     dx,cs:[vector23h]
  653.                 int     21h
  654.                 mov     ax,251bh                ;reset int 1Bh vector
  655.                 lds     dx,cs:[vector1bh]
  656.                 int     21h
  657.                 pop     ds
  658. ;-----------------------------------------------------------------------------
  659. ;Restore register values, switch back to original stack, and return to caller.
  660. ;-----------------------------------------------------------------------------
  661. main_exit:
  662.                 call    restore_regs            ;Restore registers
  663.                 assume  ds:nothing
  664.                 cli                             ;make sure interrupts are off
  665.                 inc     cs:no_switch            ;Don't allow task switch
  666.                 mov     ss,cs:ss_register       ;switch to original stack
  667.                 mov     sp,cs:sp_register
  668.                 dec     cs:[main_active]        ;clear program status flag
  669.                 dec     cs:no_switch            ;Allow task switch
  670.                 sti                             ;interrupts on
  671.                 ret                             ;Return to interrupt routine
  672. main            endp
  673.  
  674. ;-----------------------------------------------------------------------------
  675. ; DOSPSPCALL modifies critical error flag on PSP calls to DOS is using 2.x
  676. ;-----------------------------------------------------------------------------
  677. dospspcall      proc    near
  678.                 assume  cs:code
  679.                 cmp     cs:[dos_version],30Ah   ;See if DOS < 3.1
  680.                 jae     dospspcall_ok           ;no, just call DOS
  681.                 push    ds
  682.                 push    di
  683.                 lds     di,cs:criterr_ptr       ;retrieve crit err flag adr
  684.                 inc     byte ptr [di]           ;Set DOS in crit error state
  685.                 pop     di
  686.                 pop     ds
  687.                 int     21h                     ;Call   DOS
  688.                 push    ds
  689.                 push    di
  690.                 lds     di,cs:criterr_ptr       ;retrieve crit err flag adr
  691.                 dec     byte ptr [di]           ;Set DOS in crit error state
  692.                 pop     di
  693.                 pop     ds
  694.                 ret
  695. dospspcall_ok:
  696.                 int     21h                     ;Call DOS
  697.                 ret
  698. dospspcall      endp
  699.  
  700. ;-----------------------------------------------------------------------------
  701. ; STOP SWITCH  Signals the task switcher (if active) to not switch this
  702. ;              session.
  703. ;-----------------------------------------------------------------------------
  704. stop_switch     proc    near
  705.                 assume  cs:code
  706.                 inc     cs:no_switch            ;Set no switch flag for TS
  707.                 cmp     win_enhanced,0
  708.                 jne     stop_switch_1
  709. stop_switch_exit:
  710.                 ret
  711. stop_switch_1:
  712.                 mov     ax,1681h                ;Win begin critical section
  713.                 int     2fh
  714.                 jmp     short stop_switch_exit
  715. stop_switch     endp
  716.  
  717. ;-----------------------------------------------------------------------------
  718. ; GO SWITCH  Signals the task switcher (if active) it is OK to switch this
  719. ;            session.
  720. ;-----------------------------------------------------------------------------
  721. go_switch       proc    near
  722.                 assume  cs:code
  723.                 dec     cs:no_switch            ;Clear switch flag for TS
  724.                 cmp     win_enhanced,0
  725.                 jne     go_switch_1
  726. go_switch_exit:
  727.                 ret
  728. go_switch_1:
  729.                 mov     ax,1682h                ;Win end critical section
  730.                 int     2fh
  731.                 jmp     short go_switch_exit
  732. go_switch       endp
  733.  
  734. ;-----------------------------------------------------------------------------
  735. ; TSR IDLE  Signals the system that the TSR is idle.
  736. ;-----------------------------------------------------------------------------
  737. TSR_idle        proc    near
  738.                 assume  cs:code
  739.                 int     28h                     ;Old DOS Idle
  740.                 cmp     dos_version,300h        ;No Multiplex interrupt for
  741.                 jb      TSR_Idle_exit           ;  DOS 2.x
  742.                 mov     ax,1680h                ;Win-OS/2 release timeslice.
  743.                 int     2fh
  744. TSR_idle_exit:
  745.                 ret
  746. TSR_idle        endp
  747.  
  748. ;============================================================================
  749. ; SWNOTIFY  Routine to parse switcher notification messages
  750. ;============================================================================
  751. SWNotify        proc    far
  752.                 assume  cs:code,ds:nothing,es:nothing
  753.                 push    si
  754.                 push    ds
  755.                 push    cs
  756.                 pop     ds
  757.                 assume  ds:code
  758.                 mov     word ptr [SWService],di ;Save ptr to service rtn
  759.                 mov     word ptr [SWService+2],es
  760.                 cmp     ax,7
  761.                 ja      SWN1                    ;If unknown type, skip
  762.                 mov     si,ax
  763.                 shl     si,1
  764.                 call    [SWNotifyJT+si]         ;Call proper notification func
  765.                 mov     ax,0
  766. SWN1:
  767.                 pop     ds
  768.                 pop     si
  769.                 ret
  770.  
  771. ;---------------------------------------------------------------------------
  772. ; SWINIT - Switcher initialization notification
  773. ;---------------------------------------------------------------------------
  774. SWNInit         proc    near
  775.                 assume  cs:code,ds:code
  776.                 mov     ax,0                    ;Allow switcher init
  777.                 ret
  778. SWNInit         endp
  779. ;---------------------------------------------------------------------------
  780. ; SWQSUSPENDINIT - Switcher query suspend notification
  781. ;---------------------------------------------------------------------------
  782. SWNQSuspend     proc    near
  783.                 assume  cs:code,ds:code
  784.                 mov     ax,no_switch            ;Switch only if not in
  785.                 ret                             ;  critical section
  786. SWNQSuspend     endp
  787. ;---------------------------------------------------------------------------
  788. ; SWSUSPEND - Switcher suspend notification
  789. ;---------------------------------------------------------------------------
  790. SWNSuspend      proc    near
  791.                 assume  cs:code,ds:code
  792.                 mov     ax,no_switch            ;Switch only if not in
  793.                 ret                             ;  critical section
  794. SWNSuspend      endp
  795. ;---------------------------------------------------------------------------
  796. ; SWACTIVATE - Switcher going active notification
  797. ;---------------------------------------------------------------------------
  798. SWNActivate     proc    near
  799.                 assume  cs:code,ds:code
  800.                 mov     ax,0                    ;Allow session activate
  801.                 ret
  802. SWNActivate     endp
  803. ;---------------------------------------------------------------------------
  804. ; SWACTIVE - Switcher session active notification
  805. ;---------------------------------------------------------------------------
  806. SWNActive       proc    near
  807.                 assume  cs:code,ds:code
  808.                 mov     ax,0                    ;Allow session activate
  809.                 ret
  810. SWNActive       endp
  811. ;---------------------------------------------------------------------------
  812. ; SWCSESSION - Switcher create session notification
  813. ;---------------------------------------------------------------------------
  814. SWNCSession     proc    near
  815.                 assume  cs:code,ds:code
  816.                 mov     ax,0                    ;Allow session create
  817.                 ret
  818. SWNCSession     endp
  819. ;---------------------------------------------------------------------------
  820. ; SWDSESSION - Switcher destroy session notification
  821. ;---------------------------------------------------------------------------
  822. SWNDSession     proc    near
  823.                 assume  cs:code,ds:code
  824.                 mov     ax,0                    ;Allow session destroy
  825.                 ret
  826. SWNDSession     endp
  827.  
  828. ;---------------------------------------------------------------------------
  829. ; SWEXIT - Switcher exit notification
  830. ;---------------------------------------------------------------------------
  831. SWNExit         proc    near
  832.                 assume  cs:code,ds:code
  833.                 mov     ax,0                    ;Allow switcher exit
  834.                 ret
  835. SWNExit         endp
  836. SWNotify        endp
  837.  
  838. ;-----------------------------------------------------------------------------
  839. ; GETEMSMEM Allocates pages of memory from the Expanded memory manager
  840. ; Entry: BX - number of 16K pages to request
  841. ; Exit:  DX - handle to pages
  842. ;        ZF - Set if call successful
  843. ;-----------------------------------------------------------------------------
  844. get_emsmem      proc    near
  845.                 mov     ah,43h                  ;Allocate EMS pages
  846.                 int     67h
  847.                 or      ah,ah
  848.                 ret
  849. get_emsmem      endp
  850.  
  851. ;-----------------------------------------------------------------------------
  852. ; FREEEMSMEM  Frees pages of memory from the Expanded memory manager
  853. ; Entry: DX - handle to memory pages to free
  854. ; Exit:  ZF - Set if call successful
  855. ;-----------------------------------------------------------------------------
  856. free_emsmem     proc    near
  857.                 mov     ah,45h                  ;Free EMS page
  858.                 int     67h
  859.                 or      ah,ah
  860.                 ret
  861. free_emsmem     endp
  862.  
  863. ;-----------------------------------------------------------------------------
  864. ; MAPEMSMEM  Maps a page of Expanded memory to the EMS page frame
  865. ; Entry: AL - Physical page in page frame
  866. ;        BX - logical page to map
  867. ;        DX - handle to memory pages
  868. ; Exit:  ZF - Set if call successful
  869. ;-----------------------------------------------------------------------------
  870. map_emsmem      proc    near
  871.                 mov     ah,44h                  ;Map EMS page
  872.                 int     67h
  873.                 or      ah,ah
  874.                 ret
  875. map_emsmem      endp
  876.  
  877. ;-----------------------------------------------------------------------------
  878. ; SAVEREGS saves all the registers used in the interrupt routines and sets DS.
  879. ;-----------------------------------------------------------------------------
  880. save_regs       proc    near
  881.                 pop     cs:[ret_addr]           ;Get address to return to
  882.                 push    ax                      ;save all registers
  883.                 push    bx
  884.                 push    cx
  885.                 push    dx
  886.                 push    bp
  887.                 push    si
  888.                 push    di
  889.                 push    ds
  890.                 push    es
  891.                 push    cs                      ;Set DS = CS
  892.                 pop     ds
  893.                 assume  ds:code
  894.                 jmp     word ptr [ret_addr]     ;Return
  895. save_regs       endp
  896.  
  897. ;-----------------------------------------------------------------------------
  898. ;RESTOREREGS restores register values.
  899. ;-----------------------------------------------------------------------------
  900. restore_regs    proc    near
  901.                 pop     ret_addr                ;Save return address
  902.                 pop     es                      ;restore registers
  903.                 pop     ds
  904.                 assume  ds:nothing
  905.                 pop     di
  906.                 pop     si
  907.                 pop     bp
  908.                 pop     dx
  909.                 pop     cx
  910.                 pop     bx
  911.                 pop     ax
  912.                 jmp     word ptr cs:[ret_addr]  ;Return
  913. restore_regs    endp
  914.  
  915. ;=============================================================================
  916. ; End of resident code.  Resident stack and mouse save area sits just
  917. ; above resident code
  918. ;=============================================================================
  919. ResCodeEnd      = $
  920. ;=============================================================================
  921. ; Non-Resident data
  922. ;=============================================================================
  923.  
  924. errmsg1         db      13,10,"Usage: TEMPLATE [/U][/X][/E]$"
  925. errmsg2         db      "Bad switch$"
  926. errmsg3         db      "Expanded memory driver not found$"
  927. errmsg4         db      "DOS 2.0 or greater required$"
  928. errmsg5         db      "Not able to uninstall$"
  929. errmsg6         db      "TEMPLATE not installed$"
  930.  
  931. infomsg1        db      "TEMPLATE installed$"
  932. infomsg2        db      "TEMPLATE removed$"
  933.  
  934. errmsg8         db      "Program uninstalled$"
  935. errmsg9         db      "Can't install$"
  936.  
  937. installed_seg   dw      0                       ;Segment of installed code
  938. TSRResident     db      0                       ;TSR already installed flag
  939. def_disk        db      ?                       ;Default disk drive
  940. ems_header      db      "EMMXXXX0"              ;EMS driver header
  941. mouse_savesize  dw      0                       ;Size of mouse save area
  942.  
  943. cmd_switches    db      "eu"                    ;Letters of valid commands.
  944. cmd_switch_end  =       $
  945. cmd_jmptbl      dw      offset remove           ;Jump table to rouines that
  946.                 dw      offset use_expanded     ;  impliment the cmd line args
  947.  
  948. ;=============================================================================
  949. ; INITIALIZE
  950. ;=============================================================================
  951. initialize      proc    near
  952.                 assume cs:code, ds:code
  953.                 cld                             ;String operations UP
  954.                 mov     dx,offset program       ;Print copyright
  955.                 call    message
  956. ;-----------------------------------------------------------------------------
  957. ;Get DOS version, Determine if TSR already installed.
  958. ;-----------------------------------------------------------------------------
  959.                 mov     ah,30h                  ;Get DOS version
  960.                 int     21h
  961.                 xchg    al,ah                   ;Put version in proper order
  962.                 mov     dos_version,ax          ;Save DOS version
  963.                 cmp     ax,200h                 ;See if at least DOS ver 2
  964.                 ja      init_0
  965.                 mov     dx,offset errmsg4
  966.                 jmp     short error_exit
  967. init_0:
  968.                 call    find_copy               ;See if TSR already installed
  969.                 jc      init_1
  970.                 inc     TSRResident             ;Set already installed flag
  971.                 mov     installed_seg,es        ;save installed code segment
  972. init_1:
  973.                 push    cs
  974.                 pop     es
  975. ;-----------------------------------------------------------------------------
  976. ;Parse the command line for switches.
  977. ;-----------------------------------------------------------------------------
  978.                 mov     di,offset command_tail  ;Point SI to command line text
  979.                 xor     cx,cx
  980.                 or      cl,[di]                 ;Get length of command line.
  981.                 jz      init_3                  ;If 0, skip parse
  982.                 inc     di
  983. init_2:
  984.                 mov     al,"/"                  ;Put switch in AL
  985.                 repne   scasb                   ;Scan for cmd line switches
  986.                 jne     init_3
  987.                 mov     al,[di]
  988.                 or      al,20h                  ;Make lower case
  989.                 push    cx
  990.                 push    di
  991.                 mov     di,offset cmd_switches
  992.                 mov     cx,offset cmd_switch_end - offset cmd_switches
  993.                 repne   scasb
  994.                 mov     bx,cx                   ;Copy index into list
  995.                 pop     di
  996.                 pop     cx
  997.                 mov     dx,offset errmsg2       ;Command not found msg
  998.                 jne     error_exit
  999.                 shl     bx,1                    ;Convert to word offset
  1000.                 push    cx
  1001.                 push    di
  1002.                 call    cs:[bx+cmd_jmptbl]      ;Call command routine.
  1003.                 pop     di
  1004.                 pop     cx
  1005.                 jc      error_exit              ;If error terminate parse.
  1006.                 jcxz    init_3                  ;If at file end, exit parse.
  1007.                 jmp     short init_2
  1008. init_3:
  1009. ;-----------------------------------------------------------------------------
  1010. ;If not installed, install.
  1011. ;-----------------------------------------------------------------------------
  1012.                 cmp     TSRResident,0           ;Is TSR installed?
  1013.                 je      install
  1014.                 mov     ax,4c00h                ;No, terminate with RC = 0.
  1015.                 int     21h
  1016.  
  1017. ;=============================================================================
  1018. ;Display error message and exit with Return Code = 1.
  1019. ;=============================================================================
  1020. error_exit:     call    message
  1021.                 mov     es,installed_seg        ;point ES to installed code
  1022.                 dec     es:[main_active]        ;enable background task.
  1023.                 mov     ax,4c01h                ;Exit RC = 1
  1024.                 int     21h
  1025.  
  1026. ;=============================================================================
  1027. ;Install. Get address of INDOS and DOS Critical Error flags.
  1028. ;=============================================================================
  1029. install:
  1030.                 mov     ah,34h                  ;Get INDOS address from DOS
  1031.                 int     21h
  1032.                 mov     word ptr [indos_ptr],bx
  1033.                 mov     word ptr [indos_ptr+2],es
  1034.                 call    find_cefptr             ;Find critical error flag
  1035.                 jnc     ceffound
  1036.                 mov     dx,offset errmsg9       ;Critical error flag not found
  1037.                 jmp     short error_exit
  1038. ceffound:
  1039.                 mov     word ptr criterr_ptr,bx ;store it
  1040.                 mov     word ptr criterr_ptr[2],es
  1041. ;-----------------------------------------------------------------------------
  1042. ;Initialize task switcher structures. See if task switcher active.
  1043. ;-----------------------------------------------------------------------------
  1044.                 cmp     word ptr dos_version,300h ;DOS 3.0 and up
  1045.                 jb      nowin
  1046.  
  1047.                 mov     ax,offset TSRInstData   ;Init instance memory struc
  1048.                 mov     word ptr [InstItem1],ax
  1049.                 mov     word ptr [InstItem1+2],cs
  1050.                 mov     ax,offset TSRInstDataEnd - offset TSRInstData
  1051.                 mov     [InstSize1],ax
  1052.  
  1053.                 mov     ax,offset ResCodeEnd    ;Init instance stack struc
  1054.                 mov     word ptr [InstItem2],ax
  1055.                 mov     word ptr [InstItem2+2],cs
  1056.                 mov     ax,RESSTACKSIZE
  1057.                 mov     [InstSize2],ax
  1058.  
  1059.                 mov     ax,offset InstItem1             ;Init ptr to instance
  1060.                 mov     word ptr [sisInstData],ax       ;  memory structure.
  1061.                 mov     word ptr [sisInstData+2],cs
  1062.  
  1063.                 mov     ax,offset SWNotify              ;Init ptr to
  1064.                 mov     word ptr [scbiEntryPoint],ax    ;  notification
  1065.                 mov     word ptr [scbiEntryPoint+2],cs  ;  routine.
  1066.  
  1067.                 mov     ax,4b02h                ;See if switcher active
  1068.                 int     2fh                     ;Use multiplex interrupt
  1069.                 or      ax,ax
  1070.                 jne     noswitcher
  1071.                 mov     word ptr [SWService],di ;Save ptr to service routine
  1072.                 mov     word ptr [SWService+2],es
  1073.  
  1074.                 mov     ax,4                    ;Hook notification chain
  1075.                 push    cs                      ;ES:BX point to callback struc
  1076.                 pop     es
  1077.                 mov     di,offset CallbackInfo
  1078.                 call    SWService
  1079. noswitcher:
  1080. ;-----------------------------------------------------------------------------
  1081. ;Check for Windows active
  1082. ;-----------------------------------------------------------------------------
  1083.                 mov     ax,1600h                ;See if Enhanced mode windows
  1084.                 int     2fh
  1085.                 or      al,al
  1086.                 je      nowin
  1087.                 inc     win_enhanced            ;Set enhanced mode flag
  1088. nowin:
  1089. ;-----------------------------------------------------------------------------
  1090. ;Determine if extended memory manager active
  1091. ;-----------------------------------------------------------------------------
  1092.                 mov     ax,4300h                ;Look for HIMEM.SYS
  1093.                 int     2fh
  1094.                 or      al,al
  1095.                 jne     noxms
  1096.                 mov     ax,4310h                ;Get entry point for XMM
  1097.                 int     2fh
  1098.                 mov     word ptr [xms_service],bx
  1099.                 mov     word ptr [xms_service+2],es
  1100.                 push    cs
  1101.                 pop     es
  1102.                 inc     xms_flag
  1103. noxms:
  1104. ;-----------------------------------------------------------------------------
  1105. ;Set up EMS memory if necessary.
  1106. ;-----------------------------------------------------------------------------
  1107.                 cmp     ems_flag,0              ;See if expanded memory
  1108.                 je      no_emsmem               ;  requested
  1109.  
  1110.                 call    check4ems               ;See if EMS driver installed
  1111.                 jnc     install_1
  1112.                 mov     dx,offset errmsg3       ;EMS driver error
  1113.                 jmp     error_exit
  1114. install_1:
  1115.                 mov     ems_segment,bx          ;Save seg of EMS page frame
  1116.                 mov     ems_version,dl          ;Save EMS version
  1117.  
  1118.                 mov     bx,1                    ;Allocate 1 page
  1119.                 call    get_emsmem
  1120.                 mov     ems_handle,dx           ;Save EMS handle
  1121.  
  1122.                 xor     al,al                   ;Map to EMS page 0
  1123.                 xor     bx,bx
  1124.                 call    map_emsmem
  1125. no_emsmem:
  1126. ;-----------------------------------------------------------------------------
  1127. ;See if mouse driver loaded
  1128. ;-----------------------------------------------------------------------------
  1129.                 xor     ax,ax
  1130.                 int     33h
  1131.                 or      ax,ax
  1132.                 je      no_mouse
  1133.                 inc     mouse_flag              ;Set mouse found flag, get
  1134.                 mov     ax,15h                  ;  size of mouse driver save
  1135.                 int     33h                     ;  context area.
  1136.                 mov     mouse_savesize,bx
  1137. no_mouse:
  1138. ;-----------------------------------------------------------------------------
  1139. ;Set interrupts used by TSR
  1140. ;-----------------------------------------------------------------------------
  1141.                 mov     al,08h                  ;Get/set the timer interrupt
  1142.                 mov     dx,offset timerint
  1143.                 mov     di,offset int08h
  1144.                 call    set_interrupt
  1145.                 mov     al,09h                  ;Get/set the keyboard int
  1146.                 mov     dx,offset keyint
  1147.                 mov     di,offset int09h
  1148.                 call    set_interrupt
  1149.                 mov     al,10h                  ;Get/set the video interrupt
  1150.                 mov     dx,offset videoint
  1151.                 mov     di,offset int10h
  1152.                 call    set_interrupt
  1153.                 mov     al,13h                  ;Get/set the disk interrupt
  1154.                 mov     dx,offset diskint
  1155.                 mov     di,offset int13h
  1156.                 call    set_interrupt
  1157.                 mov     al,16h                  ;Get/set the BIOS keyboard int
  1158.                 mov     dx,offset bioskeyint
  1159.                 mov     di,offset int16h
  1160.                 call    set_interrupt
  1161.                 mov     al,28h                  ;Get/set the DOS idle int
  1162.                 mov     dx,offset idleint
  1163.                 mov     di,offset int28h
  1164.                 call    set_interrupt
  1165.  
  1166.                 cmp     dos_version,300h        ;DOS 3.0 and up
  1167.                 jb      skip_hook2f
  1168.                 mov     al,2fh                  ;Get/set the DOS multiplex int
  1169.                 mov     dx,offset muxint
  1170.                 mov     di,offset int2fh
  1171.                 call    set_interrupt
  1172. skip_hook2f:
  1173. ;-----------------------------------------------------------------------------
  1174. ;Deallocate the program's environment block.
  1175. ;-----------------------------------------------------------------------------
  1176.                 mov     ax,ds:[2ch]             ;get environment segment
  1177.                 mov     es,ax
  1178.                 mov     ah,49h                  ;free it
  1179.                 int     21h
  1180.                 mov     dx,offset infomsg1      ;Tell user that we are
  1181.                 call    message                 ;  installed.
  1182.  
  1183.                 mov     ax,3100h                ;terminate with ERRORLEVEL = 0
  1184.                 mov     dx,offset ResCodeEnd-offset code + RESSTACKSIZE
  1185.                 add     dx,mouse_savesize
  1186.                 mov     resident_sp,dx
  1187.                 add     dx,15
  1188.                 mov     cl,4
  1189.                 shr     dx,cl
  1190.                 int     21h
  1191. initialize      endp
  1192.  
  1193. ;-----------------------------------------------------------------------------
  1194. ; USE EXPANDED  Sets a flag to use expanded memory
  1195. ;-----------------------------------------------------------------------------
  1196. use_expanded    proc    near
  1197.                 mov     ems_flag,1
  1198.                 ret
  1199. use_expanded    endp
  1200.  
  1201. ;-----------------------------------------------------------------------------
  1202. ; REMOVE deallocates the memory block addressed by ES and restores the
  1203. ; interrupt vectors displaced on installation.
  1204. ;   Exit:   CF clear - program uninstalled
  1205. ;           CF set   - can't uninstall
  1206. ;-----------------------------------------------------------------------------
  1207. remove          proc    near
  1208.                 assume  cs:code,ds:code
  1209.  
  1210.                 cmp     TSRResident,0           ;See if TSR installed
  1211.                 jne     remove_1
  1212.                 mov     dx,offset errmsg6
  1213.                 jmp     remove_error1
  1214. remove_1:
  1215.                 mov     es,installed_seg
  1216.                 mov     ax,5                    ;Unhook notification chain
  1217.                 mov     di,offset CallbackInfo
  1218.                 cmp     word ptr es:[SWService+2],0
  1219.                 je      remove_2
  1220.                 call    es:[SWService]
  1221. remove_2:
  1222.                 mov     al,8                    ;check interrupt 8 vector
  1223.                 call    checkvector
  1224.                 jne     jmp_remove_error
  1225.                 mov     al,9                    ;check interrupt 9 vector
  1226.                 call    checkvector
  1227.                 jne     jmp_remove_error
  1228.                 mov     al,10h                  ;check interrupt 10 vector
  1229.                 call    checkvector
  1230.                 jne     jmp_remove_error
  1231.                 mov     al,13h                  ;check interrupt 13h vector
  1232.                 call    checkvector
  1233.                 jne     jmp_remove_error
  1234.                 mov     al,16h                  ;check interrupt 16 vector
  1235.                 call    checkvector
  1236.                 jne     jmp_remove_error
  1237.                 mov     al,28h                  ;check interrupt 28h vector
  1238.                 call    checkvector
  1239.                 je      remove_3
  1240. jmp_remove_error:
  1241.                 jmp     remove_error
  1242. remove_3:
  1243.                 cmp     dos_version,300h        ;DOS 3.0 and up
  1244.                 jb      skip_check2f
  1245.                 mov     al,2Fh                  ;check interrupt 2Fh vector
  1246.                 call    checkvector
  1247.                 jne     remove_error
  1248. skip_check2f:
  1249.                 cmp     ems_flag,0              ;If using Expanded memory
  1250.                 je      skip_remove_ems         ;  free it
  1251.                 mov     dx,ems_handle           ;Free Expanded memory
  1252.                 call    free_emsmem
  1253.                 jne     remove_error
  1254. skip_remove_ems:
  1255.                 push    ds                      ;save DS
  1256.                 assume  ds:nothing
  1257.                 mov     ax,2508h                ;restore interrupt 8 vector
  1258.                 lds     dx,es:[int08h]
  1259.                 int     21h
  1260.                 mov     ax,2509h                ;restore interrupt 9 vector
  1261.                 lds     dx,es:[int09h]
  1262.                 int     21h
  1263.                 mov     ax,2510h                ;restore interrupt 10 vector
  1264.                 lds     dx,es:[int10h]
  1265.                 int     21h
  1266.                 mov     ax,2513h                ;restore interrupt 13h vector
  1267.                 lds     dx,es:[int13h]
  1268.                 int     21h
  1269.                 mov     ax,2516h                ;restore interrupt 16 vector
  1270.                 lds     dx,es:[int16h]
  1271.                 int     21h
  1272.                 mov     ax,2528h                ;restore interrupt 28h vector
  1273.                 lds     dx,es:[int28h]
  1274.                 int     21h
  1275.  
  1276.                 cmp     cs:dos_version,300h     ;DOS 3.0 and up
  1277.                 jb      skip_restore2f
  1278.                 mov     ax,252Fh                ;restore interrupt 2Fh vector
  1279.                 lds     dx,es:[int2Fh]
  1280.                 int     21h
  1281. skip_restore2f:
  1282.                 pop     ds                      ;Restore DS
  1283.                 assume  ds:code
  1284.                 not     word ptr es:[begin]     ;Destroy fingerprint
  1285.                 mov     ah,49h                  ;Free memory given to
  1286.                 int     21h                     ;  original program block
  1287.                 jc      remove_error            ;branch on error
  1288.  
  1289.                 mov     dx,offset infomsg2      ;Indicate program removed
  1290.                 call    message
  1291.                 clc                             ;clear CF for exit
  1292. remove_exit:
  1293.                 ret                             ;exit with CF intact
  1294. remove_error:
  1295.                 mov     dx,offset errmsg5
  1296. remove_error1:  stc
  1297.                 jmp     remove_exit             ;Error during remove
  1298. remove          endp
  1299.  
  1300. ;-----------------------------------------------------------------------------
  1301. ; CHECKVECTOR is called by REMOVE to compare the segment pointed to by an
  1302. ; interrupt vector against a segment value supplied by the caller.
  1303. ;   Entry:  AL - interrupt number
  1304. ;   Exit:   ZF clear - segments do not match
  1305. ;           ZF set   - segments match
  1306. ;-----------------------------------------------------------------------------
  1307. checkvector     proc    near
  1308.                 push    es
  1309.                 mov     cx,es
  1310.                 mov     ah,35h                  ;get vector
  1311.                 int     21h
  1312.                 mov     ax,es                   ;transfer segment to AX
  1313.                 cmp     ax,cx                   ;compare
  1314.                 pop     es
  1315.                 ret
  1316. checkvector     endp
  1317.  
  1318. ;-----------------------------------------------------------------------------
  1319. ; SETINTERRUPT Get and sets an interrupt
  1320. ; Entry: AL - Interrupt number
  1321. ;        DX - Pointer to new interrupt routine
  1322. ;        DI - Pointer to storage location for old interrupt vector
  1323. ;-----------------------------------------------------------------------------
  1324.                 assume  cs:code,ds:code,es:nothing
  1325. set_interrupt   proc    near
  1326.                 push    es
  1327.                 push    ax
  1328.                 mov     ah,35h                  ;DOS get interrupt
  1329.                 int     21h
  1330.                 pop     ax
  1331.                 mov     word ptr [di],bx        ;Save old vector
  1332.                 mov     word ptr [di+2],es
  1333.                 mov     ah,25h                  ;DOS set interrupt
  1334.                 int     21h
  1335.                 pop     es
  1336.                 ret
  1337. set_interrupt   endp
  1338.  
  1339. ;-----------------------------------------------------------------------------
  1340. ; FINDCOPY Determines if the TSR is already resident
  1341. ; Exit:  CF - Clear if copy found
  1342. ;        ES - Segment of installed code (if CF = 0)
  1343. ;-----------------------------------------------------------------------------
  1344. find_copy       proc    near
  1345.                 not     word ptr [begin]        ;initialize fingerprint
  1346.                 mov     bx,0a000h               ;Start scan in UMBs
  1347.                 mov     ax,cs                   ;keep CS value in AX
  1348. find_copy1:
  1349.                 inc     bx                      ;increment search segment value
  1350.                 mov     es,bx
  1351.                 cmp     ax,bx                   ;not installed if current
  1352.                 je      find_copy2              ;  segment is looped back to
  1353.                 mov     si,offset begin         ;search this segment for ASCII
  1354.                 mov     di,si                   ;  fingerprint
  1355.                 mov     cx,16
  1356.                 repe    cmpsb
  1357.                 jne     find_copy1              ;loop back if not found
  1358.                 clc                             ;Set copy found flag
  1359. find_copy_exit:
  1360.                 ret
  1361. find_copy2:
  1362.                 stc
  1363.                 jmp     short find_copy_exit
  1364.                 ret
  1365. find_copy       endp
  1366. ;-----------------------------------------------------------------------------
  1367. ; GETCEFPtr Returns a pointer to the DOS ErrorMode flag
  1368. ; Exit:    CF - Clear if ErrorMode Flag found
  1369. ;       ES:BX - Segment:offset of ErrorMode flag
  1370. ;
  1371. ;  For versions of DOS before 3.1, search for following code in DOS seg
  1372. ;
  1373. ;  36: 80 3E ???? 00    cmp  byte ptr ss:[ErrorMode],0
  1374. ;  75 ??                jne  near label
  1375. ;  CD 28                int  28h
  1376. ;
  1377. ;  For DOS 3.1 and later, ErrorMode sits before InDOS flag
  1378. ;
  1379. ;-----------------------------------------------------------------------------
  1380. find_cefptr     proc    near
  1381.                 mov     ah,34h                  ;Get ptr to INDOS
  1382.                 int     21h                     ;After DOS 3.1, the CEF is
  1383.                 dec     bx                      ;  documented to be the byte
  1384.                 cmp     dos_version,30ah        ;  before the INDOS flag
  1385.                 jnc     find_cef_exit
  1386.  
  1387.                 mov     ax,3e80h                ;CMP opcode
  1388.                 mov     cx,-1                   ;Max segment size
  1389.                 mov     di,bx                   ;Start at INDOS address
  1390. find_cef_1:
  1391.                 repne   scasb                   ;Scan for CMP
  1392.                 jcxz    find_cef_notfound       ;Error if CMP not found
  1393.                 cmp     es:[di],ah              ;Check other half of CMP opcode
  1394.                 jne     find_cef_1
  1395.                 cmp     byte ptr es:[di+4],075h ;Check for JNE
  1396.                 jne     find_cef_1
  1397.                 cmp     word ptr es:[di+6],028cdh ; Check for Int 28h call
  1398.                 jne     find_cef_1              ;Resume loop if not found
  1399. find_cef_found:
  1400.                 inc     di
  1401.                 mov     bx,es:[di]              ;Get offset of ErrorMode flag
  1402.                 clc
  1403. find_cef_exit:
  1404.                 ret
  1405. find_cef_notfound:
  1406.                 stc
  1407.                 jmp     short find_cef_exit
  1408. find_cefptr     endp
  1409.  
  1410. ;-----------------------------------------------------------------------------
  1411. ; CHECK4EMS Determines if an Expanded memory driver is loaded.
  1412. ; Exit:    BX - Segment of EMS page frame if CF clear
  1413. ;          DL - EMS driver version number
  1414. ;          CF - Clear if EMS driver found
  1415. ;-----------------------------------------------------------------------------
  1416. check4ems       proc    near
  1417.                 push    es
  1418.                 push    di
  1419.                 mov     ax,3567h                ;Get EMS vector
  1420.                 int     21h
  1421.                 mov     di,0ah                  ;Using the segment from the
  1422.                 mov     si,offset ems_header    ;  67h vector, look at offset
  1423.                 mov     cx,8                    ;  0ah. Compare the next 8
  1424.                 cld                             ;  bytes with the expected
  1425.                 repe    cmpsb                   ;  EMS header. If they are
  1426.                 pop     di                      ;  the same, EMS driver
  1427.                 pop     es                      ;  found.
  1428.                 je      check4ems_found
  1429. check4ems_error:
  1430.                 stc                             ;Set not found flag
  1431.                 jmp     short check4ems_exit
  1432. check4ems_found:
  1433.                 mov     ah,40h                  ;Check status
  1434.                 int     67h
  1435.                 or      ah,ah
  1436.                 jne     check4ems_error
  1437.                 mov     ah,41h                  ;Get page frame segment
  1438.                 int     67h
  1439.                 or      ah,ah
  1440.                 jne     check4ems_error
  1441.                 mov     ah,47h                  ;Get EMM version number
  1442.                 int     67h
  1443.                 or      ah,ah
  1444.                 jne     check4ems_error
  1445.                 mov     dl,al                   ;Copy version number
  1446. check4ems_exit:
  1447.                 ret
  1448.  
  1449. check4ems       endp
  1450.  
  1451. ;----------------------------------------------------------------------
  1452. ; MESSAGE Prints a message to screen
  1453. ; Entry: DX - Offset of '$' terminated message
  1454. ;----------------------------------------------------------------------
  1455. crlf$           db      13,10,"$"
  1456.  
  1457. message         proc    near
  1458.                 assume  cs:code,ds:code
  1459.  
  1460.                 mov     ah,9                    ;Print string
  1461.                 int     21h
  1462.                 mov     dx,offset crlf$         ;Append carrage return
  1463.                 mov     ah,9
  1464.                 int     21h
  1465.                 ret
  1466. message         endp
  1467.  
  1468.  
  1469.  
  1470. EndOfCode       =       $
  1471. code            ends
  1472.                 end     begin
  1473.