'===========================================================================
' Subject: CHECK IF WINDOWS IS RUNNING        Date: 01-08-97 (18:02)       
'  Author: Hans Lunsing                       Code: QB, PDS                
'  Origin: FidoNet QUIK_BAS Echo            Packet: DOS.ABC
'===========================================================================
' > I was
' > wondering if I could have the programs run in the same EXE; and the
' > EXE will find out if it is being run in DOS mode, or Windows mode.

'Windows programs have DOS stubs that say "This program requires
'Microsoft Windows". 32-bit Windows (95) programs have 16-bit Windows (3)
'stubs that tell that they cannot run under 16-bit Windows. So in
'principle what you want is possible. At all events you need a linker
'able to make such a combined exe from the three different parts, but I
'don't know if a suitable linker exist.

' > How is it
' > possible to find out whether the program is run under DOS or WIN
' > '95 or WIN 3.1? Any help will be accepted!

'The following module will do that:

'******************************************************************************
'*                            ISWIN.BAS
'*
'*   This program will determine whether Windows is running and, if so,
'*   its operating mode.
'*   QuickBASIC must be loaded, as follows: QB /L QB
'*
'*   Translated by Hans Lunsing from ISWIN.C by Andrew Schulman,
'*   February 1993, which you can find on pages 170-172 of
'*
'*   "Undocumented DOS Second edition, A Programmer's Guide to Reserved
'*   MS-DOS Functions ans Data Structures",
'*   by Andrew Schulman, Ralf Brown, David Maxey, Raymond J. Michels,
'*   and Jim Kyle,
'*   published 1994 by Addison-Wesley Publishing Company,
'*   ISBN 0-201-63287-X
'******************************************************************************
DEFINT A-Z
' Type for segmented address

TYPE FarPtr
  Offset AS INTEGER             'offset
  Segment AS INTEGER            'segment
END TYPE

DECLARE FUNCTION DetectSwitcher ()
DECLARE SUB DOSGetVector (Number AS INTEGER, Vector AS FarPtr)
DECLARE FUNCTION WinGetVM ()
DECLARE FUNCTION IsWin (Major AS INTEGER, Minor AS INTEGER, Mode AS INTEGER)

'$INCLUDE: 'Qb.bi'              'Include file for interrupt calls

CONST FALSE = 0, TRUE = NOT FALSE

CONST MULTIPLEX = &H2F          'multiplex interrupt number

                                'Modes:
CONST REALmode = 1              'Windows in real mode
CONST STANDARDmode = 2          'Windows in standard mode
CONST ENHANCEDmode = 3          'Windows in enhanced mode

CONST SYSTEMVM = 1              'System Virtual Machine ID

DIM Major AS INTEGER            'Primary version number
DIM Minor AS INTEGER            'Secondary version number
DIM Mode AS INTEGER             'Mode in which Windows is running
DIM sMode AS STRING             'Mode string
DIM Version AS STRING           'Version string

IF NOT IsWin(Major, Minor, Mode) THEN
  PRINT "Windows is not running"
ELSEIF Major = 2 THEN
  PRINT "Running Windows-386 V 2.x"
ELSE
  Version = LTRIM$(STR$(Major)) + "." + RIGHT$("0" + LTRIM$(STR$(Minor)), 2)
  SELECT CASE Mode
  CASE 1: sMode = "Real"
  CASE 2: sMode = "Standard"
  CASE 3: sMode = "Enhanced"
  END SELECT
  PRINT "Running Windows "; Version; " (or higher) "; sMode; " mode"
END IF
IF Mode = ENHANCEDmode THEN
  ' If the task at hand is running within the System-VM the system must
  ' be some hacked version of Windows like MSDPMI, or the task must be
  ' running inside WINSTART.BAT.
  IF WinGetVM = SYSTEMVM THEN
    PRINT "Running DOS application in System VM:"
    PRINT "Must be WINSTART.BAT or hacked Windows!"
  END IF
END IF
END

FUNCTION DetectSwitcher
'-----------------------------------------------------------------------
' Function returns TRUE if DOSSHELL task switcher is loaded,
' and returns FALSE otherwise.
'-----------------------------------------------------------------------
DIM R AS RegTypeX
R.BX = 0
R.DI = 0
R.ES = 0
R.AX = &H4B02
CALL InterruptX(MULTIPLEX, R, R)        'DOSSHELL 5+ installation check
DetectSwitcher = (R.ES <> 0 OR R.DI <> 0)
END FUNCTION

SUB DOSGetVector (IntNum AS INTEGER, IntVec AS FarPtr)
'-----------------------------------------------------------------------
' Function returns IntVec of interrupt number IntNum as a segmented
' address in IntVec.
' (It is the same function as MBHANCE's SaveCurrentVec.)
'-----------------------------------------------------------------------
DIM R AS RegTypeX
R.AX = &H3500 OR (IntNum AND &HFF)
CALL InterruptX(&H21, R, R)
IntVec.Segment = R.ES
IntVec.Offset = R.BX
END SUB

FUNCTION IsWin (Major AS INTEGER, Minor AS INTEGER, Mode AS INTEGER)
'-----------------------------------------------------------------------
' Tests for Windows. Returns TRUE if running in Windows, and FALSE if
' otherwise. Moreover returns version number and mode as parameters.
'-----------------------------------------------------------------------
DIM R AS RegTypeX               'Processor registers for interrupt call
DIM IntVec AS FarPtr

Major = 0                       'Initialize version numbers
Minor = 0
Mode = 0                        'Initialize mode

' Make sure someone, anyone has INT 2Fh

DOSGetVector &H2F, IntVec
IF IntVec.Segment = 0 AND IntVec.Offset = 0 THEN
  IsWin = FALSE
  EXIT FUNCTION
END IF

'Call MULTIPLEX/160A to see if Windows 3.1+

R.AX = &H160A
CALL InterruptX(MULTIPLEX, R, R)
IF R.AX = 0 THEN                'AX = 0 if Windows running
  Mode = R.CX                   'Mode, 2 = Std., 3 = Enhanced
                                'Calculation of major version number is
                                'OK as long as it is < 128
  Major = R.BX \ 256            'Major version number
  Minor = R.BX AND 255          'Minor version number
  IsWin = TRUE
ELSE

  'Call MULTIPLEX/1600 to see if Windows 3.0 Enhanced mode or Windows/386

  R.AX = &H1600
  CALL InterruptX(MULTIPLEX, R, R)
                                'Calculation of minor version number is
                                'OK as long as it is < 128
  Major = R.AX AND 255          'Major version number
  Minor = R.AX \ 256            'Minor version number
  SELECT CASE Major
  CASE 1, &HFF                  'Windows/386 2.x is running
    Major = 2                   'Windows/386 2.x
    Minor = 1                   'don't know; assume 1
    Mode = ENHANCEDmode         'Windows/386 sort of like Enhanced
    IsWin = TRUE
  CASE 0, &H80                  'AL = 0 or 80h if no Windows

    'Call MULTIPLEX/4680h to see if Windows 3.0 Standard or Real mode;
    'but, this could be a "3.0 derivative" such as DOSSHELL task
    'switcher!

    R.AX = &H4680
    CALL InterruptX(MULTIPLEX, R, R)
    IF R.AX = 0 THEN            'AX = 0 if MULTIPLEX/4680 handled
      'Make sure it isn't DOSSHELL task switcher
      IF DetectSwitcher THEN
        IsWin = FALSE           'DOSSHELL taskswitcher
      ELSE
        Major = 3
        Minor = 0
        'Either have Windows Standard mode or Real mode; to distinguish
        'have to do fake Windows broadcasts with MULTIPLEX/1605h. Yuk!
        'We'll avoid that here by assuming 3.0 Standard mode. If you
        'really want to distinguish 3.0 Standard mode and real mode
        'See Microsoft Systems Journal, March 1991, p. 113; and Micro-
        'soft Knowledge Base articles Q75943 and Q75338.
        Mode = STANDARDmode
        IsWin = TRUE
      END IF
    ELSE
      IsWin = FALSE             'No Windows
    END IF
  CASE ELSE
    'Must be Windows 3.0 Enhanced mode
    Mode = ENHANCEDmode
    IsWin = TRUE
  END SELECT
END IF

END FUNCTION

FUNCTION WinGetVM
'-----------------------------------------------------------------------
' Function returns Virtual machine ID within Windows Enhanced Mode.
'-----------------------------------------------------------------------
DIM R AS RegTypeX
R.AX = &H1683
CALL InterruptX(MULTIPLEX, R, R)        'Get Virtual Machine ID
WinGetVM = R.BX
END FUNCTION
