💾 Archived View for gemini.spam.works › mirrors › textfiles › magazines › MISC › qbnws103.nws captured on 2022-06-12 at 13:24:11.

View Raw

More Information

-=-=-=-=-=-=-

     Volume  1, Number  3                                      May 22, 1990

     
     
     
     
     
     
     
     
     
     
     
                   **************************************************
                   *                                                *
                   *                    QBNews                      *
                   *                                                *
                   *      International QuickBASIC Electronic       *
                   *                  Newsleter                     *
                   *                                                *
                   *    Dedicated to promoting QuickBASIC around    *
                   *                  the world                     *
                   *                                                *
                   **************************************************
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
        The  QBNews  is  an electronic newsletter  published  by  Clearware
     Computing. It can be freely distributed providing NO CHARGE is charged
     for  distribution.  The  QBNews is copyrighted in  full  by  Clearware
     Computing.  The  authors  hold  the  copyright  to  their   individual
     articles.  All program code appearing in QBNews is released  into  the
     public  domain.   You  may  do what you  wish  with  the  code  except
     copyright  it.  QBNews  must  be  distributed  whole  and  unmodified.
     
     You can write The QBNews at:
     
          The QBNews
          P.O. Box 507
          Sandy Hook, CT 06482
     
     Copyright (c) 1989 by Clearware Computing.
     
     
     
     The QBNews                                                   Page    i
     Volume  1, Number  3                                      May 22, 1990


     
 
     ----------------------------------------------------------------------

                        T A B L E   O F   C O N T E N T S

     
     1.  From the Editors Desk
          From the Editor ..............................................  1

     2.  Mail Bag
          QBNews in Europe .............................................  2

     3.  Beginners Corner
          BASIC Menuing and Graphics by Ryan Snodgrass .................  4

     4.  Who ya gonna call? CALL INTERRUPT
          Directory Swapping by Hector Plasmic .........................  6

     5.  The Tool Shed
          P-Screen+ and P-Screen Professional by David Cleary ..........  8
          Index Manager - B-Tree indexing for QB by David Cleary ....... 10

     6.  Product Announcements
          P-Screen, P-Screen Professional, P~F Presents ................ 12

     7.  Under The Hood
          Fast File I/O in QuickBASIC by Ethan Winer ................... 16

     8.  Power Programming
          How to Make a Self-Cloning Exe in QuickBASIC by Larry Stone .. 19
          Programming UEVENT by Jim Mack ............................... 23

     9.  Some Assembly Required 
          Assembler Programming for QuickBASIC by Tom Hanlin ........... 26

     10.  And I Heard it Through the Grapevine
          Exerpts from the QUIK_BAS echo ............................... 29

     11.  Swap Shop
           Screen Scrolling with Call Interrupt ........................ 33
           Getting the Day of the Week with Call Interrupt ............. 35
           Yes/No Response DEF FN ...................................... 37
           A Replacement for INPUT with MUCH MORE programmer control. .. 39
           Windowing Routines with Shading ............................. 41

     12.  Input Past End
           Get the QBNews on Disk ...................................... 42
           Contacting the QBNews ....................................... 43

     The QBNews                                                   Page   ii
     Volume  1, Number  3                                      May 22, 1990



     ----------------------------------------------------------------------
                    F r o m   t h e   E d i t o r s   D e s k
     ----------------------------------------------------------------------

     From the Editor
     
          Welcome  to the third issue of The QBNews. I know it has  been  a
     while  coming  but I hope it was worth the wait. There  are  some  big
     changes  in  store for the news. I have realized that putting  out  an
     issue  every  2 months is impractical. Therefore, The QBNews  will  be
     published quarterly. Expect issues around these dates:
     
     May 30
     August 30
     November 30
     February 28
     
          I  have also received alot of requests for the news on disk.  You
     can  now  receive the QBNews on disk. Information on this  service  is
     available in the back of this issue.
     
          The  QBNews is distributed through SDS on Fidonet. It seems  that
     SDS  is not as far reaching as I had thought. In order that  everybody
     knows that the can get the news reasonably close to them, I would like
     to set up distribution hubs around the country. I am looking for BBS's
     in these areas who would like to be QBNews hubs: Baltimore/Washington,
     Charlotte  NC,  Atlanta,  Orlando,  Memphis,  New  Orleans,   Chicago,
     Cincinnati, Minneapolis, Kansas City MO, Dallas, Denver, Phoenix,  Los
     Angeles,  San  Francisco, and Portland. I do require a few  things  in
     order  to be a hub. First, first time callers must be granted  limited
     download privledges. Second, you must accept file requests from  Point
     systems.  Last, you must be willing to send the news down the line  to
     the next hub. If you meet these conditions and are interested in being
     a hub, write me.
     
          I want to hear from you. After the first issue, I received  quite
     a  bit of feedback. I wasn't too happy with that issue. I thought  the
     second issue was really good. I didn't receive as much feedback on  it
     as  the first though. It was kind of disappointing. Let me  hear  your
     complaints, suggestions, coding tips, or whatever. It always helps  to
     know people are interested.
     
          Thanks and enjoy.
          David Cleary
     










     The QBNews                                                     Page  1
     Volume  1, Number  3                                      May 22, 1990



     ----------------------------------------------------------------------
                                 M a i l   B a g
     ----------------------------------------------------------------------

     
     Hello David,
     
          Today I've picked up 2 QBNews files and I've read them both. Most
     interesting  stuff! Just the electronic magazine I need!  Coming  from
     the  TRS80 Model I computer on which I've learned basic and  wrote  my
     own  BBS and videotext systems in basic (the system is  still  online)
     I've  entered the PC community and started with RBBS-PC which  is,  as
     you  would  know,  almost  completely  written  in  QuickBasic.   I've
     purchased   the  package  a  few  years  ago  and  developed   a   few
     administrative  applications  in  it for a friend  his  firm.  At  the
     moment,  due  to  lack of time, I'm only do  a  little  debugging  and
     modifying RBBS-PC. I recently discovered a bug (well, I think it is  a
     bug) which I will give you here:
     
     DEFINT A-Z :' so every variable is by default integer
     Single precision! = 3600 * Hour
     
          The  maximum  value of an integer is 32767 and  when  you  expect
     "Hour"  can  have a maximum value of 24, then the  receiving  variable
     must  be  a single precision variable 'cause by example 20  *  3600  =
     72000. So the construction above looks good but isn't. QuickBasic will
     evaluate "3600 * Hour" as an integer expression 'cause both  variables
     are  integers. The result will be an overflow error. I've  tested  the
     same  construction on my TRS80 and on the PC in GWBASIC and they  both
     work fine!!
     
     The solution for this problem is very simple. The technique is  called
     typecasting.
     
     Single  precision!  =  3600.0  * Hour  :' 3600.0  is  of  type  single
     precision
     
     When  you enter this in the QB environment, QB will change  3600.0  in
     3600! which is the same.
     
     Some undocumented META statements, nice to know:
     ' $LINESIZE:132
     ' $PAGE
     ' $TITLE: 'put the main title here'
     ' $SUBTITLE: 'put the sub-title here'
     
          Anyway,  I hope this is some contribution to the  magazine.  From
     now  on  I will put the QBNews files in my two BBS  systems  and  will
     upload them to some other systems here in Holland. I hope more  QBNews
     will  come  from the other side of the ocean. Please  respond  through
     Fidonet  if you receive this message. Where I living, well, in a  city
     called Amsterdam, that's in Holland or The Netherlands and that is  in
     Europe  ('cause many Americans don't know what's on the other side  of
     the ocean ;-)
     
     
     The QBNews                                                     Page  2
     Volume  1, Number  3                                      May 22, 1990

     Cu, Kim Kodde (2:500/41.1433) Holland
     
     
     
     Hello David,
     
          A  very  good initiative! I give my full support  for  whit  it's
     worth.  I am not a professional programmer and I have no education  in
     this area, but I have been programming in BASIC for some years for fun
     and  during  that  time gone from an VIC64 to an AMSTRAD  6128  to  an
     Artech 286/AT (and IBM ps 20). I started out with QB 2.00 a couple  of
     years ago but recently upgraded to 4.50. It is a marvelous difference.
     
          I have also included an extract from a program I have written for
     my work.  I am a journalist and the program is used to store things we
     are  to  check  or  cover in the  future.  Certain  things  come  back
     regularly on certain weekdays no matter which date it is. I  therefore
     needed  a simple routine to check which weekday a certain date  is  so
     when  the  agenda  for  that date is printed  out  the  correct  items
     depending on the weekday is included.  I found my answer in  interrupt
     33,  function 2a00.  The low part of register AX returns a number  for
     the  weekday. 0 for Sunday to 6 for Saturday.  This is very  good  for
     the future.  If you are interested in checking which day you were born
     for  example you need something else because the computer only  covers
     dates  from  the  early 80-ies.  I have seen  programs  in  genealogy-
     packages which covers this part.
     
     Johan Lindgren
     Sundsvall, Sweden
     
     
          I  would  be interested in hearing from you.  Please  write  with
     comments,  suggestions, complaints, or whatever you feel like  talking
     about. Send it to:
     
     The QBNews
     P.O. Box 507
     Sandy Hook, CT 06482
     
















     The QBNews                                                     Page  3
     Volume  1, Number  3                                      May 22, 1990



     ----------------------------------------------------------------------
                         B e g i n n e r s   C o r n e r
     ----------------------------------------------------------------------

     BASIC Menuing and Graphics by Ryan Snodgrass
     
          This  section  of  QB News is dedicated to the  readers  who  are
     novices to Quick BASIC.  In this issue we will talk about creating and
     editing simple menu programs and about some of the elementary commands
     used  in making computerized graphics.  The first thing we talk  about
     is  making simple menus.  The first step you take in making a menu  is
     to plan what selections you will have.  In our example we will use the
     following selections: DIR, make the computer beep, and quit.  The next
     step  is  to  plan whether to use numbers, letters, or  both.  In  our
     example  we  will use both numbers and letters.  The following  is  an
     example program; you may edit it as much as you like.
     
          Menu:
          PRINT "(1) - DIR"    'Shows the first selection (DIR)
          PRINT "(2) - BEEP"    'Shows the second selection (BEEP)
          PRINT "(Q) - QUIT"    'Shows the third selection (QUIT)
         MenuInput:
               A$=INPUT$(1)     'Waits  for the input from  the  keyboard
               IF A$="1" THEN GOTO Selection1   'See if one was pressed
               IF A$="2" THEN GOTO Selection2   'See if two was pressed
               IF A$="Q" OR A$="q" THEN CLS:END    'See if Q was pressed
          GOTO MenuInput    'Go back and wait for another key
     
          Selection1:
               SHELL"DIR"     'Do a DIR of the current  directory
               GOTO Menu    'Redisplay the menu
          Selection2:
               BEEP     'Produce a beep
               GOTO  Menu    'Redisplay the menu
     
     -+* To edit selections on this menu do the following: *+-
     
     1) Change the menu listing by replacing one of the selections by
     another (i.e. PRINT "(1) - DIR" replace with the following:
          PRINT "(1) - DIR/P")
     
     2) Change the selection commands (i.e. change the Selection1  commands
     to:
          Selection2:
               SHELL"DIR/P"
               GOTO Menu
     
     -+*  To add selections to the menu do the following: *+-
     
     1) After the PRINT "(2) - BEEP" add PRINT "(3) - Your Selection"
     
     2) After IF A$="2" THEN... add IF A$="3" THEN GOTO Selection3
     
     3) After the GOTO Menu on Selection2 add:
          Selection3:
     
     The QBNews                                                     Page  4
     Volume  1, Number  3                                      May 22, 1990

               'Your  command
               GOTO  Menu
     
     
          The  next  subject  we will discuss is  elementary  commands  for
     creating  graphics  screens.   A graphics  screen  is  represented  by
     a  number of pixels or points on the screen, which is referred  to  as
     the resolution of your screen.  The first step we must do is select  a
     screen  number  which  corresponds to your  resolution  or  any  other
     resolution you can use.  The following is a list of screen number  and
     their attributes:
     
     +-----------+------------------+-------------+------------------+
     |Screen #:   | # of colors:    | Resolution: | Width of  Screen:|
     +-----------+------------------+-------------+------------------+
     | 1 (CGA)    | 4 out of 16     | 320x200     | 40 Characters    |
     | 2 (CGA)    | 2 out of 2      | 640x200     | 80 Characters    |
     | 7 (EGA)    | 16 out of 64    | 320x200     | 40 Characters    |
     | 8 (EGA)    | 16 out of 64    | 640x200     | 80 Characters    |
     | 9 (EGA)    | 16 out of 64    | 640x350     | 80 Characters    |
     | 10 (MONO)  | 9 grays         | 640x350     | 80 Characters    |
     | 11 (VGA)   | 2 out of 2      | 640x480     | 80 Characters    |
     | 12 (VGA)   | 16 out of 256000| 640x480     | 80 Characters    |
     +-----------+------------------+-------------+------------------+
     
          The  next step is to type: SCREEN (and then the type of  graphics
     you want).  The first and easiest command is LINE.  The usage is  LINE
     (X,Y)-(X,Y),Color  (i.e. LINE (100,100)-(200,200),1 would draw a  line
     from  100,100 to 200,200 using the color 1). Using that in an  example
     program  would be as  follows:
     
          SCREEN  1
          LINE(100,100)-(200,200),1
          END
     
          You  can  also  draw  an open  rectangle  by  using  LINE  (X,Y)-
     (X,Y),Color,B or a solid rectangle by using LINE (X,Y)-(X,Y),Color,BF.
     The  next command we will go into is the DRAW command.  The  usage  is
     DRAW  "(Attributes)" (i.e. DRAW "U4 R4 D4L4").  The attributes are  as
     follows:  C#=Color Number, U#=Up a number of pixels, D#=Down a  number
     of  pixels, L#=Left a number of pixels, R#=Right a number  of  pixels,
     E#=Up and to the right a number of pixels, F#=Down and to the right  a
     number of pixels, G#=Down and left a number of pixels, H#=Up and  left
     a  number  of  pixels, M X,Y=Moves to a certain pixel  (i.e.  DRAW  "M
     100,100"). Our example program draws a 3-D box:
     
          SCREEN  1
          DRAW "M 100,100 C1 U10 R10 D10 L10 H10 U10 F10 R10 H10 L10"
          END
     
          If  you have any suggestions as to what you would like to see  in
     this  column,  please send them to the QBNews at the  address  in  the
     back.
     

     The QBNews                                                     Page  5
     Volume  1, Number  3                                      May 22, 1990



     ----------------------------------------------------------------------
        W h o   y a   g o n n a   c a l l ?   C A L L   I N T E R R U P T
     ----------------------------------------------------------------------

     Directory Swapping by Hector Plasmic
     
          You've  all seen professional programs that let you Shell to  DOS
     and  always return you to the proper drive and subdirectory  when  you
     Exit.  It's not too hard to implement something similar for  your  own
     QuickBASIC programs.  QB doesn't have all the functions you need to do
     it, but DOS can lend a hand via Interrupt.
     
          What we need to do is handle all SHELL calls from a common  point
     (Sub).   In   this  Sub,  we'll  determine  the  current   drive   and
     subdirectory,  perform  the  SHELL, then restore  the  old  drive  and
     subdirectory  before  Exitting  the  Sub.
     
          Interrupt 21h function 19h returns the number of the current disk
     drive  in  register  .al as a number (0=A,  1=B,  etc.).
     
          Interrupt  21h function 47h copies the current directory  of  the
     drive  #  in  .dl  (0=default, 1=A, 2=B,  etc.)  as  an  ASCIIZ  (null
     terminated) string into a buffer pointed to by .ds:.si.  The  pathname
     does  not  include the drive identifier or a  leading  backslash.   An
     error can occur if you use an invalid drive specification; this is not
     likely since we are using the default drive, but if you are using this
     function to attempt to read the default directory on a drive that  may
     not   exist,   check   the  carry  flag   (IF   OutReg.FLAGS   AND   1
     THEN...oops!).  .ax will contain 0Fh (invalid drive spec) if the error
     occurs.
     
          Finally, Interrupt 21h function 0Eh sets the default drive to the
     drive  number passed in register .dx (0=A, 1=B,  etc.).This  completes
     the  list of DOS functions we'll need to perform our switching.   What
     follows  is some sample code to show a practical application of  these
     interrupt  functions:
     
     DEFINT A-Z
     
     TYPE RegType2
          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
     
     'You must link with QB.LIB (QB.QLB) to use Interrupt functions
     
     DECLARE SUB InterruptX (Intr%, InReg AS RegType2, OutReg AS RegType2)
     
     The QBNews                                                     Page  6
     Volume  1, Number  3                                      May 22, 1990

     DECLARE SUB DoShell (Before$, Args$, After$)
     
     DoShell "Type EXIT to return", "", "Welcome back"   'Just to test it
     END
     
     SUB DoShell (Before$, Args$, After$)'Declare some stuff to use
     
     DIM InReg AS RegType2
     DIM OutReg AS RegType2
     DIM CurrentDrive AS INTEGER
     DIM CurrentDir AS STRING * 64
     
     'Get current disk drive
     
     InReg.AX = &H19 * 256
     InterruptX &H21, InReg, OutReg
     CurrentDrive = OutReg.AX MOD 256
     
     'Get current directory
     
     InReg.AX = &H47 * 256
     InReg.DX = CurrentDrive + 1  'Note adding one to drive for this, or
                                  'could use 0 for default drive
     InReg.DS = VARSEG(CurrentDir)
     InReg.SI = VARPTR(CurrentDir)
     InterruptX &H21, InReg, OutReg
     
     'Do the shell
     IF Before$ <> "" THEN CLS : PRINT Before$  'Optional
     SHELL Args$
     IF After$ <> "" THEN CLS : PRINT After$    'Optional
     
     'Change to old disk drive
     InReg.AX = &HE * 256
     InReg.DX = CurrentDrive
     InterruptX &H21, InReg, OutReg
          '(InReg.AX MOD 256 is the # of logical drives in the
          'system if anyone is interested)
     
     'Change to old subdirectory (Could use Int &H21 func &H3B instead)
     ToDir$ = CHR$(ASC("A") + CurrentDrive) + ":\" + LEFT$(CurrentDir,_
          INSTR(CurrentDir, CHR$(0)))
     CHDIR ToDir$
     
     END SUB
     









     The QBNews                                                     Page  7
     Volume  1, Number  3                                      May 22, 1990



     ----------------------------------------------------------------------
                            T h e   T o o l   S h e d
     ----------------------------------------------------------------------

     P-Screen+ and P-Screen Professional by David Cleary
     
          *** IMPORTANT ***
          It took me a while to write this review. As you read it, you will
     see  I have two major complaints concerning these programs.  They  are
     lack  of  mouse support and an easier user interface.  These  problems
     have  been  corrected in the latest release. Please  see  the  product
     announcement for the new version in this issue.
     
          A program's user interface can be the difference between  success
     and  failure.  You  could have the best program in the  world  but  if
     people  don't like using it, it won't succeed. The user  interface  is
     also  the part of a program I hate doing the most. I know what I  like
     in  a  user interface but I have a hard time translating  it  into  my
     programs. I also find the coding of user interfaces very tedious.  So,
     in  this  issue,  I  will review a tool that  helps  you  design  user
     interfaces quickly and easily.
     
          The  product  is  called P-Screen and is  from  Pro~Formance.  P-
     Screen+  is  a  shareware  program  while  P-Screen  Professional   is
     commercial.  This program combines a screen drawing utility, a  screen
     storage  and  display  utility, and the Professional  version  adds  a
     QuickBASIC  3  and  4  code generator and  a  variety  of  user  input
     routines. These programs allows you to create screens and forms, store
     them  in libraries, and access them from your QuickBASIC programs.  We
     will examine these features individually.
     
          As  a screen generator, I feel that P-Screen has one major  flaw.
     It  lacks  mouse  support. Personally, I like mice and  I  don't  like
     having to navigate the screen with the cursor keys. When you start  up
     P-Screen Professional, you get a nice title screen that tells you your
     options  and waits for you to press a key. After you press a key,  you
     are  left with a blank screen and a "What do I do now?" look  on  your
     face. Pressing F1 for help shows you 2 screens of commands but that is
     all. To learn how to use P-Screen, you will need a copy of the printed
     documentation next to you.
     
          After  you  start using the commands and learn what they  do,  P-
     Screen  is a pleasure to use. It allows you to draw your  screens  and
     store  them  in  either ASCII or a compressed  format.  P-Screen  also
     allows  you to load screens saved in QB's BSAVE format but  won't  let
     you  save them that way. If P-Screen had mouse support and  better  on
     line  help,  it would be one of the best screen  designers  available.
     Without it though, it still is very good.
     
          Next  comes  the  screen storage and  display  utility.  P-Screen
     stores  screens on disk in a compressed screen format. The savings  in
     size  is  very noticeable the more screens you have in a  library.  P-
     Screen  then has two routines that load the screens into an array  and
     display  them. They are written in Assembler and are very fast.  These
     routines  allow  you to display full or partial screens  anywhere  you
     
     The QBNews                                                     Page  8
     Volume  1, Number  3                                      May 22, 1990

     want. I couldn't find anything to complain about. They are nicely done
     and will add a professional look to your programs.
     
          Now  to  what  I  think  is  the  best  part  of  P-Screen.   The
     Professional   version   comes  with  a   form   generator.   P-Screen
     Professional  comes with the ability to create forms and it  generates
     code that handles user input on these forms. See the program Index.Bas
     for an example of the code P-Screen Professional generated for a small
     index card screen I created. The user input routine is nicely done  in
     Assembler and includes a variety of formatting options and masks. Some
     of these include Date, Phone Number, Zip Code, Social Sec. Number, and
     Currency.  With these options, your program makes sure that  the  user
     types in only valid keys and in the format you want. The code that  P-
     Screen Professional generates is then inserted into your program. This
     allows  you to create professional looking documents with very  little
     effort.  I  am  very impressed with  these  capabilities  in  P-Screen
     Professional.
     
          Two  shareware programs you should be aware of are  P-Screen  and
     P~F  Presents.  P-Screen  is the screen drawing  and  library  utility
     portion of P-Screen Professional. Gone are the code generator and form
     utilities and the ability to display partial screens. My advice to you
     is  to get the shareware version and try out the screen generator.  If
     you  like using it to create your screens, then you  should  certainly
     buy the professional version. You won't be disappointed.
     
          P~F  Presents is a screen presentation system. It lets  you  take
     screens created with P-Screen and create slide shows out of them. This
     is great for presentations or prototyping applications before you  get
     down  to  writing  code.  With it, you  can  create  your  whole  user
     interface  and let the users give you there comments on it BEFORE  you
     write  any code. This saves a lot of headaches from having to  rewrite
     your  programs when your views on how the program should  operate  are
     different from the intended users.
     
          P-Screen Professional is available from:
     
               Pro~Formance
               132 Alpine Terrace
               San Francisco, CA 94117
               (415) 863-0530
     
          The  cost  is  $49 plus $3 shipping and handling.  You  also  can
     download the shareware version of P-Screen and P~F Presents from Peter
     Tiffany's  BBS,  (415)  458-6404 or on CompuServe in  the  IBMPro  and
     IBMApp areas. The filenames are PSCRN35.ZIP and PFPRES35.ZIP.
     








     The QBNews                                                     Page  9
     Volume  1, Number  3                                      May 22, 1990

     Index Manager - B-Tree indexing for QB by David Cleary
     
          Databases  are  an  important  part  of  computers  and  computer
     programming. QuickBASIC has built in capabilities that make it easy to
     write a simple database. The problem is, as your database gets  larger
     and larger, it takes longer to find the information you need. That  is
     where Index Manager helps out.
     
          Index  Manager  allows  you to build single  user  ISAM  (Indexed
     Sequential  Access Method) databases using a B+ Tree index. A B+  Tree
     is  a  data  structure that allows you  to  find  information  quickly
     without  searching something from start to finish. All  Index  Manager
     does is handle the index of your database allowing you to handle  your
     datafile as you please. All you do is to associate a unique "Key" with
     each record and Index Manager does the rest. This key could be a  name
     or  customer  number or what have you. The only thing you have  to  be
     sure of is that each record in your database has it's own unique key.
     
          The specifics of Index Manager are as follows:
     
     1.   Create an indexed-access file using the key of your choice.
     
     2.   Read  any record on you indexed-access files by  specifying  it's
     key.
     
     3.   Browse  through your indexed-access file by specifying a  partial
     key.
     
     4.   Read  your indexed-access file sequentially sorted by key  either
     forward or backward.
     
     5.   Work with up to ten indexed-access files at the same time.
     
          All  of Index Manager's functions are incorporated into one  call
     making  it very easy to use. It is also written in  assembly  language
     making  it extremely fast and small. It only adds 5k of code  size  to
     your QB programs. It utilizes a large cache buffer to cut down on disk
     accesses  when searching for a key. This makes it very fast  but  also
     introduces one of it's drawbacks. It uses 24k of string space for it's
     buffers. This makes string space kind of tight on large  applications.
     I  would  like to see some sort of variable buffer allocation  so  you
     could reclaim the string space while sacrificing some speed.
     
          Although  Index  Manager  is  very easy to  use  and  comes  with
     examples  showing  how  to use every function, it  doesn't  teach  you
     database  principles.  If  you  know nothing of how  to  set  up  good
     databases, you could find yourself making errors that could cause your
     program  to not be as useful as it can. The example programs show  you
     how  the  functions work but they are not real world  applications.  I
     would  like  to  see  some  examples of  things  like  a  small  phone
     directory,  ect.  that will help someone not  familiar  with  database
     programming go in the right direction.
     
          Aside from the string space problem and the lack of good database
     examples,  I  love this program. I received my copy of  Index  Manager
     
     The QBNews                                                     Page 10
     Volume  1, Number  3                                      May 22, 1990

     free  for the purpose of doing this review. At the time, I  had  never
     written  a database program before. As luck would have it, a  database
     programming application had just come up where I work. I decided  that
     I would give Index Manager a try in helping me with this project.  The
     project  turned  out so well that my company decided to pay  for  this
     copy.
     
          Index  Manager  is  for those people who just want  to  add  fast
     indexing  to their QB programs. It is an alternative to going out  and
     spending more money on products like DB-Lib or B-Trieve when you don't
     need  all the functions of these products. Index Manager is also  alot
     easier  to  use  than those products and allows  you  to  handle  your
     datafiles anyway you choose.
     
          Index  Manager costs $59 and is compatible with QB 2 to  4.5  and
     Bascom  6. A Basic 7 PDS version that supports far strings is  in  the
     works. You can get Index Manager by contacting:
     
                    CDP Consultants
                    1700 Circo del Cielo Drive
                    El Cajon, CA 90202
     
                    619-440-6482
     































     The QBNews                                                     Page 11
     Volume  1, Number  3                                      May 22, 1990



     ----------------------------------------------------------------------
                    P r o d u c t   A n n o u n c e m e n t s
     ----------------------------------------------------------------------

     P-Screen, P-Screen Professional, P~F Presents
     
     Rob W. Smetana      (415) 863 - 0530
     Pro~Formance        132 Alpine Terrace  San Francisco Ca  94117
     
     Program Name            Cost     Summary
     ---------------------   ----     -----------------------------------
     P-Screen "Plus"         $ 29     Screen Design, Display, Library
                                      system for QuickBASIC 3.0 - 4.x.
     
     P-Screen "Professional" $ 49     PS Pro writes programs for you! and
                                      includes other CALLable routines.
     
     P~F Presents         $ 49/$ 79   Presentation system to display
                                      P-Screen's "text" screens -or-
                                      BSAVEd "graphics."  See below for
                                      many "uses" for presentations.
     
     P-Screen "Pro"  AND              Enhanced versions of BOTH.
     P~F Presents ($79 ver.) $110
     
     NOTE:   P-Screen and P~F Presents are "shareware."  Registered
             versions cost 1/2 to 2/3 LESS than commercial examples.
             Yet they're finely tuned, professional quality programs
             that'll save you enormous amounts of time, and give your
             programs a professional appearance -- f-a-s-t, easily.
     
     P-Screen and P-Screen Professional are among the most sophisti-
     cated "screen management systems" available.  They were written
     BY Quick- BASIC programmers FOR QuickBASIC programmers (we
     support QB 3.0-4.x).  P-Screen "+" and P-Screen Pro share most
     features.  These are described immediately below.  Later we'll
     explain features that PS Pro adds.
     
     DESIGNING help screens, menus, data entry screens, etc. is a snap.
      * Use a mouse or fast keyboard "hot keys" (eg., alt-B = Box).
      * Choose options using hot keys or pull down menus.
      * Many design options:  Boxes, lines, "auto-joining" of lines
        and boxes, text, Big! Font text (tm), clipboard, paint,
        center, copy, move, erase, WalkAbout, re-color, repeat, add
        any Ascii character, view in Monochrome, UnDo, and much more.
     
     LOAD screens for editing from Screen Libraries, ASCII or BSAVE files.
      * A RAM-resident program is included letting you: 1) "Capture"
        screens from other applications (to later load and edit); and
        2) Save ANY text screen in BSAVE format when you need them.
     
     SAVE screens to Screen Libraries, ASCII or "Com" files.
      * Screens saved to libraries or Com files are COMPRESSED,
        saving disk space and RAM.  Libraries store 1-100 screens;
        libraries "index" screens, letting us display or edit them fast.
     
     The QBNews                                                     Page 12
     Volume  1, Number  3                                      May 22, 1990

      * Com screens are "executable!"  Run them from batch files or DOS
        for instant screens -- complete with color, lines, shading, etc.
     
     DISPLAY screens from your programs fast and easily -- just CALL
     two routines we include.
     
     OTHER FEATURES
      * Blazing speed!  Assembler language routines plus "indexed"
        screen libraries mean your programs display screens f-a-s-t!
        10-20 screens per second is typical.  We've seen 75 per second!
        - We've eliminated the disadvantages of storing screens on disk.
        - Screen libraries let you keep "screen text" OUT of your
          programs, preserving string space and memory.  And you can
          edit screens WITHOUT changing your programs.
        - And there are NO RAM-resident screen loaders to worry about!
     
      * Big! Font (tm) lets you easily add large-character messages.
        We include several Big! Fonts.  You can create your own Big!
        Fonts, or customize them "on the fly."
     
      * Supports 25, 43 or 50 line screen modes.
     
     =================================================================
                       P-Screen Professional   ($ 49)
     =================================================================
     
     P-Screen Professional (PS Pro) has all the features of P-Screen
     described above, but also saves you enormous amounts of time by:
     
      * Writing your QuickBASIC 4.x programs for you!
     
      * Including several other subprograms you can use in ANY Quick-
        BASIC 4.x program you write (most also work with QB 3.0).
     
     In short, you focus on what your programs "look like."  Once
     you have your screen designed, PS Pro can write your BASIC code.
     Just add any routines you need for printing or database manage-
     ment.  Then compile your programs and away you go.
     
     
     PS Pro writes your data entry programs for you!  Just "mark" a
     "field" on your screen and tell PS Pro what "type" of field it is.
      * You can create fields with are "editable," and fields which
        are "calculated."  For calculated fields, enter ANY Quick-
        BASIC formula, and PS Pro will handle the calculations for
        you and print their results.
     
      * And you can link "help screens" to each field if you like.
     
      * Once you've "formatted" each field on your screen just press
        a key.  PS Pro writes your program in about 2-3 seconds!
     
     
      PS Pro lets you choose from among 13 field types.
       * Choose a field type and PS Pro formats editing, printing,
     
     The QBNews                                                     Page 13
     Volume  1, Number  3                                      May 22, 1990

         and displaying the results of "calculated fields" for you.
     
       * Choose field types from among:  string, upper case, proper
         name, date, phone number, Zip Code, Social Security number,
         numeric string, integer, long integer, single precision,
         currency and double precision.
     
      PS Pro comes with several subroutines you can use in any program.
      These include:  rsMinput, OneKey, Mask/StripMask, FormatUsing,
      ProperName, rsQprint, Exists, and StripTail.  Use them to:
       * Handle ALL user input (text, extended keys, printer codes).
         Get a single key, or a full line of text.  rsMinput offers
         the full array of editing features, includes UnDo, AND
         offers "masked" input for easy, accurate editing of fields
         like Phone Numbers [(...) ...-....] or Zip Codes  [.....-....].
     
       * Format text and numbers for easy editing or printing
     
       * Print with assembler speed
     
       * Convert all lower case text to "proper name" format
     
       * Determine if files exist (before you try to open them)
     
     =================================================================
                   Product Announcement:     P~F PRESENTS
     =================================================================
     
     P~F Presents (PFP) is our desktop presentation system.  It dis-
     plays screens from P-Screen's screen libraries.  It also displays
     BSAVED "graphics" screens.  Text, graphics or both; it's your call.
     
     Presentations (or slide shows) can include, among other things:
      * Full- or Sub- screen displays.
      * Menus, in 3 different styles.
      * Display and sound effects.
      * Special options including:  "If x Goto," "Gosub", "Loop,"
        "Pause," "MakeMono" (to display colored screens on
         monochrome monitors).
      * Timed slides (which pause as long as you want between slides),
        -or- slides which wait for the viewer to press a key.
     
     And you can create self-running presentations, or run 'em yourself.
     
     Why would a programmer be interested in a presentation system?
     For many of the same reasons programmers like Dan Bricklin's DEMO
     program (at about 1/4 the cost)!  Plus, P~F Presents offers
     many other opportunities as well.  Consider these:
     
     PROGRAM PROTOTYPES
      * You can create "working prototypes" of programs in minutes or
        just a few hours.
      * Since presentations can include menus (3 types), display effects,
        sound effects, etc. your prototypes can have the "look and feel"
        of your actual program.
     
     The QBNews                                                     Page 14
     Volume  1, Number  3                                      May 22, 1990

      * Letting your clients, customers or potential users see how your
        program will look and feel (BEFORE you've written a line of code):
        1) Helps you "beta test" your ideas; 2) Helps eliminate time-
        consuming re-writes; and, 3) Speeds up program development.
      * And creating "mock ups" helps you think through a program's
        logic before you write any code.
     
     PROGRAM:  DEMOS, MARKETING TOOLS, TUTORIALS
      * You can easily and quickly create demos, marketing tools or
        program tutorials -- using many of the SAME SCREENS your
        programs will display.
     
     As an example, we recently used PFP to create, in 2 hours, a
     working prototype of a new program.  We had it back to a
     prospective client the day after we first talked to him.  It
     had the complete "look & feel" of the program he wanted.  And
     creating it helped us think through our program design.
     





































     The QBNews                                                     Page 15
     Volume  1, Number  3                                      May 22, 1990



     ----------------------------------------------------------------------
                           U n d e r   T h e   H o o d
     ----------------------------------------------------------------------

     Fast File I/O in QuickBASIC by Ethan Winer
     
     [EDITOR'S NOTE] This article first appeared in the March 1990 issue of
     Programmer's   Journal.  Back  issues  can  be  ordered   by   calling
     1-800-234-0386.
     
          Without  doubt,  one  of the slowest  operations  a  program  can
     perform is saving and loading disk data files.  In many cases, this is
     dictated by the physical access delay of the disk device, and the time
     required to transfer data based on its rotation speed.  One exception,
     however,  is  when  many reads or writes must be  performed  on  small
     pieces  of data.  For example, it is quite common to save or  load  an
     entire numeric array.  In the case of an integer array that  contains,
     say, ten thousand elements, that many individual calls to the DOS file
     I/O  services will be needed.  Even though DOS is written in  assembly
     language, it still takes a fair amount of time to process each read or
     write request.
     
          One obvious solution is to process the file operation as a single
     large  read  or  write.   Indeed, I  have  written  assembly  language
     routines  to do just that for use in company's  QuickPak  Professional
     add-on library product.  But it is also possible to call  QuickBASIC's
     internal  PUT and GET routines directly.  By bypassing the  QuickBASIC
     compiler and its syntax checking, you can coerce it to read and  write
     up  to  64K  of  data in a single  operation.   Larger  files  can  be
     accommodated  by  processing  the file in pieces.   The  trick  is  to
     determine  the  names of these routines, and the number  and  type  of
     parameters they expect to receive.
     
          QuickBASIC versions 4.0 and later contain four different internal
     routines for reading and writing binary data.  Two of these are  meant
     for  reading  data from a file, with one using the  current  DOS  SEEK
     location  and  the  other  accepting a  long  integer  SEEK  argument.
     Similarly, there are two separate routines for writing data to disk.
     
          Most of QuickBASIC's internal routines begin with the  characters
     "B$", which are illegal in a subroutine name.  Fortunately, the  ALIAS
     keyword allows you to declare a procedure with two different names  --
     the name you will use when calling it from the program, and the actual
     name  that is made public for the linker.  When  Microsoft  introduced
     inter-language  calling  capabilities in QuickBASIC version  4.00,  it
     needed a way to allow access to routines written in C.  These routines
     always start with an underscore character, which is also illegal as  a
     QuickBASIC procedure name.
     
          The example program shown in Figure 1 declares the four  internal
     routines  as follows:  BigSave writes data using the current DOS  file
     pointer  position,  and BigSaveS expects a SEEK  argument.   Likewise,
     BigLoad reads from the current file position, and BigLoadS requires an
     offset to SEEK to before reading.  All four of these routines  require
     the  parameters  to be passed "by value", as opposed to  "by  address"
     
     The QBNews                                                     Page 16
     Volume  1, Number  3                                      May 22, 1990

     which  is BASIC's usual method of passing parameters. This results  in
     code  that  is  both faster and smaller, because  an  extra  level  of
     indirection  is avoided.  That is, the routines can obtain the  values
     directly  from  the stack, rather than having to  first  determine  an
     address,  and  then  go to that address for the  actual  value.   Even
     though BYVAL and SEG *look* like they would result in additional  code
     being  added  to  a program, they are really just  directives  to  the
     compiler.
     
          Before  any  of these routines may be called, you must  open  the
     file  to  be read or written for BINARY operation.   Then,  the  first
     parameter that each routine expects is the BASIC file number that  was
     used  to  open  the file.  The address parameter is passed  as  a  SEG
     value,  which  means  that both a segment  and  offset  are  required.
     Notice that a file may be loaded to or saved from any area of  memory,
     by replacing [SEG Address] with [BYVAL Segment, BYVAL Address].   When
     SEG is used as part of a CALL statement, the "value" of the variable's
     segment is pushed on the stack, followed by the value of its  address.
     Substituting  two  separate arguments "by value" is  functionally  the
     same thing as far as the routines are concerned.  Also notice that the
     internal routine names are not available within the QuickBASIC editing
     environment.  Therefore, this example program must be compiled to disk
     before it may be tested.
     
          In  my own informal tests, I have found this technique to  be  as
     much  as  ten times faster than reading or  writing  individual  array
     elements  using  a BASIC FOR/NEXT loop.  The actual  savings  will  of
     course  depend  on the number of elements being  processed  and  their
     length  in  bytes.   Unfortunately, this method cannot  be  used  with
     QuickBASIC  string  arrays, because they are not kept  in  consecutive
     memory  locations.   However, numeric arrays may be  accommodated,  as
     well as any fixed-length or user-defined TYPE array.
     
          It  is  important to understand that when manipulating  a  fixed-
     length  string array, the SEG operator must not be used.   Whenever  a
     fixed-length  string  or array element is used as an  argument  to  an
     external  routine, QuickBASIC first makes a copy of it into a  regular
     string  variable.   Then, the address of the copy is  passed  instead.
     Since  the address of a copy of an array element has no  relevance  to
     the address of the actual array, we must use a different approach.  In
     fact, there are two possible solutions.
     
          One is to create a TYPE definition that is comprised solely of  a
     fixed-length  string  portion.  Although the example below  assumes  a
     string  length of twenty characters, you would of course use  whatever
     is appropriate for your program.
     
     TYPE FLen
          S AS STRING * 20
     END TYPE
     
     DIM Array(1 TO 10000) AS FLen
     
          The  second solution is to use a combination of BYVAL VARSEG  and
     BYVAL  VARPTR, to pass the segment and address of the  starting  array
     
     The QBNews                                                     Page 17
     Volume  1, Number  3                                      May 22, 1990

     element directly.  When QuickBASIC sees VARSEG or VARPTR, it  realizes
     that  you  do  in  fact want the actual segment  and  address  of  the
     specified  array  element.  Thus, you would use the  following  syntax
     when calling BigSave to save a fixed-length string array:
     
     CALL BigSave(FileNumber, BYVAL VARSEG(Array(First)), BYVAL _
          VARPTR(Array(First)), NumBytes)
     
          One final note concerns saving or loading more than 32767  bytes.
     QuickBASIC does not support unsigned integers, so you must instead use
     an  equivalent  negative value.  This is quite easy to  determine,  by
     simply  subtracting 65536 from the required number of bytes.  It is  a
     common trick to avoid negative numbers when calling assembly  language
     routines  by instead substituting a long integer number  or  variable.
     However, that will not work in this case, because two extra bytes will
     be  pushed  onto  the stack by the use of  BYVAL.   Therefore,  it  is
     essential that you specify the correct type of parameters when calling
     these routines.
     
     **********************************************************************
          Ethan Winer is the president of Crescent Software, and the author
     of  QuickPak  Professional  and P.D.Q. He can be  reached  by  calling
     Cresent Software at (203) 846-2500.
     **********************************************************************
     
     [EDITOR'S  NOTE]  Source  code  for  this  article  is  contained   in
     FASTFILE.ZIP.
     



























     The QBNews                                                     Page 18
     Volume  1, Number  3                                      May 22, 1990



     ----------------------------------------------------------------------
                        P o w e r   P r o g r a m m i n g
     ----------------------------------------------------------------------

     How to Make a Self-Cloning Exe in QuickBASIC by Larry Stone
     
     [EDITOR'S NOTE]
          All  extended  ASCII  codes have  been replaced  in the following
     article.
     
          Have  you  ever  had the need to create a program  that  holds  a
     password  away  from  prying  eyes of  others?   Or,  maybe  you  have
     discovered that writing shareware rewards your ego by making your name
     familiar to the PC world, but doesn't reward your pocket-book  because
     most  people will register their programs when they get around to  it,
     which,  often-times,  is never.  Or, maybe you just wish  to  write  a
     program  that  holds  it's configuration without having  to  create  a
     configuration file.
     
          One  of the easiest methods to accomplish the above listed  tasks
     is  to  create an EXE file that "clones" information to  itself.   The
     trick is to create a "recognizable" area inside of the EXE itself that
     can be quickly read and modified.
     
          What  makes  this such an easy trick?  Well, have you  ever  used
     Vernon  D.  Buerg's LIST utility to list your EXE's?  If you  do,  you
     will notice that towards the end of the program, every string that you
     have  defined  within your program is CLEARLY VISIBLE!  What  you  are
     viewing is the EXE's token definition area.  When you compile and link
     your programs, a token is defined for every string used.  For example,
     your  program might have the code, Strike$ = "Strike any  key".   When
     you  list the EXE, it may show something like, 0TStrike any key.   The
     symbols 0T would be the programs marker to the definition, "Strike any
     key".  Under no circumstance do you want to change this marker because
     really  weird results could ensue.  However, you can create  a  string
     that contains a marker that is exclusive to your use, i.e.,
     
     Special$ = "<*!@#%>This is my special string"
     
          In the above example, <*!@#%> then becomes your special marker to
     the  data that immediately follows.  Then, all your program has to  do
     is  to look for your special marker and modify the next 25  characters
     as needed!
     
          CAUTION!   Never,  never, never try to reserve a  data  area  for
     cloning by defining a string as:
     
     Special$ = "<*!@#%>" + SPACE$(25)
     Special$ = "<*!@#%>                         "
     
          Both  of  the above examples will *NOT* create the  25  character
     data  area  desired because BC will optimize the SPACE$(25) as  a  two
     byte token!
     
          Let's assume that we need to build a program that needs to hold a
     
     The QBNews                                                     Page 19
     Volume  1, Number  3                                      May 22, 1990

     user-defined,  sixteen character password and a token that  determines
     whether the EXE is shareware (limited in scope) or registered.   Let's
     further  say that when a registration is received by you, the  author,
     you  then mail that person a key which redefines the definition  of  a
     token so that features not available to the shareware user now  become
     available.   Let's  further state that your program is going  to  hold
     configuration information within a 13 byte string.
     
          The first thing to do is to create a unique string inside of  the
     program  itself, as well as, two or three variables shared within  the
     program.  At the top of the program, do something like the following:
     
     DIM SHARED StoredData$, BytesToData&
     
          Now,  if your program does not "clone" configuration  information
     or  passwords, then BytesToData& does not need to be SHARED.   Rather,
     in this case, only the information itself (Shareware/registration key)
     needs to be shared.  However, for this discussion, we're going for the
     entire pie.
     
          Next, someplace within your initialization subprogram (or in your
     main module), you should place code such as the following:
     
     SpotForKey$ = "<%*@#!>123456789012345678901234567890"
     
          Now,  because  your program needs to read itself,  modify  itself
     and,  at  the  same time, hold part of the  original  string  as  your
     special marker, we need to do the following:
     
     tempKey$ = LEFT$(SpotForKey$, 6)
     
          In  this way, no matter what we do to the following 30  character
     spaces, <%*@#!> will always remain our special marker that the program
     looks for.
     
     Let's build the routine that reads in this data.
     
     '--------------------- Get Special Data Routine ---------------------
     
     DIM SHARED StoredData$, BytesToData&
     
     SpotForKey$ = "<%*@#!>123456789012345678901234567890"
     
     tempKey$ = LEFT$(SpotForKey$, 6)       'Our special marker.
     
     'The Bytes% variable is the number of bytes to read.If your program is
     'less than 16000 bytes then this routine adjusts accordingly. Also, if
     'a 16K byte "GET" cuts the marker field in two then you need to change
     'it to another value, such as 15550.
     
     Bytes%  =  16000
     BytesToData& = 0
     portion& = 1
     countToKey% = 0
     StoredDataLen% = 30
     
     The QBNews                                                     Page 20
     Volume  1, Number  3                                      May 22, 1990

     
     OPEN MyProg$ FOR BINARY AS #1 FiSize& = LOF(1)
     'Get the size of the file
     DO WHILE NOT EOF(1)
          IF Bytes% > FiSize& THEN Bytes% = FiSize&
          IF Bytes% + portion& > FiSize& THEN Bytes% = FiSize& - portion&
          A$ = INPUT$(Bytes%, 1)         'Read Bytes% number of characters.
          countToKey% = INSTR(A$, tempKey$)  'Look for our special marker.
          IF countToKey% THEN              'If we found it then process it.
            BytesToData& = portion& + countToKey% + 5 'Get past our marker.
            SEEK #1, BytesToData&              'Get the data from the file.
            StoredData$ = INPUT$(StoredDataLen%, 1)
            EXIT DO                     'We found it so out of the DO LOOP
          END IF
     
          portion& = Bytes% + portion&   'Determine where the next SEEK is.
     
     'If we're within 800 bytes of the end of the EXE then we are past  the
     'token definition area of the QB program.  In this case, we're done.
     
          IF portion& >= FiSize& - 800 THEN EXIT DO
     
     'Move pointer to the next 16000 byte block to read from the file.
     
          SEEK #1, portion&
     
     LOOP
     CLOSE #1
     
     '--------------------- End Special Data Routine ---------------------
     
          Now,  whenever  our  program  needs to look  for  a  password,  a
     registration  key  value, or it's configuration information,  it  need
     only do the following:
     
     Password$ = LEFT$(StoredData$, 16)
     RegisValue = VAL(MID$(StoredData$, 17, 1))
     
     IF   RegisValue  =  7  THEN
          PRINT "Shareware Edition"
     ELSE
          PRINT "Registered Edition"
     END IF
     
     ConfigData$ = MID$(StoredData$, 18)
     
          To  prove  this works, snip out the special routine and  add  the
     following  statement at the end of the routine:     PRINT  StoredData$
     Next, compile and link it, then run it.  You will see the above string
     printed (you will also notice just how fast QB's INSTR function really
     is! - It's blazingly fast! - Couple this with BINARY access and you'll
     discover that load time is not appreciably degredated).  Don't  forget
     to define MyProg$ as something or you'll get a nasty error message!
     
          Okay,  okay,  so how do we write new information to  our  special
     
     The QBNews                                                     Page 21
     Volume  1, Number  3                                      May 22, 1990

     data area? Simple - just do the following:
     
     Password$ = "Lawrence Stone  "
     RegisValue$ = "0"
     ConfigData$ = "Config Area 1"
     
     OPEN  MyProg$  FOR  BINARY  AS  #1
     PUT #1, BytesToData&, Password$        'To write the new password.
     RegisValue$ = "0"
     PUT #1, BytesToData& + 16, RegisValue


To create a registered version.
     PUT #1, BytesToData& + 17, ConfigData$ 'To clone configuration data.
     CLOSE #1
     
          Now, re-run your compiled program and have these values print  to
     the monitor.  Notice how easy it was to change the data?
     
          If  you are going to have an external "key" program  that  "turns
     on"  the registered version then it needs to simply read in  the  data
     using  the same special marker that we created as a marker  to  search
     for.  Also, you might wish to make another small program that converts
     your  pre-  defined  password  and  configuration  space  to   spaces.
     Otherwise,  you need to run your program before you distribute  it  so
     that   you   can   change   the   password   (which   is   equal    to
     "1234567890123456")  to  something like SPACE$(16).  In  other  words,
     nullify  the  temporary string used by our program that forced  BC  to
     give us the data space we needed in the first place.
     
          Now, for demonstration purposes, we have used the default "7" for
     indicating  that the program is shareware and "0" for  registered.   I
     would recommend that you reserve at least 8 character spaces for  this
     field because then you can create unique codes for every key and every
     user.   In this way, your program can look for the key in both  itself
     and  within the key program as well.  This would also offer  one  more
     level of safeguards for you.
     
          One  final  word:  Any casual hacker can use LIST  to  find  your
     password if you leave it in it's native ASCII.  You should consider  a
     routine  that  converts the appearance of your data so that  it  looks
     like the rest of the binary code.  Routines can be as simple as taking
     each character in the strings and adding 100 to their ASCII value  for
     writing, then, subtracting 100 from their ASCII value for reading,  to
     some  truely cryptive procedure, depending on how sensitive  you  want
     the information contained therein to remain.
     
     **********************************************************************
          Larry  Stone is President of LSRGroup and is involved in  writing
     software  for  marine  and  aquatic research. He  can  be  reached  at
     LSRGroup,  P.O.  Box 5715, Charleston, OR 97420, or in  care  of  this
     newsletter.
     **********************************************************************
     
     [EDITOR'S  NOTE]  The  file CLONE.BAS  contains  a  slightly  modified
     version of Larry's code above. I have modified it to make it easier to
     add to your program. It is contained in CLONE.ZIP.
     
     The QBNews                                                     Page 22
     Volume  1, Number  3                                      May 22, 1990

     In Search of the Elusive UEVENT by Jim Mack
     
          QB allows you to trap a number of different "events", such as the
     TIMER  tick,  the arrival of a byte in a COM buffer, the  press  of  a
     specific  KEY,  and  so on.  It does so by  adding  extra  code  after
     each statement (/V) or each line (/W) which checks the state of  flags
     associated  with  enabled  events.   Special handlers  deal  with  the
     actual interrupt and set these internal flags as appropriate.
     
          This  is  a three-stage process: first, an interrupt  (an  event)
     occurs  and is handled quickly by the QB runtime, which sets the  flag
     and  variables  associated with the event.  This happens  behind  your
     program's  back,  as  it  were.  Second,  when  the  current  line  or
     statement  completes, QB checks the flags to see if any active  events
     (those  for  which  you  have executed "ON xxx  GOSUB"  and  "xxx  ON"
     commands)  have occurred.  Third, on discovering such a  condition  QB
     executes the GOSUB code you wrote to deal with it.
     
          The only area where UEVENT differs from events like KEY is in the
     first  part  of  the first step.  In defining  a  UEVENT,  _you_  take
     responsibility  for dealing with the interrupt, and for notifying  the
     QB  runtime that such an event has occurred.  From that point on,  the
     action  is exactly the same.
     
          The  difference  between invoking a GOSUB via SetUEvent  (or  any
     trap)  and  calling  it  directly is that when  you  invoke  it,  it's
     executed  only  when QB gets around to it, and only if  UEVENT  ON  is
     currently  in  effect.  A side effect of this is that you  may  "lose"
     events  if more than one occurs between occasions when QB  checks  its
     internal flags.
     
          This  whole business of interrupts can be broken down in  several
     ways: shared vs. exclusive vs. chained, or software vs. hardware,  and
     so  on.  The code packages included here give examples of  two  common
     combinations.
     
          You can trigger a UEvent in QB with no interrupt at all, by  just
     saying "CALL SetUEvent".  In MASM, declaring SetUEvent as an EXTRN far
     procedure  lets  you do the same thing: CALL SetUEvent.  In  C,  you'd
     declare "setuevent" as a void far external function and then reference
     "setuevent()"  to cause your QB handler to be invoked.  Simple...  and
     practically  useless  by  itself.  You need to  combine  this  with  a
     software  or hardware interrupt.
     
     >>  "Software interrupts" are really misnamed: they have more in
     >>  common with a subroutine call than with a hardware interrupt.
     >>  Since they occur under direct program control, there's nothing
     >>  unexpected or asynchronous about them.  They do however use
     >>  the same table of vectors that the hardware interrupts use.
     
          A small step up is the exclusive "true" software interrupt.  This
     involves  taking over an unused interrupt vector, writing a tiny  MASM
     routine  which intercepts INTs directed at this vector and performs  a
     CALL  SetUEvent.   There's no reason to take this  extra  step  unless
     you're  working with a canned other-language program which must use  a
     
     The QBNews                                                     Page 23
     Volume  1, Number  3                                      May 22, 1990

     pre-defined  INT to access your code.  If you're using DOS  3.x,  this
     can  be  done  in exactly the same manner as  the  "chained"  software
     interrupt  described  below,  since what you're  chaining  onto  is  a
     pre-defined Dismiss This Interrupt routine.
     
     >>      A "vector" in this context is a memory location reserved by
     >>  the computer as a pointer: it contains the address of a routine
     >>  intended to service an interrupt.  There are 255 such vectors in
     >>  the PC, occupying the memory from 0000:0000 through 0000:03FF.
     >>  Eight of these (sixteen in the AT) are reserved for use by the
     >>  hardware Interrupt ReQuest lines, or IRQs.  When an enabled
     >>  interrupt occurs, the PC stops what it's doing and executes the
     >>  routine whose address is stored in the appropriate vector.
     
          Next  most  complicated is the chained software  interrupt.   One
     example  of an existing software interrupt is the BIOS  disk  service,
     which uses INT 13H.  If you wanted your handler to be invoked whenever
     disk  activity  occurred, you'd chain onto this interrupt  vector  and
     monitor the registers using MASM.  When an event of interest occurred,
     you'd  "CALL  SetUEvent" to notify QB.  In any case,  you'd  pass  the
     interrupt  along to the original INT 13H handler.  Closely related  to
     this  is  the chained hardware interrupt.  The setup  is  exactly  the
     same:  hook  the interrupt vector, monitor the  registers,  etc.   All
     other  details  are taken care of by an existing handler.
     
          The code in CHNEVENT.BAS is an example of a chained handler which
     will  work for any hardware or software interrupt.  The assumption  is
     that you're just monitoring existing events (and sometimes  activating
     SetUEvent), but not touching any hardware.  In the example we  monitor
     INT  9,  the  keyboard interrupt, but you can monitor  almost  any  of
     the256  vectors by replacing "9" with the appropriate number.  Try  an
     experiment:  replace the INKEY loop with a LINE INPUT  statement.   If
     you can explain what happens, you've grasped the essentials of QBevent
     handling.
     
     >>    "Hooking" a vector means only that you store the address of your
     >>  own service routine in the vector.  To facilitate cleanup, it's
     >>  usual to first retrieve and store the existing contents of the
     >>  vector so that they can be replaced on exit.  If you're "chaining"
     >>  onto this vector, then you'll also use that original address when
     >>  your routine is finished, by performing a JMP directly to it.
     >>  Since this can happen to several routines in sequence, it's easy
     >>  to see why it's known as chaining.
     
          The  next step up in complexity (and it's a pretty big  step)  is
     the exclusive hardware interrupt.  Here, you're responsible for all of
     the  nitty-gritty  of  the PC hardware, in  addition  to  any  details
     associated  with  the  hardware device.  You must  program  the  8259A
     Programmable  Interrupt  Controller to allow interrupts  on  your  IRQ
     level,  then  issue  a command to clear the PIC when  you  service  an
     interrupt.  These must be done in MASM, as your QB event handler  will
     not be executed in a timely fashion and so cannot be relied on to take
     care  of these high-speed events.  The code in EVENTHDW.ASM shows  how
     to  deal with an event occurring on an arbitrary IRQ line  (determined
     at  install  time), but because we aren't dealing with a  real  device
     
     The QBNews                                                     Page 24
     Volume  1, Number  3                                      May 22, 1990

     here, the specific instructions for the interrupting hardware can only
     be hinted at.
     
     >>      Each hardware IRQ line is intimately tied to a vector: in the
     >>  case of the lower IRQs (0-7) the INT number (the vector number) is
     >>  simply the IRQ number plus 8.  That's why the KB interrupt, which
     >>  uses IRQ 1, is vectored through INT 9.
     
          Slightly  more complicated is the shared hardware interrupt.   In
     order  for  two hardware devices to share an IRQ line, there  must  be
     away to determine which device requested service by interrupting.   An
     example of sharing an interrupt might be COM1 and COM3, which both use
     IRQ4  and hence INT 0CH.  When an interrupt occurs on IRQ4,  the  COM3
     service routine gains control and examines a register in the UART it's
     responsible  for  to  see if that UART caused the  interrupt.   If  it
     didn't,  control  is passed to the COM1 service  routine.   I  haven't
     included  a  specific example of adding a shared handler, but  if  you
     need one and can't figure it out from the code shown, you can  contact
     me and I'll try to help.
     
          In  addition  to the above, whenever you take over  an  interrupt
     vector  you  must somehow put things back in order when  your  program
     terminates.   At a minimum this means restoring the original  contents
     of  the  vector; for hardware interrupts, you must  also  restore  the
     8259A Interrupt Mask Register bit to the state in which you found it.
     
          To  make  this  process a bit more  automatic,  QB  includes  the
     B_OnExit  routine.   Any  running BC program takes over  a  number  of
     interrupt  vectors  for its own use (for example,  BC  math  functions
     invoke INT 04H whenever an overflow occurs) which must be restored  on
     any  exit,  normal  or abnormal.  BC and QB  provide  B_OnExit  as  an
     extension of this internal cleanup.  You still must write the code  to
     do  the actual restoring of vectors, etc., but BC can call  that  code
     automatically  on  *any* exit, even an error crash, if  you  "register
     "your  routine via B_OnExit.  Each of the included code packages  uses
     B_OnExit in this way.
     
     **********************************************************************
     Jim  Mack  is a programmer specializing in real-time systems  for  the
     entertainment  industry.  He can be reached via CIS ID  76630,2012  on
     the MSSYS forum in the BASIC or MASM sections, or at Editing  Services
     Co., PO Box 599, Plymouth MI 48170, (313) 459-4618
     **********************************************************************
     
     [EDITORS NOTE]
          For some reason, the program CHNEVENT.BAS will cause my  computer
     to crash when run in the QB 4.5 enviroment. This is not the case  when
     run in the QBX (BC7) enviroment. Caution is advised if you try to  run
     this  in the enviroment. Source code for this article is contained  in
     UEVENT.ZIP.
     




     The QBNews                                                     Page 25
     Volume  1, Number  3                                      May 22, 1990



     ----------------------------------------------------------------------
                  S o m e   A s s e m b l y   R e q u i r e d  
     ----------------------------------------------------------------------

     Assembler Programming for QuickBASIC by Tom Hanlin
     
          Perhaps  you  already  know a little  bit  about  programming  in
     assembly  language,  or perhaps you've never given  it  much  thought.
     After  all,  it's  supposed to be  frighteningly  difficult  to  write
     assembler programs, and you've already got QuickBASIC anyway.
     
          Well,  it's true that there's a lot of work involved  in  writing
     large programs in assembly language.  If you keep to the small  stuff,
     however,  there's actually very little to it.  One of the easiest  and
     most  rewarding  uses for assembly language lies in  writing  routines
     that can be called from a higher-level language like QuickBASIC.  This
     can give you entirely new capabilities or make your existing  programs
     smaller  and  faster.   By  mixing the  capabilities  of  a  low-level
     language  like assembler with a high-level language  like  QuickBASIC,
     you  can  gain  a  lot  of  flexibility  when  you  need  it,  without
     sacrificing the ease of use of good ol' BASIC.
     
          Microsoft's documentation on mixed-language programming is rather
     daunting.  It's not exactly clear and the examples never seem to cover
     quite  what you had in mind.  Once you understand a few simple  rules,
     though,  you'll see that adding assembler routines to your  QuickBASIC
     programs can be readily accomplished.
     
          I'm  going  to assume you have some notion of how to  program  in
     both  QuickBASIC  and assembly language, since  explaining  an  entire
     language would be a bit more than a single article could cover!   With
     that in mind, let's take a look at the basic rules of writing assembly
     routines for QuickBASIC and follow that up with the code for a working
     routine.
     
          The first thing you need to know is which registers you can  use.
     The  answer  is, "all of them."  However, certain  registers  must  be
     preserved  for  BASIC,  so if you use them,  you  must  restore  their
     original  values  before  returning to the main  BASIC  program.   The
     registers  that  must be preserved are SI, DI, BP, and DS.   You  also
     need  to  preserve  the stack (SS and SP)  and  direction  flag.   The
     direction  flag  must  always be "forward" when you exit,  so  if  you
     change it using the "STD" instruction, be sure to restore it using the
     "CLD" instruction.
     
          Believe  it  or not, that's most of what you need to  know  right
     there.  The other important thing to know is how to pass parameters to
     or  from the assembler routine.  I'll keep it simple by  assuming  you
     use the standard convention, which is "pass by reference", rather than
     "pass by value", which has to be explicitly declared.
     
          What  do I mean by "pass by reference?"  I mean that, instead  of
     getting the actual value of a parameter, your routine gets the address
     of  that parameter and has to look up the value.  It's useful to  have
     the address of the parameter, since that means you can return a  value
     
     The QBNews                                                     Page 26
     Volume  1, Number  3                                      May 22, 1990

     by storing it in the parameter's address.
     
          Integral  numbers are stored simply.  For integers,  the  address
     you  are  given points directly to the integer (a word).  If  you  use
     long integers, the address points to the long integer (a doubleword).
     
          Strings  are  stored  in a slightly more  complex  fashion.   The
     address  you  are  given  points  to  a  "string  descriptor".    This
     descriptor is composed of two words, with the first giving the  length
     of  the string and the second the address of the string.  You are  not
     allowed  to  change  the  length or address  of  the  string  in  your
     assembler routine, although you may change the string itself.
     
          I  won't  go into single precision or double  precision  numbers,
     because  they  are rather tricky to handle in assembler.  I  won't  go
     into  arrays,  TYPEd values, or fixed-length strings here  either,  to
     keep it reasonably brief.  Perhaps in a later article...
     
          Parameters  are passed on the stack, starting at offset  6  (six)
     for  the -last- parameter and going up by two as you move towards  the
     first parameter.
     
          Finally, you need to end your routine with a special "RET" opcode
     that will clean the parameters off the stack for QuickBASIC.  The  RET
     must  have a number after it which is twice the number  of  parameters
     passed to the routine.
     
          Clear  as mud?  Well, perhaps the example routine will help  show
     what I'm talking about.  The DOSVER.ASM file contains the source code.
     To assemble it just type: ASM DOSVER; (where "ASM" is the name of your
     assembler: MASM, TASM, or OPTASM)
     
          Convert  the  resulting DOSVER.OBJ file to a library so  you  can
     easily  use  it  both from the command line and  QB  environment:
          LIB   DOSVER;                     (this  creates   DOSVER.LIB)
          LINK DOSVER/Q,,NUL,BQLB45;        (this creates DOSVER.QLB)
     
          If you are using QuickBASIC 4.0, change the BQLB45 to BQLB40.  If
     you are using QuickBASIC 4.0a or 4.0b, change it to BQLB41.
     
          You  can  now use the DOSVER routine from the QB  environment  by
     specifying the library name when you start QuickBASIC: QB /L DOSVER
     
          Use of the DECLARE statement is optional, but it will help  catch
     any errors you might make when calling DOSVER.  Use this: DECLARE  SUB
     DOSVER(VERSION$, MAJORV%, MINORV%)
     
          Before  calling the routine, you must set the VERSION$ string  to
     at  least four characters, since the routine is not allowed to  change
     the  length  of the string.  Call the routine like  this:
          VERSION$  = SPACE$(4)
          CALL DOSVER(VERSION$, MAJORV%, MINORV%)
     
          Typical  results will be "3.11" for VERSION$, 3 for MAJORV%,  and
     11 for MINORV%.
     
     The QBNews                                                     Page 27
     Volume  1, Number  3                                      May 22, 1990

     
          In  later articles, if there is any interest in it, I'll  explain
     how  to handle arrays, TYPEd variables, and fixed-length strings,  and
     also  how  to  pass  values back  from  functions  rather  than  using
     subprograms.
     
     **********************************************************************
     Tom  Hanlin  is  the author of the very  popular  ADVBAS  library  for
     QuickBASIC. His  new  shareware library is called BASWIZ.  He  can  be
     reached  through  the  QUIK_BAS echo on Fidonet or  in  care  of  this
     newsletter.
     **********************************************************************
     
     [EDITOR'S NOTE]
          The archive ASMREQ.ZIP contains the assembler source code plus an
     assembled .OBJ file for the routine contained in the article.
     






































     The QBNews                                                     Page 28
     Volume  1, Number  3                                      May 22, 1990



     ----------------------------------------------------------------------
     A n d   I   H e a r d   i t   T h r o u g h   t h e   G r a p e v i n e
     ----------------------------------------------------------------------

     
     From:   Mike Sinak
     To:     All
     Subj:   PEEK & POKE
     
     I  am just beginning to study DOS and BIOS calls and don't  understand
     how to do it at all.  Does anybody have any info on the PEEK and  POKE
     usage?   Like  if you want to peek and poke to turn caps lock  on  and
     off, how in the world do you know what address to peek and poke?   I'm
     lost!   I would like to learn more about this stuff and get some  kind
     of comprehensive list of peeks and pokes.
     
     Also I learned that at DEF SEG 0 you can turn on and off caps lock  by
     POKE &H0417, PEEK &H0417 OR &H40 (to turn on)
     
     and
     
     POKE &H0417, PEEK &H0417 AND &HBF (to turn off)
     
     Now how in the world did they know that?  The AND and OR statments are
     supposed  to be turning on and off bit 6 of the &H0417  address.   How
     did they know these particular numbers turn on and off bit 6?   Better
     yet, how did they know that bit 6 had to be turned on and off at  this
     particular address to turn caps lock on and off.  Is there a pattern?
     
     Obviously  my ignorance is being displayed. Go ahead and laugh  <grin>
     but I would sure like to know more about this.
     
     ANY HELP?
     
     
     From:   Robin Hunziker @ 965/1
     To:     Mike Sinak
     Subj:   Re: PEEK & POKE
     
     Perhaps  your  best  bet  for figuring out  how  DOS  operates  is  by
     purchasing the following book:
     
          Advanced MSDOS Programming
          2nd Edition
          Ray Duncan
          Microsoft Press
          ISBN 1-55615-157-8
     
     For  example,  on  page 582 the book discusses exactly  your  area  of
     question  in easy-to-understand tabular format.  It discusses  how  to
     call Int 16H Function 02H to "get keyboard flags".  Although the front
     cover states that it is "The Microsoft guide for Assembly Language and
     C programmers", it is very relevant to much of the discussion in  this
     echo.
     
     
     The QBNews                                                     Page 29
     Volume  1, Number  3                                      May 22, 1990

     
     From:   David Martin
     To:     Mike Sinak
     Subj:   Peek & Poke
     
     A better way to set upper and lower case is the following:
     Lower Case:  POKE 1047, PEEK(1047) AND 191
     Upper Case:  POKE 1047, PEEK(1047) OR 64
     Lots  of stuff can be done with poke such as disable  the  CTRL-BREAK,
     turn  number lock key on and off, read hardware  configurements,  read
     size  of  RAM.  The list goes on and on.  If you want a  list  of  the
     commands  let me know.  These commands must be preceded by: DEF SEG  =
     0.  Let me know what kind of stuff you are working with so I can  give
     you the commands.
     
     
     From:   Tom Hanlin
     To:     Mike Sinak
     Subj:   Re: PEEK & POKE
     
          In  order  to understand bit numbering, you need to  convert  the
     number  to  binary.  Bits are numbered from right to  left,  with  the
     lowest bit being number zero.  So:
       &H40 = 64 = 0100,0000b (note that bit 6 is turned on)
       &HBF =191 = 1011,1111b (note that all bits except 6 are turned on)
     when  you OR a number with another number, the result contains all  of
     the  bits  that were turned on in the first number OR  in  the  second
     number. When you AND two numbers, the result contains all of the  bits
     that were turned on in the first number AND in the second number.  So,
     to turn on a specific bit, you OR with a number that has only that bit
     turned on (which leaves the other bits in the original number  alone).
     To  turn a specific bit off, you AND with a number that has only  that
     bit  turned  off (which leaves the other bits in the  original  number
     alone).  See?
     
          Knowing  which  memory locations have special purposes,  such  as
     keeping  track  of Caps Lock and Num Lock, comes from  (mostly)  IBM's
     listing  of  the  system  BIOS.   Many  reference  books  contain  the
     information  in a decoded format, so you can use it without having  to
     understand  the  BIOS  at all.  If you can  find  a  copy,  COMPUTE!'s
     "Mapping  the IBM PC and PCjr" is an excellent guide to this  sort  of
     thing, although there are many others.
     
          You  may  also  want something like Norton's  guide  to  assembly
     language, to give you some idea about converting numbers between  hex,
     decimal and binary, and how PC memory mapping works.  Things like...
          DEF SEG=0:PRINT PEEK(&H417)
     is the same as
          DEF SEG=&H40:PRINT PEEK(&H17)
     
     
     From:   David Martin
     To:     Mike Sinak
     Subj:   Peek & Poke
     
     
     The QBNews                                                     Page 30
     Volume  1, Number  3                                      May 22, 1990

     The following list is some things that can be done with peek & poke.
     KEYBOARD KEYS:
     PEEK (1047) AND 8:            value 8 if ALT is pressed.
                     4:                       CTRL
                     2:                  2    LEFT SHIFT.
                     1:                  1    RIGHT SHIFT.
                     3:                  3    NIETHER SHIFT.
     PEEK (1048) AND 4:                  4    PRINT SCREEN KEY.
     PEEK (1047) AND 64                  0 if in LOWER CASE.
                                         64      UPPER CASE.
     POKE 1047, PEEK(1047) AND 191       specify LOWER CASE.
                           OR 64         specify UPPER CASE.
     FOR J=0 TO 3:POKE (108+J),PEEK(112+J):NEXT:      DISABLE CTRL-BREAK
     CONFIGURATION OF COMPUTER:
     (PEEK(1041) AND 192)/64:            number of PRINTER ADAPTERS.
     (PEEK(1040) AND 1)*(1+PEEK(1040)/64 number of DISK DRIVES.
     (PEEK(1041) AND 14)/2               number of RS232 ports.
     PEEK(1043)+256*PEEK(1044)           size of RAM.
     NUMBER LOCK KEY:
     PEEK(1047) AND 32                   0 if OFF, 32 if ON.
     POKE 1047,PEEK(1047) AND 223:       turn NUM LOCK key OFF.
                              32:        turn NUM LOCK key ON.
     Alot  of  these commands are abreviated.  If nothing appears  below  a
     line just type in the line on top of what you want along with what  is
     changed. Got it? Let me know if you have any questions.  Glad to help!
     All  lines must be preceded by: DEF SEG =0  (Only one DEF SEG =  0  at
     the beginning of the program)
     
     
     From:   Ronny Ong
     To:     Mike Sinak
     Subj:   Re: PEEK & POKE
     
     Mike, I also have Duncan's book and find it useful, but I do happen to
     use a number of languages including assembler, C, and QuickBASIC.
     
     Let  me suggest "DOS Programmer's Reference" (2nd Edition),  by  Terry
     Dettmann,  Revised by Jim Kyle.  It is published by Que
     ISBN  0-88022-458-4.  List price is $27.95 U.S.   This  book  contains
     roughly the same type of information as Duncan's, but it has  specific
     QuickBASIC  4.xx  examples,  so it's probably easier to  use  for  the
     QuickBASIC programmer with less experience in assembler and C.
     
     
     
     From:   Ronny Ong
     To:     Mike Sinak
     Subj:   Re: Peek & Poke
     
     Hi,  Mike.   You might try getting a general intro/computers  type  of
     book  and  brushing up on binary numbers.  All  digital  computers  of
     today do everything in binary, or base 2.  In others words,  computers
     are  simply  made  up  of billions  of  tiny  on/off  switches.   "On"
     represents  the  binary digit (or "bit" for short) of  "1"  and  "off"
     represents "0."
     
     The QBNews                                                     Page 31
     Volume  1, Number  3                                      May 22, 1990

     
     When  you see "POKE xxx, PEEK(xxx) AND 64," here's what happens  (I've
     simplified this slightly):
     Let's  say  that PEEK(xxx) currently contains the byte value  98.   In
     binary, that's 01100010.  The decimal number 64 is 01000000 in binary.
     The "AND" operator means to produce a result which has a "1" in  every
     position  which is "1" in both of the operands and has a "0"  for  all
     other positions.
     
     01100010 <--- 98
     01000000 <--- 64
     --------
     01000000 <--- Result of 64, to be POKE'd back into memory location xxx
     
     The  end result is that all bits were turned "off" (set to  0)  except
     that  one bit which corresponded to 64.  So, essentially, the  AND  64
     "stuff" you see is manipulating individual on/off switches inside  the
     computer.
     
     A  good  book  will walk you through  conversion  between  binary  and
     decimal.  Also,  you'll  see that hexadecimal  ("hex")  numbers  which
     you've  probably  come across, are shorthand forms  of  binary.   Good
     luck!
     
     
     [EDITOR'S NOTE]
          The purpose of this conference is to discuss Microsoft QuickBASIC
     and  related  applications and utilities. SysOps looking for  a  Group
     Mail  or EchoMail link into QUIK_BAS should contact the Alliance  node
     known  as 520/323, the FidoNet node known as 107/323, or the Good  Egg
     Net  Node known as 9230/323, or simply 1-201-247-8252 for  information
     on local feeds.
     






















     The QBNews                                                     Page 32
     Volume  1, Number  3                                      May 22, 1990



     ----------------------------------------------------------------------
                                S w a p   S h o p
     ----------------------------------------------------------------------

     ***** Screen Scrolling with Call Interrupt
     
     DECLARE SUB scroll.ner (rader!, left!, up!, right!, down!)
     DECLARE SUB scroll.up (rader!, left!, up!, right!, down!)
     
     'To demonstrate the use of interrupt 10H ah=06
     'To scroll any part of the screen up or down
     'QB must be invoked with the /l switch. In QB.BI the RegType is
     'defined and the INTERRUPT-Call set up.
     'By Johan Lindgren (BBS:+46 60115371)
     
     '$INCLUDE: 'QB.BI'
     
     DIM SHARED inregs AS RegType, outregs AS RegType
     
     '---------------------------------------------------------------------
     ' Fill the screen with numbers to indicate where scrolling takes place
     '---------------------------------------------------------------------
     
     FOR i = 1 TO 24
     FOR j = 1 TO 40
     
     PRINT USING "##"; i;
     
     NEXT j
     NEXT i
     
     '----------------------------------------------------------
     
     ' Do one scroll up first. Give values and call the sub
     '----------------------------------------------------------
     
     rader = 2: up = 5: left = 5: down = 10: right = 20
     
     scroll.up rader, left, up, right, down
     
     '------------------------------------------------------------
     
     ' Do a scroll down. Give values and call the sub
     '------------------------------------------------------------
     
     rader = 3: up = 10: left = 35: down = 15: right = 70
     
     scroll.ner rader, left, up, right, down
     
     
     'END of demo.
     
     SUB scroll.ner (rader, left, up, right, down)
     
     '-----------------------------------------------------------
     
     The QBNews                                                     Page 33
     Volume  1, Number  3                                      May 22, 1990

     'First put up and down in right hexadecimal postion
     'Then enter the values into the registers and call interrupt
     '------------------------------------------------------------
     
     up = up * 256
     down = down * 256
     
     inregs.ax = &H700 + rader
     inregs.cx = up + left
     inregs.dx = down + right
     
     
     CALL INTERRUPT(16, inregs, outregs)
     
     
     END SUB
     
     SUB scroll.up (rader, left, up, right, down)
     
     '-----------------------------------------------------------
     'First put up and down in right hexadecimal postion
     'Then enter the values into the registers and call interrupt
     '------------------------------------------------------------
     
     
     up = up * 256
     down = down * 256
     
     inregs.ax = &H600 + rader
     inregs.cx = up + left
     inregs.dx = down + right
     
     
     CALL INTERRUPT(16, inregs, outregs)
     
     
     END SUB
     

















     The QBNews                                                     Page 34
     Volume  1, Number  3                                      May 22, 1990

     ***** Getting the Day of the Week with Call Interrupt
     
     DECLARE FUNCTION dag$ (nr!)
     
     ' This is just an example to illustrate the use of an interrupt
     ' to get the day of any date.
     ' By Johan Lindgren (+46 60-121497 (BBS System))
     
     '$INCLUDE: 'QB.BI'
     
     DIM inregs AS RegType, outregs AS RegType
     
     inregs.ax = &H2A00
     
     spardat$ = DATE$
     
     CLS
     PRINT
     PRINT "This is just to show the function of interrupt 33,function 2a"
     PRINT "It works well for our time and the future."
     PRINT "If you need this function for old dates, you have to use"
     PRINT "something else."
     
     ON ERROR GOTO fel.datum       'In case you enter a bad date
     
     main:
     
     svar$ = " "
     DO UNTIL svar$ = ""
     INPUT "Input the date to check in the format MM-DD-YEAR"; svar$
     IF svar$ <> "" THEN
          DATE$ = svar$            'Set the date we want to check
                                   'Call the interrupt to get the day
          CALL Interrupt (33, inregs, outregs)
          dagnr = outregs.ax MOD 256 'Extract the daynumber returned
          DATE$ = spardat$         'Restore proper date
     
          SELECT CASE dagnr
               CASE 0
                    dag$ = "Sunday"
               CASE 1
                    dag$ = "Monday"
               CASE 2
                    dag$ = "Tuesday"
               CASE 3
                    dag$ = "Wednesday"
               CASE 4
                    dag$ = "Thursday"
               CASE 5
                    dag$ = "Friday"
               CASE 6
                    dag$ = "Saturday
          END SELECT
     
          PRINT "The day of the week for ";svar$;" is ";dag$
     
     The QBNews                                                     Page 35
     Volume  1, Number  3                                      May 22, 1990

          PRINT
     END IF
     
     
     
     
     
     
     LOOP
     
     CLS
     END
     
     fel.datum:
     RESUME main
     







































     The QBNews                                                     Page 36
     Volume  1, Number  3                                      May 22, 1990

     ***** A YES/NO response DEF FN
     
     ' TO: DAVID CLEARY  76510,1725
     ' FROM: BEN HARTLEY  70033,2612
     ' SUBJECT: For QBNews -- CHOOSE.BAS -- (FUNCTION)
     '===================================================================
     'Dear David,
     '
     '     Liked your newsletter, which I downloaded from Exec-PC BBS.
     ' I'm not what you might call an experienced programmer, but the
     ' enclosed function might be of interest.
     '     There are LOTS of routines around that allow selection of
     ' a simple "Yes" or "No" response.  There are times, however, when
     ' the flow of a program is improved if the choices are something
     ' other than "Y" or "N".  That's where this one comes in.  If there
     ' are no more than two choices, then they can be explicitly stated.
     ' Whether this is any faster, or, heaven save us all, more "elegant"
     ' than using SELECT CASE, I haven't the foggiest.  I do know that it
     ' works!
     '     You can load this entire file into your QuickBASIC editor,
     ' and run it.  It was originally written in QB 3.0, but seems to
     ' run fine in QB 4.5 --
     '     Hope this is something along the lines of what you're
     ' looking for.
     '
     '                                Ben Hartley
     '                                Jaffrey, NH
     
     '-------------------------------------------------------------------
     DEF FNChoose (prompt$, Response1$, Response2$)
             R1$ = UCASE$(LEFT$(Response1$, 1))
             R2$ = UCASE$(LEFT$(Response2$, 1))
             alpha$ = R1$ + R2$
     
             PRINT prompt$; " ("; R1$; " or "; R2$; ") "
             reply$ = ""
             charPos% = 0
             WHILE charPos% = 0
                      reply$ = UCASE$(INKEY$)
                      IF (reply$ <> "") THEN
                             charPos% = INSTR(alpha$, reply$)
                             IF (charPos% = 0) THEN BEEP
                      END IF
             WEND
             reply$ = UCASE$(MID$(alpha$, charPos%, 1))
             FNChoose = (reply$ = R1$)
     END DEF
     '-------------------------------------------------------------------
     COLOR 15, 1
     beginhere:
     CLS
     LOCATE 10, 5
     PRINT "Which option do you wish..."
     LOCATE 12, 7
     IF FNChoose("...The First or the Second ?", "First", "Second") THEN
     
     The QBNews                                                     Page 37
     Volume  1, Number  3                                      May 22, 1990

             PRINT
             PRINT TAB(20); "You chose the First Option."
     ELSE
             PRINT
             PRINT TAB(20); "You chose the Second Option."
     END IF
     LOCATE 16, 7
     IF FNChoose("Do It Again or Quit ?", "Again", "Quit") THEN
             GOTO beginhere
     END IF
     PRINT
     PRINT TAB(30); "**** All done! ****"
     END
     









































     The QBNews                                                     Page 38
     Volume  1, Number  3                                      May 22, 1990

     ***** A Powerful Replacement for INPUT
     
     'SYNTAX: Enput$(Row%,Col%,FLen%,Default$,Allow$,EndKeys$,ExitKey$)
     'WHERE: Row% & Col% - where input to occur
     '       FLen% - Field Length - maximum allowable
     '       Default$ - Field's beginning default value
     '       Allow$ - Character Set allowable for input
     '       EndKeys$ - Keystrokes acceptable for finishing.
     '          SUCH: [Enter] is CHR$(13)
     '                [Esc] is CHR$(27)
     '                [F1] is CHR$(255)+CHR$(59)
     '                [Ctrl+PgUp] is CHR$(255)+CHR$(132)
     '                ... etc
     '       ExitKey$ - The keystroke (from above EndKeys$)
     '                  which was struck at function end.
     'SIMPLEST USE:  A$ = Enput$(0,0,0,"",","",Any$)
     '       Will default to cursor's current row/col, length is
     '       autoset to right margin, allowable chars are ALL,
     '       only ending key is [Enter].
     '==========================================> Frederick Volking
     
     FUNCTION  Enput$ (Row%, Col%, FieldLen%,  Default$,  AllowCharsMask$_
                       ,EndingKeys$, ExitKey$) STATIC
     
        SHARED ScreenWidth%, BackSpaceKeyStrokes$, EmptySpaceChar$
     
        ' verify SHARED globals are set
     
        IF ScreenWidth% = 0 THEN ScreenWidth% = 40
        IF BackSpaceKeyStrokes$ = "" THEN BackSpaceKeyStrokes$ = _
                                  CHR$(8) + CHR$(255) + CHR$(75)
        IF EmptySpaceChar$ = "" THEN EmptySpaceChar$ = CHR$(254)
     
        ' If not specified then supply defaults to incomming vars
     
        IF AllowCharsMask$ = "" THEN AllowCharsMask$ = CHR$(34) +_
            " !#$%&'()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]_
            ^_abcdefghijklmnopqrstuvwxyz|~"
     
        IF EndingKeys$ = "" THEN EndingKeys$ = CHR$(13)
        IF Row% = 0 THEN Row% = CSRLIN
        IF Col% = 0 THEN Col% = POS(0)
        IF FieldLen% = 0 THEN FieldLen% = ScreenWidth% - Col%
        IF LEN(Default$) > FieldLen% THEN Default$ = LEFT$(Default$_
            , FieldLen%)
     
        ' define internal defaults
     
        CharsCollected% = 0
        ReturnVar$ = ""
        ' begin main loop
        DO
           NotDone% = 1
           IF CharsCollected% = 0 THEN
              LOCATE Row%, Col%, 0
     
     The QBNews                                                     Page 39
     Volume  1, Number  3                                      May 22, 1990

              PRINT Default$ + STRING$(FieldLen% - LEN(Default$), _
                 EmptySpaceChar$);
           END IF
           IF CharsCollected% = FieldLen% THEN
              LOCATE Row%, Col% + CharsCollected% - 1, 1
           ELSE
              LOCATE Row%, Col% + CharsCollected%, 1
           END IF
           DO
              KeyStroke$ = INKEY$
           LOOP WHILE KeyStroke$ = ""
           IF LEN(KeyStroke$) = 2 THEN KeyStroke$ = CHR$(255) + _
               RIGHT$(KeyStroke$, 1)
           IF INSTR(AllowCharsMask$, KeyStroke$) > 0 THEN
              IF CharsCollected% < FieldLen% THEN
                 IF CharsCollected% = 0 THEN
                    PRINT STRING$(FieldLen%, EmptySpaceChar$);
                    LOCATE Row%, Col%, 0
                 END IF
                 ReturnVar$ = ReturnVar$ + KeyStroke$
                 CharsCollected% = CharsCollected% + 1
                 PRINT KeyStroke$;
              END IF
           ELSE
              IF INSTR(BackSpaceKeyStrokes$, KeyStroke$) > 0 THEN
                 IF CharsCollected% > 1 THEN
                    CharsCollected% = CharsCollected% - 1
                    LOCATE Row%, Col% + CharsCollected%, 0
                    PRINT EmptySpaceChar$;
                    LOCATE Row%, Col% + CharsCollected%, 1
                    ReturnVar$ = LEFT$(ReturnVar$, CharsCollected%)
                 ELSE
                    CharsCollected% = 0
                    ReturnVar$ = Default$
                 END IF
              ELSE
                 IF INSTR(EndingKeys$, KeyStroke$) > 0 THEN
                    ExitKeys$ = KeyStroke$
                    NotDone% = 0
                 ELSE
                    SOUND 500, 1
                 END IF
              END IF
           END IF
        LOOP WHILE NotDone%
        Enput$ = ReturnVar$
     END FUNCTION
     







     The QBNews                                                     Page 40
     Volume  1, Number  3                                      May 22, 1990

     ***** Windowing Routines with Shading
     
     'FRAME.BAS test program
     'Lawrence Stone, 1990
     '
     'Purpose: Demonstrate the versitility of the Frame subprogram.
     'Note: I built this routine just for the fun of it.  I designed it to
     'be easy to use and versitile. This demonstration program simply makes
     'six calls to the frame subprogram-the subprogram does the rest.
     
     
     DECLARE  SUB Frame (TopRow%, leftCol%, botRow%, rightCol%,  boxType%,_
               boxFg%, boxBg%, filFg%, filBg%, fillChar%, shadow%, header$)
     
        COLOR 12, 4                     'Set a fancy color
        FOR A% = 1 TO 25
            LOCATE A%, 1
            PRINT STRING$(80, 206);     'Draw a complex background
        NEXT
     
                              'Test the Frame subprogram
        Frame 5, 20, 21, 75, 2, 15, 3, 9, 7, 178, -1, "This is a Test"
     
                              'Overlay the 1st box with a smaller 2nd box
        Frame 4, 3, 10, 36, 1, 15, 6, 6, 0, 219, -1, "This is Test 2"
     
                              'What the heck, let's draw another box
        Frame 13, 33, 22, 70, 3, 14, 2, 15, 3, 221, -1, "This is Test 3"
     
                              'What the heck, draw box #4 without a header
        Frame 15, 5, 19, 65, 4, 13, 0, 0, 7, 32, -1, ""
        LOCATE 17,14:PRINT "Box #4 has a shadow but doesn't have a Header."
     
                              'What the heck, draw box #5 without a shadow
        Frame 8, 40, 10, 73, 4, 11, 0, 11, 0, 32, 0, ""
        LOCATE 9, 43: PRINT "Box #5 doesn't have a Shadow!"
     
                              'What the heck, draw a frame around it all
        Frame 1, 1, 25, 80, 2, 15, 0, 0, 0, 32, 0, _
           "Box #6 Frames Without Clearing"
     
        COLOR 7, 0                  'Restore color before ending
        A$ = INPUT$(1)              'Give a keystroke to end this test.
        END                         'We're out of here!
     
     [EDITOR'S NOTE]
          Due to the formatting of the FRAME subprogram, it is not  printed
     here. You can find the sub program in the file FRAME.BAS
     






     The QBNews                                                     Page 41
     Volume  1, Number  3                                      May 22, 1990



     ----------------------------------------------------------------------
                           I n p u t   P a s t   E n d
     ----------------------------------------------------------------------

     Due to demand, you can now get the QBNews mailed to you on disk for  a
     nominal charge. The rates are as follows:
     
     United States                $3.00
     
     North America (outside US)   $4.00
     
     Outside US                   $6.00
     
     Please  add $1.00 if you want it on 3.5" media. Also, you can  receive
     it  in either ZIP, PAK, or LHZ format. If you don't specify, you  will
     receive it in ZIP format.
     
     The first time you request the QBNews, you will receive all  available
     issues. That way you won't miss any.
     
     And  of course, you can always download it free from Treasure  Island.
     First time callers are granted limited download privlidges so you  can
     get it. Treasure Island is 9600 HST, is at FIDO address 1:141/730, and
     its phone is 203-791-8532. To request your copy on disk, send US funds
     to:
     
     The QBNews
     P.O. Box 507
     Sandy Hook, CT 06482
     
     Remember to specify which archive format you want.
     























     The QBNews                                                     Page 42
     Volume  1, Number  3                                      May 22, 1990

     WE NEED AUTHORS!
     
          If you are interested in writing for the QBNews, you can  contact
     me  at  the  address below. I can also be  reached  on  Compuserve  as
     76510,1725 or on Prodigy as HSRW18A. If you are submitting articles, I
     ask that they be ASCII text with no more than 70 characters per  line.
     As  far as reviews go, I am pretty well set so what I really  want  is
     code.
     
     
     You can write me at:
     
          The QBNews
          P.O. Box 507
          Sandy Hook, CT 06482
     
     David Cleary
     





































     The QBNews                                                     Page 43