home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / progbas / qbnws103.arj / QBNWS103.NWS < prev    next >
Encoding:
Text File  |  1990-05-23  |  108.1 KB  |  2,657 lines

  1.      Volume  1, Number  3                                      May 22, 1990
  2.  
  3.      
  4.      
  5.      
  6.      
  7.      
  8.      
  9.      
  10.      
  11.      
  12.      
  13.      
  14.                    **************************************************
  15.                    *                                                *
  16.                    *                    QBNews                      *
  17.                    *                                                *
  18.                    *      International QuickBASIC Electronic       *
  19.                    *                  Newsleter                     *
  20.                    *                                                *
  21.                    *    Dedicated to promoting QuickBASIC around    *
  22.                    *                  the world                     *
  23.                    *                                                *
  24.                    **************************************************
  25.      
  26.      
  27.      
  28.      
  29.      
  30.      
  31.      
  32.      
  33.      
  34.      
  35.      
  36.      
  37.      
  38.      
  39.      
  40.      
  41.         The  QBNews  is  an electronic newsletter  published  by  Clearware
  42.      Computing. It can be freely distributed providing NO CHARGE is charged
  43.      for  distribution.  The  QBNews is copyrighted in  full  by  Clearware
  44.      Computing.  The  authors  hold  the  copyright  to  their   individual
  45.      articles.  All program code appearing in QBNews is released  into  the
  46.      public  domain.   You  may  do what you  wish  with  the  code  except
  47.      copyright  it.  QBNews  must  be  distributed  whole  and  unmodified.
  48.      
  49.      You can write The QBNews at:
  50.      
  51.           The QBNews
  52.           P.O. Box 507
  53.           Sandy Hook, CT 06482
  54.      
  55.      Copyright (c) 1989 by Clearware Computing.
  56.      
  57.      
  58.      
  59.      The QBNews                                                   Page    i
  60.      Volume  1, Number  3                                      May 22, 1990
  61.  
  62.  
  63.      
  64.  
  65.      ----------------------------------------------------------------------
  66.  
  67.                         T A B L E   O F   C O N T E N T S
  68.  
  69.      
  70.      1.  From the Editors Desk
  71.           From the Editor ..............................................  1
  72.  
  73.      2.  Mail Bag
  74.           QBNews in Europe .............................................  2
  75.  
  76.      3.  Beginners Corner
  77.           BASIC Menuing and Graphics by Ryan Snodgrass .................  4
  78.  
  79.      4.  Who ya gonna call? CALL INTERRUPT
  80.           Directory Swapping by Hector Plasmic .........................  6
  81.  
  82.      5.  The Tool Shed
  83.           P-Screen+ and P-Screen Professional by David Cleary ..........  8
  84.           Index Manager - B-Tree indexing for QB by David Cleary ....... 10
  85.  
  86.      6.  Product Announcements
  87.           P-Screen, P-Screen Professional, P~F Presents ................ 12
  88.  
  89.      7.  Under The Hood
  90.           Fast File I/O in QuickBASIC by Ethan Winer ................... 16
  91.  
  92.      8.  Power Programming
  93.           How to Make a Self-Cloning Exe in QuickBASIC by Larry Stone .. 19
  94.           Programming UEVENT by Jim Mack ............................... 23
  95.  
  96.      9.  Some Assembly Required 
  97.           Assembler Programming for QuickBASIC by Tom Hanlin ........... 26
  98.  
  99.      10.  And I Heard it Through the Grapevine
  100.           Exerpts from the QUIK_BAS echo ............................... 29
  101.  
  102.      11.  Swap Shop
  103.            Screen Scrolling with Call Interrupt ........................ 33
  104.            Getting the Day of the Week with Call Interrupt ............. 35
  105.            Yes/No Response DEF FN ...................................... 37
  106.            A Replacement for INPUT with MUCH MORE programmer control. .. 39
  107.            Windowing Routines with Shading ............................. 41
  108.  
  109.      12.  Input Past End
  110.            Get the QBNews on Disk ...................................... 42
  111.            Contacting the QBNews ....................................... 43
  112.  
  113.      The QBNews                                                   Page   ii
  114.      Volume  1, Number  3                                      May 22, 1990
  115.  
  116.  
  117.  
  118.      ----------------------------------------------------------------------
  119.                     F r o m   t h e   E d i t o r s   D e s k
  120.      ----------------------------------------------------------------------
  121.  
  122.      From the Editor
  123.      
  124.           Welcome  to the third issue of The QBNews. I know it has  been  a
  125.      while  coming  but I hope it was worth the wait. There  are  some  big
  126.      changes  in  store for the news. I have realized that putting  out  an
  127.      issue  every  2 months is impractical. Therefore, The QBNews  will  be
  128.      published quarterly. Expect issues around these dates:
  129.      
  130.      May 30
  131.      August 30
  132.      November 30
  133.      February 28
  134.      
  135.           I  have also received alot of requests for the news on disk.  You
  136.      can  now  receive the QBNews on disk. Information on this  service  is
  137.      available in the back of this issue.
  138.      
  139.           The  QBNews is distributed through SDS on Fidonet. It seems  that
  140.      SDS  is not as far reaching as I had thought. In order that  everybody
  141.      knows that the can get the news reasonably close to them, I would like
  142.      to set up distribution hubs around the country. I am looking for BBS's
  143.      in these areas who would like to be QBNews hubs: Baltimore/Washington,
  144.      Charlotte  NC,  Atlanta,  Orlando,  Memphis,  New  Orleans,   Chicago,
  145.      Cincinnati, Minneapolis, Kansas City MO, Dallas, Denver, Phoenix,  Los
  146.      Angeles,  San  Francisco, and Portland. I do require a few  things  in
  147.      order  to be a hub. First, first time callers must be granted  limited
  148.      download privledges. Second, you must accept file requests from  Point
  149.      systems.  Last, you must be willing to send the news down the line  to
  150.      the next hub. If you meet these conditions and are interested in being
  151.      a hub, write me.
  152.      
  153.           I want to hear from you. After the first issue, I received  quite
  154.      a  bit of feedback. I wasn't too happy with that issue. I thought  the
  155.      second issue was really good. I didn't receive as much feedback on  it
  156.      as  the first though. It was kind of disappointing. Let me  hear  your
  157.      complaints, suggestions, coding tips, or whatever. It always helps  to
  158.      know people are interested.
  159.      
  160.           Thanks and enjoy.
  161.           David Cleary
  162.      
  163.  
  164.  
  165.  
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173.      The QBNews                                                     Page  1
  174.      Volume  1, Number  3                                      May 22, 1990
  175.  
  176.  
  177.  
  178.      ----------------------------------------------------------------------
  179.                                  M a i l   B a g
  180.      ----------------------------------------------------------------------
  181.  
  182.      
  183.      Hello David,
  184.      
  185.           Today I've picked up 2 QBNews files and I've read them both. Most
  186.      interesting  stuff! Just the electronic magazine I need!  Coming  from
  187.      the  TRS80 Model I computer on which I've learned basic and  wrote  my
  188.      own  BBS and videotext systems in basic (the system is  still  online)
  189.      I've  entered the PC community and started with RBBS-PC which  is,  as
  190.      you  would  know,  almost  completely  written  in  QuickBasic.   I've
  191.      purchased   the  package  a  few  years  ago  and  developed   a   few
  192.      administrative  applications  in  it for a friend  his  firm.  At  the
  193.      moment,  due  to  lack of time, I'm only do  a  little  debugging  and
  194.      modifying RBBS-PC. I recently discovered a bug (well, I think it is  a
  195.      bug) which I will give you here:
  196.      
  197.      DEFINT A-Z :' so every variable is by default integer
  198.      Single precision! = 3600 * Hour
  199.      
  200.           The  maximum  value of an integer is 32767 and  when  you  expect
  201.      "Hour"  can  have a maximum value of 24, then the  receiving  variable
  202.      must  be  a single precision variable 'cause by example 20  *  3600  =
  203.      72000. So the construction above looks good but isn't. QuickBasic will
  204.      evaluate "3600 * Hour" as an integer expression 'cause both  variables
  205.      are  integers. The result will be an overflow error. I've  tested  the
  206.      same  construction on my TRS80 and on the PC in GWBASIC and they  both
  207.      work fine!!
  208.      
  209.      The solution for this problem is very simple. The technique is  called
  210.      typecasting.
  211.      
  212.      Single  precision!  =  3600.0  * Hour  :' 3600.0  is  of  type  single
  213.      precision
  214.      
  215.      When  you enter this in the QB environment, QB will change  3600.0  in
  216.      3600! which is the same.
  217.      
  218.      Some undocumented META statements, nice to know:
  219.      ' $LINESIZE:132
  220.      ' $PAGE
  221.      ' $TITLE: 'put the main title here'
  222.      ' $SUBTITLE: 'put the sub-title here'
  223.      
  224.           Anyway,  I hope this is some contribution to the  magazine.  From
  225.      now  on  I will put the QBNews files in my two BBS  systems  and  will
  226.      upload them to some other systems here in Holland. I hope more  QBNews
  227.      will  come  from the other side of the ocean. Please  respond  through
  228.      Fidonet  if you receive this message. Where I living, well, in a  city
  229.      called Amsterdam, that's in Holland or The Netherlands and that is  in
  230.      Europe  ('cause many Americans don't know what's on the other side  of
  231.      the ocean ;-)
  232.      
  233.      
  234.      The QBNews                                                     Page  2
  235.      Volume  1, Number  3                                      May 22, 1990
  236.  
  237.      Cu, Kim Kodde (2:500/41.1433) Holland
  238.      
  239.      
  240.      
  241.      Hello David,
  242.      
  243.           A  very  good initiative! I give my full support  for  whit  it's
  244.      worth.  I am not a professional programmer and I have no education  in
  245.      this area, but I have been programming in BASIC for some years for fun
  246.      and  during  that  time gone from an VIC64 to an AMSTRAD  6128  to  an
  247.      Artech 286/AT (and IBM ps 20). I started out with QB 2.00 a couple  of
  248.      years ago but recently upgraded to 4.50. It is a marvelous difference.
  249.      
  250.           I have also included an extract from a program I have written for
  251.      my work.  I am a journalist and the program is used to store things we
  252.      are  to  check  or  cover in the  future.  Certain  things  come  back
  253.      regularly on certain weekdays no matter which date it is. I  therefore
  254.      needed  a simple routine to check which weekday a certain date  is  so
  255.      when  the  agenda  for  that date is printed  out  the  correct  items
  256.      depending on the weekday is included.  I found my answer in  interrupt
  257.      33,  function 2a00.  The low part of register AX returns a number  for
  258.      the  weekday. 0 for Sunday to 6 for Saturday.  This is very  good  for
  259.      the future.  If you are interested in checking which day you were born
  260.      for  example you need something else because the computer only  covers
  261.      dates  from  the  early 80-ies.  I have seen  programs  in  genealogy-
  262.      packages which covers this part.
  263.      
  264.      Johan Lindgren
  265.      Sundsvall, Sweden
  266.      
  267.      
  268.           I  would  be interested in hearing from you.  Please  write  with
  269.      comments,  suggestions, complaints, or whatever you feel like  talking
  270.      about. Send it to:
  271.      
  272.      The QBNews
  273.      P.O. Box 507
  274.      Sandy Hook, CT 06482
  275.      
  276.  
  277.  
  278.  
  279.  
  280.  
  281.  
  282.  
  283.  
  284.  
  285.  
  286.  
  287.  
  288.  
  289.  
  290.  
  291.  
  292.      The QBNews                                                     Page  3
  293.      Volume  1, Number  3                                      May 22, 1990
  294.  
  295.  
  296.  
  297.      ----------------------------------------------------------------------
  298.                          B e g i n n e r s   C o r n e r
  299.      ----------------------------------------------------------------------
  300.  
  301.      BASIC Menuing and Graphics by Ryan Snodgrass
  302.      
  303.           This  section  of  QB News is dedicated to the  readers  who  are
  304.      novices to Quick BASIC.  In this issue we will talk about creating and
  305.      editing simple menu programs and about some of the elementary commands
  306.      used  in making computerized graphics.  The first thing we talk  about
  307.      is  making simple menus.  The first step you take in making a menu  is
  308.      to plan what selections you will have.  In our example we will use the
  309.      following selections: DIR, make the computer beep, and quit.  The next
  310.      step  is  to  plan whether to use numbers, letters, or  both.  In  our
  311.      example  we  will use both numbers and letters.  The following  is  an
  312.      example program; you may edit it as much as you like.
  313.      
  314.           Menu:
  315.           PRINT "(1) - DIR"    'Shows the first selection (DIR)
  316.           PRINT "(2) - BEEP"    'Shows the second selection (BEEP)
  317.           PRINT "(Q) - QUIT"    'Shows the third selection (QUIT)
  318.          MenuInput:
  319.                A$=INPUT$(1)     'Waits  for the input from  the  keyboard
  320.                IF A$="1" THEN GOTO Selection1   'See if one was pressed
  321.                IF A$="2" THEN GOTO Selection2   'See if two was pressed
  322.                IF A$="Q" OR A$="q" THEN CLS:END    'See if Q was pressed
  323.           GOTO MenuInput    'Go back and wait for another key
  324.      
  325.           Selection1:
  326.                SHELL"DIR"     'Do a DIR of the current  directory
  327.                GOTO Menu    'Redisplay the menu
  328.           Selection2:
  329.                BEEP     'Produce a beep
  330.                GOTO  Menu    'Redisplay the menu
  331.      
  332.      -+* To edit selections on this menu do the following: *+-
  333.      
  334.      1) Change the menu listing by replacing one of the selections by
  335.      another (i.e. PRINT "(1) - DIR" replace with the following:
  336.           PRINT "(1) - DIR/P")
  337.      
  338.      2) Change the selection commands (i.e. change the Selection1  commands
  339.      to:
  340.           Selection2:
  341.                SHELL"DIR/P"
  342.                GOTO Menu
  343.      
  344.      -+*  To add selections to the menu do the following: *+-
  345.      
  346.      1) After the PRINT "(2) - BEEP" add PRINT "(3) - Your Selection"
  347.      
  348.      2) After IF A$="2" THEN... add IF A$="3" THEN GOTO Selection3
  349.      
  350.      3) After the GOTO Menu on Selection2 add:
  351.           Selection3:
  352.      
  353.      The QBNews                                                     Page  4
  354.      Volume  1, Number  3                                      May 22, 1990
  355.  
  356.                'Your  command
  357.                GOTO  Menu
  358.      
  359.      
  360.           The  next  subject  we will discuss is  elementary  commands  for
  361.      creating  graphics  screens.   A graphics  screen  is  represented  by
  362.      a  number of pixels or points on the screen, which is referred  to  as
  363.      the resolution of your screen.  The first step we must do is select  a
  364.      screen  number  which  corresponds to your  resolution  or  any  other
  365.      resolution you can use.  The following is a list of screen number  and
  366.      their attributes:
  367.      
  368.      +-----------+------------------+-------------+------------------+
  369.      |Screen #:   | # of colors:    | Resolution: | Width of  Screen:|
  370.      +-----------+------------------+-------------+------------------+
  371.      | 1 (CGA)    | 4 out of 16     | 320x200     | 40 Characters    |
  372.      | 2 (CGA)    | 2 out of 2      | 640x200     | 80 Characters    |
  373.      | 7 (EGA)    | 16 out of 64    | 320x200     | 40 Characters    |
  374.      | 8 (EGA)    | 16 out of 64    | 640x200     | 80 Characters    |
  375.      | 9 (EGA)    | 16 out of 64    | 640x350     | 80 Characters    |
  376.      | 10 (MONO)  | 9 grays         | 640x350     | 80 Characters    |
  377.      | 11 (VGA)   | 2 out of 2      | 640x480     | 80 Characters    |
  378.      | 12 (VGA)   | 16 out of 256000| 640x480     | 80 Characters    |
  379.      +-----------+------------------+-------------+------------------+
  380.      
  381.           The  next step is to type: SCREEN (and then the type of  graphics
  382.      you want).  The first and easiest command is LINE.  The usage is  LINE
  383.      (X,Y)-(X,Y),Color  (i.e. LINE (100,100)-(200,200),1 would draw a  line
  384.      from  100,100 to 200,200 using the color 1). Using that in an  example
  385.      program  would be as  follows:
  386.      
  387.           SCREEN  1
  388.           LINE(100,100)-(200,200),1
  389.           END
  390.      
  391.           You  can  also  draw  an open  rectangle  by  using  LINE  (X,Y)-
  392.      (X,Y),Color,B or a solid rectangle by using LINE (X,Y)-(X,Y),Color,BF.
  393.      The  next command we will go into is the DRAW command.  The  usage  is
  394.      DRAW  "(Attributes)" (i.e. DRAW "U4 R4 D4L4").  The attributes are  as
  395.      follows:  C#=Color Number, U#=Up a number of pixels, D#=Down a  number
  396.      of  pixels, L#=Left a number of pixels, R#=Right a number  of  pixels,
  397.      E#=Up and to the right a number of pixels, F#=Down and to the right  a
  398.      number of pixels, G#=Down and left a number of pixels, H#=Up and  left
  399.      a  number  of  pixels, M X,Y=Moves to a certain pixel  (i.e.  DRAW  "M
  400.      100,100"). Our example program draws a 3-D box:
  401.      
  402.           SCREEN  1
  403.           DRAW "M 100,100 C1 U10 R10 D10 L10 H10 U10 F10 R10 H10 L10"
  404.           END
  405.      
  406.           If  you have any suggestions as to what you would like to see  in
  407.      this  column,  please send them to the QBNews at the  address  in  the
  408.      back.
  409.      
  410.  
  411.      The QBNews                                                     Page  5
  412.      Volume  1, Number  3                                      May 22, 1990
  413.  
  414.  
  415.  
  416.      ----------------------------------------------------------------------
  417.         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
  418.      ----------------------------------------------------------------------
  419.  
  420.      Directory Swapping by Hector Plasmic
  421.      
  422.           You've  all seen professional programs that let you Shell to  DOS
  423.      and  always return you to the proper drive and subdirectory  when  you
  424.      Exit.  It's not too hard to implement something similar for  your  own
  425.      QuickBASIC programs.  QB doesn't have all the functions you need to do
  426.      it, but DOS can lend a hand via Interrupt.
  427.      
  428.           What we need to do is handle all SHELL calls from a common  point
  429.      (Sub).   In   this  Sub,  we'll  determine  the  current   drive   and
  430.      subdirectory,  perform  the  SHELL, then restore  the  old  drive  and
  431.      subdirectory  before  Exitting  the  Sub.
  432.      
  433.           Interrupt 21h function 19h returns the number of the current disk
  434.      drive  in  register  .al as a number (0=A,  1=B,  etc.).
  435.      
  436.           Interrupt  21h function 47h copies the current directory  of  the
  437.      drive  #  in  .dl  (0=default, 1=A, 2=B,  etc.)  as  an  ASCIIZ  (null
  438.      terminated) string into a buffer pointed to by .ds:.si.  The  pathname
  439.      does  not  include the drive identifier or a  leading  backslash.   An
  440.      error can occur if you use an invalid drive specification; this is not
  441.      likely since we are using the default drive, but if you are using this
  442.      function to attempt to read the default directory on a drive that  may
  443.      not   exist,   check   the  carry  flag   (IF   OutReg.FLAGS   AND   1
  444.      THEN...oops!).  .ax will contain 0Fh (invalid drive spec) if the error
  445.      occurs.
  446.      
  447.           Finally, Interrupt 21h function 0Eh sets the default drive to the
  448.      drive  number passed in register .dx (0=A, 1=B,  etc.).This  completes
  449.      the  list of DOS functions we'll need to perform our switching.   What
  450.      follows  is some sample code to show a practical application of  these
  451.      interrupt  functions:
  452.      
  453.      DEFINT A-Z
  454.      
  455.      TYPE RegType2
  456.           AX    AS INTEGER
  457.           BX    AS INTEGER
  458.           CX    AS INTEGER
  459.           DX    AS INTEGER
  460.           BP    AS INTEGER
  461.           SI    AS INTEGER
  462.           DI    AS INTEGER
  463.           Flags AS INTEGER
  464.           DS AS INTEGER
  465.           ES AS INTEGER
  466.      END TYPE
  467.      
  468.      'You must link with QB.LIB (QB.QLB) to use Interrupt functions
  469.      
  470.      DECLARE SUB InterruptX (Intr%, InReg AS RegType2, OutReg AS RegType2)
  471.      
  472.      The QBNews                                                     Page  6
  473.      Volume  1, Number  3                                      May 22, 1990
  474.  
  475.      DECLARE SUB DoShell (Before$, Args$, After$)
  476.      
  477.      DoShell "Type EXIT to return", "", "Welcome back"   'Just to test it
  478.      END
  479.      
  480.      SUB DoShell (Before$, Args$, After$)'Declare some stuff to use
  481.      
  482.      DIM InReg AS RegType2
  483.      DIM OutReg AS RegType2
  484.      DIM CurrentDrive AS INTEGER
  485.      DIM CurrentDir AS STRING * 64
  486.      
  487.      'Get current disk drive
  488.      
  489.      InReg.AX = &H19 * 256
  490.      InterruptX &H21, InReg, OutReg
  491.      CurrentDrive = OutReg.AX MOD 256
  492.      
  493.      'Get current directory
  494.      
  495.      InReg.AX = &H47 * 256
  496.      InReg.DX = CurrentDrive + 1  'Note adding one to drive for this, or
  497.                                   'could use 0 for default drive
  498.      InReg.DS = VARSEG(CurrentDir)
  499.      InReg.SI = VARPTR(CurrentDir)
  500.      InterruptX &H21, InReg, OutReg
  501.      
  502.      'Do the shell
  503.      IF Before$ <> "" THEN CLS : PRINT Before$  'Optional
  504.      SHELL Args$
  505.      IF After$ <> "" THEN CLS : PRINT After$    'Optional
  506.      
  507.      'Change to old disk drive
  508.      InReg.AX = &HE * 256
  509.      InReg.DX = CurrentDrive
  510.      InterruptX &H21, InReg, OutReg
  511.           '(InReg.AX MOD 256 is the # of logical drives in the
  512.           'system if anyone is interested)
  513.      
  514.      'Change to old subdirectory (Could use Int &H21 func &H3B instead)
  515.      ToDir$ = CHR$(ASC("A") + CurrentDrive) + ":\" + LEFT$(CurrentDir,_
  516.           INSTR(CurrentDir, CHR$(0)))
  517.      CHDIR ToDir$
  518.      
  519.      END SUB
  520.      
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530.      The QBNews                                                     Page  7
  531.      Volume  1, Number  3                                      May 22, 1990
  532.  
  533.  
  534.  
  535.      ----------------------------------------------------------------------
  536.                             T h e   T o o l   S h e d
  537.      ----------------------------------------------------------------------
  538.  
  539.      P-Screen+ and P-Screen Professional by David Cleary
  540.      
  541.           *** IMPORTANT ***
  542.           It took me a while to write this review. As you read it, you will
  543.      see  I have two major complaints concerning these programs.  They  are
  544.      lack  of  mouse support and an easier user interface.  These  problems
  545.      have  been  corrected in the latest release. Please  see  the  product
  546.      announcement for the new version in this issue.
  547.      
  548.           A program's user interface can be the difference between  success
  549.      and  failure.  You  could have the best program in the  world  but  if
  550.      people  don't like using it, it won't succeed. The user  interface  is
  551.      also  the part of a program I hate doing the most. I know what I  like
  552.      in  a  user interface but I have a hard time translating  it  into  my
  553.      programs. I also find the coding of user interfaces very tedious.  So,
  554.      in  this  issue,  I  will review a tool that  helps  you  design  user
  555.      interfaces quickly and easily.
  556.      
  557.           The  product  is  called P-Screen and is  from  Pro~Formance.  P-
  558.      Screen+  is  a  shareware  program  while  P-Screen  Professional   is
  559.      commercial.  This program combines a screen drawing utility, a  screen
  560.      storage  and  display  utility, and the Professional  version  adds  a
  561.      QuickBASIC  3  and  4  code generator and  a  variety  of  user  input
  562.      routines. These programs allows you to create screens and forms, store
  563.      them  in libraries, and access them from your QuickBASIC programs.  We
  564.      will examine these features individually.
  565.      
  566.           As  a screen generator, I feel that P-Screen has one major  flaw.
  567.      It  lacks  mouse  support. Personally, I like mice and  I  don't  like
  568.      having to navigate the screen with the cursor keys. When you start  up
  569.      P-Screen Professional, you get a nice title screen that tells you your
  570.      options  and waits for you to press a key. After you press a key,  you
  571.      are  left with a blank screen and a "What do I do now?" look  on  your
  572.      face. Pressing F1 for help shows you 2 screens of commands but that is
  573.      all. To learn how to use P-Screen, you will need a copy of the printed
  574.      documentation next to you.
  575.      
  576.           After  you  start using the commands and learn what they  do,  P-
  577.      Screen  is a pleasure to use. It allows you to draw your  screens  and
  578.      store  them  in  either ASCII or a compressed  format.  P-Screen  also
  579.      allows  you to load screens saved in QB's BSAVE format but  won't  let
  580.      you  save them that way. If P-Screen had mouse support and  better  on
  581.      line  help,  it would be one of the best screen  designers  available.
  582.      Without it though, it still is very good.
  583.      
  584.           Next  comes  the  screen storage and  display  utility.  P-Screen
  585.      stores  screens on disk in a compressed screen format. The savings  in
  586.      size  is  very noticeable the more screens you have in a  library.  P-
  587.      Screen  then has two routines that load the screens into an array  and
  588.      display  them. They are written in Assembler and are very fast.  These
  589.      routines  allow  you to display full or partial screens  anywhere  you
  590.      
  591.      The QBNews                                                     Page  8
  592.      Volume  1, Number  3                                      May 22, 1990
  593.  
  594.      want. I couldn't find anything to complain about. They are nicely done
  595.      and will add a professional look to your programs.
  596.      
  597.           Now  to  what  I  think  is  the  best  part  of  P-Screen.   The
  598.      Professional   version   comes  with  a   form   generator.   P-Screen
  599.      Professional  comes with the ability to create forms and it  generates
  600.      code that handles user input on these forms. See the program Index.Bas
  601.      for an example of the code P-Screen Professional generated for a small
  602.      index card screen I created. The user input routine is nicely done  in
  603.      Assembler and includes a variety of formatting options and masks. Some
  604.      of these include Date, Phone Number, Zip Code, Social Sec. Number, and
  605.      Currency.  With these options, your program makes sure that  the  user
  606.      types in only valid keys and in the format you want. The code that  P-
  607.      Screen Professional generates is then inserted into your program. This
  608.      allows  you to create professional looking documents with very  little
  609.      effort.  I  am  very impressed with  these  capabilities  in  P-Screen
  610.      Professional.
  611.      
  612.           Two  shareware programs you should be aware of are  P-Screen  and
  613.      P~F  Presents.  P-Screen  is the screen drawing  and  library  utility
  614.      portion of P-Screen Professional. Gone are the code generator and form
  615.      utilities and the ability to display partial screens. My advice to you
  616.      is  to get the shareware version and try out the screen generator.  If
  617.      you  like using it to create your screens, then you  should  certainly
  618.      buy the professional version. You won't be disappointed.
  619.      
  620.           P~F  Presents is a screen presentation system. It lets  you  take
  621.      screens created with P-Screen and create slide shows out of them. This
  622.      is great for presentations or prototyping applications before you  get
  623.      down  to  writing  code.  With it, you  can  create  your  whole  user
  624.      interface  and let the users give you there comments on it BEFORE  you
  625.      write  any code. This saves a lot of headaches from having to  rewrite
  626.      your  programs when your views on how the program should  operate  are
  627.      different from the intended users.
  628.      
  629.           P-Screen Professional is available from:
  630.      
  631.                Pro~Formance
  632.                132 Alpine Terrace
  633.                San Francisco, CA 94117
  634.                (415) 863-0530
  635.      
  636.           The  cost  is  $49 plus $3 shipping and handling.  You  also  can
  637.      download the shareware version of P-Screen and P~F Presents from Peter
  638.      Tiffany's  BBS,  (415)  458-6404 or on CompuServe in  the  IBMPro  and
  639.      IBMApp areas. The filenames are PSCRN35.ZIP and PFPRES35.ZIP.
  640.      
  641.  
  642.  
  643.  
  644.  
  645.  
  646.  
  647.  
  648.  
  649.      The QBNews                                                     Page  9
  650.      Volume  1, Number  3                                      May 22, 1990
  651.  
  652.      Index Manager - B-Tree indexing for QB by David Cleary
  653.      
  654.           Databases  are  an  important  part  of  computers  and  computer
  655.      programming. QuickBASIC has built in capabilities that make it easy to
  656.      write a simple database. The problem is, as your database gets  larger
  657.      and larger, it takes longer to find the information you need. That  is
  658.      where Index Manager helps out.
  659.      
  660.           Index  Manager  allows  you to build single  user  ISAM  (Indexed
  661.      Sequential  Access Method) databases using a B+ Tree index. A B+  Tree
  662.      is  a  data  structure that allows you  to  find  information  quickly
  663.      without  searching something from start to finish. All  Index  Manager
  664.      does is handle the index of your database allowing you to handle  your
  665.      datafile as you please. All you do is to associate a unique "Key" with
  666.      each record and Index Manager does the rest. This key could be a  name
  667.      or  customer  number or what have you. The only thing you have  to  be
  668.      sure of is that each record in your database has it's own unique key.
  669.      
  670.           The specifics of Index Manager are as follows:
  671.      
  672.      1.   Create an indexed-access file using the key of your choice.
  673.      
  674.      2.   Read  any record on you indexed-access files by  specifying  it's
  675.      key.
  676.      
  677.      3.   Browse  through your indexed-access file by specifying a  partial
  678.      key.
  679.      
  680.      4.   Read  your indexed-access file sequentially sorted by key  either
  681.      forward or backward.
  682.      
  683.      5.   Work with up to ten indexed-access files at the same time.
  684.      
  685.           All  of Index Manager's functions are incorporated into one  call
  686.      making  it very easy to use. It is also written in  assembly  language
  687.      making  it extremely fast and small. It only adds 5k of code  size  to
  688.      your QB programs. It utilizes a large cache buffer to cut down on disk
  689.      accesses  when searching for a key. This makes it very fast  but  also
  690.      introduces one of it's drawbacks. It uses 24k of string space for it's
  691.      buffers. This makes string space kind of tight on large  applications.
  692.      I  would  like to see some sort of variable buffer allocation  so  you
  693.      could reclaim the string space while sacrificing some speed.
  694.      
  695.           Although  Index  Manager  is  very easy to  use  and  comes  with
  696.      examples  showing  how  to use every function, it  doesn't  teach  you
  697.      database  principles.  If  you  know nothing of how  to  set  up  good
  698.      databases, you could find yourself making errors that could cause your
  699.      program  to not be as useful as it can. The example programs show  you
  700.      how  the  functions work but they are not real world  applications.  I
  701.      would  like  to  see  some  examples of  things  like  a  small  phone
  702.      directory,  ect.  that will help someone not  familiar  with  database
  703.      programming go in the right direction.
  704.      
  705.           Aside from the string space problem and the lack of good database
  706.      examples,  I  love this program. I received my copy of  Index  Manager
  707.      
  708.      The QBNews                                                     Page 10
  709.      Volume  1, Number  3                                      May 22, 1990
  710.  
  711.      free  for the purpose of doing this review. At the time, I  had  never
  712.      written  a database program before. As luck would have it, a  database
  713.      programming application had just come up where I work. I decided  that
  714.      I would give Index Manager a try in helping me with this project.  The
  715.      project  turned  out so well that my company decided to pay  for  this
  716.      copy.
  717.      
  718.           Index  Manager  is  for those people who just want  to  add  fast
  719.      indexing  to their QB programs. It is an alternative to going out  and
  720.      spending more money on products like DB-Lib or B-Trieve when you don't
  721.      need  all the functions of these products. Index Manager is also  alot
  722.      easier  to  use  than those products and allows  you  to  handle  your
  723.      datafiles anyway you choose.
  724.      
  725.           Index  Manager costs $59 and is compatible with QB 2 to  4.5  and
  726.      Bascom  6. A Basic 7 PDS version that supports far strings is  in  the
  727.      works. You can get Index Manager by contacting:
  728.      
  729.                     CDP Consultants
  730.                     1700 Circo del Cielo Drive
  731.                     El Cajon, CA 90202
  732.      
  733.                     619-440-6482
  734.      
  735.  
  736.  
  737.  
  738.  
  739.  
  740.  
  741.  
  742.  
  743.  
  744.  
  745.  
  746.  
  747.  
  748.  
  749.  
  750.  
  751.  
  752.  
  753.  
  754.  
  755.  
  756.  
  757.  
  758.  
  759.  
  760.  
  761.  
  762.  
  763.  
  764.  
  765.  
  766.      The QBNews                                                     Page 11
  767.      Volume  1, Number  3                                      May 22, 1990
  768.  
  769.  
  770.  
  771.      ----------------------------------------------------------------------
  772.                     P r o d u c t   A n n o u n c e m e n t s
  773.      ----------------------------------------------------------------------
  774.  
  775.      P-Screen, P-Screen Professional, P~F Presents
  776.      
  777.      Rob W. Smetana      (415) 863 - 0530
  778.      Pro~Formance        132 Alpine Terrace  San Francisco Ca  94117
  779.      
  780.      Program Name            Cost     Summary
  781.      ---------------------   ----     -----------------------------------
  782.      P-Screen "Plus"         $ 29     Screen Design, Display, Library
  783.                                       system for QuickBASIC 3.0 - 4.x.
  784.      
  785.      P-Screen "Professional" $ 49     PS Pro writes programs for you! and
  786.                                       includes other CALLable routines.
  787.      
  788.      P~F Presents         $ 49/$ 79   Presentation system to display
  789.                                       P-Screen's "text" screens -or-
  790.                                       BSAVEd "graphics."  See below for
  791.                                       many "uses" for presentations.
  792.      
  793.      P-Screen "Pro"  AND              Enhanced versions of BOTH.
  794.      P~F Presents ($79 ver.) $110
  795.      
  796.      NOTE:   P-Screen and P~F Presents are "shareware."  Registered
  797.              versions cost 1/2 to 2/3 LESS than commercial examples.
  798.              Yet they're finely tuned, professional quality programs
  799.              that'll save you enormous amounts of time, and give your
  800.              programs a professional appearance -- f-a-s-t, easily.
  801.      
  802.      P-Screen and P-Screen Professional are among the most sophisti-
  803.      cated "screen management systems" available.  They were written
  804.      BY Quick- BASIC programmers FOR QuickBASIC programmers (we
  805.      support QB 3.0-4.x).  P-Screen "+" and P-Screen Pro share most
  806.      features.  These are described immediately below.  Later we'll
  807.      explain features that PS Pro adds.
  808.      
  809.      DESIGNING help screens, menus, data entry screens, etc. is a snap.
  810.       * Use a mouse or fast keyboard "hot keys" (eg., alt-B = Box).
  811.       * Choose options using hot keys or pull down menus.
  812.       * Many design options:  Boxes, lines, "auto-joining" of lines
  813.         and boxes, text, Big! Font text (tm), clipboard, paint,
  814.         center, copy, move, erase, WalkAbout, re-color, repeat, add
  815.         any Ascii character, view in Monochrome, UnDo, and much more.
  816.      
  817.      LOAD screens for editing from Screen Libraries, ASCII or BSAVE files.
  818.       * A RAM-resident program is included letting you: 1) "Capture"
  819.         screens from other applications (to later load and edit); and
  820.         2) Save ANY text screen in BSAVE format when you need them.
  821.      
  822.      SAVE screens to Screen Libraries, ASCII or "Com" files.
  823.       * Screens saved to libraries or Com files are COMPRESSED,
  824.         saving disk space and RAM.  Libraries store 1-100 screens;
  825.         libraries "index" screens, letting us display or edit them fast.
  826.      
  827.      The QBNews                                                     Page 12
  828.      Volume  1, Number  3                                      May 22, 1990
  829.  
  830.       * Com screens are "executable!"  Run them from batch files or DOS
  831.         for instant screens -- complete with color, lines, shading, etc.
  832.      
  833.      DISPLAY screens from your programs fast and easily -- just CALL
  834.      two routines we include.
  835.      
  836.      OTHER FEATURES
  837.       * Blazing speed!  Assembler language routines plus "indexed"
  838.         screen libraries mean your programs display screens f-a-s-t!
  839.         10-20 screens per second is typical.  We've seen 75 per second!
  840.         - We've eliminated the disadvantages of storing screens on disk.
  841.         - Screen libraries let you keep "screen text" OUT of your
  842.           programs, preserving string space and memory.  And you can
  843.           edit screens WITHOUT changing your programs.
  844.         - And there are NO RAM-resident screen loaders to worry about!
  845.      
  846.       * Big! Font (tm) lets you easily add large-character messages.
  847.         We include several Big! Fonts.  You can create your own Big!
  848.         Fonts, or customize them "on the fly."
  849.      
  850.       * Supports 25, 43 or 50 line screen modes.
  851.      
  852.      =================================================================
  853.                        P-Screen Professional   ($ 49)
  854.      =================================================================
  855.      
  856.      P-Screen Professional (PS Pro) has all the features of P-Screen
  857.      described above, but also saves you enormous amounts of time by:
  858.      
  859.       * Writing your QuickBASIC 4.x programs for you!
  860.      
  861.       * Including several other subprograms you can use in ANY Quick-
  862.         BASIC 4.x program you write (most also work with QB 3.0).
  863.      
  864.      In short, you focus on what your programs "look like."  Once
  865.      you have your screen designed, PS Pro can write your BASIC code.
  866.      Just add any routines you need for printing or database manage-
  867.      ment.  Then compile your programs and away you go.
  868.      
  869.      
  870.      PS Pro writes your data entry programs for you!  Just "mark" a
  871.      "field" on your screen and tell PS Pro what "type" of field it is.
  872.       * You can create fields with are "editable," and fields which
  873.         are "calculated."  For calculated fields, enter ANY Quick-
  874.         BASIC formula, and PS Pro will handle the calculations for
  875.         you and print their results.
  876.      
  877.       * And you can link "help screens" to each field if you like.
  878.      
  879.       * Once you've "formatted" each field on your screen just press
  880.         a key.  PS Pro writes your program in about 2-3 seconds!
  881.      
  882.      
  883.       PS Pro lets you choose from among 13 field types.
  884.        * Choose a field type and PS Pro formats editing, printing,
  885.      
  886.      The QBNews                                                     Page 13
  887.      Volume  1, Number  3                                      May 22, 1990
  888.  
  889.          and displaying the results of "calculated fields" for you.
  890.      
  891.        * Choose field types from among:  string, upper case, proper
  892.          name, date, phone number, Zip Code, Social Security number,
  893.          numeric string, integer, long integer, single precision,
  894.          currency and double precision.
  895.      
  896.       PS Pro comes with several subroutines you can use in any program.
  897.       These include:  rsMinput, OneKey, Mask/StripMask, FormatUsing,
  898.       ProperName, rsQprint, Exists, and StripTail.  Use them to:
  899.        * Handle ALL user input (text, extended keys, printer codes).
  900.          Get a single key, or a full line of text.  rsMinput offers
  901.          the full array of editing features, includes UnDo, AND
  902.          offers "masked" input for easy, accurate editing of fields
  903.          like Phone Numbers [(...) ...-....] or Zip Codes  [.....-....].
  904.      
  905.        * Format text and numbers for easy editing or printing
  906.      
  907.        * Print with assembler speed
  908.      
  909.        * Convert all lower case text to "proper name" format
  910.      
  911.        * Determine if files exist (before you try to open them)
  912.      
  913.      =================================================================
  914.                    Product Announcement:     P~F PRESENTS
  915.      =================================================================
  916.      
  917.      P~F Presents (PFP) is our desktop presentation system.  It dis-
  918.      plays screens from P-Screen's screen libraries.  It also displays
  919.      BSAVED "graphics" screens.  Text, graphics or both; it's your call.
  920.      
  921.      Presentations (or slide shows) can include, among other things:
  922.       * Full- or Sub- screen displays.
  923.       * Menus, in 3 different styles.
  924.       * Display and sound effects.
  925.       * Special options including:  "If x Goto," "Gosub", "Loop,"
  926.         "Pause," "MakeMono" (to display colored screens on
  927.          monochrome monitors).
  928.       * Timed slides (which pause as long as you want between slides),
  929.         -or- slides which wait for the viewer to press a key.
  930.      
  931.      And you can create self-running presentations, or run 'em yourself.
  932.      
  933.      Why would a programmer be interested in a presentation system?
  934.      For many of the same reasons programmers like Dan Bricklin's DEMO
  935.      program (at about 1/4 the cost)!  Plus, P~F Presents offers
  936.      many other opportunities as well.  Consider these:
  937.      
  938.      PROGRAM PROTOTYPES
  939.       * You can create "working prototypes" of programs in minutes or
  940.         just a few hours.
  941.       * Since presentations can include menus (3 types), display effects,
  942.         sound effects, etc. your prototypes can have the "look and feel"
  943.         of your actual program.
  944.      
  945.      The QBNews                                                     Page 14
  946.      Volume  1, Number  3                                      May 22, 1990
  947.  
  948.       * Letting your clients, customers or potential users see how your
  949.         program will look and feel (BEFORE you've written a line of code):
  950.         1) Helps you "beta test" your ideas; 2) Helps eliminate time-
  951.         consuming re-writes; and, 3) Speeds up program development.
  952.       * And creating "mock ups" helps you think through a program's
  953.         logic before you write any code.
  954.      
  955.      PROGRAM:  DEMOS, MARKETING TOOLS, TUTORIALS
  956.       * You can easily and quickly create demos, marketing tools or
  957.         program tutorials -- using many of the SAME SCREENS your
  958.         programs will display.
  959.      
  960.      As an example, we recently used PFP to create, in 2 hours, a
  961.      working prototype of a new program.  We had it back to a
  962.      prospective client the day after we first talked to him.  It
  963.      had the complete "look & feel" of the program he wanted.  And
  964.      creating it helped us think through our program design.
  965.      
  966.  
  967.  
  968.  
  969.  
  970.  
  971.  
  972.  
  973.  
  974.  
  975.  
  976.  
  977.  
  978.  
  979.  
  980.  
  981.  
  982.  
  983.  
  984.  
  985.  
  986.  
  987.  
  988.  
  989.  
  990.  
  991.  
  992.  
  993.  
  994.  
  995.  
  996.  
  997.  
  998.  
  999.  
  1000.  
  1001.  
  1002.  
  1003.      The QBNews                                                     Page 15
  1004.      Volume  1, Number  3                                      May 22, 1990
  1005.  
  1006.  
  1007.  
  1008.      ----------------------------------------------------------------------
  1009.                            U n d e r   T h e   H o o d
  1010.      ----------------------------------------------------------------------
  1011.  
  1012.      Fast File I/O in QuickBASIC by Ethan Winer
  1013.      
  1014.      [EDITOR'S NOTE] This article first appeared in the March 1990 issue of
  1015.      Programmer's   Journal.  Back  issues  can  be  ordered   by   calling
  1016.      1-800-234-0386.
  1017.      
  1018.           Without  doubt,  one  of the slowest  operations  a  program  can
  1019.      perform is saving and loading disk data files.  In many cases, this is
  1020.      dictated by the physical access delay of the disk device, and the time
  1021.      required to transfer data based on its rotation speed.  One exception,
  1022.      however,  is  when  many reads or writes must be  performed  on  small
  1023.      pieces  of data.  For example, it is quite common to save or  load  an
  1024.      entire numeric array.  In the case of an integer array that  contains,
  1025.      say, ten thousand elements, that many individual calls to the DOS file
  1026.      I/O  services will be needed.  Even though DOS is written in  assembly
  1027.      language, it still takes a fair amount of time to process each read or
  1028.      write request.
  1029.      
  1030.           One obvious solution is to process the file operation as a single
  1031.      large  read  or  write.   Indeed, I  have  written  assembly  language
  1032.      routines  to do just that for use in company's  QuickPak  Professional
  1033.      add-on library product.  But it is also possible to call  QuickBASIC's
  1034.      internal  PUT and GET routines directly.  By bypassing the  QuickBASIC
  1035.      compiler and its syntax checking, you can coerce it to read and  write
  1036.      up  to  64K  of  data in a single  operation.   Larger  files  can  be
  1037.      accommodated  by  processing  the file in pieces.   The  trick  is  to
  1038.      determine  the  names of these routines, and the number  and  type  of
  1039.      parameters they expect to receive.
  1040.      
  1041.           QuickBASIC versions 4.0 and later contain four different internal
  1042.      routines for reading and writing binary data.  Two of these are  meant
  1043.      for  reading  data from a file, with one using the  current  DOS  SEEK
  1044.      location  and  the  other  accepting a  long  integer  SEEK  argument.
  1045.      Similarly, there are two separate routines for writing data to disk.
  1046.      
  1047.           Most of QuickBASIC's internal routines begin with the  characters
  1048.      "B$", which are illegal in a subroutine name.  Fortunately, the  ALIAS
  1049.      keyword allows you to declare a procedure with two different names  --
  1050.      the name you will use when calling it from the program, and the actual
  1051.      name  that is made public for the linker.  When  Microsoft  introduced
  1052.      inter-language  calling  capabilities in QuickBASIC version  4.00,  it
  1053.      needed a way to allow access to routines written in C.  These routines
  1054.      always start with an underscore character, which is also illegal as  a
  1055.      QuickBASIC procedure name.
  1056.      
  1057.           The example program shown in Figure 1 declares the four  internal
  1058.      routines  as follows:  BigSave writes data using the current DOS  file
  1059.      pointer  position,  and BigSaveS expects a SEEK  argument.   Likewise,
  1060.      BigLoad reads from the current file position, and BigLoadS requires an
  1061.      offset to SEEK to before reading.  All four of these routines  require
  1062.      the  parameters  to be passed "by value", as opposed to  "by  address"
  1063.      
  1064.      The QBNews                                                     Page 16
  1065.      Volume  1, Number  3                                      May 22, 1990
  1066.  
  1067.      which  is BASIC's usual method of passing parameters. This results  in
  1068.      code  that  is  both faster and smaller, because  an  extra  level  of
  1069.      indirection  is avoided.  That is, the routines can obtain the  values
  1070.      directly  from  the stack, rather than having to  first  determine  an
  1071.      address,  and  then  go to that address for the  actual  value.   Even
  1072.      though BYVAL and SEG *look* like they would result in additional  code
  1073.      being  added  to  a program, they are really just  directives  to  the
  1074.      compiler.
  1075.      
  1076.           Before  any  of these routines may be called, you must  open  the
  1077.      file  to  be read or written for BINARY operation.   Then,  the  first
  1078.      parameter that each routine expects is the BASIC file number that  was
  1079.      used  to  open  the file.  The address parameter is passed  as  a  SEG
  1080.      value,  which  means  that both a segment  and  offset  are  required.
  1081.      Notice that a file may be loaded to or saved from any area of  memory,
  1082.      by replacing [SEG Address] with [BYVAL Segment, BYVAL Address].   When
  1083.      SEG is used as part of a CALL statement, the "value" of the variable's
  1084.      segment is pushed on the stack, followed by the value of its  address.
  1085.      Substituting  two  separate arguments "by value" is  functionally  the
  1086.      same thing as far as the routines are concerned.  Also notice that the
  1087.      internal routine names are not available within the QuickBASIC editing
  1088.      environment.  Therefore, this example program must be compiled to disk
  1089.      before it may be tested.
  1090.      
  1091.           In  my own informal tests, I have found this technique to  be  as
  1092.      much  as  ten times faster than reading or  writing  individual  array
  1093.      elements  using  a BASIC FOR/NEXT loop.  The actual  savings  will  of
  1094.      course  depend  on the number of elements being  processed  and  their
  1095.      length  in  bytes.   Unfortunately, this method cannot  be  used  with
  1096.      QuickBASIC  string  arrays, because they are not kept  in  consecutive
  1097.      memory  locations.   However, numeric arrays may be  accommodated,  as
  1098.      well as any fixed-length or user-defined TYPE array.
  1099.      
  1100.           It  is  important to understand that when manipulating  a  fixed-
  1101.      length  string array, the SEG operator must not be used.   Whenever  a
  1102.      fixed-length  string  or array element is used as an  argument  to  an
  1103.      external  routine, QuickBASIC first makes a copy of it into a  regular
  1104.      string  variable.   Then, the address of the copy is  passed  instead.
  1105.      Since  the address of a copy of an array element has no  relevance  to
  1106.      the address of the actual array, we must use a different approach.  In
  1107.      fact, there are two possible solutions.
  1108.      
  1109.           One is to create a TYPE definition that is comprised solely of  a
  1110.      fixed-length  string  portion.  Although the example below  assumes  a
  1111.      string  length of twenty characters, you would of course use  whatever
  1112.      is appropriate for your program.
  1113.      
  1114.      TYPE FLen
  1115.           S AS STRING * 20
  1116.      END TYPE
  1117.      
  1118.      DIM Array(1 TO 10000) AS FLen
  1119.      
  1120.           The  second solution is to use a combination of BYVAL VARSEG  and
  1121.      BYVAL  VARPTR, to pass the segment and address of the  starting  array
  1122.      
  1123.      The QBNews                                                     Page 17
  1124.      Volume  1, Number  3                                      May 22, 1990
  1125.  
  1126.      element directly.  When QuickBASIC sees VARSEG or VARPTR, it  realizes
  1127.      that  you  do  in  fact want the actual segment  and  address  of  the
  1128.      specified  array  element.  Thus, you would use the  following  syntax
  1129.      when calling BigSave to save a fixed-length string array:
  1130.      
  1131.      CALL BigSave(FileNumber, BYVAL VARSEG(Array(First)), BYVAL _
  1132.           VARPTR(Array(First)), NumBytes)
  1133.      
  1134.           One final note concerns saving or loading more than 32767  bytes.
  1135.      QuickBASIC does not support unsigned integers, so you must instead use
  1136.      an  equivalent  negative value.  This is quite easy to  determine,  by
  1137.      simply  subtracting 65536 from the required number of bytes.  It is  a
  1138.      common trick to avoid negative numbers when calling assembly  language
  1139.      routines  by instead substituting a long integer number  or  variable.
  1140.      However, that will not work in this case, because two extra bytes will
  1141.      be  pushed  onto  the stack by the use of  BYVAL.   Therefore,  it  is
  1142.      essential that you specify the correct type of parameters when calling
  1143.      these routines.
  1144.      
  1145.      **********************************************************************
  1146.           Ethan Winer is the president of Crescent Software, and the author
  1147.      of  QuickPak  Professional  and P.D.Q. He can be  reached  by  calling
  1148.      Cresent Software at (203) 846-2500.
  1149.      **********************************************************************
  1150.      
  1151.      [EDITOR'S  NOTE]  Source  code  for  this  article  is  contained   in
  1152.      FASTFILE.ZIP.
  1153.      
  1154.  
  1155.  
  1156.  
  1157.  
  1158.  
  1159.  
  1160.  
  1161.  
  1162.  
  1163.  
  1164.  
  1165.  
  1166.  
  1167.  
  1168.  
  1169.  
  1170.  
  1171.  
  1172.  
  1173.  
  1174.  
  1175.  
  1176.  
  1177.  
  1178.  
  1179.  
  1180.  
  1181.      The QBNews                                                     Page 18
  1182.      Volume  1, Number  3                                      May 22, 1990
  1183.  
  1184.  
  1185.  
  1186.      ----------------------------------------------------------------------
  1187.                         P o w e r   P r o g r a m m i n g
  1188.      ----------------------------------------------------------------------
  1189.  
  1190.      How to Make a Self-Cloning Exe in QuickBASIC by Larry Stone
  1191.      
  1192.      [EDITOR'S NOTE]
  1193.           All  extended  ASCII  codes have  been replaced  in the following
  1194.      article.
  1195.      
  1196.           Have  you  ever  had the need to create a program  that  holds  a
  1197.      password  away  from  prying  eyes of  others?   Or,  maybe  you  have
  1198.      discovered that writing shareware rewards your ego by making your name
  1199.      familiar to the PC world, but doesn't reward your pocket-book  because
  1200.      most  people will register their programs when they get around to  it,
  1201.      which,  often-times,  is never.  Or, maybe you just wish  to  write  a
  1202.      program  that  holds  it's configuration without having  to  create  a
  1203.      configuration file.
  1204.      
  1205.           One  of the easiest methods to accomplish the above listed  tasks
  1206.      is  to  create an EXE file that "clones" information to  itself.   The
  1207.      trick is to create a "recognizable" area inside of the EXE itself that
  1208.      can be quickly read and modified.
  1209.      
  1210.           What  makes  this such an easy trick?  Well, have you  ever  used
  1211.      Vernon  D.  Buerg's LIST utility to list your EXE's?  If you  do,  you
  1212.      will notice that towards the end of the program, every string that you
  1213.      have  defined  within your program is CLEARLY VISIBLE!  What  you  are
  1214.      viewing is the EXE's token definition area.  When you compile and link
  1215.      your programs, a token is defined for every string used.  For example,
  1216.      your  program might have the code, Strike$ = "Strike any  key".   When
  1217.      you  list the EXE, it may show something like, 0TStrike any key.   The
  1218.      symbols 0T would be the programs marker to the definition, "Strike any
  1219.      key".  Under no circumstance do you want to change this marker because
  1220.      really  weird results could ensue.  However, you can create  a  string
  1221.      that contains a marker that is exclusive to your use, i.e.,
  1222.      
  1223.      Special$ = "<*!@#%>This is my special string"
  1224.      
  1225.           In the above example, <*!@#%> then becomes your special marker to
  1226.      the  data that immediately follows.  Then, all your program has to  do
  1227.      is  to look for your special marker and modify the next 25  characters
  1228.      as needed!
  1229.      
  1230.           CAUTION!   Never,  never, never try to reserve a  data  area  for
  1231.      cloning by defining a string as:
  1232.      
  1233.      Special$ = "<*!@#%>" + SPACE$(25)
  1234.      Special$ = "<*!@#%>                         "
  1235.      
  1236.           Both  of  the above examples will *NOT* create the  25  character
  1237.      data  area  desired because BC will optimize the SPACE$(25) as  a  two
  1238.      byte token!
  1239.      
  1240.           Let's assume that we need to build a program that needs to hold a
  1241.      
  1242.      The QBNews                                                     Page 19
  1243.      Volume  1, Number  3                                      May 22, 1990
  1244.  
  1245.      user-defined,  sixteen character password and a token that  determines
  1246.      whether the EXE is shareware (limited in scope) or registered.   Let's
  1247.      further  say that when a registration is received by you, the  author,
  1248.      you  then mail that person a key which redefines the definition  of  a
  1249.      token so that features not available to the shareware user now  become
  1250.      available.   Let's  further state that your program is going  to  hold
  1251.      configuration information within a 13 byte string.
  1252.      
  1253.           The first thing to do is to create a unique string inside of  the
  1254.      program  itself, as well as, two or three variables shared within  the
  1255.      program.  At the top of the program, do something like the following:
  1256.      
  1257.      DIM SHARED StoredData$, BytesToData&
  1258.      
  1259.           Now,  if your program does not "clone" configuration  information
  1260.      or  passwords, then BytesToData& does not need to be SHARED.   Rather,
  1261.      in this case, only the information itself (Shareware/registration key)
  1262.      needs to be shared.  However, for this discussion, we're going for the
  1263.      entire pie.
  1264.      
  1265.           Next, someplace within your initialization subprogram (or in your
  1266.      main module), you should place code such as the following:
  1267.      
  1268.      SpotForKey$ = "<%*@#!>123456789012345678901234567890"
  1269.      
  1270.           Now,  because  your program needs to read itself,  modify  itself
  1271.      and,  at  the  same time, hold part of the  original  string  as  your
  1272.      special marker, we need to do the following:
  1273.      
  1274.      tempKey$ = LEFT$(SpotForKey$, 6)
  1275.      
  1276.           In  this way, no matter what we do to the following 30  character
  1277.      spaces, <%*@#!> will always remain our special marker that the program
  1278.      looks for.
  1279.      
  1280.      Let's build the routine that reads in this data.
  1281.      
  1282.      '--------------------- Get Special Data Routine ---------------------
  1283.      
  1284.      DIM SHARED StoredData$, BytesToData&
  1285.      
  1286.      SpotForKey$ = "<%*@#!>123456789012345678901234567890"
  1287.      
  1288.      tempKey$ = LEFT$(SpotForKey$, 6)       'Our special marker.
  1289.      
  1290.      'The Bytes% variable is the number of bytes to read.If your program is
  1291.      'less than 16000 bytes then this routine adjusts accordingly. Also, if
  1292.      'a 16K byte "GET" cuts the marker field in two then you need to change
  1293.      'it to another value, such as 15550.
  1294.      
  1295.      Bytes%  =  16000
  1296.      BytesToData& = 0
  1297.      portion& = 1
  1298.      countToKey% = 0
  1299.      StoredDataLen% = 30
  1300.      
  1301.      The QBNews                                                     Page 20
  1302.      Volume  1, Number  3                                      May 22, 1990
  1303.  
  1304.      
  1305.      OPEN MyProg$ FOR BINARY AS #1 FiSize& = LOF(1)
  1306.      'Get the size of the file
  1307.      DO WHILE NOT EOF(1)
  1308.           IF Bytes% > FiSize& THEN Bytes% = FiSize&
  1309.           IF Bytes% + portion& > FiSize& THEN Bytes% = FiSize& - portion&
  1310.           A$ = INPUT$(Bytes%, 1)         'Read Bytes% number of characters.
  1311.           countToKey% = INSTR(A$, tempKey$)  'Look for our special marker.
  1312.           IF countToKey% THEN              'If we found it then process it.
  1313.             BytesToData& = portion& + countToKey% + 5 'Get past our marker.
  1314.             SEEK #1, BytesToData&              'Get the data from the file.
  1315.             StoredData$ = INPUT$(StoredDataLen%, 1)
  1316.             EXIT DO                     'We found it so out of the DO LOOP
  1317.           END IF
  1318.      
  1319.           portion& = Bytes% + portion&   'Determine where the next SEEK is.
  1320.      
  1321.      'If we're within 800 bytes of the end of the EXE then we are past  the
  1322.      'token definition area of the QB program.  In this case, we're done.
  1323.      
  1324.           IF portion& >= FiSize& - 800 THEN EXIT DO
  1325.      
  1326.      'Move pointer to the next 16000 byte block to read from the file.
  1327.      
  1328.           SEEK #1, portion&
  1329.      
  1330.      LOOP
  1331.      CLOSE #1
  1332.      
  1333.      '--------------------- End Special Data Routine ---------------------
  1334.      
  1335.           Now,  whenever  our  program  needs to look  for  a  password,  a
  1336.      registration  key  value, or it's configuration information,  it  need
  1337.      only do the following:
  1338.      
  1339.      Password$ = LEFT$(StoredData$, 16)
  1340.      RegisValue = VAL(MID$(StoredData$, 17, 1))
  1341.      
  1342.      IF   RegisValue  =  7  THEN
  1343.           PRINT "Shareware Edition"
  1344.      ELSE
  1345.           PRINT "Registered Edition"
  1346.      END IF
  1347.      
  1348.      ConfigData$ = MID$(StoredData$, 18)
  1349.      
  1350.           To  prove  this works, snip out the special routine and  add  the
  1351.      following  statement at the end of the routine:     PRINT  StoredData$
  1352.      Next, compile and link it, then run it.  You will see the above string
  1353.      printed (you will also notice just how fast QB's INSTR function really
  1354.      is! - It's blazingly fast! - Couple this with BINARY access and you'll
  1355.      discover that load time is not appreciably degredated).  Don't  forget
  1356.      to define MyProg$ as something or you'll get a nasty error message!
  1357.      
  1358.           Okay,  okay,  so how do we write new information to  our  special
  1359.      
  1360.      The QBNews                                                     Page 21
  1361.      Volume  1, Number  3                                      May 22, 1990
  1362.  
  1363.      data area? Simple - just do the following:
  1364.      
  1365.      Password$ = "Lawrence Stone  "
  1366.      RegisValue$ = "0"
  1367.      ConfigData$ = "Config Area 1"
  1368.      
  1369.      OPEN  MyProg$  FOR  BINARY  AS  #1
  1370.      PUT #1, BytesToData&, Password$        'To write the new password.
  1371.      RegisValue$ = "0"
  1372.      PUT #1, BytesToData& + 16, RegisValue$'To create a registered version.
  1373.      PUT #1, BytesToData& + 17, ConfigData$ 'To clone configuration data.
  1374.      CLOSE #1
  1375.      
  1376.           Now, re-run your compiled program and have these values print  to
  1377.      the monitor.  Notice how easy it was to change the data?
  1378.      
  1379.           If  you are going to have an external "key" program  that  "turns
  1380.      on"  the registered version then it needs to simply read in  the  data
  1381.      using  the same special marker that we created as a marker  to  search
  1382.      for.  Also, you might wish to make another small program that converts
  1383.      your  pre-  defined  password  and  configuration  space  to   spaces.
  1384.      Otherwise,  you need to run your program before you distribute  it  so
  1385.      that   you   can   change   the   password   (which   is   equal    to
  1386.      "1234567890123456")  to  something like SPACE$(16).  In  other  words,
  1387.      nullify  the  temporary string used by our program that forced  BC  to
  1388.      give us the data space we needed in the first place.
  1389.      
  1390.           Now, for demonstration purposes, we have used the default "7" for
  1391.      indicating  that the program is shareware and "0" for  registered.   I
  1392.      would recommend that you reserve at least 8 character spaces for  this
  1393.      field because then you can create unique codes for every key and every
  1394.      user.   In this way, your program can look for the key in both  itself
  1395.      and  within the key program as well.  This would also offer  one  more
  1396.      level of safeguards for you.
  1397.      
  1398.           One  final  word:  Any casual hacker can use LIST  to  find  your
  1399.      password if you leave it in it's native ASCII.  You should consider  a
  1400.      routine  that  converts the appearance of your data so that  it  looks
  1401.      like the rest of the binary code.  Routines can be as simple as taking
  1402.      each character in the strings and adding 100 to their ASCII value  for
  1403.      writing, then, subtracting 100 from their ASCII value for reading,  to
  1404.      some  truely cryptive procedure, depending on how sensitive  you  want
  1405.      the information contained therein to remain.
  1406.      
  1407.      **********************************************************************
  1408.           Larry  Stone is President of LSRGroup and is involved in  writing
  1409.      software  for  marine  and  aquatic research. He  can  be  reached  at
  1410.      LSRGroup,  P.O.  Box 5715, Charleston, OR 97420, or in  care  of  this
  1411.      newsletter.
  1412.      **********************************************************************
  1413.      
  1414.      [EDITOR'S  NOTE]  The  file CLONE.BAS  contains  a  slightly  modified
  1415.      version of Larry's code above. I have modified it to make it easier to
  1416.      add to your program. It is contained in CLONE.ZIP.
  1417.      
  1418.      The QBNews                                                     Page 22
  1419.      Volume  1, Number  3                                      May 22, 1990
  1420.  
  1421.      In Search of the Elusive UEVENT by Jim Mack
  1422.      
  1423.           QB allows you to trap a number of different "events", such as the
  1424.      TIMER  tick,  the arrival of a byte in a COM buffer, the  press  of  a
  1425.      specific  KEY,  and  so on.  It does so by  adding  extra  code  after
  1426.      each statement (/V) or each line (/W) which checks the state of  flags
  1427.      associated  with  enabled  events.   Special handlers  deal  with  the
  1428.      actual interrupt and set these internal flags as appropriate.
  1429.      
  1430.           This  is  a three-stage process: first, an interrupt  (an  event)
  1431.      occurs  and is handled quickly by the QB runtime, which sets the  flag
  1432.      and  variables  associated with the event.  This happens  behind  your
  1433.      program's  back,  as  it  were.  Second,  when  the  current  line  or
  1434.      statement  completes, QB checks the flags to see if any active  events
  1435.      (those  for  which  you  have executed "ON xxx  GOSUB"  and  "xxx  ON"
  1436.      commands)  have occurred.  Third, on discovering such a  condition  QB
  1437.      executes the GOSUB code you wrote to deal with it.
  1438.      
  1439.           The only area where UEVENT differs from events like KEY is in the
  1440.      first  part  of  the first step.  In defining  a  UEVENT,  _you_  take
  1441.      responsibility  for dealing with the interrupt, and for notifying  the
  1442.      QB  runtime that such an event has occurred.  From that point on,  the
  1443.      action  is exactly the same.
  1444.      
  1445.           The  difference  between invoking a GOSUB via SetUEvent  (or  any
  1446.      trap)  and  calling  it  directly is that when  you  invoke  it,  it's
  1447.      executed  only  when QB gets around to it, and only if  UEVENT  ON  is
  1448.      currently  in  effect.  A side effect of this is that you  may  "lose"
  1449.      events  if more than one occurs between occasions when QB  checks  its
  1450.      internal flags.
  1451.      
  1452.           This  whole business of interrupts can be broken down in  several
  1453.      ways: shared vs. exclusive vs. chained, or software vs. hardware,  and
  1454.      so  on.  The code packages included here give examples of  two  common
  1455.      combinations.
  1456.      
  1457.           You can trigger a UEvent in QB with no interrupt at all, by  just
  1458.      saying "CALL SetUEvent".  In MASM, declaring SetUEvent as an EXTRN far
  1459.      procedure  lets  you do the same thing: CALL SetUEvent.  In  C,  you'd
  1460.      declare "setuevent" as a void far external function and then reference
  1461.      "setuevent()"  to cause your QB handler to be invoked.  Simple...  and
  1462.      practically  useless  by  itself.  You need to  combine  this  with  a
  1463.      software  or hardware interrupt.
  1464.      
  1465.      >>  "Software interrupts" are really misnamed: they have more in
  1466.      >>  common with a subroutine call than with a hardware interrupt.
  1467.      >>  Since they occur under direct program control, there's nothing
  1468.      >>  unexpected or asynchronous about them.  They do however use
  1469.      >>  the same table of vectors that the hardware interrupts use.
  1470.      
  1471.           A small step up is the exclusive "true" software interrupt.  This
  1472.      involves  taking over an unused interrupt vector, writing a tiny  MASM
  1473.      routine  which intercepts INTs directed at this vector and performs  a
  1474.      CALL  SetUEvent.   There's no reason to take this  extra  step  unless
  1475.      you're  working with a canned other-language program which must use  a
  1476.      
  1477.      The QBNews                                                     Page 23
  1478.      Volume  1, Number  3                                      May 22, 1990
  1479.  
  1480.      pre-defined  INT to access your code.  If you're using DOS  3.x,  this
  1481.      can  be  done  in exactly the same manner as  the  "chained"  software
  1482.      interrupt  described  below,  since what you're  chaining  onto  is  a
  1483.      pre-defined Dismiss This Interrupt routine.
  1484.      
  1485.      >>      A "vector" in this context is a memory location reserved by
  1486.      >>  the computer as a pointer: it contains the address of a routine
  1487.      >>  intended to service an interrupt.  There are 255 such vectors in
  1488.      >>  the PC, occupying the memory from 0000:0000 through 0000:03FF.
  1489.      >>  Eight of these (sixteen in the AT) are reserved for use by the
  1490.      >>  hardware Interrupt ReQuest lines, or IRQs.  When an enabled
  1491.      >>  interrupt occurs, the PC stops what it's doing and executes the
  1492.      >>  routine whose address is stored in the appropriate vector.
  1493.      
  1494.           Next  most  complicated is the chained software  interrupt.   One
  1495.      example  of an existing software interrupt is the BIOS  disk  service,
  1496.      which uses INT 13H.  If you wanted your handler to be invoked whenever
  1497.      disk  activity  occurred, you'd chain onto this interrupt  vector  and
  1498.      monitor the registers using MASM.  When an event of interest occurred,
  1499.      you'd  "CALL  SetUEvent" to notify QB.  In any case,  you'd  pass  the
  1500.      interrupt  along to the original INT 13H handler.  Closely related  to
  1501.      this  is  the chained hardware interrupt.  The setup  is  exactly  the
  1502.      same:  hook  the interrupt vector, monitor the  registers,  etc.   All
  1503.      other  details  are taken care of by an existing handler.
  1504.      
  1505.           The code in CHNEVENT.BAS is an example of a chained handler which
  1506.      will  work for any hardware or software interrupt.  The assumption  is
  1507.      that you're just monitoring existing events (and sometimes  activating
  1508.      SetUEvent), but not touching any hardware.  In the example we  monitor
  1509.      INT  9,  the  keyboard interrupt, but you can monitor  almost  any  of
  1510.      the256  vectors by replacing "9" with the appropriate number.  Try  an
  1511.      experiment:  replace the INKEY loop with a LINE INPUT  statement.   If
  1512.      you can explain what happens, you've grasped the essentials of QBevent
  1513.      handling.
  1514.      
  1515.      >>    "Hooking" a vector means only that you store the address of your
  1516.      >>  own service routine in the vector.  To facilitate cleanup, it's
  1517.      >>  usual to first retrieve and store the existing contents of the
  1518.      >>  vector so that they can be replaced on exit.  If you're "chaining"
  1519.      >>  onto this vector, then you'll also use that original address when
  1520.      >>  your routine is finished, by performing a JMP directly to it.
  1521.      >>  Since this can happen to several routines in sequence, it's easy
  1522.      >>  to see why it's known as chaining.
  1523.      
  1524.           The  next step up in complexity (and it's a pretty big  step)  is
  1525.      the exclusive hardware interrupt.  Here, you're responsible for all of
  1526.      the  nitty-gritty  of  the PC hardware, in  addition  to  any  details
  1527.      associated  with  the  hardware device.  You must  program  the  8259A
  1528.      Programmable  Interrupt  Controller to allow interrupts  on  your  IRQ
  1529.      level,  then  issue  a command to clear the PIC when  you  service  an
  1530.      interrupt.  These must be done in MASM, as your QB event handler  will
  1531.      not be executed in a timely fashion and so cannot be relied on to take
  1532.      care  of these high-speed events.  The code in EVENTHDW.ASM shows  how
  1533.      to  deal with an event occurring on an arbitrary IRQ line  (determined
  1534.      at  install  time), but because we aren't dealing with a  real  device
  1535.      
  1536.      The QBNews                                                     Page 24
  1537.      Volume  1, Number  3                                      May 22, 1990
  1538.  
  1539.      here, the specific instructions for the interrupting hardware can only
  1540.      be hinted at.
  1541.      
  1542.      >>      Each hardware IRQ line is intimately tied to a vector: in the
  1543.      >>  case of the lower IRQs (0-7) the INT number (the vector number) is
  1544.      >>  simply the IRQ number plus 8.  That's why the KB interrupt, which
  1545.      >>  uses IRQ 1, is vectored through INT 9.
  1546.      
  1547.           Slightly  more complicated is the shared hardware interrupt.   In
  1548.      order  for  two hardware devices to share an IRQ line, there  must  be
  1549.      away to determine which device requested service by interrupting.   An
  1550.      example of sharing an interrupt might be COM1 and COM3, which both use
  1551.      IRQ4  and hence INT 0CH.  When an interrupt occurs on IRQ4,  the  COM3
  1552.      service routine gains control and examines a register in the UART it's
  1553.      responsible  for  to  see if that UART caused the  interrupt.   If  it
  1554.      didn't,  control  is passed to the COM1 service  routine.   I  haven't
  1555.      included  a  specific example of adding a shared handler, but  if  you
  1556.      need one and can't figure it out from the code shown, you can  contact
  1557.      me and I'll try to help.
  1558.      
  1559.           In  addition  to the above, whenever you take over  an  interrupt
  1560.      vector  you  must somehow put things back in order when  your  program
  1561.      terminates.   At a minimum this means restoring the original  contents
  1562.      of  the  vector; for hardware interrupts, you must  also  restore  the
  1563.      8259A Interrupt Mask Register bit to the state in which you found it.
  1564.      
  1565.           To  make  this  process a bit more  automatic,  QB  includes  the
  1566.      B_OnExit  routine.   Any  running BC program takes over  a  number  of
  1567.      interrupt  vectors  for its own use (for example,  BC  math  functions
  1568.      invoke INT 04H whenever an overflow occurs) which must be restored  on
  1569.      any  exit,  normal  or abnormal.  BC and QB  provide  B_OnExit  as  an
  1570.      extension of this internal cleanup.  You still must write the code  to
  1571.      do  the actual restoring of vectors, etc., but BC can call  that  code
  1572.      automatically  on  *any* exit, even an error crash, if  you  "register
  1573.      "your  routine via B_OnExit.  Each of the included code packages  uses
  1574.      B_OnExit in this way.
  1575.      
  1576.      **********************************************************************
  1577.      Jim  Mack  is a programmer specializing in real-time systems  for  the
  1578.      entertainment  industry.  He can be reached via CIS ID  76630,2012  on
  1579.      the MSSYS forum in the BASIC or MASM sections, or at Editing  Services
  1580.      Co., PO Box 599, Plymouth MI 48170, (313) 459-4618
  1581.      **********************************************************************
  1582.      
  1583.      [EDITORS NOTE]
  1584.           For some reason, the program CHNEVENT.BAS will cause my  computer
  1585.      to crash when run in the QB 4.5 enviroment. This is not the case  when
  1586.      run in the QBX (BC7) enviroment. Caution is advised if you try to  run
  1587.      this  in the enviroment. Source code for this article is contained  in
  1588.      UEVENT.ZIP.
  1589.      
  1590.  
  1591.  
  1592.  
  1593.  
  1594.      The QBNews                                                     Page 25
  1595.      Volume  1, Number  3                                      May 22, 1990
  1596.  
  1597.  
  1598.  
  1599.      ----------------------------------------------------------------------
  1600.                   S o m e   A s s e m b l y   R e q u i r e d  
  1601.      ----------------------------------------------------------------------
  1602.  
  1603.      Assembler Programming for QuickBASIC by Tom Hanlin
  1604.      
  1605.           Perhaps  you  already  know a little  bit  about  programming  in
  1606.      assembly  language,  or perhaps you've never given  it  much  thought.
  1607.      After  all,  it's  supposed to be  frighteningly  difficult  to  write
  1608.      assembler programs, and you've already got QuickBASIC anyway.
  1609.      
  1610.           Well,  it's true that there's a lot of work involved  in  writing
  1611.      large programs in assembly language.  If you keep to the small  stuff,
  1612.      however,  there's actually very little to it.  One of the easiest  and
  1613.      most  rewarding  uses for assembly language lies in  writing  routines
  1614.      that can be called from a higher-level language like QuickBASIC.  This
  1615.      can give you entirely new capabilities or make your existing  programs
  1616.      smaller  and  faster.   By  mixing the  capabilities  of  a  low-level
  1617.      language  like assembler with a high-level language  like  QuickBASIC,
  1618.      you  can  gain  a  lot  of  flexibility  when  you  need  it,  without
  1619.      sacrificing the ease of use of good ol' BASIC.
  1620.      
  1621.           Microsoft's documentation on mixed-language programming is rather
  1622.      daunting.  It's not exactly clear and the examples never seem to cover
  1623.      quite  what you had in mind.  Once you understand a few simple  rules,
  1624.      though,  you'll see that adding assembler routines to your  QuickBASIC
  1625.      programs can be readily accomplished.
  1626.      
  1627.           I'm  going  to assume you have some notion of how to  program  in
  1628.      both  QuickBASIC  and assembly language, since  explaining  an  entire
  1629.      language would be a bit more than a single article could cover!   With
  1630.      that in mind, let's take a look at the basic rules of writing assembly
  1631.      routines for QuickBASIC and follow that up with the code for a working
  1632.      routine.
  1633.      
  1634.           The first thing you need to know is which registers you can  use.
  1635.      The  answer  is, "all of them."  However, certain  registers  must  be
  1636.      preserved  for  BASIC,  so if you use them,  you  must  restore  their
  1637.      original  values  before  returning to the main  BASIC  program.   The
  1638.      registers  that  must be preserved are SI, DI, BP, and DS.   You  also
  1639.      need  to  preserve  the stack (SS and SP)  and  direction  flag.   The
  1640.      direction  flag  must  always be "forward" when you exit,  so  if  you
  1641.      change it using the "STD" instruction, be sure to restore it using the
  1642.      "CLD" instruction.
  1643.      
  1644.           Believe  it  or not, that's most of what you need to  know  right
  1645.      there.  The other important thing to know is how to pass parameters to
  1646.      or  from the assembler routine.  I'll keep it simple by  assuming  you
  1647.      use the standard convention, which is "pass by reference", rather than
  1648.      "pass by value", which has to be explicitly declared.
  1649.      
  1650.           What  do I mean by "pass by reference?"  I mean that, instead  of
  1651.      getting the actual value of a parameter, your routine gets the address
  1652.      of  that parameter and has to look up the value.  It's useful to  have
  1653.      the address of the parameter, since that means you can return a  value
  1654.      
  1655.      The QBNews                                                     Page 26
  1656.      Volume  1, Number  3                                      May 22, 1990
  1657.  
  1658.      by storing it in the parameter's address.
  1659.      
  1660.           Integral  numbers are stored simply.  For integers,  the  address
  1661.      you  are  given points directly to the integer (a word).  If  you  use
  1662.      long integers, the address points to the long integer (a doubleword).
  1663.      
  1664.           Strings  are  stored  in a slightly more  complex  fashion.   The
  1665.      address  you  are  given  points  to  a  "string  descriptor".    This
  1666.      descriptor is composed of two words, with the first giving the  length
  1667.      of  the string and the second the address of the string.  You are  not
  1668.      allowed  to  change  the  length or address  of  the  string  in  your
  1669.      assembler routine, although you may change the string itself.
  1670.      
  1671.           I  won't  go into single precision or double  precision  numbers,
  1672.      because  they  are rather tricky to handle in assembler.  I  won't  go
  1673.      into  arrays,  TYPEd values, or fixed-length strings here  either,  to
  1674.      keep it reasonably brief.  Perhaps in a later article...
  1675.      
  1676.           Parameters  are passed on the stack, starting at offset  6  (six)
  1677.      for  the -last- parameter and going up by two as you move towards  the
  1678.      first parameter.
  1679.      
  1680.           Finally, you need to end your routine with a special "RET" opcode
  1681.      that will clean the parameters off the stack for QuickBASIC.  The  RET
  1682.      must  have a number after it which is twice the number  of  parameters
  1683.      passed to the routine.
  1684.      
  1685.           Clear  as mud?  Well, perhaps the example routine will help  show
  1686.      what I'm talking about.  The DOSVER.ASM file contains the source code.
  1687.      To assemble it just type: ASM DOSVER; (where "ASM" is the name of your
  1688.      assembler: MASM, TASM, or OPTASM)
  1689.      
  1690.           Convert  the  resulting DOSVER.OBJ file to a library so  you  can
  1691.      easily  use  it  both from the command line and  QB  environment:
  1692.           LIB   DOSVER;                     (this  creates   DOSVER.LIB)
  1693.           LINK DOSVER/Q,,NUL,BQLB45;        (this creates DOSVER.QLB)
  1694.      
  1695.           If you are using QuickBASIC 4.0, change the BQLB45 to BQLB40.  If
  1696.      you are using QuickBASIC 4.0a or 4.0b, change it to BQLB41.
  1697.      
  1698.           You  can  now use the DOSVER routine from the QB  environment  by
  1699.      specifying the library name when you start QuickBASIC: QB /L DOSVER
  1700.      
  1701.           Use of the DECLARE statement is optional, but it will help  catch
  1702.      any errors you might make when calling DOSVER.  Use this: DECLARE  SUB
  1703.      DOSVER(VERSION$, MAJORV%, MINORV%)
  1704.      
  1705.           Before  calling the routine, you must set the VERSION$ string  to
  1706.      at  least four characters, since the routine is not allowed to  change
  1707.      the  length  of the string.  Call the routine like  this:
  1708.           VERSION$  = SPACE$(4)
  1709.           CALL DOSVER(VERSION$, MAJORV%, MINORV%)
  1710.      
  1711.           Typical  results will be "3.11" for VERSION$, 3 for MAJORV%,  and
  1712.      11 for MINORV%.
  1713.      
  1714.      The QBNews                                                     Page 27
  1715.      Volume  1, Number  3                                      May 22, 1990
  1716.  
  1717.      
  1718.           In  later articles, if there is any interest in it, I'll  explain
  1719.      how  to handle arrays, TYPEd variables, and fixed-length strings,  and
  1720.      also  how  to  pass  values back  from  functions  rather  than  using
  1721.      subprograms.
  1722.      
  1723.      **********************************************************************
  1724.      Tom  Hanlin  is  the author of the very  popular  ADVBAS  library  for
  1725.      QuickBASIC. His  new  shareware library is called BASWIZ.  He  can  be
  1726.      reached  through  the  QUIK_BAS echo on Fidonet or  in  care  of  this
  1727.      newsletter.
  1728.      **********************************************************************
  1729.      
  1730.      [EDITOR'S NOTE]
  1731.           The archive ASMREQ.ZIP contains the assembler source code plus an
  1732.      assembled .OBJ file for the routine contained in the article.
  1733.      
  1734.  
  1735.  
  1736.  
  1737.  
  1738.  
  1739.  
  1740.  
  1741.  
  1742.  
  1743.  
  1744.  
  1745.  
  1746.  
  1747.  
  1748.  
  1749.  
  1750.  
  1751.  
  1752.  
  1753.  
  1754.  
  1755.  
  1756.  
  1757.  
  1758.  
  1759.  
  1760.  
  1761.  
  1762.  
  1763.  
  1764.  
  1765.  
  1766.  
  1767.  
  1768.  
  1769.  
  1770.  
  1771.  
  1772.      The QBNews                                                     Page 28
  1773.      Volume  1, Number  3                                      May 22, 1990
  1774.  
  1775.  
  1776.  
  1777.      ----------------------------------------------------------------------
  1778.      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
  1779.      ----------------------------------------------------------------------
  1780.  
  1781.      
  1782.      From:   Mike Sinak
  1783.      To:     All
  1784.      Subj:   PEEK & POKE
  1785.      
  1786.      I  am just beginning to study DOS and BIOS calls and don't  understand
  1787.      how to do it at all.  Does anybody have any info on the PEEK and  POKE
  1788.      usage?   Like  if you want to peek and poke to turn caps lock  on  and
  1789.      off, how in the world do you know what address to peek and poke?   I'm
  1790.      lost!   I would like to learn more about this stuff and get some  kind
  1791.      of comprehensive list of peeks and pokes.
  1792.      
  1793.      Also I learned that at DEF SEG 0 you can turn on and off caps lock  by
  1794.      POKE &H0417, PEEK &H0417 OR &H40 (to turn on)
  1795.      
  1796.      and
  1797.      
  1798.      POKE &H0417, PEEK &H0417 AND &HBF (to turn off)
  1799.      
  1800.      Now how in the world did they know that?  The AND and OR statments are
  1801.      supposed  to be turning on and off bit 6 of the &H0417  address.   How
  1802.      did they know these particular numbers turn on and off bit 6?   Better
  1803.      yet, how did they know that bit 6 had to be turned on and off at  this
  1804.      particular address to turn caps lock on and off.  Is there a pattern?
  1805.      
  1806.      Obviously  my ignorance is being displayed. Go ahead and laugh  <grin>
  1807.      but I would sure like to know more about this.
  1808.      
  1809.      ANY HELP?
  1810.      
  1811.      
  1812.      From:   Robin Hunziker @ 965/1
  1813.      To:     Mike Sinak
  1814.      Subj:   Re: PEEK & POKE
  1815.      
  1816.      Perhaps  your  best  bet  for figuring out  how  DOS  operates  is  by
  1817.      purchasing the following book:
  1818.      
  1819.           Advanced MSDOS Programming
  1820.           2nd Edition
  1821.           Ray Duncan
  1822.           Microsoft Press
  1823.           ISBN 1-55615-157-8
  1824.      
  1825.      For  example,  on  page 582 the book discusses exactly  your  area  of
  1826.      question  in easy-to-understand tabular format.  It discusses  how  to
  1827.      call Int 16H Function 02H to "get keyboard flags".  Although the front
  1828.      cover states that it is "The Microsoft guide for Assembly Language and
  1829.      C programmers", it is very relevant to much of the discussion in  this
  1830.      echo.
  1831.      
  1832.      
  1833.      The QBNews                                                     Page 29
  1834.      Volume  1, Number  3                                      May 22, 1990
  1835.  
  1836.      
  1837.      From:   David Martin
  1838.      To:     Mike Sinak
  1839.      Subj:   Peek & Poke
  1840.      
  1841.      A better way to set upper and lower case is the following:
  1842.      Lower Case:  POKE 1047, PEEK(1047) AND 191
  1843.      Upper Case:  POKE 1047, PEEK(1047) OR 64
  1844.      Lots  of stuff can be done with poke such as disable  the  CTRL-BREAK,
  1845.      turn  number lock key on and off, read hardware  configurements,  read
  1846.      size  of  RAM.  The list goes on and on.  If you want a  list  of  the
  1847.      commands  let me know.  These commands must be preceded by: DEF SEG  =
  1848.      0.  Let me know what kind of stuff you are working with so I can  give
  1849.      you the commands.
  1850.      
  1851.      
  1852.      From:   Tom Hanlin
  1853.      To:     Mike Sinak
  1854.      Subj:   Re: PEEK & POKE
  1855.      
  1856.           In  order  to understand bit numbering, you need to  convert  the
  1857.      number  to  binary.  Bits are numbered from right to  left,  with  the
  1858.      lowest bit being number zero.  So:
  1859.        &H40 = 64 = 0100,0000b (note that bit 6 is turned on)
  1860.        &HBF =191 = 1011,1111b (note that all bits except 6 are turned on)
  1861.      when  you OR a number with another number, the result contains all  of
  1862.      the  bits  that were turned on in the first number OR  in  the  second
  1863.      number. When you AND two numbers, the result contains all of the  bits
  1864.      that were turned on in the first number AND in the second number.  So,
  1865.      to turn on a specific bit, you OR with a number that has only that bit
  1866.      turned on (which leaves the other bits in the original number  alone).
  1867.      To  turn a specific bit off, you AND with a number that has only  that
  1868.      bit  turned  off (which leaves the other bits in the  original  number
  1869.      alone).  See?
  1870.      
  1871.           Knowing  which  memory locations have special purposes,  such  as
  1872.      keeping  track  of Caps Lock and Num Lock, comes from  (mostly)  IBM's
  1873.      listing  of  the  system  BIOS.   Many  reference  books  contain  the
  1874.      information  in a decoded format, so you can use it without having  to
  1875.      understand  the  BIOS  at all.  If you can  find  a  copy,  COMPUTE!'s
  1876.      "Mapping  the IBM PC and PCjr" is an excellent guide to this  sort  of
  1877.      thing, although there are many others.
  1878.      
  1879.           You  may  also  want something like Norton's  guide  to  assembly
  1880.      language, to give you some idea about converting numbers between  hex,
  1881.      decimal and binary, and how PC memory mapping works.  Things like...
  1882.           DEF SEG=0:PRINT PEEK(&H417)
  1883.      is the same as
  1884.           DEF SEG=&H40:PRINT PEEK(&H17)
  1885.      
  1886.      
  1887.      From:   David Martin
  1888.      To:     Mike Sinak
  1889.      Subj:   Peek & Poke
  1890.      
  1891.      
  1892.      The QBNews                                                     Page 30
  1893.      Volume  1, Number  3                                      May 22, 1990
  1894.  
  1895.      The following list is some things that can be done with peek & poke.
  1896.      KEYBOARD KEYS:
  1897.      PEEK (1047) AND 8:            value 8 if ALT is pressed.
  1898.                      4:                       CTRL
  1899.                      2:                  2    LEFT SHIFT.
  1900.                      1:                  1    RIGHT SHIFT.
  1901.                      3:                  3    NIETHER SHIFT.
  1902.      PEEK (1048) AND 4:                  4    PRINT SCREEN KEY.
  1903.      PEEK (1047) AND 64                  0 if in LOWER CASE.
  1904.                                          64      UPPER CASE.
  1905.      POKE 1047, PEEK(1047) AND 191       specify LOWER CASE.
  1906.                            OR 64         specify UPPER CASE.
  1907.      FOR J=0 TO 3:POKE (108+J),PEEK(112+J):NEXT:      DISABLE CTRL-BREAK
  1908.      CONFIGURATION OF COMPUTER:
  1909.      (PEEK(1041) AND 192)/64:            number of PRINTER ADAPTERS.
  1910.      (PEEK(1040) AND 1)*(1+PEEK(1040)/64 number of DISK DRIVES.
  1911.      (PEEK(1041) AND 14)/2               number of RS232 ports.
  1912.      PEEK(1043)+256*PEEK(1044)           size of RAM.
  1913.      NUMBER LOCK KEY:
  1914.      PEEK(1047) AND 32                   0 if OFF, 32 if ON.
  1915.      POKE 1047,PEEK(1047) AND 223:       turn NUM LOCK key OFF.
  1916.                               32:        turn NUM LOCK key ON.
  1917.      Alot  of  these commands are abreviated.  If nothing appears  below  a
  1918.      line just type in the line on top of what you want along with what  is
  1919.      changed. Got it? Let me know if you have any questions.  Glad to help!
  1920.      All  lines must be preceded by: DEF SEG =0  (Only one DEF SEG =  0  at
  1921.      the beginning of the program)
  1922.      
  1923.      
  1924.      From:   Ronny Ong
  1925.      To:     Mike Sinak
  1926.      Subj:   Re: PEEK & POKE
  1927.      
  1928.      Mike, I also have Duncan's book and find it useful, but I do happen to
  1929.      use a number of languages including assembler, C, and QuickBASIC.
  1930.      
  1931.      Let  me suggest "DOS Programmer's Reference" (2nd Edition),  by  Terry
  1932.      Dettmann,  Revised by Jim Kyle.  It is published by Que
  1933.      ISBN  0-88022-458-4.  List price is $27.95 U.S.   This  book  contains
  1934.      roughly the same type of information as Duncan's, but it has  specific
  1935.      QuickBASIC  4.xx  examples,  so it's probably easier to  use  for  the
  1936.      QuickBASIC programmer with less experience in assembler and C.
  1937.      
  1938.      
  1939.      
  1940.      From:   Ronny Ong
  1941.      To:     Mike Sinak
  1942.      Subj:   Re: Peek & Poke
  1943.      
  1944.      Hi,  Mike.   You might try getting a general intro/computers  type  of
  1945.      book  and  brushing up on binary numbers.  All  digital  computers  of
  1946.      today do everything in binary, or base 2.  In others words,  computers
  1947.      are  simply  made  up  of billions  of  tiny  on/off  switches.   "On"
  1948.      represents  the  binary digit (or "bit" for short) of  "1"  and  "off"
  1949.      represents "0."
  1950.      
  1951.      The QBNews                                                     Page 31
  1952.      Volume  1, Number  3                                      May 22, 1990
  1953.  
  1954.      
  1955.      When  you see "POKE xxx, PEEK(xxx) AND 64," here's what happens  (I've
  1956.      simplified this slightly):
  1957.      Let's  say  that PEEK(xxx) currently contains the byte value  98.   In
  1958.      binary, that's 01100010.  The decimal number 64 is 01000000 in binary.
  1959.      The "AND" operator means to produce a result which has a "1" in  every
  1960.      position  which is "1" in both of the operands and has a "0"  for  all
  1961.      other positions.
  1962.      
  1963.      01100010 <--- 98
  1964.      01000000 <--- 64
  1965.      --------
  1966.      01000000 <--- Result of 64, to be POKE'd back into memory location xxx
  1967.      
  1968.      The  end result is that all bits were turned "off" (set to  0)  except
  1969.      that  one bit which corresponded to 64.  So, essentially, the  AND  64
  1970.      "stuff" you see is manipulating individual on/off switches inside  the
  1971.      computer.
  1972.      
  1973.      A  good  book  will walk you through  conversion  between  binary  and
  1974.      decimal.  Also,  you'll  see that hexadecimal  ("hex")  numbers  which
  1975.      you've  probably  come across, are shorthand forms  of  binary.   Good
  1976.      luck!
  1977.      
  1978.      
  1979.      [EDITOR'S NOTE]
  1980.           The purpose of this conference is to discuss Microsoft QuickBASIC
  1981.      and  related  applications and utilities. SysOps looking for  a  Group
  1982.      Mail  or EchoMail link into QUIK_BAS should contact the Alliance  node
  1983.      known  as 520/323, the FidoNet node known as 107/323, or the Good  Egg
  1984.      Net  Node known as 9230/323, or simply 1-201-247-8252 for  information
  1985.      on local feeds.
  1986.      
  1987.  
  1988.  
  1989.  
  1990.  
  1991.  
  1992.  
  1993.  
  1994.  
  1995.  
  1996.  
  1997.  
  1998.  
  1999.  
  2000.  
  2001.  
  2002.  
  2003.  
  2004.  
  2005.  
  2006.  
  2007.  
  2008.  
  2009.      The QBNews                                                     Page 32
  2010.      Volume  1, Number  3                                      May 22, 1990
  2011.  
  2012.  
  2013.  
  2014.      ----------------------------------------------------------------------
  2015.                                 S w a p   S h o p
  2016.      ----------------------------------------------------------------------
  2017.  
  2018.      ***** Screen Scrolling with Call Interrupt
  2019.      
  2020.      DECLARE SUB scroll.ner (rader!, left!, up!, right!, down!)
  2021.      DECLARE SUB scroll.up (rader!, left!, up!, right!, down!)
  2022.      
  2023.      'To demonstrate the use of interrupt 10H ah=06
  2024.      'To scroll any part of the screen up or down
  2025.      'QB must be invoked with the /l switch. In QB.BI the RegType is
  2026.      'defined and the INTERRUPT-Call set up.
  2027.      'By Johan Lindgren (BBS:+46 60115371)
  2028.      
  2029.      '$INCLUDE: 'QB.BI'
  2030.      
  2031.      DIM SHARED inregs AS RegType, outregs AS RegType
  2032.      
  2033.      '---------------------------------------------------------------------
  2034.      ' Fill the screen with numbers to indicate where scrolling takes place
  2035.      '---------------------------------------------------------------------
  2036.      
  2037.      FOR i = 1 TO 24
  2038.      FOR j = 1 TO 40
  2039.      
  2040.      PRINT USING "##"; i;
  2041.      
  2042.      NEXT j
  2043.      NEXT i
  2044.      
  2045.      '----------------------------------------------------------
  2046.      
  2047.      ' Do one scroll up first. Give values and call the sub
  2048.      '----------------------------------------------------------
  2049.      
  2050.      rader = 2: up = 5: left = 5: down = 10: right = 20
  2051.      
  2052.      scroll.up rader, left, up, right, down
  2053.      
  2054.      '------------------------------------------------------------
  2055.      
  2056.      ' Do a scroll down. Give values and call the sub
  2057.      '------------------------------------------------------------
  2058.      
  2059.      rader = 3: up = 10: left = 35: down = 15: right = 70
  2060.      
  2061.      scroll.ner rader, left, up, right, down
  2062.      
  2063.      
  2064.      'END of demo.
  2065.      
  2066.      SUB scroll.ner (rader, left, up, right, down)
  2067.      
  2068.      '-----------------------------------------------------------
  2069.      
  2070.      The QBNews                                                     Page 33
  2071.      Volume  1, Number  3                                      May 22, 1990
  2072.  
  2073.      'First put up and down in right hexadecimal postion
  2074.      'Then enter the values into the registers and call interrupt
  2075.      '------------------------------------------------------------
  2076.      
  2077.      up = up * 256
  2078.      down = down * 256
  2079.      
  2080.      inregs.ax = &H700 + rader
  2081.      inregs.cx = up + left
  2082.      inregs.dx = down + right
  2083.      
  2084.      
  2085.      CALL INTERRUPT(16, inregs, outregs)
  2086.      
  2087.      
  2088.      END SUB
  2089.      
  2090.      SUB scroll.up (rader, left, up, right, down)
  2091.      
  2092.      '-----------------------------------------------------------
  2093.      'First put up and down in right hexadecimal postion
  2094.      'Then enter the values into the registers and call interrupt
  2095.      '------------------------------------------------------------
  2096.      
  2097.      
  2098.      up = up * 256
  2099.      down = down * 256
  2100.      
  2101.      inregs.ax = &H600 + rader
  2102.      inregs.cx = up + left
  2103.      inregs.dx = down + right
  2104.      
  2105.      
  2106.      CALL INTERRUPT(16, inregs, outregs)
  2107.      
  2108.      
  2109.      END SUB
  2110.      
  2111.  
  2112.  
  2113.  
  2114.  
  2115.  
  2116.  
  2117.  
  2118.  
  2119.  
  2120.  
  2121.  
  2122.  
  2123.  
  2124.  
  2125.  
  2126.  
  2127.  
  2128.      The QBNews                                                     Page 34
  2129.      Volume  1, Number  3                                      May 22, 1990
  2130.  
  2131.      ***** Getting the Day of the Week with Call Interrupt
  2132.      
  2133.      DECLARE FUNCTION dag$ (nr!)
  2134.      
  2135.      ' This is just an example to illustrate the use of an interrupt
  2136.      ' to get the day of any date.
  2137.      ' By Johan Lindgren (+46 60-121497 (BBS System))
  2138.      
  2139.      '$INCLUDE: 'QB.BI'
  2140.      
  2141.      DIM inregs AS RegType, outregs AS RegType
  2142.      
  2143.      inregs.ax = &H2A00
  2144.      
  2145.      spardat$ = DATE$
  2146.      
  2147.      CLS
  2148.      PRINT
  2149.      PRINT "This is just to show the function of interrupt 33,function 2a"
  2150.      PRINT "It works well for our time and the future."
  2151.      PRINT "If you need this function for old dates, you have to use"
  2152.      PRINT "something else."
  2153.      
  2154.      ON ERROR GOTO fel.datum       'In case you enter a bad date
  2155.      
  2156.      main:
  2157.      
  2158.      svar$ = " "
  2159.      DO UNTIL svar$ = ""
  2160.      INPUT "Input the date to check in the format MM-DD-YEAR"; svar$
  2161.      IF svar$ <> "" THEN
  2162.           DATE$ = svar$            'Set the date we want to check
  2163.                                    'Call the interrupt to get the day
  2164.           CALL Interrupt (33, inregs, outregs)
  2165.           dagnr = outregs.ax MOD 256 'Extract the daynumber returned
  2166.           DATE$ = spardat$         'Restore proper date
  2167.      
  2168.           SELECT CASE dagnr
  2169.                CASE 0
  2170.                     dag$ = "Sunday"
  2171.                CASE 1
  2172.                     dag$ = "Monday"
  2173.                CASE 2
  2174.                     dag$ = "Tuesday"
  2175.                CASE 3
  2176.                     dag$ = "Wednesday"
  2177.                CASE 4
  2178.                     dag$ = "Thursday"
  2179.                CASE 5
  2180.                     dag$ = "Friday"
  2181.                CASE 6
  2182.                     dag$ = "Saturday
  2183.           END SELECT
  2184.      
  2185.           PRINT "The day of the week for ";svar$;" is ";dag$
  2186.      
  2187.      The QBNews                                                     Page 35
  2188.      Volume  1, Number  3                                      May 22, 1990
  2189.  
  2190.           PRINT
  2191.      END IF
  2192.      
  2193.      
  2194.      
  2195.      
  2196.      
  2197.      
  2198.      LOOP
  2199.      
  2200.      CLS
  2201.      END
  2202.      
  2203.      fel.datum:
  2204.      RESUME main
  2205.      
  2206.  
  2207.  
  2208.  
  2209.  
  2210.  
  2211.  
  2212.  
  2213.  
  2214.  
  2215.  
  2216.  
  2217.  
  2218.  
  2219.  
  2220.  
  2221.  
  2222.  
  2223.  
  2224.  
  2225.  
  2226.  
  2227.  
  2228.  
  2229.  
  2230.  
  2231.  
  2232.  
  2233.  
  2234.  
  2235.  
  2236.  
  2237.  
  2238.  
  2239.  
  2240.  
  2241.  
  2242.  
  2243.  
  2244.  
  2245.      The QBNews                                                     Page 36
  2246.      Volume  1, Number  3                                      May 22, 1990
  2247.  
  2248.      ***** A YES/NO response DEF FN
  2249.      
  2250.      ' TO: DAVID CLEARY  76510,1725
  2251.      ' FROM: BEN HARTLEY  70033,2612
  2252.      ' SUBJECT: For QBNews -- CHOOSE.BAS -- (FUNCTION)
  2253.      '===================================================================
  2254.      'Dear David,
  2255.      '
  2256.      '     Liked your newsletter, which I downloaded from Exec-PC BBS.
  2257.      ' I'm not what you might call an experienced programmer, but the
  2258.      ' enclosed function might be of interest.
  2259.      '     There are LOTS of routines around that allow selection of
  2260.      ' a simple "Yes" or "No" response.  There are times, however, when
  2261.      ' the flow of a program is improved if the choices are something
  2262.      ' other than "Y" or "N".  That's where this one comes in.  If there
  2263.      ' are no more than two choices, then they can be explicitly stated.
  2264.      ' Whether this is any faster, or, heaven save us all, more "elegant"
  2265.      ' than using SELECT CASE, I haven't the foggiest.  I do know that it
  2266.      ' works!
  2267.      '     You can load this entire file into your QuickBASIC editor,
  2268.      ' and run it.  It was originally written in QB 3.0, but seems to
  2269.      ' run fine in QB 4.5 --
  2270.      '     Hope this is something along the lines of what you're
  2271.      ' looking for.
  2272.      '
  2273.      '                                Ben Hartley
  2274.      '                                Jaffrey, NH
  2275.      
  2276.      '-------------------------------------------------------------------
  2277.      DEF FNChoose (prompt$, Response1$, Response2$)
  2278.              R1$ = UCASE$(LEFT$(Response1$, 1))
  2279.              R2$ = UCASE$(LEFT$(Response2$, 1))
  2280.              alpha$ = R1$ + R2$
  2281.      
  2282.              PRINT prompt$; " ("; R1$; " or "; R2$; ") "
  2283.              reply$ = ""
  2284.              charPos% = 0
  2285.              WHILE charPos% = 0
  2286.                       reply$ = UCASE$(INKEY$)
  2287.                       IF (reply$ <> "") THEN
  2288.                              charPos% = INSTR(alpha$, reply$)
  2289.                              IF (charPos% = 0) THEN BEEP
  2290.                       END IF
  2291.              WEND
  2292.              reply$ = UCASE$(MID$(alpha$, charPos%, 1))
  2293.              FNChoose = (reply$ = R1$)
  2294.      END DEF
  2295.      '-------------------------------------------------------------------
  2296.      COLOR 15, 1
  2297.      beginhere:
  2298.      CLS
  2299.      LOCATE 10, 5
  2300.      PRINT "Which option do you wish..."
  2301.      LOCATE 12, 7
  2302.      IF FNChoose("...The First or the Second ?", "First", "Second") THEN
  2303.      
  2304.      The QBNews                                                     Page 37
  2305.      Volume  1, Number  3                                      May 22, 1990
  2306.  
  2307.              PRINT
  2308.              PRINT TAB(20); "You chose the First Option."
  2309.      ELSE
  2310.              PRINT
  2311.              PRINT TAB(20); "You chose the Second Option."
  2312.      END IF
  2313.      LOCATE 16, 7
  2314.      IF FNChoose("Do It Again or Quit ?", "Again", "Quit") THEN
  2315.              GOTO beginhere
  2316.      END IF
  2317.      PRINT
  2318.      PRINT TAB(30); "**** All done! ****"
  2319.      END
  2320.      
  2321.  
  2322.  
  2323.  
  2324.  
  2325.  
  2326.  
  2327.  
  2328.  
  2329.  
  2330.  
  2331.  
  2332.  
  2333.  
  2334.  
  2335.  
  2336.  
  2337.  
  2338.  
  2339.  
  2340.  
  2341.  
  2342.  
  2343.  
  2344.  
  2345.  
  2346.  
  2347.  
  2348.  
  2349.  
  2350.  
  2351.  
  2352.  
  2353.  
  2354.  
  2355.  
  2356.  
  2357.  
  2358.  
  2359.  
  2360.  
  2361.  
  2362.      The QBNews                                                     Page 38
  2363.      Volume  1, Number  3                                      May 22, 1990
  2364.  
  2365.      ***** A Powerful Replacement for INPUT
  2366.      
  2367.      'SYNTAX: Enput$(Row%,Col%,FLen%,Default$,Allow$,EndKeys$,ExitKey$)
  2368.      'WHERE: Row% & Col% - where input to occur
  2369.      '       FLen% - Field Length - maximum allowable
  2370.      '       Default$ - Field's beginning default value
  2371.      '       Allow$ - Character Set allowable for input
  2372.      '       EndKeys$ - Keystrokes acceptable for finishing.
  2373.      '          SUCH: [Enter] is CHR$(13)
  2374.      '                [Esc] is CHR$(27)
  2375.      '                [F1] is CHR$(255)+CHR$(59)
  2376.      '                [Ctrl+PgUp] is CHR$(255)+CHR$(132)
  2377.      '                ... etc
  2378.      '       ExitKey$ - The keystroke (from above EndKeys$)
  2379.      '                  which was struck at function end.
  2380.      'SIMPLEST USE:  A$ = Enput$(0,0,0,"",","",Any$)
  2381.      '       Will default to cursor's current row/col, length is
  2382.      '       autoset to right margin, allowable chars are ALL,
  2383.      '       only ending key is [Enter].
  2384.      '==========================================> Frederick Volking
  2385.      
  2386.      FUNCTION  Enput$ (Row%, Col%, FieldLen%,  Default$,  AllowCharsMask$_
  2387.                        ,EndingKeys$, ExitKey$) STATIC
  2388.      
  2389.         SHARED ScreenWidth%, BackSpaceKeyStrokes$, EmptySpaceChar$
  2390.      
  2391.         ' verify SHARED globals are set
  2392.      
  2393.         IF ScreenWidth% = 0 THEN ScreenWidth% = 40
  2394.         IF BackSpaceKeyStrokes$ = "" THEN BackSpaceKeyStrokes$ = _
  2395.                                   CHR$(8) + CHR$(255) + CHR$(75)
  2396.         IF EmptySpaceChar$ = "" THEN EmptySpaceChar$ = CHR$(254)
  2397.      
  2398.         ' If not specified then supply defaults to incomming vars
  2399.      
  2400.         IF AllowCharsMask$ = "" THEN AllowCharsMask$ = CHR$(34) +_
  2401.             " !#$%&'()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]_
  2402.             ^_abcdefghijklmnopqrstuvwxyz|~"
  2403.      
  2404.         IF EndingKeys$ = "" THEN EndingKeys$ = CHR$(13)
  2405.         IF Row% = 0 THEN Row% = CSRLIN
  2406.         IF Col% = 0 THEN Col% = POS(0)
  2407.         IF FieldLen% = 0 THEN FieldLen% = ScreenWidth% - Col%
  2408.         IF LEN(Default$) > FieldLen% THEN Default$ = LEFT$(Default$_
  2409.             , FieldLen%)
  2410.      
  2411.         ' define internal defaults
  2412.      
  2413.         CharsCollected% = 0
  2414.         ReturnVar$ = ""
  2415.         ' begin main loop
  2416.         DO
  2417.            NotDone% = 1
  2418.            IF CharsCollected% = 0 THEN
  2419.               LOCATE Row%, Col%, 0
  2420.      
  2421.      The QBNews                                                     Page 39
  2422.      Volume  1, Number  3                                      May 22, 1990
  2423.  
  2424.               PRINT Default$ + STRING$(FieldLen% - LEN(Default$), _
  2425.                  EmptySpaceChar$);
  2426.            END IF
  2427.            IF CharsCollected% = FieldLen% THEN
  2428.               LOCATE Row%, Col% + CharsCollected% - 1, 1
  2429.            ELSE
  2430.               LOCATE Row%, Col% + CharsCollected%, 1
  2431.            END IF
  2432.            DO
  2433.               KeyStroke$ = INKEY$
  2434.            LOOP WHILE KeyStroke$ = ""
  2435.            IF LEN(KeyStroke$) = 2 THEN KeyStroke$ = CHR$(255) + _
  2436.                RIGHT$(KeyStroke$, 1)
  2437.            IF INSTR(AllowCharsMask$, KeyStroke$) > 0 THEN
  2438.               IF CharsCollected% < FieldLen% THEN
  2439.                  IF CharsCollected% = 0 THEN
  2440.                     PRINT STRING$(FieldLen%, EmptySpaceChar$);
  2441.                     LOCATE Row%, Col%, 0
  2442.                  END IF
  2443.                  ReturnVar$ = ReturnVar$ + KeyStroke$
  2444.                  CharsCollected% = CharsCollected% + 1
  2445.                  PRINT KeyStroke$;
  2446.               END IF
  2447.            ELSE
  2448.               IF INSTR(BackSpaceKeyStrokes$, KeyStroke$) > 0 THEN
  2449.                  IF CharsCollected% > 1 THEN
  2450.                     CharsCollected% = CharsCollected% - 1
  2451.                     LOCATE Row%, Col% + CharsCollected%, 0
  2452.                     PRINT EmptySpaceChar$;
  2453.                     LOCATE Row%, Col% + CharsCollected%, 1
  2454.                     ReturnVar$ = LEFT$(ReturnVar$, CharsCollected%)
  2455.                  ELSE
  2456.                     CharsCollected% = 0
  2457.                     ReturnVar$ = Default$
  2458.                  END IF
  2459.               ELSE
  2460.                  IF INSTR(EndingKeys$, KeyStroke$) > 0 THEN
  2461.                     ExitKeys$ = KeyStroke$
  2462.                     NotDone% = 0
  2463.                  ELSE
  2464.                     SOUND 500, 1
  2465.                  END IF
  2466.               END IF
  2467.            END IF
  2468.         LOOP WHILE NotDone%
  2469.         Enput$ = ReturnVar$
  2470.      END FUNCTION
  2471.      
  2472.  
  2473.  
  2474.  
  2475.  
  2476.  
  2477.  
  2478.  
  2479.      The QBNews                                                     Page 40
  2480.      Volume  1, Number  3                                      May 22, 1990
  2481.  
  2482.      ***** Windowing Routines with Shading
  2483.      
  2484.      'FRAME.BAS test program
  2485.      'Lawrence Stone, 1990
  2486.      '
  2487.      'Purpose: Demonstrate the versitility of the Frame subprogram.
  2488.      'Note: I built this routine just for the fun of it.  I designed it to
  2489.      'be easy to use and versitile. This demonstration program simply makes
  2490.      'six calls to the frame subprogram-the subprogram does the rest.
  2491.      
  2492.      
  2493.      DECLARE  SUB Frame (TopRow%, leftCol%, botRow%, rightCol%,  boxType%,_
  2494.                boxFg%, boxBg%, filFg%, filBg%, fillChar%, shadow%, header$)
  2495.      
  2496.         COLOR 12, 4                     'Set a fancy color
  2497.         FOR A% = 1 TO 25
  2498.             LOCATE A%, 1
  2499.             PRINT STRING$(80, 206);     'Draw a complex background
  2500.         NEXT
  2501.      
  2502.                               'Test the Frame subprogram
  2503.         Frame 5, 20, 21, 75, 2, 15, 3, 9, 7, 178, -1, "This is a Test"
  2504.      
  2505.                               'Overlay the 1st box with a smaller 2nd box
  2506.         Frame 4, 3, 10, 36, 1, 15, 6, 6, 0, 219, -1, "This is Test 2"
  2507.      
  2508.                               'What the heck, let's draw another box
  2509.         Frame 13, 33, 22, 70, 3, 14, 2, 15, 3, 221, -1, "This is Test 3"
  2510.      
  2511.                               'What the heck, draw box #4 without a header
  2512.         Frame 15, 5, 19, 65, 4, 13, 0, 0, 7, 32, -1, ""
  2513.         LOCATE 17,14:PRINT "Box #4 has a shadow but doesn't have a Header."
  2514.      
  2515.                               'What the heck, draw box #5 without a shadow
  2516.         Frame 8, 40, 10, 73, 4, 11, 0, 11, 0, 32, 0, ""
  2517.         LOCATE 9, 43: PRINT "Box #5 doesn't have a Shadow!"
  2518.      
  2519.                               'What the heck, draw a frame around it all
  2520.         Frame 1, 1, 25, 80, 2, 15, 0, 0, 0, 32, 0, _
  2521.            "Box #6 Frames Without Clearing"
  2522.      
  2523.         COLOR 7, 0                  'Restore color before ending
  2524.         A$ = INPUT$(1)              'Give a keystroke to end this test.
  2525.         END                         'We're out of here!
  2526.      
  2527.      [EDITOR'S NOTE]
  2528.           Due to the formatting of the FRAME subprogram, it is not  printed
  2529.      here. You can find the sub program in the file FRAME.BAS
  2530.      
  2531.  
  2532.  
  2533.  
  2534.  
  2535.  
  2536.  
  2537.      The QBNews                                                     Page 41
  2538.      Volume  1, Number  3                                      May 22, 1990
  2539.  
  2540.  
  2541.  
  2542.      ----------------------------------------------------------------------
  2543.                            I n p u t   P a s t   E n d
  2544.      ----------------------------------------------------------------------
  2545.  
  2546.      Due to demand, you can now get the QBNews mailed to you on disk for  a
  2547.      nominal charge. The rates are as follows:
  2548.      
  2549.      United States                $3.00
  2550.      
  2551.      North America (outside US)   $4.00
  2552.      
  2553.      Outside US                   $6.00
  2554.      
  2555.      Please  add $1.00 if you want it on 3.5" media. Also, you can  receive
  2556.      it  in either ZIP, PAK, or LHZ format. If you don't specify, you  will
  2557.      receive it in ZIP format.
  2558.      
  2559.      The first time you request the QBNews, you will receive all  available
  2560.      issues. That way you won't miss any.
  2561.      
  2562.      And  of course, you can always download it free from Treasure  Island.
  2563.      First time callers are granted limited download privlidges so you  can
  2564.      get it. Treasure Island is 9600 HST, is at FIDO address 1:141/730, and
  2565.      its phone is 203-791-8532. To request your copy on disk, send US funds
  2566.      to:
  2567.      
  2568.      The QBNews
  2569.      P.O. Box 507
  2570.      Sandy Hook, CT 06482
  2571.      
  2572.      Remember to specify which archive format you want.
  2573.      
  2574.  
  2575.  
  2576.  
  2577.  
  2578.  
  2579.  
  2580.  
  2581.  
  2582.  
  2583.  
  2584.  
  2585.  
  2586.  
  2587.  
  2588.  
  2589.  
  2590.  
  2591.  
  2592.  
  2593.  
  2594.  
  2595.  
  2596.  
  2597.      The QBNews                                                     Page 42
  2598.      Volume  1, Number  3                                      May 22, 1990
  2599.  
  2600.      WE NEED AUTHORS!
  2601.      
  2602.           If you are interested in writing for the QBNews, you can  contact
  2603.      me  at  the  address below. I can also be  reached  on  Compuserve  as
  2604.      76510,1725 or on Prodigy as HSRW18A. If you are submitting articles, I
  2605.      ask that they be ASCII text with no more than 70 characters per  line.
  2606.      As  far as reviews go, I am pretty well set so what I really  want  is
  2607.      code.
  2608.      
  2609.      
  2610.      You can write me at:
  2611.      
  2612.           The QBNews
  2613.           P.O. Box 507
  2614.           Sandy Hook, CT 06482
  2615.      
  2616.      David Cleary
  2617.      
  2618.  
  2619.  
  2620.  
  2621.  
  2622.  
  2623.  
  2624.  
  2625.  
  2626.  
  2627.  
  2628.  
  2629.  
  2630.  
  2631.  
  2632.  
  2633.  
  2634.  
  2635.  
  2636.  
  2637.  
  2638.  
  2639.  
  2640.  
  2641.  
  2642.  
  2643.  
  2644.  
  2645.  
  2646.  
  2647.  
  2648.  
  2649.  
  2650.  
  2651.  
  2652.  
  2653.  
  2654.  
  2655.      The QBNews                                                     Page 43
  2656.  
  2657.