Microsoft KB Archive/43534

From BetaArchive Wiki

Article ID: 43534

Article Last Modified on 8/16/2005



APPLIES TO

  • Microsoft Visual Basic for MS-DOS
  • Microsoft QuickBasic 4.0
  • Microsoft QuickBASIC 4.0b
  • Microsoft QuickBasic 4.5 for MS-DOS
  • Microsoft BASIC Compiler 6.0
  • Microsoft BASIC Compiler 6.0b
  • Microsoft BASIC Professional Development System 7.0
  • Microsoft BASIC Professional Development System 7.1



This article was previously published under Q43534

SUMMARY

The information in this article is also included in the Help file provided with the Standard and Professional Editions of Microsoft Visual Basic for MS-DOS, version 1.0.

The CALL INTERRUPT and CALL INTERRUPTX statements documented in this application note are similar to the CALL INT86 and CALL INT86X statements supported in QuickBasic for MS-DOS, versions 2.0, 2.01, and 3.0. The CALL INT86 and CALL INT86X statements also provide access to the ROM BIOS and MS-DOS Interrupts, but use an array interface instead of user-defined TYPEs. CALL INT86 and CALL INT86X are documented on pages 148-149 of the "Microsoft QuickBasic Compiler" manual for QuickBasic for MS-DOS, versions 2.0, 2.01, and 3.0. Although there are differences, some of the information in this application note will be useful to those who use QuickBasic for MS-DOS, versions 2.0, 2.01, and 3.0.

MORE INFORMATION

CALL INTERRUPT is a complicated statement that allows programmers to have access to low-level MS-DOS and ROM BIOS information and control from Basic. Effective use of the complex CALL INTERRUPT interface requires an understanding of the Basic programming environment, the Basic language, and lower-level MS-DOS and ROM BIOS functions. This article explains many of these necessary features, including the following:

  1. Libraries and Quick libraries
  2. User-defined TYPEs
  3. INCLUDE files
  4. CALL INTERRUPT input and output
  5. Example of CALL INTERRUPT
  6. Differences between CALL INTERRUPT and CALL INTERRUPTX
  7. References for documentation on Interrupts

The CALL INTERRUPT statement is designed to call only MS-DOS interrupts, and is not supported in MS OS/2 protected mode. Most of the functions provided by MS-DOS Interrupts are available in MS OS/2 protected mode, but are accessed through API (application programming interface) calls. Most Interrupts will work correctly in OS/2's real mode (the MS-DOS version 3.x box).

Libraries and Quick Libraries

The object code for the Interrupt routines is located in the VBDOS.LIB, VBDOS.QLB, QB.LIB, QB.QLB , QBX.LIB, and QBX.QLB files, which are supplied with Visual Basic for MS-DOS, version 1.0; and QuickBasic for MS-DOS, versions 4.0, 4.0b, and 4.5; and Basic Compiler for MS-DOS, versions 6.0 and 6.0b.

The difference between LINK libraries (LIB files) and Quick libraries (QLB files) is that Quick libraries serve as executable code modules for use within the VBDOS or QuickBasic environment, and LINK libraries are used at link time to produce executable programs.

To load a Quick library for use with the VBDOS or QuickBasic environment, you must start VBDOS or QuickBasic with the /L option (that is, VBDOS /L VBDOS.QLB or QB /L QB.QLB or QBX /L QBX.QLB). This will allow you to make CALLs to the routines in that Quick library. When you open the Run menu and choose Make EXE File, your program will automatically be linked with the library (LIB file) of the same name as your Quick library (in this case, VBDOS.LIB, QB.LIB or QBX.LIB).

User-Defined Types

To use the CALL INTERRUPT statement, you must first create a user- defined TYPE to contain the registers for the Interrupt. The TYPEs defined in the INCLUDE file (VBDOS.BI, QB.BI, or QBX.BI) that come with Visual Basic for MS-DOS, version 1.0, QuickBasic for MS-DOS, versions 4.0, 4.0b, and 4.50, and Basic PDS for MS-DOS, versions 7.0 and 7.1 are as follows:

TYPE RegType
     ax    AS INTEGER
     bx    AS INTEGER
     cx    AS INTEGER
     dx    AS INTEGER
     bp    AS INTEGER
     si    AS INTEGER
     di    AS INTEGER
     flags AS INTEGER
END TYPE
                
TYPE RegTypeX                     ' See Note below.
     ax    AS INTEGER
     bx    AS INTEGER
     cx    AS INTEGER
     dx    AS INTEGER
     bp    AS INTEGER
     si    AS INTEGER
     di    AS INTEGER
     flags AS INTEGER
     ds    AS INTEGER
     es    AS INTEGER
END TYPE
                

Note: RegTypeX is used with the CALL INTERRUPTX statement, which allows you to specify the DS and ES registers. For more information on CALL INTERRUPTX, please refer to the section "Differences Between CALL INTERRUPT and CALL INTERRUPTX" on page 4 of this application note.

INCLUDE Files

To simplify the TYPE definition for Interrupts, the INCLUDE file VBDOS.BI, QB.BI, or QBX.BI is shipped with Visual Basic for MS-DOS, version 1.0, with QuickBasic for MS-DOS, versions 4.0, 4.0, and 4.5, with Basic Compiler for MS-DOS, versions 6.0 and 6.0b and Basic PDS for MS-DOS, versions 7.0 and 7.1. VBDOS.BI, QB.BI, and QBX.BI have the TYPE definitions (see page 3 of this application note for TYPE example) and SUB DECLARations needed for Interrupts. To use this file, place the metacommand $INCLUDE at the beginning of your code. The syntax of this statement is as follows:

   ' Use the following include statement for Visual Basic for MS-DOS:
   REM $INCLUDE: 'VBDOS.BI'
   ' Use the following include statement for QuickBasic for MS-DOS:
   REM $INCLUDE: 'QB.BI'
   ' Use the following include statement for Basic PDS for MS-DOS:
   REM $INCLUDE: 'QBX.BI'
                

Please note the following:

  1. The $INCLUDE metacommand is placed in a REM (comment) statement.
  2. A colon (:) follows $INCLUDE.
  3. The filename VBODS.BI, QB.BI, or QBX.BI is enclosed in single quotation marks ('VBDOS.BI' or 'QB.BI' or 'QBX.BI').

CALL INTERRUPT Input and Output

Besides the Interrupt number, there are two other parameters for the CALL INTERRUPT statement: the input registers and the output registers. Before you use these registers, you must dimension two variables AS the RegType defined earlier, as follows:

   DIM inregs AS RegType, outregs AS RegType
                

For most Interrupts, you need to pass some information (function number, function parameters) in one or more of the registers. This assignment is done into individual elements of the user-defined TYPE inregs, such as the following:

   inregs.AX = &H1A00
                

Note that the above assignment uses hexadecimal values -- denoted by the "&H"-- instead of decimal values. Most references for Interrupts use hexadecimal numbers rather than decimal numbers because the high (1A) and low (00) bytes are easier to distinguish in hexadecimal notation.

For some Interrupts, it is necessary to set the high-order or low- order byte of a register. These bytes are referred to in technical literature with H and L replacing X. For example, the high and low bytes of the BX register are BH and BL, respectively. To assign the registers when given high and low bytes, concatenate the hexadecimal values. For example, if you need to assign CH the value 2B hex and assign CL the value 3D hex, you would assign CX as follows:

   inregs.CX = &H2B3D     ' High byte = &H2B    Low byte = &H3D
                

If you are given only 1 byte (high or low), the other byte should be assigned 00 (two zeros). For example, you would set AH to the value 01 hex as follows:

   inregs.AX = &H0100     ' High byte = &H01    Low byte = &H00
                

Note: The above statement is NOT equivalent to inregs.AX=&H01. You must specify the low-order byte or the value will be stored as &H0001.

Once you have set the values of the input registers, you are ready to make the CALL. The CALL INTERRUPT syntax is as follows:

   CALL INTERRUPT(IntNum%, inregs, outregs)
                

If an Interrupt returns any values, those values will be passed back in the outregs variable. As with inregs, values will often be passed in the high or low bytes of a register. The routine BreakWord() in the "Example CALL INTERRUPT" section below breaks a register into the 2- byte values.

With many Interrupts, you need to check only a single bit (or a few bits) of any register. This is done using the bitwise operators AND, OR, XOR, and NOT. For example, the following statement will check to see if the third bit of AX is set:

   IF (outregs.AX AND &H4) THEN     ' 4 in hex = 100 in binary
     PRINT "3rd Bit is on"
   END IF
                

Example of CALL INTERRUPT

The following program gives an example of the CALL INTERRUPT statement and provides two utility SUB programs for processing output:

'__________________________ INTSKEL.BAS _________________________
'
'     Skeleton program for calling MS-DOS or ROM BIOS Interrupts from
'     from Visual Basic, QuickBasic, or Basic PDS.
'
'     To try this example in VBDOS.EXE:
'     1. From the File menu, choose New project.
'     2. Copy the code example to the Code window.
'     3. Press F5 to run the program.
'
'
'     NOTE: The VBDOS and QuickBasic environments must be started
'           with the /L option to load the default Quick library.
'           The VBDOS.QLB, QB.QLB, or QBX.QLB Quick libraries provide
'           support for CALL INTERRUPT and CALL INTERRUPTX.
'
'     There are also two SUBPROGRAMS, BreakWord() and IntToBin(), that
'     you may find useful when CALLing Interrupts.
'_________________________________________________________________

DEFINT A-Z
CONST TRUE = -1
CONST FALSE = NOT TRUE      ' FALSE is assigned to 0 here.

' Use the following include file for Visual Basic for MS-DOS:
REM $INCLUDE: 'VBDOS.BI'        ' Take a look at what is in this file.
' Use the following include file for QuickBasic for MS-DOS:
REM $INCLUDE: 'QB.BI'           ' Take a look at what is in this file.
' Use the following include file for Basic PDS for MS-DOS:
REM $INCLUDE: 'QBX.BI'          ' Take a look at what is in this file.

DIM inregs AS RegType, outregs AS RegType

'---------------------------------------------------------------------
' Load Registers with the required input parameters for the call that
' you want to make. (See any reference for MS-DOS and/or ROM BIOS
'  calls.)
'
' Example: for Interrupt 10h, with function 0Ah (ROM BIOS Write Char)
'          AH = 0Ah. Note: The function number usually goes in AH.
'          AL = Character Code (ASCII).
'          BH = Video Page Number = 0 normally.
'          BL = Color in graphics mode.
'          CX = Number of these characters to write to screen.
'--------------------------------------------------------------------
CLS
character% = &HFB    ' ASCII character 251 decimal, square root symbol.
functnum% = &HA00    ' Remember you want the function in the HIGH Byte
                     ' of AX.

   ' VERY IMPORTANT! Don't put the function number into the wrong byte
   ' of AX, or the program may hang or give unpredictable results!

inregs.ax = character% OR &HA00
inregs.cx = 2000      ' Fill the screen.
CALL interrupt(&H10, inregs, outregs)

DEFINT A-Z
'_____________________________________________________________________
'
'     BreakWord() takes an integer argument and returns two integers
'     representing the high and low bytes of the original.
'_____________________________________________________________________
'
SUB BreakWord (dataword, highbyte, lowbyte)
   IF dataword < 0 THEN
     highbyte = (dataword + 2 ^ 16) \ 256   ' Check for high BIT set.
   ELSE
     highbyte = dataword \ 256  ' Integer division to remove low byte.
   END IF
   lowbyte = dataword AND 255   ' AND operator to remove the top byte.
END SUB

DEFINT A-Z
'_____________________________________________________________________
'
'    The IntToBin() SUBprogram below takes an INTEGER argument
'    and produces a binary string representation of the INTEGER.
'_____________________________________________________________________
'
SUB IntToBin (byte%, bin$)
bin$ = ""
temp% = byte%
FOR i = 0 TO 7     ' Loop through bits 0 through 7 (8 total).
   IF temp% AND 1 THEN
      bin$ = "1" + bin$
   ELSE
      bin$ = "0" + bin$
   END IF
   temp% = temp% \ 2  ' Division by 2 shifts right 1 binary digit
                      ' (bit).
NEXT
END SUB
                

Differences Between CALL INTERRUPT and CALL INTERRUPTX

The CALL INTERRUPT and CALL INTERRUPTX statements are very similar. Either statement allows you to make calls to MS-DOS and ROM BIOS Interrupts.

The only difference is that with INTERRUPTX, you can specify the DS and ES registers. (The documentation for Interrupts -- see the following reference section -- will state whether those registers are necessary. For most Interrupts, DS and ES are not needed.)

References for Documentation on Interrupts

The following books are excellent resources for the different Interrupts available from MS-DOS and the ROM BIOS. Be aware that the code in these books is written in assembly language; however, the necessary input and output is given by register.

  1. "Advanced MS-DOS Programming", Second Edition by Ray Duncan, published by Microsoft Press (1988)
  2. "The New Peter Norton Programmer's Guide to the IBM PC & PS/2" by Peter Norton, published by Microsoft Press (1988)



Additional query words: VBmsdos QuickBas BasicCom 1.00 2.00 2.01 3.00 4.00 4.00b 4.50 6.00 6.00b 7.00 7.10

Keywords: kbcode KB43534