home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / database / baswiz14.zip / BASWIZ.DOC < prev    next >
Text File  |  1990-10-10  |  91KB  |  2,003 lines

  1.                           The BASIC Wizard's Library                    page 1
  2.                           =------------------------=
  3.                                   Version 1.4
  4.  
  5.                BASWIZ  Copyright (c) 1990  Thomas G. Hanlin III
  6.  
  7.  
  8.  
  9. This is BASWIZ, a library of assembly language and BASIC routines for use
  10. with QuickBASIC version 4.5.  Support for other recent versions of the BASIC
  11. compiler is provided with registration.  The BASWIZ collection is copyrighted
  12. and may be distributed only under the following conditions:
  13.  
  14.    1) No fee of over $10.00 may be charged for distribution.  This
  15.       restriction applies only to physical copies and is not meant to
  16.       prevent distribution by telecommunication services.
  17.  
  18.    2) All BASWIZ files must be distributed together in original, unaltered
  19.       form.  This includes BASWIZ.DOC, BASWIZ.LIB, BASWIZ.NEW, BASWIZ.QLB,
  20.       BASWIZ.REF, BIBLIO.TXT, CATALOG.TXT, CREATE.BAT, DEMO.BAS, DEMO.DAT,
  21.       FILES.LST, LIBRARY.TXT, QUESTION.TXT, REGISTER.TXT and TERM.BAS.
  22.  
  23. You use this library at your own risk.  It has been tested by me on my own
  24. computer, but I will not assume any responsibility for any problems which
  25. BASWIZ may cause you.  If you do encounter a problem, please let me know
  26. about it, and I will do my best to verify and repair the error.
  27.  
  28. It is expected that if you find BASWIZ useful, you will register your copy.
  29. You may not use BASWIZ routines in programs intended for sale unless you have
  30. registered.  Registration entitles you to receive the latest version of
  31. BASWIZ, complete with full source code in assembly language and BASIC.  The
  32. assembly code is designed for the OPTASM assembler by SLR Systems and will
  33. require modifications if you wish to use it with MASM or TASM.  You will then
  34. be able to compile the BASIC code with whatever version of the compiler you
  35. have, allowing you to use BASWIZ with QuickBASIC versions 4.0 - 4.5 and
  36. BASCOM versions 6.0 - 7.1.  Note that Microsoft's "far strings" can't be used
  37. with BASWIZ at this time, so BASWIZ can't be used with QBX.
  38.  
  39. Warning: Use of BASWIZ for more than 30 days without registering has been
  40. determined to cause cancer in laboratory animals!  If you use this product,
  41. please do register.
  42.  
  43. For an example of how to set up your program to access the BASWIZ library,
  44. how to LINK the routines, and so forth, take a look at the CREATE.BAT and
  45. DEMO.BAS files.  The LIBRARY.TXT file explains how to use libraries.
  46.  
  47. So who's the BASIC Wizard?  Why, with this library, you will be!  Read this
  48. tome well, for invoking these routines without proper preparation may bring
  49. unexpected results.  Cape and hat (optional) not included.  No assembly
  50. required.
  51.  
  52. NOTE!!!  The Hercules Graphics routines will be expanded and moved into my
  53. GRAFWIZ library as of the next version!  Since GRAFWIZ focuses on graphics,
  54. it is a more appropriate place for the Hercules routines than BASWIZ.  This
  55. will also help keep the size of BASWIZ manageable in the near future.
  56.  
  57.                               Table of Contents                         page 2
  58.  
  59.  
  60.  
  61.  Expression Evaluator .................................................. 3
  62.  
  63.  Far Strings ........................................................... 4
  64.  
  65.  File Handling ......................................................... 6
  66.  
  67.  Hercules Graphics ..................................................... 14
  68.  
  69.  Memory Management and Pointers ........................................ 16
  70.  
  71.  Telecommunications .................................................... 19
  72.  
  73.  Virtual Windowing System .............................................. 25
  74.  
  75.  Just for Kicks ........................................................ 36
  76.  
  77.  Miscellaneous Notes ................................................... 37
  78.  
  79.  Error Codes ........................................................... 38
  80.  
  81.  Troubleshooting ....................................................... 40
  82.  
  83.  History & Philosophy .................................................. 42
  84.  
  85.  Using BASWIZ with PDQ ................................................. 43
  86.  
  87.                              Expression Evaluator                       page 3
  88.  
  89.  
  90.  
  91. The expression evaluator allows you to find the result of an expression
  92. contained in a string.  Normal algebraic precedence is used, e.g. 4+3*5
  93. evaluates to 19.  The usual numeric operators (*, /, +, -, ^) are supported
  94. (multiply, divide, add, subtract, and raise to a power). Use of negative
  95. numbers is just fine, of course.  Parentheses for overriding the default
  96. order of operations are also supported.
  97.  
  98. To evaluate an expression, you pass it to the evaluator as a string.  You
  99. will get back either an error code or a single-precision result.  Try this
  100. example to see how the expression evaluator works:
  101.  
  102.    REM $INCLUDE: 'BASWIZ.BI'
  103.    DEFINT A-Z
  104.    DO
  105.       INPUT "Expression? "; Expr$
  106.       IF LEN(Expr$) THEN
  107.          Evaluate Expr$, Result!, ErrCode
  108.          IF ErrCode THEN
  109.             PRINT "Invalid expression.  Error code = "; ErrCode
  110.          ELSE
  111.             PRINT "Result: "; Result!
  112.          END IF
  113.       END IF
  114.    LOOP WHILE LEN(Expr$)
  115.    END
  116.  
  117. An expression evaluator adds convenience to any program that needs to accept
  118. numbers.  Why make someone reach for a calculator when number crunching is
  119. what a computer does best?
  120.  
  121.                                  Far Strings                            page 4
  122.  
  123.  
  124.  
  125. One of the best things about BASIC is its support for variable-length
  126. strings.  Few other languages support such dynamically-allocated strings and
  127. they're a terrifically efficient way of using memory.  At least, they would
  128. be, except for one minor limitation... in every version of QuickBASIC and
  129. BASCOM (except for the new, very expensive BASCOM 7.0 "Professional
  130. Development System"), string space is limited to a mere 50K-60K bytes.  As if
  131. this weren't trouble enough, this space is also shared with a number of other
  132. things.  Running out of string space is a common and painful problem.
  133.  
  134. Anyway, it used to be.  The BASWIZ library comes with an assortment of
  135. routines and functions which allow you to keep variable-length strings
  136. outside of BASIC's tiny string area.  Currently, you may have up to 65,535
  137. far strings of up to 255 characters each, subject to available memory.
  138. Either normal system memory or expanded memory may be used.  Extended memory
  139. can also be used if you have a driver that converts extended memory to
  140. expanded memory.
  141.  
  142. Using far strings works almost the same way as using normal strings.  Rather
  143. than referring to a far string with a string variable name, however, you
  144. refer to it with an integer variable called a "handle".  To create a new far
  145. string, you use a handle of zero.  A new handle will be returned to you which
  146. will identify that string for future reference.
  147.  
  148. Before you use any far strings, you must initialize the far string handler.
  149. When you are done using far strings, you must terminate the far string
  150. handler.  Normally, each of these actions will take place only once in your
  151. program: you initialize at the beginning and terminate at the end.
  152.  
  153. On the next page is an example program that reads a file into an array of far
  154. strings, then displays it.  I'll leave out such niceties as error trapping to
  155. keep the example easy to follow.
  156.  
  157.                                  Far Strings                            page 5
  158.  
  159.  
  160.  
  161.    REM $INCLUDE: 'BASWIZ.BI'
  162.    DEFINT A-Z
  163.    REDIM Text(1 TO 5000)                   ' array for far string handles
  164.    FSInit 0                                ' initialize far string handler
  165.    TextLines = 0
  166.    OPEN "ANYFILE.TXT" FOR INPUT AS #1
  167.    DO UNTIL EOF(1)
  168.       LINE INPUT#1, TextRow$
  169.       Handle = 0                           ' use zero to create new far string
  170.       FSSet Handle, TextRow$               ' set the far string
  171.       TextLines = TextLines + 1
  172.       Text(TextLines) = Handle             ' save the far string handle
  173.    LOOP
  174.    CLOSE
  175.    FOR Row = 1 TO TextLines
  176.       PRINT FSGet$(Text(Row))              ' display a far string
  177.    NEXT
  178.    FSDone                                  ' terminate far string handler
  179.    END
  180.  
  181. If you wanted to change an existing far string, you would specify its
  182. existing handle for FSSet.  The handle of zero is used only to create new far
  183. strings, rather in the manner of using a new variable for the first time.
  184.  
  185. Note the zero after the FSInit call.  That specifies that main system memory
  186. is to be used.  If you would prefer to use expanded memory, use a one
  187. instead.  If EMS memory is not available, BASWIZ will ignore the one and use
  188. main memory instead.
  189.  
  190.                                 File Handling                           page 6
  191.  
  192.  
  193.  
  194. The file handling capabilities of BASIC were improved considerably as of
  195. QuickBASIC 4.0.  A binary mode was added and it became possible to use
  196. structured (TYPE) variables instead of the awkward FIELD-based random access
  197. handling.  Even today, however, BASIC file handling is inefficient for many
  198. tasks.  It requires error trapping to avoid problems like open floppy drive
  199. doors and cannot transfer information in large quantities at a time.
  200.  
  201. The BASWIZ routines provide additional flexibility and power.  They allow you
  202. to access files at as low or high a level as you wish.  Here are some of the
  203. features of BASWIZ file handling:
  204.  
  205.   - File sharing is automatically used if the DOS version is high enough,
  206.     providing convenient network compatibility.
  207.   - Critical errors, like other errors, are detected at any point you find
  208.     convenient via a single function call.
  209.   - Optional input buffers speed up reading from files.
  210.   - Up to 32K of data may be read or written at one time.
  211.   - Files can be flushed to disk to avoid loss due to power outages, etc.
  212.  
  213. Files are not considered to be strongly moded by BASWIZ, although there are a
  214. few limitations on how you can deal with text files as opposed to other kinds
  215. of files.  Reads and writes normally take place sequentially, like the INPUT
  216. and OUTPUT modes allowed by BASIC.  However, you can also do random access by
  217. moving the file pointer to anywhere in the file, just as with the RANDOM and
  218. BINARY modes allowed by BASIC.  These routines place no arbitrary limitations
  219. on the programmer.
  220.  
  221. As with BASIC, files are referred to by a number after they are opened for
  222. access.  Unlike BASIC, the number is returned to you when the file is
  223. successfully opened, rather than being specified by you when you open the
  224. file.  This means that you never have to worry about a file number already
  225. being in use.  We'll refer to the file number as a "file handle" from now on.
  226.  
  227.                                 File Handling                           page 7
  228.  
  229.  
  230.  
  231. Before doing anything else, you must initialize the file handling routines.
  232. This is typically done only once, at the beginning of your program.  The
  233. FInit routine needs to know the number of files you want to deal with.  This
  234. can be up to 15 files, or possibly up to 50 if you are using DOS 3.3 or
  235. higher.  Support for over 15 files has not been tested, since I don't have
  236. DOS 3.3 or higher, so you use that feature at your own risk!  A future
  237. version of BASWIZ will support over 15 open files for DOS 3.0 and above.
  238.  
  239.    FInit Files, ErrCode
  240.  
  241. A file is opened for access like so:
  242.  
  243.    FOpen File$, FMode$, BufferLen, Handle, ErrCode
  244.  
  245. You pass the File$, FMode$, and BufferLen.  The Handle and ErrCode are
  246. returned to you.  The "BufferLen" is the length of the buffer desired for
  247. input.  This must be zero if you want to write to the file.  The filename is
  248. passed in File$, naturally enough.  There is a choice of various modes for
  249. FMode$ and these can be combined to some extent:
  250.  
  251.    A   Append to file      used to add more information to an existing file
  252.    C   Create file         creates a new file
  253.    R   Read access         allows reading (input) from a file
  254.    T   Text mode file      allows text-mode input from a file
  255.    W   Write access        allows writing (output) to a file
  256.  
  257. For the most part, the combinations are self-explanatory.  For instance, it
  258. would be reasonable to open a file for read and write, for create and write,
  259. for append and write, or for read and text.  Text files always require a
  260. buffer.  If you request text access without specifying a buffer, a buffer of
  261. 512 bytes will be provided for you.  If you request create access without
  262. additional parameters, the file will be opened for write by default.
  263.  
  264. You may not use a buffer if you want to write to a file.  This includes text
  265. files, which always use a buffer, as well as binary files.  This is an
  266. artificial limitation which will change in a future version of BASWIZ.  It
  267. exists now to reduce the internal complexity of the routines which write to
  268. the file, so that they do not have to account for any buffering as well as
  269. the current file pointer.  However, writing may be done to a text-type file
  270. if the file was not opened in text mode.  We'll see how that works presently.
  271.  
  272. When you are done using a particular file, you can close it, just as in
  273. ordinary BASIC:
  274.  
  275.    FClose Handle
  276.  
  277. Before your program ends, you should terminate the file handler.  This will
  278. close any open files as well as concluding use of the file routines:
  279.  
  280.    FDone
  281.  
  282.                                 File Handling                           page 8
  283.  
  284.  
  285.  
  286. That covers the basic set-up routines: initialize, open, close, and
  287. terminate.  Of more interest are the routines which actually deal with the
  288. file itself.  These provide assorted read/write services, the ability to get
  289. or set the file read/write pointer, size, time, and date, and the ability to
  290. get or set the error code for a specific file, among other things.  Let's
  291. take a look at the error handler first.
  292.  
  293. The FInit and FOpen routines return an error code directly, since you need to
  294. know immediately if these have failed.  The other file routines do not return
  295. a direct error code, however.  In order to discover whether an error has
  296. occurred, you use the FGetError% function.  This will return an error of zero
  297. if there was no error, or a specific error code (listed at the end of this
  298. manual) if some problem occurred.  The error code will remain the same until
  299. you reset it using FError.  The FError service also allows you to test your
  300. error handler by forcing specific error codes even when everything is fine.
  301.  
  302.    PRINT "Error code: "; FGetError(Handle)
  303.    FError Handle, 0                          ' clear the error code
  304.  
  305. It is recommended that you check for errors after any file routine is used if
  306. there is a chance that your program will be executed on a floppy disk.  These
  307. are particularly prone to user errors (like leaving the drive door open) or
  308. running out of space.  If your program will only run on a hard drive, you may
  309. not need to check as frequently.  It's your choice.  Note that the error code
  310. is not cleared automatically-- use FError to reset the error code to zero if
  311. you determine that it wasn't a "fatal" error.
  312.  
  313. Down to the nitty-gritty... we've seen how to open and close a file, how to
  314. check operations for errors, and so forth.  So how do we actually manipulate
  315. the file?  There are assorted alternatives, depending on how you want to deal
  316. with the file: text reads, text writes, byte-oriented reads and writes, and
  317. block reads and writes, not to mention handling the time, date, size, and
  318. read/write pointer.  We'll start off with the routines which read from a
  319. file.
  320.  
  321. If you opened the file for text access, you must want to read the file a line
  322. at a time.  Each line is assumed to be less than 256 characters and delimited
  323. by a carriage return and linefeed (<CR><LF>, or ^M^L, in normal notation).
  324. In that case, you should use the FReadLn$ function:
  325.  
  326.    St$ = FReadLn$(Handle)
  327.  
  328. A simple program to display a text file directly on the screen might look
  329. something like this in BASIC:
  330.  
  331.    OPEN COMMAND$ FOR INPUT AS #1
  332.    WHILE NOT EOF(1)
  333.       LINE INPUT#1, St$
  334.       PRINT St$
  335.    WEND
  336.    CLOSE #1
  337.  
  338.                                 File Handling                           page 9
  339.  
  340.  
  341.  
  342. The same program using BASWIZ would look something like this:
  343.  
  344.    REM $INCLUDE: 'BASWIZ.BI'
  345.    DEFINT A-Z
  346.    FInit 15, ErrCode
  347.    FOpen COMMAND$, "RT", 0, Handle, ErrCode
  348.    WHILE NOT FEOF(Handle)
  349.       PRINT FReadLn$(Handle)
  350.    WEND
  351.    FDone
  352.  
  353. In either case, we're accepting a command-line parameter which specifies the
  354. name of the file.  In the BASWIZ example, note the use of the FEOF% function,
  355. which tells whether we've gone past the end of the file.  This works like the
  356. EOF function in BASIC.
  357.  
  358. There are two ways of reading from binary files.  You can get the results as
  359. a string of a specified (maximum) length:
  360.  
  361.    St$ = FRead$(Handle, Bytes)
  362.  
  363. In plain BASIC, the same thing might be expressed this way:
  364.  
  365.    St$ = INPUT$(Bytes, FileNumber)
  366.  
  367. The other way of reading from a binary file has no equivalent in BASIC.  It
  368. allows you to read in up to 32K bytes at a time, directly into an array or
  369. TYPEd variable.  You can read the information into anything that doesn't
  370. contain normal strings (the fixed-length string type can be used, though):
  371.  
  372.    Segm = VARSEG(Array(0))
  373.    Offs = VARPTR(Array(0))
  374.    FBlockRead Handle, Segm, Offs, Bytes
  375.  
  376. That would read the specified number of bytes into the array "Array",
  377. starting at array element zero.  You can use any data type, whether single
  378. variable or array, as long as it is not a variable length string.  In other
  379. words, Vbl$ and Vbl$(0) would not work.  If you want to use a string with the
  380. block read, it must be a fixed-length string.  For example:
  381.  
  382.    DIM Vbl AS STRING * 1024
  383.    Segm = VARSEG(Vbl)
  384.    Offs = VARPTR(Vbl)
  385.    FBlockRead Handle, Segm, Offs, Bytes
  386.  
  387. It's a good idea to calculate the Segm and Offs values each time.  These tell
  388. FBlockRead where to store the information it reads.  QuickBASIC may move the
  389. variable around in memory, so VARSEG and VARPTR should be used just before
  390. FBlockRead, to insure that they return current and correct information.
  391.  
  392.                                 File Handling                          page 10
  393.  
  394.  
  395.  
  396. The file output commands are similar.  File output can only be done if there
  397. is no input buffer.  This means that you can't use file output if the file
  398. was opened in text mode, either, since text mode always requires an input
  399. buffer.  That's a limitation that will be removed in a future version of
  400. BASWIZ.  It is possible to do text output on a file that was opened in binary
  401. mode, however.  The limitation just means that you can't open a file for both
  402. reading and writing if you use a buffer (or text mode).
  403.  
  404. To output (write) a string to a file, use this:
  405.  
  406.    FWrite Handle, St$
  407.  
  408. This is like the plain BASIC statement:
  409.  
  410.    PRINT #FileNumber, St$;
  411.  
  412. If you would like the string to be terminated by a carriage return and
  413. linefeed, use this instead:
  414.  
  415.    FWriteLn Handle, St$
  416.  
  417. This is like the plain BASIC statement:
  418.  
  419.    PRINT #FileNumber, St$
  420.  
  421. In BASIC, the difference between the two writes is controlled by whether you
  422. put a semicolon at the end.  With BASWIZ, different routines are used
  423. instead.  FWrite is like PRINT with a semicolon and FWriteLn is like PRINT
  424. without a semicolon.
  425.  
  426. As well as simple string output, you can also output TYPEd variables and
  427. even entire arrays.  This type of output has no corresponding BASIC
  428. instruction, although it's somewhat similar to the file PUT statement.  Up to
  429. 32K can be output at a time:
  430.  
  431.    Segm = VARSEG(Array(0))
  432.    Offs = VARPTR(Array(0))
  433.    FBlockWrite Handle, Segm, Offs, Bytes
  434.  
  435. If you haven't already read the section on FBlockRead, go back a page and
  436. review it.  The same comments apply for FBlockRead: it can handle
  437. fixed-length strings but not old-style strings, and VARSEG/VARPTR should
  438. immediately preceed the block I/O, among other things.
  439.  
  440.                                 File Handling                          page 11
  441.  
  442.  
  443.  
  444. Normally, reads and writes take place sequentially.  If you want to move to a
  445. specific spot in the file, though, that's easy.  You can do it in text mode
  446. or binary mode, whether or not you have a buffer, giving you additional
  447. flexibility over the usual BASIC file handling.  Set the location for the
  448. next read or write like so:
  449.  
  450.    FLocate Handle, Position&
  451.  
  452. The Position& specified will be where the next read or write takes place.  It
  453. starts at one and (since it's specified as a LONG integer) can go up to
  454. however many bytes are in the file.  If you want a record position rather
  455. than a byte position, you can do that too.  Just convert the record number to
  456. a byte number, like so:
  457.  
  458.    Position& = (RecordNumber& - 1&) * RecordLength& + 1&
  459.  
  460. If you do not want to maintain RecordNumber and RecordLength as LONG
  461. integers, convert them to such by using the CLNG() function on them before
  462. doing the calculation.  Otherwise you may get an overflow error in the
  463. calculation, since QuickBASIC will assume that the result will be an integer.
  464.  
  465. You can get the current position of the file read/write pointer too:
  466.  
  467.    Position& = FGetLocate&(Handle)
  468.  
  469. Let's see... we've examined initialization and termination, opening and
  470. closing, reading and writing, and manipulating the file read/write pointer.
  471. What else could there be?  Well, how about checking the size of a file and
  472. getting or setting the file time and date?  Why, sure!  The "get" routines
  473. are pretty well self-explanatory:
  474.  
  475.    FileSize& = FGetSize&(Handle)
  476.    FileTime$ = FGetTime$(Handle)
  477.    FileDate$ = FGetDate$(Handle)
  478.  
  479. Setting the time and date is equally easy.  This should be done just before
  480. you close the file with FClose or FDone.  You may use any date and time
  481. delimiters you choose.  If a field is left blank, the appropriate value from
  482. the current time or date will be used.  Years may be specified in four-digit
  483. or two-digit format.  Two-digit years will be assumed to be in the 20th
  484. century ("90" == "1990").  Careful there!  Your program should allow
  485. four-digit dates to be used or disaster will strike when the year 2000
  486. rolls around.  The 21st century is closer than you think!
  487.  
  488.    FTime Handle, FileTime$
  489.    FDate Handle, FileDate$
  490.  
  491.                                 File Handling                          page 12
  492.  
  493.  
  494.  
  495. There's just one more file routine.  It allows you to "flush" a file to disk.
  496. This insures that the file has been properly updated to the current point, so
  497. nothing will be lost if there is a power outage or similar problem.  If you
  498. do not use the "flush" routine, data may be lost if the program terminates
  499. unexpectedly (without going through FClose or FDone).  Note that use of
  500. FFlush requires that a free file handle be available, under most DOS versions.
  501.  
  502.    FFlush Handle
  503.  
  504. That's it for the BASWIZ file handler.  As a quick review, let's run through
  505. the available routines, then try a couple of example programs.  Remember that
  506. the BASWIZ.REF file contains a brief reference for all of these routines too!
  507. You might also wish to examine the DEMO.BAS program, which also makes use of
  508. the file routines.
  509.  
  510. FInit         initialize the file handler
  511. FDone         terminate the file handler and close any open files
  512.  
  513. FOpen         open a file for access (like OPEN)
  514. FClose        close a file (like CLOSE)
  515.  
  516. FRead$        read a string from a binary file (like INPUT$)
  517. FReadLn$      read a string from a text file (like LINE INPUT)
  518. FBlockRead    read an item (TYPE, STRING*##, or array) from a binary file
  519.  
  520. FWrite        write a string to a binary file
  521. FWriteLn      write a string with a <CR><LF> to a binary file
  522. FBlockWrite   write an item (TYPE, STRING*##, or array) to a binary file
  523.  
  524. FLocate       set the read/write pointer to a specified position
  525. FTime         set the time stamp
  526. FDate         set the date stamp
  527. FError        set the error code
  528.  
  529. FGetLocate&   get the read/write pointer
  530. FGetTime$     get the time stamp
  531. FGetDate$     get the date stamp
  532. FGetError     get the error code
  533.  
  534. FFlush        flush to disk (makes sure file is updated and current)
  535. FGetSize&     get size
  536. FEOF          determine whether the end of the file has been reached
  537.  
  538.                                 File Handling                          page 13
  539.  
  540.  
  541.  
  542. So much for theory.  Let's try something practical.  A common problem is
  543. copying one file to another.  We'll limit this to text files, so we can do it
  544. in both plain BASIC and with BASWIZ.  Although BASWIZ can handle any type of
  545. file readily, BASIC has problems in efficiently handling variable-length
  546. binary files.  So, we'll do this first in BASIC, then BASWIZ, for text files.
  547.  
  548. In BASIC, a text-file copying program might look like this:
  549.  
  550.    INPUT "File to copy"; FromFile$
  551.    INPUT "Copy file to"; ToFile$
  552.    OPEN FromFile$ FOR INPUT AS #1
  553.    OPEN ToFile$ FOR OUTPUT AS #2
  554.    WHILE NOT EOF(1)
  555.       LINE INPUT#1, St$
  556.       PRINT#2, St$
  557.    WEND
  558.    CLOSE
  559.  
  560. With BASWIZ, the same program would look more like this:
  561.  
  562.    REM $INCLUDE: 'BASWIZ.BI'
  563.    DEFINT A-Z
  564.    INPUT "File to copy"; FromFile$
  565.    INPUT "Copy file to"; ToFile$
  566.    FInit 15, ErrCode
  567.    FOpen FromFile$, "RT", 1024, FromHandle, ErrCode
  568.    FOpen ToFile$, "CW", 0, ToHandle, ErrCode
  569.    FileTime$ = FGetTime$(FromHandle)
  570.    FileDate$ = FGetDate$(FromHandle)
  571.    WHILE NOT FEOF(FromHandle)
  572.       WriteLn ToHandle, ReadLn$(FromHandle)
  573.    WEND
  574.    FTime ToHandle, FileTime$
  575.    FDate ToHandle, FileDate$
  576.    FDone
  577.  
  578. You might have noticed that the BASWIZ version of the program is a bit longer
  579. than the plain BASIC version.  It has a number of advantages, however.  It's
  580. faster, produces smaller code under ordinary circumstances, and also
  581. preserves the date and time of the original file in the copied file.  Unlike
  582. BASIC, the BASWIZ routines do not automatically add a ^Z to the end of text
  583. files, so the BASWIZ example will not alter the original file.
  584.  
  585.                               Hercules Graphics                        page 14
  586.  
  587.  
  588.  
  589. Even in this age of super VGA displays, there are still many people using
  590. monochrome systems.  After all, they're extremely inexpensive and are
  591. adequate for many purposes.  As an alternative graphics standard, the
  592. Hercules monochrome adapter is quite popular.
  593.  
  594. Curiously enough, QuickBASIC provides only indirect support for the Hercules
  595. through a TSR.  The BASWIZ library allows you to dispense with this TSR and
  596. to take advantage of the full resolution of the Hercules.  Rather than
  597. attempt to emulate 25x80 text mode and get the bottom row truncated, as
  598. QuickBASIC does, BASWIZ provides a handy 43x90 text mode which makes the best
  599. use of the Herc's capabilities.
  600.  
  601. The first thing you need to do in order to use these Hercules routines is to
  602. put the display into graphics mode.  That's done like so:
  603.  
  604.    HGMode 1
  605.  
  606. When you are done, you do the same thing, but with a zero instead of a one.
  607. That puts the display back into text mode, which is important.  The computer
  608. does not know how to handle Hercules graphics mode by itself (I'm afraid IBM
  609. snubbed this poor adapter!) and will display only garbage otherwise.  Any
  610. time you want to display something, use the routines provided here.  The
  611. normal PRINT statement will do you no good in Hercules graphics mode.
  612.  
  613. Since we can't rely on the usual BASIC display statements, we need to have
  614. replacements for them.  As a matter of fact, the following routines are not
  615. merely replacements but extensions to BASIC's display capabilities.  They are
  616. for use in Hercules graphics mode only.
  617.  
  618. To start off with, let's check out the replacements for LOCATE, COLOR, CLS
  619. and PRINT:
  620.  
  621.    HGCls
  622.    HGColor Fore, Back
  623.    HGLocate Row, Column
  624.    HGWrite St$
  625.    HGWriteLn St$
  626.  
  627. Pretty straightforward, isn't it?  The legal colors are 0 (black) and 1
  628. (white, or actually green or amber depending on your display).  Valid rows
  629. are 1-43 and valid columns are 1-90.  Note that the range of rows is the same
  630. as an EGA or VGA allows!
  631.  
  632. Don't forget to put the display back into text mode before your program
  633. exits!  You'll get really funny looking screens otherwise.
  634.  
  635.    HGMode 0
  636.  
  637.                            Hercules Display Adapter                    page 15
  638.  
  639.  
  640.  
  641. The HGWrite and HGWriteLn routines deserve a bit of additional explanation.
  642. HGWrite is like PRINT with a semicolon-- the cursor is not moved down a line
  643. after the string is printed.  HGWriteLn is like PRINT without a semicolon.
  644. Both of these routines use standard ASCII control codes rather than the
  645. idiosyncratic interpretation offered by QuickBASIC.  This means that CHR$(13)
  646. homes the cursor to the start of the line, CHR$(10) moves the cursor directly
  647. down one line without homing it, and CHR$(8) does a backspace.  Other
  648. supported control codes include bell (CHR$(7)), tab (CHR$(9)), and formfeed
  649. (CHR$(12)).  The latter is interpreted as meaning "clear screen", which is
  650. the usual way of handling it on display-based systems.
  651.  
  652. If you need to print a number rather than a string, you can do that too.
  653. Just convert the number to a string using the STR$ function provided by
  654. BASIC.
  655.  
  656. Suppose you want to get the current colors or cursor position?  That's
  657. handled by these routines:
  658.  
  659.    HGGetColor Fore, Back
  660.    HGGetLocate Fore, Back
  661.  
  662. Last but not least, there are two graphics routines.  Graphics mode wouldn't
  663. be much fun without graphics, now would it...
  664.  
  665.    HGPlot Column, Row, Colour
  666.    HGLine Column1, Row1, Column2, Row2, Colour
  667.  
  668. As you might have noticed, the coordinates are in (Column, Row) order as is
  669. appropriate for graphics mode, rather than the (Row, Column) used by text
  670. mode.  Why does the convention change like this?  Well, probably not even
  671. Microsoft can answer that any more!  It's just the way it works.
  672.  
  673. Graphics mode coordinates may range 0-719 (columns) and 0-347 (rows).  The
  674. color range is the same as for text, i.e., 0-1.
  675.  
  676.                         Memory Management and Pointers                 page 16
  677.  
  678.  
  679.  
  680. On the whole, BASIC is easily a match for any other language, as far as
  681. general-purpose programming goes.  There is one major lack, however-- a set
  682. of valuable features that is supported by most other languages, but was
  683. inexplicably left out of BASIC.  Perhaps Microsoft felt it was too advanced
  684. and dangerous for a so-called "beginner's" language.  In truth, using
  685. pointers and memory management takes a little understanding of what you're
  686. doing-- the compiler can't protect you from all of your mistakes.  However,
  687. they can be extraordinarily useful for many things, so I have added these
  688. capabilities to BASWIZ.
  689.  
  690. A "pointer" is essentially just the address of an item.  It is useful in two
  691. respects: it allows you to pass just the pointer, rather than the whole item
  692. (be it a TYPEd variable, normal variable, entire array, or whatever) to a
  693. subprogram.  This is faster and more memory-efficient than the alternatives.
  694. Secondly, a pointer combined with memory management allows you to allocate
  695. and deallocate memory "on the fly", in just the amount you need.  You don't
  696. have to worry about DIMensioning an array too large or too small, or even
  697. with how large each element of the array should be, for example.  You can
  698. determine that when your program -runs-, rather than at compile time, and set
  699. up your data structures accordingly.  You can also create a large variety of
  700. data structures, such as trees and linked lists, which would be difficult and
  701. cumbersome to emulate using BASIC alone.
  702.  
  703. The BASWIZ memory/pointer routines allow you to allocate and deallocate
  704. memory, fill, copy or move a block of memory, get or put a single character
  705. according to a pointer, and convert back and forth between a segment/offset
  706. address and a pointer.
  707.  
  708. Pointers are kept in LONG integers, using an absolute memory addressing
  709. scheme.  This means that you can manipulate pointers just like any ordinary
  710. LONG integer, e.g. to move to the next memory address, just add one.  Since
  711. you can convert from a segment/offset address to a pointer and you can copy
  712. information from one pointer to another, you can move information back and
  713. forth between allocated memory and a TYPEd variable, numeric variable, or
  714. array.  You can even do things like set a pointer to screen memory and
  715. transfer the screen into a variable or vice versa!  Or implement your own
  716. "far string" routines, heirarchical evaluations, or any number of other
  717. things.  Pointers are incredibly powerful!
  718.  
  719. Note that there are different ways of representing the same segment/offset
  720. address, but only one absolute pointer representation.  If you need to
  721. compare two addresses, using pointers is terrific.  However, it's good to
  722. keep in mind that an segment/offset address may -appear- to change if you
  723. convert it to a pointer and then back to a segment/offset address.  When you
  724. convert from a pointer to a segment/offset, the segment will be maximized and
  725. the offset minimized.
  726.  
  727. Although the byte count for these routines is handled through a LONG integer,
  728. the routines handle a maximum of 65,520 bytes at a time.  In other words, a
  729. pointer can only access a bit less than 64K at a time.  If I get enough
  730. requests to extend this range, I will do so.  Meantime, that's the limit!
  731.  
  732.                         Memory Management and Pointers                 page 17
  733.  
  734.  
  735.  
  736. There are two routines which take care of memory management.  These allow you
  737. to allocate or deallocate memory.  Note that if you allocate too much memory,
  738. QuickBASIC won't have any memory to work with!  Use the BASIC function
  739. "SETMEM" to see how much memory is available before going hog-wild.
  740.  
  741. You can allocate memory like so:
  742.  
  743.    MAllocate Bytes&, Ptr&, ErrCode%
  744.  
  745. If there isn't enough memory available, an error code will be returned.
  746. Otherwise, Ptr& will point to the allocated memory.  Memory is allocated in
  747. chunks of 16 bytes, so there may be some memory wasted if you choose a number
  748. of bytes that isn't evenly divisible by 16.
  749.  
  750. When you are finished with that memory, you can free it up by deallocation:
  751.  
  752.    MDeallocate Ptr&, ErrCode%
  753.  
  754. An error code will be returned if Ptr& doesn't point to previously allocated
  755. memory.
  756.  
  757. In the best of all possible worlds, there would be a third routine which
  758. would allow you to reallocate or resize a block of memory.  However, due to
  759. certain peculiarities of QuickBASIC, I was unable to implement that.  You can
  760. simulate such a thing by allocating a new area of memory of the desired size,
  761. moving an appropriate amount of information from the old block to the new,
  762. and finally deallocating the old block.
  763.  
  764. Once you've allocated memory, you can move any sort of information in or out
  765. of it except normal strings-- fixed-length strings, TYPEd values, arrays, or
  766. numeric values.  To do that, you use BASIC's VARSEG and VARPTR functions on
  767. the variable.  Convert the resulting segment/offset address to a pointer:
  768.  
  769.    TSeg% = VARSEG(Variable)
  770.    TOfs% = VARPTR(Variable)
  771.    VariablePtr& = MJoinPtr&(TSeg%, TOfs%)
  772.  
  773. Moving the information from one pointer to another works like so:
  774.  
  775.    MMove FromPtr&, ToPtr&, Bytes&
  776.  
  777. For STRING or TYPEd values, you can get the number of bytes via the LEN
  778. function.  For numeric values, the following applies:
  779.  
  780.    Type       Bytes per value
  781.    =======    ===============
  782.    INTEGER           2
  783.    LONG              4
  784.    SINGLE            4
  785.    DOUBLE            8
  786.  
  787.                         Memory Management and Pointers                 page 18
  788.  
  789.  
  790.  
  791. The "memory move" (MMove) routine is good for more than just transferring
  792. information between a variable and allocated memory, of course.  Pointers can
  793. refer to any part of memory.  For instance, CGA display memory starts at
  794. segment &HB800, offset 0, and goes on for 4000 bytes in text mode.  That
  795. gives a pointer of &HB8000.  You can transfer from the screen to a variable
  796. or vice versa.  For that matter, you can scroll the screen up, down, left, or
  797. right by using the appropriate pointers.  Add two to the pointer to move it
  798. to the next character or 160 to move it to the next row.  As I said, pointers
  799. have all kinds of applications!  You don't need to worry about overlapping
  800. memory-- if the two pointers, combined with the bytes to move, overlap at
  801. some point, why, the MMove routine takes care of that for you.  It avoids
  802. pointer conflicts.  MMove is a very efficient memory copying routine.
  803.  
  804. Suppose you've got a pointer and would like to convert it back to the
  805. segment/offset address that BASIC understands.  That's no problem:
  806.  
  807.    MSplitPtr Ptr&, TSeg%, TOfs%
  808.  
  809. You might also want to fill an area of memory with a specified byte value,
  810. perhaps making freshly-allocated memory zeroes, for example:
  811.  
  812.    MFill Ptr&, Value%, Bytes&
  813.  
  814. Finally, there may be many occasions when you might want to transfer a single
  815. character.  Rather than going through putting the character into a STRING*1,
  816. getting the VARSEG/VARPTR, and using MJoinPtr&, there is a simpler method:
  817.  
  818.    MPutChr Ptr&, Ch$
  819.    Ch$ = MGetChr$(Ptr&)
  820.  
  821. Hopefully, this will give you some ideas to start with.  I'll expand on the
  822. uses of pointers and give further examples in future versions of BASWIZ.
  823. There are many, many possible uses for such capabilities.  Pointers and
  824. memory management used to be the only real way in which BASIC could be
  825. considered inferior to other popular languages-- that is no more!
  826.  
  827. NOTE:
  828.    QuickBASIC may move its arrays around in memory!  Don't expect the address
  829.    of an array to remain constant while your program is running.  Be sure to
  830.    get the VARSEG/VARPTR for arrays any time you're not sure they're in the
  831.    same location.  Among the things which can cause arrays to move are use of
  832.    DIM, REDIM, or ERASE, and possibly calls to SUBs or FUNCTIONs.  I'm not
  833.    sure if anything else may cause the arrays to move, so be cautious!
  834.  
  835.                               Telecommunications                       page 19
  836.  
  837.  
  838.  
  839. BASIC is unusual among languages in that it comes complete with built-in
  840. telecommunications support.  Unfortunately, that support is somewhat crude.
  841. Amongst other problems, it turns off the DTR when the program SHELLs or ends,
  842. making it difficult to write doors for BBSes or good terminal programs.  It
  843. also requires use of the /E switch for error trapping, since it generates
  844. errors when line noise is encountered, and doesn't provide much control.  It
  845. doesn't even support COM3 and COM4, which have been available for years.
  846.  
  847. BASWIZ rectifies these troubles.  It allows comprehensive control over
  848. communications, includes COM3 and COM4, and doesn't require error trapping.
  849. It won't fiddle with the DTR unless you tell it to do so.  The one limitation
  850. is that you may use only a single comm port at a time.
  851.  
  852. Before you can use communications, you must initialize the communications
  853. handler.  If you didn't have BASWIZ, you would probably use something like:
  854.  
  855.    OPEN "COM1:2400,N,8,1,RS,CS,DS" AS #1
  856.  
  857. With BASWIZ, you do not have to set the speed, parity, and so forth.
  858. Communications will proceed with whatever the current settings are, unless
  859. you choose to specify your own settings.  When you initialize the comm
  860. handler, you specify only the port number (1-4) and the size of the input and
  861. output buffers (1-32,767 bytes):
  862.  
  863.    TCInit Port, InSize, OutSize, ErrCode
  864.  
  865. The size you choose for the buffers should be guided by how your program will
  866. use communications.  Generally, a small output buffer of 128 bytes will be
  867. quite adequate.  You may wish to expand it up to 1,500 bytes or so if you
  868. expect to write file transfer protocols.  For the input buffer, you will want
  869. perhaps 512 bytes for normal use.  For file transfer protocols, perhaps 1,500
  870. bytes would be better.  If a high baud rate is used, or for some other reason
  871. you might not be emptying the buffer frequently, you may wish to expand the
  872. input buffer size to 4,000 bytes or more.
  873.  
  874. When you are done with the telecomm routines, you must terminate them.  In
  875. BASIC, this would be done with something like:
  876.  
  877.    CLOSE #1
  878.  
  879. With the BASWIZ routines, though, you would use this instead:
  880.  
  881.    TCDone
  882.  
  883. The BASWIZ "TCDone" does not drop the DTR, unlike BASIC's "CLOSE".  This
  884. means that the modem will not automatically be told to hang up.  With BASWIZ,
  885. you have complete control over the DTR with the TCDTR routine.  Use a value
  886. of zero to drop the DTR or nonzero to raise the DTR:
  887.  
  888.    TCDTR DTRstate
  889.  
  890.                               Telecommunications                       page 20
  891.  
  892.  
  893.  
  894. You may set the speed of the comm port to any baud rate from 1-65,535.  If
  895. you will be dealing with comm programs that were not written using BASWIZ,
  896. you may wish to restrict that to the more common rates: 300, 1200, 2400,
  897. 4800, 9600, 19200, and 38400.
  898.  
  899.    TCSpeed Baud&
  900.  
  901. The parity, word length, and stop bits can also be specified.  You may use
  902. 1-2 stop bits, 6-8 bit words, and parity settings of None, Even, Odd, Mark,
  903. or Space.  Nearly all BBSes use settings of None, 8 bit words, and 1 stop
  904. bit, although you will sometimes see Even, 7 bit words, and 1 stop bit.  The
  905. other capabilities are provided for dealing with mainframes and other systems
  906. which may require unusual communications parameters.
  907.  
  908. When specifying parity, only the first character in the string is used, and
  909. uppercase/lowercase distinctions are ignored.  Thus, using either "none" or
  910. "N" would specify that no parity is to be used.
  911.  
  912.    TCParms Parity$, WordLength, StopBits
  913.  
  914. If your program needs to be aware of when a carrier is present, it can check
  915. the carrier detect signal from the modem with the TCCarrier function.  This
  916. function returns zero if no carrier is present:
  917.  
  918.    IF TCCarrier THEN
  919.       PRINT "Carrier detected"
  920.    ELSE
  921.       PRINT "No carrier"
  922.    END IF
  923.  
  924. Suppose, though, that you need to know immediately when someone has dropped
  925. the carrier?  It wouldn't be too convenient to have to spot TCCarrier
  926. functions all over your program!  In that case, use the "ON TIMER" facility
  927. provided by BASIC for keeping an eye on things.  It will enable you to check
  928. the carrier at specified intervals and act accordingly.  Here's a brief
  929. framework for writing such code:
  930.  
  931.    ON TIMER(30) GOSUB CarrierCheck
  932.    TIMER ON
  933.    ' ...your program goes here...
  934. CarrierCheck:
  935.    IF TCCarrier THEN              ' if the carrier is present...
  936.       RETURN                      ' ...simply resume where we left off
  937.    ELSE                           ' otherwise...
  938.       RETURN Restart              ' ...return to the "Restart" label
  939.    END IF
  940.  
  941.                               Telecommunications                       page 21
  942.  
  943.  
  944.  
  945. To get a character from the comm port, use the TCInkey$ function:
  946.  
  947.    ch$ = TCInkey$
  948.  
  949. To send a string to the comm port, use TCWrite:
  950.  
  951.    TCWrite St$
  952.  
  953. If you are dealing strictly with text, you may want to have a carriage return
  954. and a linefeed added to the end of the string.  No problem:
  955.  
  956.    TCWriteLn St$
  957.  
  958. Note that the length of the output buffer affects how the TCWrite and
  959. TCWriteLn routines work.  They don't actually send string directly to the
  960. comm port.  Instead, they put the string into the output buffer, and it gets
  961. sent to the comm port whenever the comm port is ready.  If there is not
  962. enough room in the output buffer for the whole string, the TCWrite/TCWriteLn
  963. routines are forced to wait until enough space has been cleared for the
  964. string.  This can delay your program.  You can often avoid this delay simply
  965. by making the output buffer larger.
  966.  
  967. If you'd like to know how many bytes are waiting in the input buffer or
  968. output buffer, there are functions which will tell you:
  969.  
  970.    PRINT "Bytes in input buffer:"; TCInStat
  971.    PRINT "Bytes in output buffer:"; TCOutStat
  972.  
  973. Finally, if you would like to clear the buffers for some reason, you can do
  974. that too.  The following routines clear the buffers, discarding anything
  975. which was waiting in them:
  976.  
  977.    TCFlushIn
  978.    TCFlushOut
  979.  
  980. Don't forget to use TCDone to terminate the comm handler before ending your
  981. program!  If you do, the computer will lock up.  Worse, it may not lock up
  982. immediately, so forgetting TCDone can be very unpleasant.
  983.  
  984.                               Telecommunications                       page 22
  985.  
  986.  
  987.  
  988. Finally, there is a routine which allows you to handle ANSI codes in a
  989. window.  Besides the IBM semi-ANSI display code subset, mock-ANSI music is
  990. allowed.  This routine is designed as a subroutine that you can access via
  991. GOSUB, since there are a number of variables that the routine needs to
  992. maintain that would be a nuisance to pass as parameters, and QuickBASIC
  993. unfortunately can't handle SUBs in $INCLUDE files (so SHARED won't work).
  994. To use it, either include ANSI.BAS directly in your code, or use:
  995.  
  996.    REM $INCLUDE: 'ANSI.BAS'
  997.  
  998. Set St$ to the string to process, set Win% to the handle of the window to
  999. which to display, and set Music% to zero if you don't want sounds or -1 if
  1000. you do want sounds.  Then:
  1001.  
  1002.    GOSUB ANSIprint
  1003.  
  1004. Note that the virtual screen tied to the window must be at least an 80 column
  1005. by 25 row screen, since ANSI expects that size.  You are also advised to have
  1006. an ON ERROR trap if you use ANSIprint with Music% = -1, just in case a "bad"
  1007. music sequence slips through and makes BASIC unhappy.  Check for ERR = 5
  1008. (Illegal Function Call).  I'll add a music handler later to avoid this.
  1009.  
  1010. To get some idea of how these routines all tie together in practice, see the
  1011. TERM.BAS example program.  It provides a simple "dumb terminal" program to
  1012. demonstrate the BASWIZ comm handler.  Several command-line switches are
  1013. allowed:
  1014.    /43     use 43-line mode (EGA and VGA only)
  1015.    /COM2   use COM2
  1016.    /COM3   use COM3
  1017.    /COM4   use COM4
  1018.    /300    use 300 baud
  1019.    /1200   use 1200 baud
  1020.    /QUIET  ignore "ANSI" music
  1021.  
  1022. By default, the TERM.BAS program will use COM1 at 2400 baud with no parity, 8
  1023. bit words and 1 stop bit.  You can exit the program by pressing Alt-X.
  1024.  
  1025.                               Telecommunications                       page 23
  1026.  
  1027.  
  1028.  
  1029. The Xmodem file transfer protocol is currently supported for sending files
  1030. only.  It automatically handles any of the usual variants on the Xmodem
  1031. protocol: 128-byte or 1024-byte blocks, plus checksum or CRC error detection.
  1032. In other words, it is compatible with Xmodem (checksum), Xmodem CRC, and
  1033. Xmodem-1K (single-file Ymodem-like variant).
  1034.  
  1035. There are only two routines which must be used to transfer a file.  The first
  1036. is called once to initialize the transfer.  The second is called repeatedly
  1037. until the transfer is finished or aborted.  Complete status information is
  1038. returned by both routines.  You can ignore most of this information or
  1039. display it any way you please.
  1040.  
  1041. The initialization routine looks like this:
  1042.  
  1043.    StartXmodemSend Handle, Protocol$, Baud$, MaxRec, Record, EstTime$, ErrCode
  1044.  
  1045. Only the first three parameters are passed to the routine.  These are the
  1046. Handle of the file that you wish to send (use FOpen to get the handle) and
  1047. the Protocol$ that you wish to use ("Xmodem" or "Xmodem-1K"), and the current
  1048. Baud$.  On return, you will get an ErrCode if the other computer did not
  1049. respond, or MaxRec (the number of blocks to be sent), Record (the current
  1050. block number), and EstTime$ (an estimate of the time required to complete the
  1051. transfer.  The Protocol$ will have "CHK" or "CRC" added to it to indicate
  1052. whether checksum or CRC error detection is being used, depending on which the
  1053. receiver requested.
  1054.  
  1055. The secondary routine looks like this:
  1056.  
  1057.    XmodemSend Handle, Protocol$, MaxRec, Record, ErrCount, ErrCode
  1058.  
  1059. The ErrCode may be zero (no error), greater than zero (error reading file),
  1060. or less than zero (file transfer error, completion or abort).  See the
  1061. appendix on Error Codes for specific details.  The TERM.BAS example program
  1062. shows how these routines work together in practice.
  1063.  
  1064. The file accessed by the Xmodem routine will remain open.  Remember to close
  1065. it when the transfer is done (for whatever reason), using the FClose routine.
  1066.  
  1067.                               Telecommunications                       page 24
  1068.  
  1069.  
  1070.  
  1071. A few notes on the ins and outs of telecommunications...
  1072.  
  1073. The DTR signal is frequently used to control the modem.  When the DTR is
  1074. "raised" or "high", the modem knows that we're ready to do something.  When
  1075. the DTR is "dropped" or "low", the modem knows that we're not going to do
  1076. anything.  In most cases, this tells it to hang up or disconnect the phone
  1077. line.  Some modems may be set to ignore the DTR, in which case it will not
  1078. disconnect when the DTR is dropped.  Usually this can be fixed by changing a
  1079. switch on the modem.  On some modems, a short software command may suffice.
  1080.  
  1081. The DTR is generally the best way to disconnect.  The Hayes "ATH" command is
  1082. supposed to hang up, but it doesn't work very well.
  1083.  
  1084. The BASWIZ comm handler makes sure the DTR is raised when TCInit is used.  It
  1085. does not automatically drop the DTR when TCDone is used, so you can keep the
  1086. line connected in case another program wants to use it.  If this is not
  1087. suitable, just use TCDTR to drop the DTR.  Your program must always use
  1088. TCDone before it exits, but it need only drop the DTR if you want it that
  1089. way.
  1090.  
  1091. If you want to execute another program via SHELL, it is ok to leave
  1092. communications running as long as control will return to your program when
  1093. the SHELLed program is done.  In that case, the input buffer will continue to
  1094. receive characters from the comm port unless the SHELLed program provides
  1095. its own comm support.  The output buffer will likewise continue to transmit
  1096. characters unless overruled.
  1097.  
  1098. An assortment of file transfer protocols will be provided in future versions
  1099. of BASWIZ.  Among the ones supported will be Xmodem, Xmodem-1K, Ymodem
  1100. (batch), and Modem7 (batch).  I do not expect to support Kermit or Zmodem,
  1101. since they are unduly complicated.  You can handle any file transfer protocol
  1102. you like by SHELLing to an external protocol program, or of course you can
  1103. write your own support code.
  1104.  
  1105.                          The Virtual Windowing System                  page 25
  1106.  
  1107.  
  1108.  
  1109. The virtual windowing system offers pop-up and collapsing windows, yes... but
  1110. that is just a small fraction of what it provides.  When you create a window,
  1111. the part that you see on the screen may be only a view port on a much larger
  1112. window, called a virtual screen.  You can make virtual screens of up to 255
  1113. rows long or 255 columns wide.  The only limitation is that any single
  1114. virtual screen must take up less than 65,520 bytes.  Each virtual screen is
  1115. treated much like the normal screen display, with simple replacements for the
  1116. standard PRINT, LOCATE, and COLOR commands.  Many other commands are provided
  1117. for additional flexibility.  The window on the virtual screen may be moved,
  1118. resized, or requested to display a different portion of the virtual screen.
  1119. If you like, you may choose to display a frame and/or title around a window.
  1120. When you open a new window, any windows under it are still there and can
  1121. still be updated-- nothing is ever destroyed unless you want it that way!
  1122. With the virtual windowing system, you get a tremendous amount of control for
  1123. a very little bit of work.
  1124.  
  1125. The current version of the virtual windowing system only allows text mode
  1126. screens to be used.  All standard text modes are supported, however.  This
  1127. includes 25x40 CGA screens, the standard 25x80 screen, and longer screens
  1128. such as the 43x80 EGA screen.  The virtual windowing system is designed for
  1129. computers that offer hardware-level compatibility with the IBM PC, which
  1130. includes almost all MS-DOS/PC-DOS computers in use today.
  1131.  
  1132. Note that certain old and inexpensive CGAs may flicker noticeably when the
  1133. virtual windowing system updates the display.  If the performance penalty is
  1134. acceptable, this will be remedied in a future version.
  1135.  
  1136.  
  1137.  
  1138. Terminology:
  1139. -----------
  1140.  
  1141. DISPLAY
  1142.    The actual screen.
  1143.  
  1144. SHADOW SCREEN
  1145.    This is a screen kept in memory which reflects any changes you make to
  1146.    windows.  Rather than making changes directly on the actual screen, the
  1147.    virtual windowing system works with a "shadow screen" for increased speed
  1148.    and flexibility.  You specify when to update the display from the shadow
  1149.    screen.  This makes any changes appear very smoothly.
  1150.  
  1151. VIRTUAL SCREEN
  1152.    This is a screen kept in memory which can be treated much like the actual
  1153.    screen.  You may choose to make a virtual screen any reasonable size.
  1154.    Every virtual screen will have a corresponding window.
  1155.  
  1156. WINDOW
  1157.    This is the part of a virtual screen which is actually displayed.  You
  1158.    might think of a window as a "view port" on a virtual screen.  A window
  1159.    may be smaller than its virtual screen or the same size.  It may have a
  1160.    frame or a title and can be moved or resized.
  1161.  
  1162.                          The Virtual Windowing System                  page 26
  1163.  
  1164.  
  1165.  
  1166. Frankly, the virtual windowing system is one of those things that's more
  1167. difficult to explain than to use.  It's very easy to use, as a matter of
  1168. fact, but the basic concepts will need a little explanation.  Rather than
  1169. launching into a tedious and long-winded description of the system, I'm
  1170. going to take a more tutorial approach, giving examples and explaining as I
  1171. go along.  Take a look at the DEMO.BAS program for additional insights.
  1172.  
  1173. Let's begin with the simplest possible scenario, where only a background
  1174. window is created.  This looks just like a normal screen.
  1175.  
  1176.    REM $INCLUDE: 'BASWIZ.BI'
  1177.    DEFINT A-Z
  1178.    Rows = 25: Columns = 80                         ' define display size
  1179.    WInit Rows, Columns, ErrCode                    ' initialize window system
  1180.    IF ErrCode THEN                                 ' stop if we couldn't...
  1181.       PRINT "Insufficient memory"
  1182.       END
  1183.    END IF
  1184.    Handle = 0                                      ' use background handle
  1185.    WWriteLn Handle, "This is going to be displayed on the background window."
  1186.    WWriteLn Handle, "Right now, that's the full screen."
  1187.    WUpdate                                         ' update the display
  1188.    WDone                                           ' terminate window system
  1189.  
  1190. What we just did was to display two lines on the screen-- nothing at all
  1191. fancy, but it gives you the general idea of how things work.  Let's take a
  1192. closer look at what the program does:
  1193.  
  1194.   - We INCLUDE the BASWIZ.BI definition file to let QuickBASIC know that
  1195.     we'll be using the BASWIZ routines.
  1196.  
  1197.   - We define the size of the display using the integer variables Rows and
  1198.     Columns (you can use any variable names you want).  If you have an EGA
  1199.     display and had previously used WIDTH ,43 to go into 43x80 mode, you'd
  1200.     use "Rows = 43" here, for example.
  1201.  
  1202.   - We initialize the windowing system with WInit, telling it how large the
  1203.     display is.  It returns an error code if it is unable to initialize.
  1204.  
  1205.   - We define the Handle of the window that we want to use.  The "background
  1206.     window" is always available as handle zero, so we choose "Handle = 0".
  1207.  
  1208.   - We print two strings to the background window with WWriteLn, which is
  1209.     like a PRINT without a semicolon on the end (it moves to the next line).
  1210.  
  1211.   - At this point, only the shadow screen has been updated.  We're ready to
  1212.     display the information, so we use WUpdate to update the actual screen.
  1213.  
  1214.   - We're all done with the program, so we finish up with WDone.
  1215.  
  1216.                          The Virtual Windowing System                  page 27
  1217.  
  1218.  
  1219.  
  1220. See, there's nothing to it!  We initialize the screen, print to it or
  1221. whatever else we need to do, tell the windowing system to update the display,
  1222. and when the program is done, we close up shop.
  1223.  
  1224. The background screen is always available.  It might help to think of it as a
  1225. virtual screen that's the size of the display.  The window on this virtual
  1226. screen is exactly the same size, so the entire virtual screen is displayed.
  1227. As with other virtual screens, you can print to it without disturbing
  1228. anything else.  That means you can treat the background screen the same way
  1229. regardless of whether it has other windows on top of it-- the other windows
  1230. just "cover" the background information, which will still be there.
  1231.  
  1232. This leads us to the topic of creating windows.  Both a virtual screen and a
  1233. window are created simultaneously-- remember, a window is just a view port on
  1234. a virtual screen.  The window can be the same size as the virtual screen, in
  1235. which case the entire virtual screen is visible (as with the background
  1236. window) or it can be smaller than the virtual screen, in which case just a
  1237. portion of the virtual screen will be visible.
  1238.  
  1239. A window is created like so:
  1240.  
  1241.    ' This is a partial program and can be inserted in the original example
  1242.    ' after the second WWriteLn statement...
  1243.    VRows = 43: VColumns = 80                       ' define virtual screen size
  1244.    WOpen VRows, VColumns, 1, 1, Rows, Columns, Handle, ErrCode ' create window
  1245.    IF ErrCode THEN                                 ' error if we couldn't...
  1246.       PRINT "Insufficient memory available"
  1247.       WDone                                        ' (or use an error handler)
  1248.       END
  1249.    END IF
  1250.  
  1251. What we have done here is to create a virtual screen of 43 rows by 80
  1252. columns.  The window will be the size of the display, so if you are in the
  1253. normal 25x80 mode, only the first 25 rows of the virtual screen will be
  1254. visible.  If you have an EGA or VGA in 43x80 mode, though, the entire virtual
  1255. screen will be visible!  So, this window lets you treat a screen the same way
  1256. regardless of the display size.
  1257.  
  1258. The Handle returned is used any time you want to print to this new window or
  1259. otherwise deal with it.  If you are using many windows, you might want to
  1260. keep an array of handles, to make it easier to keep track of which is which.
  1261.  
  1262. By default, a virtual screen is created with the following attributes:
  1263.  
  1264.   - The cursor is at (1,1), the upper left corner of the virtual screen.
  1265.   - The cursor size is 0 (invisible).
  1266.   - The text color is 7,0 (white foreground on a black background).
  1267.   - There is no title or frame.
  1268.   - The window starts at (1,1) in the virtual screen, which displays the
  1269.     area starting at the upper left corner of the virtual screen.
  1270.  
  1271.                          The Virtual Windowing System                  page 28
  1272.  
  1273.  
  1274.  
  1275. When you create a new window, it becomes the "top" window, and will be
  1276. displayed on top of any other windows that are in the same part of the
  1277. screen.  Remember, you can print to a window or otherwise deal with it, even
  1278. if it's only partially visible or entirely covered by other windows.
  1279.  
  1280. Don't forget WUpdate!  None of your changes are actually displayed until
  1281. WUpdate is used.  You can make as many changes as you like before calling
  1282. WUpdate, which will display the results smoothly and at lightning speed.
  1283.  
  1284. We've created a window which is exactly the size of the display, but which
  1285. might well be smaller than its virtual screen.  Let's assume that the normal
  1286. 25x80 display is being used, in which case our virtual screen (43x80) is
  1287. larger than the window.  We can still print to the virtual screen normally,
  1288. but if we print below line 25, the results won't be displayed.  What a
  1289. predicament!  How do we fix this?
  1290.  
  1291. The window is allowed to start at any given location in the virtual screen,
  1292. so if we want to see a different portion of the virtual screen, all we have
  1293. to do is tell the window to start somewhere else.  When the window is
  1294. created, it starts at the beginning of the virtual screen, coordinate (1,1).
  1295. The WView routine allows us to change this.
  1296.  
  1297. In our example, we're displaying a 43x80 virtual screen in a 25x80 window.
  1298. To begin with, then, rows 1-25 of the virtual screen are visible.  To make
  1299. rows 2-26 of the virtual screen visible, we simply do this:
  1300.  
  1301.    WView Handle, 2, 1
  1302.  
  1303. That tells the window to start at row 2, column 1 in the virtual screen.
  1304. Sounds easy enough, doesn't it?  Well, if not, don't despair.  Play with it
  1305. in the QuickBASIC environment a little until you get the hang of it.
  1306.  
  1307. You've noticed that the window doesn't need to be the same size as the
  1308. virtual screen.  Suppose we don't want it the same size as the display,
  1309. either... suppose we want it in a nice box, sitting out of the way in a
  1310. corner of the display?  Well, we could have created it that way to begin with
  1311. when we used WOpen.  Since we've already created it, though, let's take a
  1312. look at the routines to change the size of a window and to move it elsewhere.
  1313. The window can be made as small as 1x1 or as large as its virtual screen, and
  1314. it can be moved anywhere on the display you want it.
  1315.  
  1316. Let's make the window a convenient 10 rows by 20 columns:
  1317.  
  1318.    WSize Handle, 10, 20
  1319.  
  1320. And move it into the lower right corner of the display:
  1321.  
  1322.    WPlace Handle, 12, 55
  1323.  
  1324.                          The Virtual Windowing System                  page 29
  1325.  
  1326.  
  1327.  
  1328. Don't forget to call WUpdate or the changes won't be visible!  Note also that
  1329. we didn't really lose any text.  The virtual screen, which holds all the
  1330. text, is still there.  We've just changed the size and position of the
  1331. window, which is the part of the virtual screen that we see, so less of the
  1332. text (if there is any!) is visible.  If we made the window larger again, the
  1333. text in the window would expand accordingly.
  1334.  
  1335. If you were paying close attention, you noticed that we didn't place the
  1336. resized window flush against the corner of the display.  We left a little bit
  1337. of room so we can add a frame and a title.  Let's proceed to do just that.
  1338.  
  1339. Window frames are displayed around the outside of a window and will not be
  1340. displayed unless there is room to do so.  We have four different types of
  1341. standard frames available:
  1342.  
  1343.    0   (no frame)
  1344.    1   single lines
  1345.    2   double lines
  1346.    3   single horizontal lines, double vertical lines
  1347.    4   single vertical lines, double horizontal lines
  1348.  
  1349. We must also choose the colors for the frame.  It usually looks best if the
  1350. background color is the same background color as used by the virtual screen.
  1351. Let's go ahead and create a double-line frame in bright white on black:
  1352.  
  1353.    FType = 2: Fore = 15: Back = 0
  1354.    WFrame Handle, FType, Fore, Back
  1355.  
  1356. If you'd rather not use the default frame types, there's ample room to get
  1357. creative!  Frames 5-9 can be defined any way you please.  They are null by
  1358. default.  To create a new frame type, you must specify the eight characters
  1359. needed to make the frame: upper left corner, upper middle columns, upper
  1360. right corner, left middle rows, right middle rows, lower left corner, lower
  1361. middle columns, and lower right corner.
  1362.  
  1363.    +----------------------------------------+
  1364.    |  Want a plain text frame like this?    |
  1365.    |  Use the definition string "+-+||+-+"  |
  1366.    +----------------------------------------+
  1367.  
  1368. The above window frame would be defined something like this:
  1369.  
  1370.    Frame = 5
  1371.    FrameInfo$ = "+-+||+-+"
  1372.    WUserFrame Frame, FrameInfo$
  1373.  
  1374. Of course, you can choose any values you like.  As always, the names of the
  1375. variables can be anything, as long as you name them consistently within your
  1376. program.  You can even use constants if you prefer:
  1377.  
  1378.    WUserFrame 5, "+-+||+_+"
  1379.  
  1380.                          The Virtual Windowing System                  page 30
  1381.  
  1382.  
  1383.  
  1384. We can have a title regardless of whether a frame is present or not.  Like
  1385. the frame, the title is displayed only if there is enough room for it.  If
  1386. the window is too small to accommodate the full title, only the part of the
  1387. title that fits will be displayed.  The maximum length of a title is 70
  1388. characters.  Titles have their own colors.
  1389.  
  1390.    Title$ = "Wonderful Window!"
  1391.    Fore = 0: Back = 7
  1392.    WTitle Handle, Title$, Fore, Back
  1393.  
  1394. To get rid of a title, just use a null title string (Title$ = "").
  1395.  
  1396. There are only a few more ways of dealing with windows themselves.  After
  1397. that, I'll explain the different things you can do with text in windows and
  1398. how to get information about a specific window or virtual screen.
  1399.  
  1400. If you have a lot of windows, one window may be on top of another, obscuring
  1401. part or all of the window(s) below.  In order to make sure a window is
  1402. visible, all you need to do is to put it on top, right?  Hey, is this easy or
  1403. what?!
  1404.  
  1405.    WTop Handle
  1406.  
  1407. Note that the background window will always be the background window.  You
  1408. can't put handle zero, the background window, on top.  What?  You say you
  1409. need to do that?!  Well, that's one of the ways you can use the WCopy
  1410. routine.  WCopy copies one virtual screen to another one of the same size:
  1411.  
  1412.    WCopy FromHandle, ToHandle
  1413.  
  1414. You can copy the background window (or any other window) to another window.
  1415. The new window can be put on top, resized, moved, or otherwise spindled and
  1416. mutilated.  The demo program uses this trick.
  1417.  
  1418. We've been through how to open windows, print to them, resize them and move
  1419. them around, among other things.  We've seen how to put a frame and a title
  1420. on a window and pop it onto the display.  If you're a fan of flashy displays,
  1421. though, you'd probably like to be able to make a window "explode" onto the
  1422. screen or "collapse" off.  It's the little details like that which make a
  1423. program visually exciting and professional-looking.  I wouldn't disappoint
  1424. you by leaving something fun like that out!
  1425.  
  1426. Since we're using a virtual windowing system rather than just a plain ol'
  1427. ordinary window handler, there's an extra benefit.  When a window explodes or
  1428. collapses, it does so complete with its frame, title, and even its text.
  1429. This adds rather nicely to the effect.
  1430.  
  1431.                          The Virtual Windowing System                  page 31
  1432.  
  1433.  
  1434.  
  1435. To "explode" a window, we just set up all its parameters the way we normally
  1436. would-- open the window, add a title or frame if we like, print any text that
  1437. we want displayed, and set the screen position.  Then we use WExplode to zoom
  1438. the window from a tiny box up to its full size:
  1439.  
  1440.    WExplode Handle
  1441.  
  1442. The "collapse" routine works similarly.  It should be used only when you are
  1443. through with a window, because it closes the window when it's done.  The
  1444. window is collapsed from its full size down to a tiny box, then eliminated
  1445. entirely:
  1446.  
  1447.    WCollapse Handle
  1448.  
  1449. Note that WExplode and WCollapse automatically use WUpdate to update the
  1450. display.  You do not need to use WUpdate yourself and you should make sure
  1451. that the screen is the way you want it displayed before you call either
  1452. routine.
  1453.  
  1454. The WCollapse and WExplode routines were written in BASIC, so they'll be easy
  1455. to customize just the way you want them if you register BASWIZ and get the
  1456. source code.  They're not particularly difficult routines, however, so you
  1457. might want to design a set of your own similar routines just for the
  1458. exercise.  All it takes is moving and resizing the windows.
  1459.  
  1460. The great thing about being a programmer is that you can do it your way.
  1461. Hold the pickles, hold the lettuce!  Might be fun to add some sound effects
  1462. to those exploding windows, hmmm?  I'll do that in a later version, but don't
  1463. feel obliged to wait for me!
  1464.  
  1465. That's it for the windows.  We've been through all the "tricky stuff".  There
  1466. are a number of useful things you can do with a virtual screen, though,
  1467. besides printing to it with WWriteLn.  Let's take a look at what we can do.
  1468.  
  1469. WWriteLn is fine if you want to use a "PRINT St$" sort of operation.  Suppose
  1470. you don't want to move to a new line afterward, though?  In BASIC, you'd use
  1471. something like "PRINT St$;" (with a semicolon).  With the virtual windowing
  1472. system, you use WWrite, which is called just like WWriteLn:
  1473.  
  1474.    WWrite Handle, St$
  1475.  
  1476. There are also routines that work like CLS, COLOR and LOCATE:
  1477.  
  1478.    WClear Handle
  1479.    WColor Handle, Fore, Back
  1480.    WLocate Handle, Row, Column
  1481.  
  1482. The WClear routine is not quite like CLS in that it does not affect the
  1483. cursor position.  If you want the cursor "homed", use WLocate.
  1484.  
  1485.                          The Virtual Windowing System                  page 32
  1486.  
  1487.  
  1488.  
  1489. Note that the coordinates for WLocate are based on the virtual screen, not
  1490. the window.  If you move the cursor to a location outside the view port
  1491. provided by the window, it will disappear.  Speaking of disappearing cursors,
  1492. you might have noticed that our WLocate doesn't mimic LOCATE exactly: it
  1493. doesn't provide for controlling the cursor size.  Don't panic!  There's
  1494. another routine available for that:
  1495.  
  1496.    WCursor Handle, CSize
  1497.  
  1498. The CSize value may range from zero (in which case the cursor will be
  1499. invisible) to the maximum size allowed by your display adapter.  This will
  1500. always be at least eight.
  1501.  
  1502. Now, since each virtual screen is treated much like the full display, you may
  1503. be wondering what happens if the cursor is "on" in more than one window.
  1504. Does that mean multiple cursors are displayed?  Well, no.  That would get a
  1505. little confusing!  Only the cursor for the top window is displayed.  If you
  1506. put a different window on top, the cursor for that window will be activated
  1507. and the cursor for the old top window will disappear.  The virtual windowing
  1508. system remembers the cursor information for each window, but it only actually
  1509. displays the cursor for the window that's on top.
  1510.  
  1511. In addition to the usual screen handling, the windowing system provides four
  1512. new capabilities which you may find very handy.  These are routines to insert
  1513. and delete both characters and rows.  This is done at the current cursor
  1514. position within a selected virtual screen:
  1515.  
  1516.    WDelChr Handle
  1517.    WDelLine Handle
  1518.    WInsChr Handle
  1519.    WInsLine Handle
  1520.  
  1521. These routines can also be used for scrolling.  Remember, the display isn't
  1522. updated until you use WUpdate, and then it's updated all at once.  You can
  1523. use any of the routines multiple times and the display will still be updated
  1524. perfectly smoothly-- all the real work goes on behind the scene!
  1525.  
  1526. When you are done with a virtual screen and no longer need it, you can
  1527. dispose of it like so:
  1528.  
  1529.    WClose Handle
  1530.  
  1531. All of the information that can be "set" can also be retrieved.  That's
  1532. useful in general, of course, but it's also a great feature for writing
  1533. portable subprograms.  You can create subprograms that will work with any
  1534. virtual screen, since it can retrieve any information it needs to know about
  1535. the virtual screen or its window.  That's power!
  1536.  
  1537.                          The Virtual Windowing System                  page 33
  1538.  
  1539.  
  1540.  
  1541. Here is a list of the available window data retrieval routines:
  1542.  
  1543.    WGetColor Handle, Fore, Back
  1544.    ' gets the current foreground and background colors
  1545.  
  1546.    WGetCursor Handle, CSize
  1547.    ' gets the cursor size
  1548.  
  1549.    WGetFrame Handle, Frame, Fore, Back
  1550.    ' gets the frame type and frame colors
  1551.  
  1552.    WGetLocate Handle, Row, Column
  1553.    ' gets the cursor position
  1554.  
  1555.    WGetPlace Handle, Row, Column
  1556.    ' gets the starting position of a window on the display
  1557.  
  1558.    WGetSize Handle, Rows, Columns
  1559.    ' gets the size of a window
  1560.  
  1561.    Title$ = SPACE$(70)
  1562.    WGetTitle Handle, Title$, TLen, Fore, Back
  1563.    Title$ = LEFT$(Title$, TLen)
  1564.    ' gets the title string (null if there's no title) and title colors
  1565.  
  1566.    WGetTop Handle
  1567.    ' gets the handle of the top window
  1568.  
  1569.    FrameInfo$ = SPACE$(8)
  1570.    WGetUFrame$ Frame, FrameInfo$
  1571.    ' gets the specification for a given user-defined frame type
  1572.  
  1573.    WGetView Handle, Row, Column
  1574.    ' gets the starting position of a window within a virtual screen
  1575.  
  1576.    WGetVSize Handle, Rows, Columns
  1577.    ' gets the size of a virtual screen
  1578.  
  1579.                          The Virtual Windowing System                  page 34
  1580.  
  1581.  
  1582.  
  1583. As well as displaying information in a window, you will frequently want to
  1584. allow for getting input from the user.  Of course, INKEY$ will still work
  1585. fine, but that's not an effective way of handling more than single
  1586. characters.  The virtual windowing system includes a flexible string input
  1587. routine which is a lot more powerful:
  1588.  
  1589.    WInput Handle, Valid$, ExitCode$, ExtExitCode$, MaxLength, St$, ExitKey$
  1590.  
  1591. The Valid$ variable allows you to specify a list of characters which may be
  1592. entered.  If you use a null string (""), any character will be accepted.
  1593.  
  1594. ExitCode$ specifies the normal keys that can be used to exit input.  You'll
  1595. probably want to use a carriage return, CHR$(13), for this most of the time.
  1596. You can also specify exit on extended key codes like arrow keys and function
  1597. keys via ExtExitCode$.
  1598.  
  1599. MaxLength is the maximum length of the string you want.  Use zero to get the
  1600. longest possible string.  The length may go up to the width of the virtual
  1601. screen, minus one character.  The window will be scrolled sideways as needed
  1602. to accomodate the full length of the string.
  1603.  
  1604. The St$ variable is used to return the entered string, but you can also use
  1605. it to pass a default string to the routine.
  1606.  
  1607. ExitKey$ returns the key that was used to exit input.
  1608.  
  1609. A fairly strong set of editing capabilities is available through WInput.
  1610. The editing keys can be overridden by ExitCode$ or ExtExitCode$, but by
  1611. default they include support for both the cursor keypad and WordStar:
  1612.  
  1613.    Control-S   LeftArrow    move left once
  1614.    Control-D   RightArrow   move right once
  1615.    Control-V   Ins          switch between insert and overstrike modes
  1616.    Control-G   Del          delete current character
  1617.    Control-H   Backspace    destructive backspace
  1618.                Home         move to the start of input
  1619.                End          move to the end of input
  1620.  
  1621.                          The Virtual Windowing System                  page 35
  1622.  
  1623.  
  1624.  
  1625. There are two more routines which allow the virtual windowing system to work
  1626. on a wide variety of displays: WFixColor and WSnow.
  1627.  
  1628. Chances are, as a software developer you have a color display.  However,
  1629. there are many people out there who have monochrome displays, whether due to
  1630. preference, a low budget, or use of notebook-style computers with LCD or
  1631. plasma screens.  WFixColor allows you to develop your programs in color while
  1632. still supporting monochrome systems.  It tells the VWS whether to keep the
  1633. colors as specified or to translate them to their monochrome equivalents:
  1634.  
  1635.    WFixColor Convert%
  1636.  
  1637. Set Convert% to zero if you want true color (default), or to any other value
  1638. if you want the colors to be translated to monochrome.  In the latter case,
  1639. the translation will be done based on the relative brightness of the
  1640. foreground and background colors.  The result is guaranteed to be readable on
  1641. a monochrome system if it's readable on a color system.  You should check the
  1642. results on your system to make sure that such things as highlight bars are
  1643. still appear highlighted, however.
  1644.  
  1645. In the case of some of the older or less carefully designed CGA cards, the
  1646. high-speed displays of the virtual windowing system can cause the display to
  1647. flicker annoyingly.  You can get rid of the flicker at the expense of slowing
  1648. the display:
  1649.  
  1650.    WSnow Remove%
  1651.  
  1652. Set Remove% to zero if there is no problem with "snow" or flickering
  1653. (default), or to any other value if you need "snow removal".  Using snow
  1654. removal will slow down the display substantially, which may be a problem if
  1655. you update (WUpdate) it frequently.
  1656.  
  1657. Note that you can't detect either of these cases automatically with perfect
  1658. reliability.  Not all CGA cards have flicker problems.  Monochrome displays
  1659. may be attached to CGA displays and the computer won't know the difference.
  1660. A VGA with a paper-white monitor may well think it has color, and will mostly
  1661. act like it, but some "color" combinations can be very difficult to read.
  1662. While you can self-configure the program to some extent using the GetDisplay
  1663. routine (see Just for Kicks), you should also provide command-line switches
  1664. so that the user can override your settings.  Microsoft generally uses "/B"
  1665. to denote a monochrome ("black and white") display, so you may want to follow
  1666. that as a standard.  I would suggest "/F" to turn on flicker suppression.
  1667.  
  1668. And that, folks, is all there is to it.  See DEMO.BAS and TERM.BAS for
  1669. working examples.  Also see "Telecommunications" for information about a
  1670. routine which handles ANSI display and music codes; it displays to the window
  1671. of your choice.
  1672.  
  1673.                                 Just for Kicks                         page 36
  1674.  
  1675.  
  1676.  
  1677. There are two more routines that may be of some use to you.  One of 'em lets
  1678. you find out about the active display adapter.  The other tells how much
  1679. expanded (EMS) memory is available.
  1680.  
  1681. To see how much expanded memory is available, use the GetEMS function.  It'll
  1682. return zero if there is no expanded memory installed:
  1683.  
  1684.    PRINT "Kbytes of expanded memory:"; GetEMS
  1685.  
  1686. The GetDisplay routine tells what kind of display adapter is active and
  1687. whether it's hooked up to a color monitor.  The only time it can't detect the
  1688. monitor type is on CGA setups (it assumes "color").  It's a good idea to
  1689. allow a "/B" switch for your program so the user can specify if a monochrome
  1690. monitor is attached to a CGA.
  1691.  
  1692.    GetDisplay Adapter, Mono
  1693.    IF Mono THEN
  1694.       PRINT "Monochrome monitor"
  1695.    ELSE
  1696.       PRINT "Color monitor"
  1697.    END IF
  1698.    SELECT CASE Adapter
  1699.       CASE 1: PRINT "MDA"
  1700.       CASE 2: PRINT "Hercules"
  1701.       CASE 3: PRINT "CGA"
  1702.       CASE 4: PRINT "EGA"
  1703.       CASE 5: PRINT "MCGA"
  1704.       CASE 6: PRINT "VGA"
  1705.    END SELECT
  1706.  
  1707.                              Miscellaneous Notes                       page 37
  1708.  
  1709.  
  1710.  
  1711. Limitations:
  1712.  
  1713.    The virtual windowing system allows up to 16 windows to be open at a time,
  1714.    including the background window, which is opened automatically.  This is
  1715.    subject to available memory, of course.
  1716.  
  1717.    The far string handler allows up to 65,535 strings of up to 255 characters
  1718.    each, subject to available memory.  When the handler needs additional
  1719.    memory for string storage, it allocates more in blocks of 16 Kbytes.  If
  1720.    that much memory is not available, an "out of memory" error will be
  1721.    generated (BASIC error number 7).  You can check the size of the available
  1722.    memory pool using the SETMEM function provided by QuickBASIC.
  1723.  
  1724.    The communications handler only allows one comm port to be used at a time.
  1725.    This will change in a future version of BASWIZ.
  1726.  
  1727.    The file handler does not allow you to combine Write mode with Text mode
  1728.    or input buffering.  This will change in a future version of BASWIZ.
  1729.  
  1730. Errors:
  1731.  
  1732.    All routines are designed to be as bomb-proof as possible.  If you pass an
  1733.    invalid value to a routine which does not return an error code, it will
  1734.    simply ignore the value.
  1735.  
  1736.    It's always possible that a problem has escaped notice.  If you run into
  1737.    something that you believe to be a bug or incompatibility, please tell me
  1738.    about it, whether you've registered BASWIZ or not.
  1739.  
  1740. Feedback:
  1741.  
  1742.    Do you like what you see?  Tell me what you like, what you don't like, and
  1743.    what you'd be interested in seeing in future versions!  Chances are good
  1744.    that I'll use your suggestions.  If you don't speak up, though, I won't
  1745.    know what you're looking for.  You can reach me through U.S. Mail or
  1746.    through several of the international BASIC conferences on BBSes.
  1747.  
  1748.                                  Error Codes                           page 38
  1749.  
  1750.  
  1751.  
  1752. The expression evaluator returns the following error codes:
  1753.  
  1754.    0    No error, everything went fine
  1755.    2    A number was expected but not found
  1756.    4    Unbalanced parentheses
  1757.    8    The expression string had a length of zero
  1758.    9    The expression included an attempt to divide by zero
  1759.  
  1760.  
  1761.  
  1762. The far string handler does not return error codes.  If an invalid string
  1763. handle is specified for FSSet, it will be ignored; if for FSGet, a null
  1764. string will be returned.  If you run out of memory for far strings, an "out
  1765. of memory" error will be generated (BASIC error #7).  You can prevent this by
  1766. checking available memory beforehand with the SETMEM function provided by
  1767. QuickBASIC.  Far string space is allocated as needed in blocks of just over
  1768. 16 Kbytes, or 16,400 bytes to be exact.
  1769.  
  1770.  
  1771.  
  1772. The telecommunications handler returns the following error codes for TCInit:
  1773.  
  1774.    0    No error, everything A-Ok
  1775.    1    The comm handler is already installed (you tried to install it twice)
  1776.    2    Invalid comm port specified
  1777.    3    Not enough memory available for input and output buffers
  1778.  
  1779.  
  1780.  
  1781. The telecommunications handler returns these error codes for XmodemSend:
  1782.  
  1783.  -12    FATAL   : Abort due to excessive errors
  1784.  -11    FATAL   : Abort (by keyboard <ESC> or receiver CANcel request)
  1785.  -10    DONE    : No error, transfer completed ok
  1786.   -5    WARNING : Checksum or CRC error
  1787.   -1    WARNING : Time-out error (the receiver didn't respond)
  1788.    0    WORKING : No error, everything A-Ok
  1789.   >0    ERROR   : Problem reading from the file (see file error codes)
  1790.  
  1791.                                  Error Codes                           page 39
  1792.  
  1793.  
  1794.  
  1795. The file services return the following error codes:
  1796. (The asterisk "*" is used to identify so-called "critical errors")
  1797.  
  1798.    0    No error
  1799.    1    Invalid function number (usually means "invalid parameter(s)")
  1800.    2    File not found
  1801.    3    Path not found
  1802.    4    Too many open files
  1803.    5    Access denied (probably "write to read-only file")
  1804.    6    Invalid file handle
  1805.    7    Memory control blocks destroyed
  1806.    8    Insufficient memory (usually RAM, sometimes disk)
  1807.    9    Incorrect memory pointer specified
  1808.   15    Invalid drive specified
  1809. * 19    Tried to write on a write-protected disk
  1810. * 21    Drive not ready
  1811. * 23    Disk data error
  1812. * 25    Disk seek error
  1813. * 26    Unknown media type
  1814. * 27    Sector not found
  1815. * 28    Printer out of paper
  1816. * 29    Write fault
  1817. * 30    Read fault
  1818. * 31    General failure
  1819.   32    Sharing violation
  1820.   33    Lock violation
  1821. * 34    Invalid disk change
  1822.   36    Sharing buffer overflow
  1823.  
  1824.  
  1825.  
  1826. A "critical error" is one that would normally give you the dreaded prompt:
  1827.  
  1828.    A>bort, R>etry, I>gnore, F>ail?
  1829.  
  1830. Such errors generally require some action on the part of the user.  For
  1831. instance, they may need to close a floppy drive door or replace the paper in
  1832. a printer.  If a critical error occurs on a hard drive, it may indicate a
  1833. problem in the drive hardware or software setup.  In that case, the problem
  1834. may possibly be cleared up by "CHKDSK /F", which should be executed directly
  1835. from the DOS command line (do not execute this by SHELL).
  1836.  
  1837.                                Troubleshooting                         page 40
  1838.  
  1839.  
  1840.  
  1841. Problem:
  1842.    QB says "subprogram not defined".
  1843.  
  1844. Solution:
  1845.    The definition file was not included.  Your program must contain the line
  1846.       REM $INCLUDE: 'BASWIZ.BI'
  1847.    before any executable code in your program.  You should also start
  1848.    QuickBASIC with
  1849.       QB /L BASWIZ
  1850.    so it knows to use the BASWIZ library.
  1851.  
  1852.  
  1853. Problem:
  1854.    LINK says "unresolved external reference".
  1855.  
  1856. Solution:
  1857.    Did you specify BASWIZ as the library when you used LINK?  You should!
  1858.    The BASWIZ.LIB file must be in the current directory or along a path
  1859.    specified by the LIB environment variable (like PATH, but for LIB files).
  1860.  
  1861.  
  1862. Problem:
  1863.    The virtual windowing system doesn't display anything.
  1864.  
  1865. Solution:
  1866.    Perhaps you left out the WUpdate routine?  If so, the shadow screen is not
  1867.    reflected to the actual screen and nothing will appear.  The screen also
  1868.    needs to be in text mode (either no SCREEN statement or SCREEN 0).
  1869.    Finally, only the default "page zero" is supported on color monitors.
  1870.  
  1871.  
  1872. Problem:
  1873.    The virtual windowing system causes the display to flicker.
  1874.  
  1875. Solution:
  1876.    This is a problem with some old CGA setups.  You can cure the problem
  1877.    permanently and speed up your display into the bargain simply by buying a
  1878.    new CGA card (about $35 by mail order).  I'll add an optional anti-flicker
  1879.    switch to a later version of BASWIZ if the performance penalty is not too
  1880.    severe.
  1881.  
  1882.  
  1883. Problem:
  1884.    QuickBASIC doesn't get along with the Hercules display routines.
  1885.  
  1886. Solution:
  1887.    Are you using an adapter which includes Hercules mode along with EGA or
  1888.    VGA mode?  QuickBASIC doesn't like that, since it thinks you'll be using
  1889.    EGA or VGA mode.  Use the stand-alone compiler (BC.EXE) instead of the
  1890.    environment (QB.EXE) and you should be fine.  You might also consider
  1891.    getting a separate Herc adapter and monochrome monitor.  It's possible to
  1892.    combine a Hercules monochrome adapter with a CGA, EGA or VGA.
  1893.  
  1894.                                Troubleshooting                         page 41
  1895.  
  1896.  
  1897.  
  1898. Problem:
  1899.    QB says "out of memory" (or "range out of bounds" on a DIM or REDIM).
  1900.  
  1901. Solution:
  1902.    If you're using the memory management/pointer routines, you've probably
  1903.    allocated too much memory!  You need to leave some for QuickBASIC.  Use
  1904.    the SETMEM function provided by BASIC to determine how much memory is
  1905.    available before allocating memory.  The amount needed by QuickBASIC will
  1906.    depend on your program.  The primary memory-eaters are arrays and
  1907.    recursive subprograms or functions.
  1908.  
  1909.    Many of the BASWIZ routines need to allocate memory, including the virtual
  1910.    window manager, telecommunications handler, and memory management system.
  1911.    Besides checking with SETMEM to make sure there's memory to spare, don't
  1912.    forget to check the error codes returned by these routines to make sure
  1913.    they're working properly!
  1914.  
  1915.                             History and Philosophy                     page 42
  1916.  
  1917.  
  1918.  
  1919. "History," you say.  "Philosophy.  What the heck does that have to do with a
  1920. BASIC library?  Yuck!  Go away and leave me alone!"
  1921.  
  1922. Ok.  This section is not strictly necessary for using BASWIZ.  If you're not
  1923. interested, you can certainly avoid reading this without ill effects.  "Suit
  1924. yourself," he said with a bow and a flourish.
  1925.  
  1926. Still here?  Thank you!  I'll keep it short.
  1927.  
  1928. Back in 'bout 1984 or so, I created ADVBAS, one of the very first assembly
  1929. language libraries for BASIC.  That was for IBM BASCOM 1.0, well before
  1930. QuickBASIC came out. I created the library for my own use and ended up making
  1931. a moderately successful shareware project out of it.
  1932.  
  1933. ADVBAS was designed in bits and pieces that came along whenever I felt like
  1934. adding to the library or needed a new capability.  The routines were designed
  1935. at a low level, with most of the actual work needed to accomplish anything
  1936. useful left to BASIC.  All this resulted in a decent amount of flexibility
  1937. but also a good deal of chaos as new routines provided capabilities that
  1938. overlapped with old routines.  Although I tried to keep the calling sequence
  1939. reasonably standardized, it didn't always work out that way.  Then too, the
  1940. library was designed well before the neat capabilities of QuickBASIC 4.0 came
  1941. into being and couldn't take good advantage of them.
  1942.  
  1943. Second came ProBas, a commercial version of ADVBAS.  ProBas is a vastly more
  1944. powerful superset of the ADVBAS library.  Unfortunately, it suffers from the
  1945. same flaws.  No old routines can be discarded or even modified if at all
  1946. possible, to provide compatibility from one version to the next.  The lack of
  1947. thought inherent in the original design caused a mad proliferation of
  1948. routines, many overlapping, most still low-level and hard to use.  At version
  1949. 4.0, there are over 500 (or is it 600?!) different routines-- something for
  1950. everyone, to be sure, but tending towards complete pandemonium.
  1951.  
  1952. The BASWIZ project is a third-generation library.  It is designed to overcome
  1953. the liabilities I've encountered with ADVBAS and every other library I've
  1954. seen for BASIC.  Rather than being put together haphazardly, one routine at a
  1955. time, I have designed BASWIZ as a coordinated collection.  The virtual
  1956. windowing system is an excellent example of this.  Rather than having
  1957. separate print routines, window routines, screen saving routines, virtual
  1958. screen routines and all the rest, it is all combined into one single
  1959. package.  The routines are designed at a high level, providing a maximum of
  1960. functionality with a minimum of programming effort.  The gritty details are
  1961. kept hidden inside the library where you need never deal with them.  Consider
  1962. the apparent simplicity of the far string handler!  Many more capabilities
  1963. will be added in future versions, but... very carefully.
  1964.  
  1965. This library represents the culmination of many years of experience in the
  1966. fields of BASIC and assembly language programming.  I have spared no effort.
  1967. It's the best I can offer and I hope you'll forgive me for taking some pride
  1968. in my work!  If you find this library powerful and easy to use, I'll count my
  1969. efforts a great success.
  1970.  
  1971. As you might have guessed, I'm not exactly in it "just for the money."
  1972. Nonetheless, money is always nice!  If you like BASWIZ, please do register.
  1973. That will enable me to upgrade my equipment and design more advanced BASWIZ
  1974. routines.  Currently I have a 386SX with an EGA display.  I would like to be
  1975. able to support the VGA, scanners, sound boards and other hardware as well.
  1976.  
  1977.                             Using BASWIZ with PDQ                      page 43
  1978.  
  1979.  
  1980.  
  1981. Crescent's PDQ library does not currently support the SETMEM function, which
  1982. is required by many of the BASWIZ routines.  Fortunately, the use of PDQ
  1983. precludes the need for SETMEM, so all we need to do is to include a "dummy"
  1984. SETMEM routine to satisfy LINK:
  1985.  
  1986.    LINK program+PDQSTUB/NOE,,NUL,PDQ+BASWIZ;
  1987.  
  1988. If you use LINK differently, that's fine.  The only thing necessary is to
  1989. make sure "+PDQSTUB" is listed just after the name of your program as the
  1990. first LINK argument.  Use of /EX and other LINK parameters is no problem.
  1991. Use of other libraries, if any, is also supported.
  1992.  
  1993. Crescent thoughtfully provided me with a free copy of PDQ in order that I
  1994. might resolve any incompatibilities between it and BASWIZ.  If you are not
  1995. familiar with PDQ, it is a replacement library for BASIC's own runtime
  1996. libraries.  While not providing every capability of plain QuickBASIC, it
  1997. allows you to create substantially smaller EXE files for those programs that
  1998. qualify.  Support is currently lacking for floating point (single/double
  1999. precision) numbers, music, and graphics, among other things.  Communications
  2000. support is available as an add-on.  Check with Crescent for more recent
  2001. details.
  2002.  
  2003.