'===========================================================================
' Subject: MISC. DETECTION ROUTINES           Date: 10-28-96 (12:49)       
'  Author: Ben Kaashoek                       Code: QB, PDS                
'  Origin: robertk@worldaccess.nl           Packet: DOS.ABC
'===========================================================================
DEFINT A-Z                              'Use integers as default.

REM $INCLUDE: 'qb.bi'                   'INTERRUPT include file in QB45
'REM $INCLUDE: 'qbx.bi'                  'INTERRUPT include file in QBX/PDS

'The story:
' This little piece of code started out as a simple NDOS detection routine.
' Suddenly it became a "Why-Don't-I-Put-All-My-Detection-Routines-In-Here?"
' sort of program. Anyway. Hope you can use some of it.
' I will keep adding new detection routines to this file when I find others.
' So keep your eyes PEEKing:) for new detection stuff. There are loads
' more out there (and somewhere around here too).
' I tried to comment as much as possible. (Is there something like TOO much
' when you're commenting code?)
'
'                                                           BEN
'Resources:
' - Ralph Brown's Interrupt List. I think V43 (Get your hands on it)
'   A newer version will probably be released into the public domain.
' - Microsoft Windows V3.11 helpfile (Honest, it actually contained
'   something usefull. ;-) ).
' - NDOS helpfile.

DECLARE SUB NDOSVersion (majVer%, minVer%)         'Works OK.
DECLARE SUB SMARTDRVInfo (Hits&, misses&, dirty&, majVer%, minVer%, HitRate%, oops%)
DECLARE SUB SMARTDRVSize (full%, current%, BytesPerElement!, windows%)

DECLARE FUNCTION DetectANSI% ()
DECLARE FUNCTION DetectDOSKEY% ()
DECLARE FUNCTION DetectKSTACK% ()                  'Untested.
DECLARE FUNCTION DetectNDOS% ()                    'It detects my NDOS V7.0
DECLARE FUNCTION DetectNGUIDES% ()                 'Works OK.
DECLARE FUNCTION DetectNovellIPX% ()               'Untested.
DECLARE FUNCTION DetectSMARTDRV% ()                'Works OK.
DECLARE FUNCTION DetectXMS% ()                     'Works OK.
DECLARE FUNCTION PutKeysInKSTACK% (Keys$)          'Untested.

DIM SHARED Inreg AS RegType, Outreg AS RegType
DIM SHARED InRegX AS RegTypeX, OutRegX AS RegTypeX

'-------------------------- Begin demonstration ----------------------------

CONST False = 0: True = NOT False       'Boolean constants.

SCREEN 12: CLS : COLOR 7                'Test is independent of screenmode!
IF DetectNGUIDES THEN
 PRINT "Norton Guide is resident in memory"
ELSE
 PRINT "Norton Guide is not resident in memory"
END IF

IF DetectNDOS THEN
 NDOSVersion Maj%, Min%
 PRINT "NDOS V"; LTRIM$(STR$(Maj%)); "."; LTRIM$(STR$(Min%)); " detected"
ELSE
 PRINT "NDOS not detected"
END IF

IF DetectNovellIPX THEN
 PRINT "Novell Netware IPX driver detected"
ELSE
 PRINT "Novell Netware IPX driver not detected"
END IF

IF DetectDOSKEY THEN
 PRINT "DOSKEY detected"
ELSE
 PRINT "DOSKEY not detected"
END IF

IF DetectXMS THEN
 PRINT "V2.0+ XMS driver detected"
ELSE
 PRINT "V2.0+ XMS driver not detected"
END IF

IF DetectKSTACK THEN
 PRINT "KSTACK.COM detected"
ELSE
 PRINT "KSTACK.COM not detected"
END IF

IF DetectANSI THEN
 PRINT "ANSI.SYS detected"
ELSE
 PRINT "ANSI.SYS not detected"
END IF

IF DetectSMARTDRV THEN
 SMARTDRVInfo Hits&, misses&, dirty&, majVer%, minVer%, HitRate%, oops%
 PRINT "SMARTDRV V"; LTRIM$(STR$(majVer)); "."; LTRIM$(STR$(minVer)); " detected"
 PRINT USING " ÃÄ Cache hits   : #####"; Hits&
 PRINT USING " ÃÄ Cache misses : #####"; misses&
 PRINT USING " ÃÄ Dirty caches : #####"; dirty&
 PRINT USING " ÃÄ Cache hitrate: ###%"; HitRate%

 'Notice how the hitrate only changes after disk activity.
 'Why?, that's because the drive has become a SMART drive :-).
 'Theoretically it should not exceed 100% (if it does you have a
 'really smart one).

 SMARTDRVSize full%, current%, BytesPerElement!, windows%
 DosSize& = current% * BytesPerElement!
 WinSize& = windows% * BytesPerElement!
 TotalSize& = full% * BytesPerElement!
 PRINT " ÀÄ Cache sizes (bytes)"
 PRINT USING "     ÃÄ DOS     = ########"; DosSize&
 PRINT USING "     ÃÄ Windows = ########"; WinSize&
       PRINT "     ³          ----------- +"
 PRINT USING "     ÀÄ Total   = ########"; TotalSize&
ELSE
 PRINT "SMARTDRV not detected"
END IF
PRINT ""
COLOR 15
PRINT "Hope you can use this. Happy keyboard crunching !"

DO: LOOP UNTIL INKEY$ <> ""             'Wait until a key is pressed.
COLOR 7                                 'Restore default MS-DOS colour.
SCREEN 0                                'Restore screen (else Win95 crashes HARD)
END                                     'Terminate program.

'---------------------------- End demonstration ----------------------------

FUNCTION DetectANSI
Inreg.AX = &H1A00                       'Function 1Ah, Subfunction 0h
CALL INTERRUPT(&H2F, Inreg, Outreg)     'Call DOS (Int 2Fh)
DetectANSI = 0                          'Assume it's not there
IF Outreg.AX \ 256 = &HFF THEN DetectANSI = -1
END FUNCTION

FUNCTION DetectDOSKEY%
Inreg.AX = &H4800                       'Function 48h, Subfunction 0h
CALL INTERRUPT(&H2F, Inreg, Outreg)     'Call DOS (Int 2Fh)
DetectDOSKEY% = 0                       'Assume it's not there
IF Outreg.AX MOD 256 <> 0 THEN DetectDOSKEY% = -1
END FUNCTION

FUNCTION DetectKSTACK
Inreg.AX = &HE44F                   'Function E4h, Subfunction 4Fh
Inreg.BX = 0
CALL INTERRUPT(&H2F, Inreg, Outreg) 'Call DOS (Int 2Fh)
DetectKSTACK = 0                    'Assume it's not there.
IF Outreg.AX = &H44EE THEN DetectKSTACK = -1
END FUNCTION

FUNCTION DetectNDOS%
Inreg.AX = &HE44D                   'Function E4h, Subfunction 4Dh
CALL INTERRUPT(&H2F, Inreg, Outreg) 'Call DOS (Int 2Fh)
DetectNDOS = 0                      'Assume it's not there.
IF Outreg.AX = &H44EE THEN DetectNDOS = -1
END FUNCTION

FUNCTION DetectNGUIDES%
Inreg.AX = &HF398                       'Function F3h, Subfunction 98h
CALL INTERRUPT(&H16, Inreg, Outreg)     'Call DOS (Int 16h)
DetectNGUIDES% = 0                      'Assume it's not there.
IF Outreg.AX = &H6A73 THEN DetectNGUIDES% = -1
END FUNCTION

FUNCTION DetectNovellIPX%
'I haven't tested this routine because I don't have a network. Maybe in a few
'year's I can continue programming even when nature calls :-)
Inreg.AX = &H7A00                       'Function 7Ah, Subfunction 0h
CALL INTERRUPT(&H2F, Inreg, Outreg)     'Call DOS (Int 2Fh)
IF Outreg.AX MOD 256 = 0 THEN DetectNovellIPX% = 0
IF Outreg.AX MOD 256 = &HFF THEN DetectNovellIPX% = -1
END FUNCTION

FUNCTION DetectSMARTDRV%
Inreg.AX = &H4A10                    'function 4Ah, Subfunction 10h
Inreg.BX = 0                         'Sorry, lost the info on this !
Inreg.CX = &HEBAB                    'Sorry, lost the info on this !
CALL INTERRUPT(&H2F, Inreg, Outreg)  'Call DOS (Int 2fh)
DetectSMARTDRV = 0                   'Assume it's not there.
IF Outreg.AX = &HBABE THEN DetectSMARTDRV = -1
END FUNCTION

FUNCTION DetectXMS%
Inreg.AX = &H4300                       'Function 43h, Subfunction 0h
CALL INTERRUPT(&H2F, Inreg, Outreg)     'Call DOS (int 2Fh)
DetectXMS% = 0                          'Assume it's not there.
IF Outreg.AX MOD 256 = &H80 THEN DetectXMS% = -1
END FUNCTION

SUB NDOSVersion (majVer%, minVer%)
Inreg.AX = &HE44D                       'Function E4h, Subfunction 4Dh
CALL INTERRUPT(&H2F, Inreg, Outreg)     'Call DOS (Int 2Fh)
majVer% = minVer% = 0                   'Return zeroes if NDOS not loaded.
IF Outreg.AX = &H44EE THEN              'Modify version if it's there.
 majVer% = Outreg.BX MOD 256            'Major version in register BL
 minVer% = Outreg.BX \ 256              'Minor version in register BH
END IF
END SUB

FUNCTION PutKeysInKSTACK% (Keys$)
'If it doesn't work you may have to uncomment the line marked with "<---"
'and change the parameter of the VARSEG/SADD instruction.
'Many DOS functions require a Zero terminated string (ASCIIZ for short).

'KeysZ$ = Keys$ + CHR$(0)              '<--- Uncomment this one
InRegX.AX = &HE44F                     'Function E4h, Sub-function 4Fh
InRegX.BX = 1
InRegX.CX = LEN(Keys$)                 'Number of keystrokes being passed.
InRegX.DS = VARSEG(Keys$)              'Segment of the keystroke string.
InRegX.DX = SADD(Keys$)                'Address of the keystroke string.
CALL INTERRUPTX(&H2F, InRegX, OutRegX) '| Int 2Fh
END FUNCTION

SUB SMARTDRVInfo (Hits&, misses&, dirty&, majVer%, minVer%, HitRate%, oops%)
STATIC PrevHits&, PrevTotal&         'Keep data of previous call.
Inreg.AX = &H4A10                    'function 4Ah, subfunction 10h
Inreg.BX = 0
Inreg.CX = &HEBAB
CALL INTERRUPT(&H2F, Inreg, Outreg)  'Call DOS (int 2fh)
IF Outreg.AX = &HBABE THEN
 Hits& = Outreg.DX * &H100 + Outreg.BX
 misses& = Outreg.DI * &H100 + Outreg.SI
 dirty& = CLNG(Outreg.CX)
 majVer% = VAL(HEX$(Outreg.BP)) \ 100
 minVer% = VAL(HEX$(Outreg.BP)) - majVer * 100
 oops% = 0
ELSE
 oops% = -1
 EXIT SUB
END IF

'Calculate the hitrate with the formula as found in Microsoft Windows help.
'Hit_rate = 100 * (CurrentHits - PreviousHits) / (CurrentTotal - PreviousTotal)
CurrTotal& = Hits& + misses& + dirty&
HitRate% = 100 * (Hits& - PrevHits&) / (CurrTotal& - PrevTotal&)
END SUB

SUB SMARTDRVSize (full%, current%, BytesPerElement!, windows%)
Inreg.AX = &H4A10                     'function 4Ah, subfunction 10h
Inreg.BX = &H4
CALL INTERRUPT(&H2F, Inreg, Outreg)   'Call DOS (Int 2Fh)
full% = Outreg.AX                     'Size in elements of full sized cache
current% = Outreg.BX                  'Current size in elements
BytesPerElement! = Outreg.CX          'Size of one element in bytes
windows% = Outreg.DX                  'Number of elements under windows
END SUB
