Copy Link
Add to Bookmark
Report
QBNews Volume 3 Number 1
Volume 3, Number 1 March 29, 1992
**************************************************
* *
* QBNews *
* *
* International QuickBASIC Electronic *
* Newsleter *
* *
* Dedicated to promoting QuickBASIC around *
* the world *
* *
**************************************************
The QBNews is an electronic newsletter published by Clearware
Computing. It can be freely distributed providing NO CHARGE is charged
for distribution. The QBNews is copyrighted in full by Clearware
Computing. The authors hold the copyright to their individual
articles. All program code appearing in QBNews is released into the
public domain. You may do what you wish with the code except
copyright it. QBNews must be distributed whole and unmodified.
You can write The QBNews at:
The QBNews
P.O. Box 507
Sandy Hook, CT 06482
Copyright (c) 1992 by Clearware Computing.
The QBNews Page i
Volume 3, Number 1 March 29, 1992
----------------------------------------------------------------------
T A B L E O F C O N T E N T S
1. From the Editor's Desk
BASIC Alternatives by David Cleary ........................... 1
Receiving The QBNews ......................................... 3
Submitting Articles to The QBNews ............................ 3
2. The News Desk
Goings On in the World of BASIC
Crescent Software Expands BBS Service ...................... 5
Microsoft Expands Technical Support on Compuserve .......... 5
Microhelp Announces Network Library ........................ 6
EllTech Announces Printer Plus ............................. 6
Microsoft Announces the Visual Basic Professional Toolkit .. 6
Desaware Announces CCF-Cursors for Visual Basic ............ 7
Index Manager Now Available for Visual Basic and PowerBASIC. 7
3. Microsoft BASIC PDS 7.1
Converting ASM String Functions to BASIC 7.X by Jay Munro .... 9
Using Stub Files to Reduce EXE Size by David Cleary .......... 13
Using Overlays in Microsoft BASIC PDS 7.1 .................... 20
4. The QBNews Professional Library
Thanks for the Memories by Robin Duffy ....................... 23
5. QBASIC Corner
Extending the QBasic Interpreter by Brent Ashley ............. 28
6. Swap Shop - QB Source Code Exchange
Creating Vertical Menus by Bernard Veerman ................... 35
Windowing in BASIC by Mark Butler ............................ 38
Viewing Files in BASIC by Matt Hart .......................... 38
7. Algorithms
QuickInsert Sort Algorithm -a push from B$ASSN by Larry Stone 39
8. Fun and Games
Having A Ball - Solution to 12 Ball Problem .................. 43
9. The QBNews Volume 2 Annual Index .............................. 45
The QBNews Page ii
Volume 3, Number 1 March 29, 1992
----------------------------------------------------------------------
F r o m t h e E d i t o r ' s D e s k
----------------------------------------------------------------------
BASIC Alternatives by David Cleary
It seems to be in vogue today to bash Microsoft. This is undoubtably
because they have become the predominant software company in most
areas of computing. BASIC programmers biggest complaint is the fact
that QuickBASIC 4.5 has not been updated for some four years. They say
that Microsoft is insensitive to their customers needs. However, since
QuickBASIC 4.5, Microsoft has released BASIC PDS 7.1 and Visual Basic
1.0. Microsoft is the only major compiler vendor with a BASIC compiler
and has proven their commitment to BASIC in my eyes. Although PDS 7.1
addresses many of the features request for QuickBASIC, the fact that
it is a professional compiler and is priced like one leaves this out
as an option.
However, all is not lost. Even though you won't be able to find a
Borland or Watcom BASIC, there are a number of smaller software
companies that do provide BASIC compilers. If you feel Microsoft is
unresponsive to your needs, has lousy tech support, or has abandoned
the DOS market, then do yourself a favor and check out one of these
BASIC alternatives.
ZBASIC-PC/386
==============
32 Bit Software 800-322-4879 $149.95
BB Progression/3
=================
Basis International 800-423-1394 $199.95
Thoroughbred BASIC
===================
Concept Omega Corp 800-524-0430 $600 - $900
Workstation BASIC
==================
Emphasys Software 800-972-2742 $695
GFA BASIC for MS-DOS
=====================
GFA Software Technologies 800-766-6432 $235
387 BASIC
==========
Microway 508-746-7341 $250
NKR BASIC
==========
NKR Research 408-249-2612 $295
The QBNews Page 1
Volume 3, Number 1 March 29, 1992
Power BASIC
============
Spectra Publishing 800-245-6717 $129
True BASIC
===========
True BASIC 800-872-2742 $99.95
In future issues of The QBNews, I hope to have in depth reviews of
some of these products. In the mean time, give these companies a call
and ask for some product literature. You may find a product you like
much better than QuickBASIC.
The QBNews Page 2
Volume 3, Number 1 March 29, 1992
Receiving The QBNews
The QBNews is distributed mainly through BBS systems around the
world. Some of the networks it gets distributed through are SDS
(Software Distribution System) and PDN (Programmers Distribution
Network). Ask the sysop of your local board about these networks to
see if there is a node in your area.
The QBNews can also be found on CompuServe in the MSLang
(Microsoft Language) forum. It can be found in file area 1 or 2 of
that forum. Just search for the keyword QBNEWS. The QBNews will also
be available on PC-Link. I send them to Steve Craver, who is the BASIC
Programming Forum Host on PC-LINK and he will make them available. I
would appreciate anybody who could upload The QBNews to other services
such as GENIE since I don't have access to these.
I have also set up a high speed distribution network for people
who would like to download The QBNews at 9600 baud. The following
boards allow first time callers download privileges also. They are:
Name Sysop Location Number Node #
---------------------------------------------------------------------
Treasure Island Don Dawson Danbury, CT 203-791-8532 1:141/730
Gulf Coast BBS Jim Brewer New PortRichey,FL 904-563-2547 1:365/12
221B Baker St. James Young Panama City,FL 904-871-6536 1:3608/1
EMC/80 Jim Harre St. Louis, MO 314-843-0001 1:100/555
Apple Capitol BBS Bob Finley Wenatchee, WA 509-663-3618 1:344/61
RadioLink! Steve Craver Columbus, OH 614-766-2162 1:226/140
MedTechNet Bill Hliwa Buffalo, NY 716-688-1552 1:260/10
Finally, you can download The QBNews from these vendors BBS's:
The Crescent Software Support BBS 203-426-5958
The EllTech Support BBS 404-928-7111
The Microhelp BUG BBS 404-552-0567
404-594-9625
You do not have to be a customer of these vendors in order to download
The QBNews, but the Microhelp BBS only allows non-members 15 minutes
of time per call.
If you would like to receive The QBNews on disk, I offer a yearly
subscription for $20.00. This includes four disks containing each
The QBNews Page 3
Volume 3, Number 1 March 29, 1992
issue as it is published. If you would like a disk with all the back
issues of The QBNews, please enclose an additional $5.00. The pricing
structure is as follows:
Base Price for 1 Year - $20.00
Disk with Back Issues - $5.00
3.5" disk surcharge - $5.00
Canada and Mexico surcharge - $5.00
All other foreign orders - $10.00
The base price includes 5.25" 360k disks. Send a check or money
order in U.S. funds to:
The QBNews
P.O. Box 507
Sandy Hook, CT 06482
Please be sure to specify what archive format you want. The
QBNews normally uses PKZip as it's archiver.
----------------------------------------------------------------------
Submitting Articles to The QBNews
The QBNews relies on it's readers to submit articles. If you are
interested in submitting an article, please send a disk of Ascii text
of no more than 70 characters per line to:
The QBNews
P.O. Box 507
Sandy Hook, CT 06482
Articles can also be submitted via E-Mail. Send them via Compuserve to
76510,1725 or via FidoNet to 1:141/777. I can be reached at the above
addresses as well as on Prodigy as HSRW18A.
The QBNews Page 4
Volume 3, Number 1 March 29, 1992
----------------------------------------------------------------------
T h e N e w s D e s k
----------------------------------------------------------------------
Goings On in the World of BASIC
CRESCENT SOFTWARE EXPANDS BBS SERVICE
======================================
Crescent Software has expanded the Crescent Software Support BBS.
Crescent Software customers can now subscribe for enhanced technical
support through their BBS. Subscribers can download the latest
versions of all the Crescent Software products they own, plus receive
the kind of technical support that isn't possible over the phone such
as help modifying routines. The service costs $59 per year. You can
call Crescent Software at 800-35-BASIC, or 203-438-5300. All
QuickBASIC users are encouraged to call The Crescent Software Support
BBS at 203-426-5958 - 14.4K v.32bis.
MICROSOFT EXPANDS TECHNICAL SUPPORT ON COMPUSERVE
==================================================
Microsoft has reorganized all their tech support for software
developers under a new forum. The new forum is called Microsoft
Developers Services (GO MSDS).
Specifically, the Microsoft Developer Services area offers:
- Developer Forums. This set of forums covers information on Windows,
languages, tools, and utilities from a developers perspective. You can
use these forums to exchange messages with experienced Microsoft users
and Microsoft Developer Support engineers.
- Developer Knowledge Base. This up-to-date reference tool contains
technical information about Microsoft developer specific products
compiled by Microsoft Product Support. The Knowledge Base is full-text
searchable, and in addition to technical articles contains special
information regarding product bug lists, fix lists, documentation
errors, and Microsoft press releases.
- Software Library. A collection of binary files, sample code,
technical specification and utilities. The entire library is
keyword-searchable, and the files can be downloaded for use locally.
- Suggestion/Problem Report Form. This form can be used to make
product suggestions or to report a problem with a Microsoft product.
- Microsoft Service Requests. Microsoft now offers an optional,
private (fee-based per incident) technical support offering to help
solve your more complex development problems.
Robert Eineigl, Microsoft Support Engineer (CIS ID 76701,156) explains
what this means to BASIC programmers - "The restructuring will
The QBNews Page 5
Volume 3, Number 1 March 29, 1992
positively impact QB users in at least two ways: The concentration of
resources on the Knowledge Base will mean faster updates and one-stop
browsing for all developer-related issues. And finally Basic
developers/programmers, by being included with the more "stylish"
development languages, will garner more respect and attention to their
efforts. This move should be seen as MS's becoming more aware of and
committed to the importance of CIS as a support delivery medium."
MICROHELP ANNOUNCES NETWORK LIBRARY
====================================
Microhelp is now shipping the Microhelp Network Library, with versions
for both QuickBASIC/PDS 7.1 and Visual Basic. The Network Library is
designed to provide an easy to use wrapper for the network interface
routines. The library supports Novell, LANtastic, and NetBIOS
networks. The Microhelp Network Library costs $89 per version, or $169
for both the QB/VB library and one set of documentation. You can call
Microhelp at 800-922-3383 or 404-594-1185 for more information or to
order this product.
ELLTECH ANNOUNCES PRINTER PLUS
===============================
EllTech is now shipping the new Printer Plus library. Printer Plus
allows BASIC programmers to support over 400 printers without changing
a single line of source code. Printer Plus's features include:
- Over 50 text printing functions that allow you to control exactly
how your printed reports will look regardless of the printer used.
- Utilize advanced features found in modern printers while not
precluding the use of printers without those features.
- Utilities are provided that allow you to add new printer
descriptions to our database or edit existing descriptions.
Printer Plus has a list price of $249, but if you order before April
30, 1992, you can get it for $199. You can call EllTech at
800-553-1327 or 404-928-8960.
MICROSOFT ANNOUNCES THE VISUAL BASIC PROFESSIONAL TOOLKIT
==========================================================
"The Professional Toolkit for Visual Basic makes incredibly powerful
functionality and the latest and greatest Windows operating system
features accessible to programmers at all levels," said Michael Risse,
product manager, Professional Toolkit for Visual Basic, at Microsoft.
"The unique custom control mechanism in Visual Basic makes these
features as accessible as the click of a mouse."
Combining the Professional Toolkit with Visual Basic provides a
The QBNews Page 6
Volume 3, Number 1 March 29, 1992
single-source solution for a broad range of full-featured
Windows-based applications. Professional programmers can use it to
enhance existing applications created with Visual Basic as well as to
create new ones.
The new features include controls to enhance applications with the
following technologies:
- Object linking and embedding technology (OLE). Microsoft's OLE
technology lets developers easily create applications that can combine
spreadsheet, word processing, graphics and other OLE server
functionality into an application that's customized for specific
business uses.
- Pen-based computing. Programmers can extend their current
applications -- or write entirely new ones -- for Microsoft Windows
for Pen Computing.
- Multimedia. Developers now can easily write or enhance applications
for Microsoft Multimedia Extensions version 1.0, including video,
animation, CD-quality audio and other multimedia elements.
- Graphing. Pie and bar charts in 2-D or 3-D, in addition to nine
other charting styles, can now be added to applications easily with a
complete graphics package in the Professional Toolkit.
- Grids. Information can be presented in a table complete with
resizeable rows, columns and scroll bars. This makes the display of
tabular data a snap for programmers.
- Multiple Document Interfaces (MDI). The MDI control allows the
developer working with Visual Basic to create applications with
multiple child windows that are contained in a single parent form.
In addition, the Professional Toolkit gives programmers easy access to
the following tools and features:
- More than 15 new controls, including 3-D interface components;
animated buttons, gauges and spin buttons; and access to commonly used
dialog boxes.]
- The Windows Help Compiler, to create the custom, online Windows Help
files that users of Windows now expect in their applications.
- The Windows API Online Reference, an accessible guide to Windows
application programming interfaces (APIs) that makes it easier for
programmers to maximize their use of Windows.
- A setup kit that helps developers create standard installation
programs for their applications, plus sample applications, bitmaps and
a business clip-art library.
- Custom Control Development Kit.
The QBNews Page 7
Volume 3, Number 1 March 29, 1992
The Professional Toolkit for Visual Basic is available now for the
suggested retail price of $299. Microsoft Visual Basic with
Professional Toolkit is available for the suggested retail price of
$495. For a limited time, owners of Visual Basic can receive the
Professional Toolkit for a special price of $99.
DESAWARE ANNOUNCES CCF-CURSORS FOR VISUAL BASIC
================================================
Desaware is now shipping CCF-Cursors, a product that permits the
creation of custom cursors or mouse pointers for Visual Basic. Over 50
sample cursors and two demo programs are provided. Also, CCF-Cursors
also comes with the CCMOUSE custom control. This control supports
detection of mouse events for any Visual Basic control, including
those that do not normally detect mouse events. CCF-Cursors lists for
$35 and is available now by calling Desaware at 408-377-4770.
INDEX MANAGER NOW AVAILABLE FOR VISUAL BASIC AND POWER BASIC
=============================================================
Index Manager, the popular B+ Tree file manager for QuickBASIC has
been enhanced to support both Visual Basic and PowerBASIC. These two
new versions boast simple, one-function construction for ease of use
are written in assembler for small and fast performance. Index Manger
lists for $99 for the single user version and $250 for the network
version. Call CDP Consultants at 800-876-0098 for more information or
to place an order.
The QBNews Page 8
Volume 3, Number 1 March 29, 1992
----------------------------------------------------------------------
M i c r o s o f t B A S I C P D S 7 . 1
----------------------------------------------------------------------
Converting ASM String Functions to BASIC 7.X by Jay Munro
Life was easy when QuickBASIC only had one kind of variable length
string and it was always in DGroup. QuickBASIC used Near Strings with
descriptors in a simple format--two bytes as the length, and two bytes
as the offset into the String Segment, or DGroup. That all changed
with BASIC 7.x PDS.
While the Near String format still lives on with BASIC 7.x as a
compiler option, the QBX environment requires your assembler functions
to use Far Strings. The Far Strings data is located in segments other
than DGroup, with several to choose from. The Main module strings and
string arrays have one 64k segment, procedure level simple strings and
temporary strings share another 64k segment, and Common strings are in
yet a third 64k segment. That's a lot of space, but it does
complicate working with strings.
To begin with, the string and array descriptors for all strings are
kept in DGroup, regardless of where the data is stored. This is
important to keep in mind when working with Far Strings, since it is
still possible to run out of DGroup before you run out of Far String
space. Having the descriptors in DGroup let you pass the string to an
assembler routine as a Near Pointer, just as in earlier versions of
QuickBASIC.
The real differences between Near and Far Strings become apparent once
inside the assembler routine. To get the length of a Near String, the
first two bytes of the descriptor are the length. With Far Strings,
the pointer (or address) to the descriptor is pushed and the
StringLength function is called. Stringlength returns the length of
the string in AX. In our Trim routine, we move AX into CX for use in
the loop later.
For a Near String descriptor, the second two bytes of the descriptor
point to the string data that is stored in DGroup. To get the address
of Far String Data, the desciptor is again pushed and the
StringAddress function is called. The StringAddress function returns
the address of the string as a Far Pointer in DX:AX. An interesting
undocumented side effect of StringAddress is that CX contains the
length when it returns, along with the address in DX:AX. Microsoft
will not confirm this, and cautions against depending on undocumented
features because they are subject to change, but it does work in both
BASIC 7.0 and 7.1. You can decide for yourself if you want to drop
StringLength.
When StringAddress and StringLength are called, SS, BP, DS, SI, and DI
registers are preserved, but ES is not. You can see when running a
program under Codeview that ES returns with the segment of the far
string after the StringAddress call. Normally this is harmless, but
when your routine is juggling several incoming strings, ES may be
The QBNews Page 9
Volume 3, Number 1 March 29, 1992
pointing to another segment. The trashing of ES may go unnoticed when
all strings the routine is processing are in the same segment.
However, if the strings are from different segments, like Common and
Procedure level strings it becomes apparent.
The Far string descriptor format also applies to variable length
string arrays. To access strings in an array, the VarPtr of the first
element of the string is passed as shown in the following code
snippet, and the pointer is incremented by 4 to get each successive
string. The function AddEll adds up the lengths of the strings in the
array$().
'--- BASIC code
Declare Function AddEll&(Byval Address%,Byval NumEls%)
Dim Array$(1 to 200)
.... (fill array)....
TotalSize& = AddEll&(VARPTR (Array$(1),200)
;---- assembler code
.Model Medium,BASIC
Extrn StringLength:Proc
.code
AddEll Proc Uses SI DI, Array:Ptr, NumEls:Word
Xor DI,DI ;use DI to track total lengths
Mov CX,NumEls ;get numels (byval remember)
Jcxz Exit ;jump out if 0 els
Mov SI,Array ;get pointer to first descriptor
CountLoop:
Push CX ;preserve CX through count loop
Push SI ;push pointer
Call StringLength ;get length
Add DI,AX ;add length to counter
Pop CX
Add SI,4 ;point to next 4 byte descriptor
Loop CountLoop ;keep going til' done
Exit:
Xor DX,DX ;clear DX to return long
Mov AX,DI ;and return total count in AX
Ret
AddEll EndP
End
For QB45 or Near Strings, the code can be much more compact, and
thereby faster.
;near String version
AddEll Proc, Array:Ptr, NumEls:Word
Xor AX,AX ;use AX to track total lengths
Mov CX,NumEls ;get numels (byval remember)
Jcxz Exit ;jump out if 0 els
Mov BX,Array ;get pointer to first descriptor
The QBNews Page 10
Volume 3, Number 1 March 29, 1992
CountLoop:
Add AX,[BX] ;first word of is length
Add BX,4 ;point to next 4 byte descriptor
Loop CountLoop ;keep going til' done
Exit:
Xor DX,DX ;clear DX to return long
Ret
AddEll EndP
End
Now that we've discussed retrieving Far String information, let's move
on to our last subject--Far String Functions.
STRING FUNCTIONS
Far String Functions are only a little more complex than their Near
String counterparts. In a Near String function, the four byte
descriptor (LENGTH:ADDRESS) is created in DGroup, as is the data that
the address points to. With Far Strings, the four byte descriptor
must still be in DGroup, but the data can be in any segment. Unlike
Near String descriptors which are created by the programmer, the four
byte descriptor is created by calling BASIC's StringAssign function.
StringAssign is called with the Length, Segment and Address of the
data you want to assign, and the Length, Segment and address of the
destination. The StringAssign function can assign both variable
length and fixed length strings. With fixed length strings,
StringAssign uses the length parameter on the destination. When
assigning a variable length string, the destination length is set to
zero so StringAssign knows to create a descriptor and store the date.
The accompanying program, ZeroTrim illustrates the technique.
There are two caveats to be aware of when using Far Strings and
StringAssign. First, when StringAssign is called with the address of
the descriptor (or destination), it checks to see if the descriptor
contains a value or not. If it sees a value, StringAssign assumes it
is an old descriptor and will try to deallocate the string to make
room for the new string. On the first entry into your assembler
function, the descriptor should be null so a new descriptor is
allocated. However, if your function clears the descriptor between
calls, BASIC will end up with orphan data from old strings not being
deallocated. On the other side, if your program does a CLEAR command
after a call to a string function, variables on the BASIC side will be
cleared, but the descriptor stored in your assemblers Data area will
still exist. If the assembler routine then calls StringAssign, BASIC
will try to deallocate the data and you'll end up with a String Space
Corrupt message. The rule is don't call Clear once the program
starts, and don't clear the descriptor between calls.
If your program needs to free up the space, you may call the
StringRelease function to deallocate the descriptor. This is only
recommended if the function is not going to be called again, since
StringAssign will always release the old string before assigning a new
The QBNews Page 11
Volume 3, Number 1 March 29, 1992
one. The syntax for StringRelease is as follows.
.Data
Descriptor DD ?
.Code
Some Proc ....
..
..
Push DS
Push Offset Descriptor
Call StringRelease
Another problem programmers may encounter with Far Strings happens
when the assigning a zero length string. Under Near Strings, the
length portion of the descriptor just zeroed out and BASIC understood.
Far Strings are not quite so simple, but the concept is similar.
Though there are several ways to do it, the most reliable is to be to
point to an actual data area and tell StringAssign that the length is
zero. StringAssign will then deallocate the old descriptor if there is
one, and allocate a new one that BASIC recognizes as a zero length
string. Again, it is important to let BASIC go through the motions so
it deallocates the old strings.
As you can see, the conversion of assembler routines from Near Strings
to Far Strings is not too difficult. By using the Far String function
and watching your registers, the transition is almost painless. Once
a routine is converted to handle Far Strings, it may be used with
either BC 7.x compiler option. The Far String functions are
automatically replaced with near string code when you leave off the
/FS switch, eliminating the need for two version of the routines for
BASIC 7 support. If you need to support QuickBASIC 4.x, you will need
a second version for near strings only.
SOURCE CODE FOR THIS ARTICLE CAN BE FOUND IN FARSTRNG.ZIP
======================================================================
Jay Munro is a programmer at Crescent Software and also writes
utilities for PC Magazine in his spare time. He was given the task of
converting Crescent's QuickPak Pro to use Farstrings, and more
recently, converting QuickPak Pro for use in Visual Basic. Jay can be
contacted through The Crescent Software Support BBS at 203-426-5958,
or in care of this newsletter.
======================================================================
The QBNews Page 12
Volume 3, Number 1 March 29, 1992
Using Stub Files to Reduce EXE Size by David Cleary
Microsoft BASIC Professional Development System version 7.1 comes with
many "stub" files to help reduce the size of your EXE programs. By
linking with these stub files under certain conditions, you will see
reductions in EXE size of 2 - 15K. However, improperly using stub
files may result in your EXE actually getting larger.
Because of the complexity of the BASIC run time libraries, many times
routines will be included in your EXE even though they are never used.
For instance, when you do this:
OPEN A$ FOR RANDOM AS #1
the compiler doesn't know if A$ is referring to a file, or to the
communications port. Therefore, the compiler has no choice but to
include all the code to handle the communications port. What a stub
file does, in this instance NOCOM.OBJ, is replace the code that is not
needed with an empty procedure. This causes all external references
to be resolved and cause a decrease in EXE size.
The tricky part is figuring out when to use them. For instance, if you
changed A$ in the example above to:
OPEN "C:\INFO.DAT" FOR RANDOM AS #1
the compiler knows you want to open a file. It will not include the
communications routines in your EXE file. If you try and link with
NOCOM.OBJ, you will actually see an increase in EXE size.
There are two types of stub files provided with PDS 7.1. The first
type is used with stand alone programs (compiled with /O) are are used
to reduce the size of your EXE file. They include:
NOCGA, NOEGA, NOOGA, NOHERC, NOVGA, NOGRAPH Graphics stub files
NOCOM, NOLPT Device support stub files
SMALLERR Error message stub file
87.LIB Floating point emulation stub file
NOEMS, OVLDOS21 Overlay support stub files
NOFLTIN Floating point input support stub file
NOEDIT INPUT editting functions stub file
TSCNIO Text output stub file
NOTRNEMx.LIB Transcendental operation stub file
The second type of stub file is used when creating custom run time
libraries. They do not decrease the size of your EXE file, but rather
decrease the size of your BRUN file. They include:
NOEVENT Event trapping stub file
NOISAM ISAM support stub file
The following instructions on correctly using these stub files came
from a file located in the Microsoft Software Library on Compuserve.
You can access the Microsoft Software Library by typing GO MSDS at any
The QBNews Page 13
Volume 3, Number 1 March 29, 1992
! prompt.
When to Use the NOxxx.OBJ Graphics Stub Files
---------------------------------------------
When you code any graphics SCREEN mode, the compiler knows to generate
code that will require support only for that mode. Therefore, the
linker will only link in support for the screen mode that you are
using. If you only use SCREEN 9, the linker will only pull the EGA
graphics support out of the BASIC libraries.
The one time when all graphics support will be linked with your
program is if you use SCREEN with a variable such as the following:
SCREEN X%
In this case, the compiler does not know what graphics mode you will
be using until run time. Therefore, it is forced to generate code that
will cause ALL of the BASIC graphics support to be linked in. In this
case, you would use NOGRAPH.OBJ, or one or more of the following stub
files, to stub out support for those modes you will not be using:
NOCGA.OBJ, NOEGA.OBJ, NOOGA.OBJ, NOHERC.OBJ, NOVGA.OBJ
NOGRAPH.OBJ would only be useful if you are using SCREEN X%, where X%
is guaranteed to be zero. NOGRAPH.OBJ is only useful when building
custom run-time modules that will not support graphics. NOGRAPH is a
superset of all the other above graphics stub files and cannot be
linked with any of them.
When to Use NOCOM.OBJ or NOLPT.OBJ
----------------------------------
Normally, support for communications or printing will not be linked in
unless an OPEN "COMx:" or OPEN "LPTx:" statement exists in the
program. However, if the program contains a statement that resembles
the following
OPEN A$ FOR <mode> as #n
then the compiler must assume the A$ might be equal to "COMx:" or
"LPTx:" at some time during the program. Therefore, communications and
printing support will be linked in along with all other file support.
If A$ will never be used to open the "COMx:" port or the printer, then
the NOCOM.OBJ support module can be used to stub out support for
communications and NOLPT.OBJ can be used to stub out printer support.
This should reduce the size of the .EXE program.
When to Use SMALLERR.OBJ
------------------------
The QBNews Page 14
Volume 3, Number 1 March 29, 1992
SMALLERR substitutes smaller error message text strings for the normal
error messages and maps the BASIC error messages down to a few
messages. Use this only in a program known to be very stable.
When to Use 87.LIB
------------------
87.LIB could increase the size of the .EXE if the program does not
contain any math statements at all. However, use the 87.LIB stub file
(in the .OBJ argument list of LINK, even though it is a .LIB file) to
decrease the size of the .EXE file when the program contains a math
statement and will be run ONLY on machines with a math coprocessor.
When to Use NOEVENT.OBJ
-----------------------
The NOEVENT.OBJ stub file is useful only to reduce the size of a
customized run-time module that will not support event trapping.
NOEVENT.OBJ is NOT useful for reducing the size of your compiled BASIC
.EXE program.
If the program can be compiled without /V and /W, the program doesn't
require event trapping. In this case, mistakenly linking your BASIC
.OBJ modules directly with NOEVENT.OBJ may increase program size. If
the program requires /V or /W, you would also not want to link with
this stub file, since NOEVENT.OBJ is only useful for making customized
run-time modules.
When to Use NOEMS.OBJ
---------------------
In an overlaid program, this stub file will prevent the overlay
manager from using expanded memory (EM) even if EM is present. This
stub could be used if the program needed to use EM for other purposes
(such as ISAM) and did not want the overlay manager to use EM. This
stub file reduces code size only by about 1000 bytes. Do not use this
stub file if the program does not contain overlays or if it is an OS/2
protected mode program.
OVLDOS21.OBJ
------------
This stub file adds support for DOS version 2.10 to an overlaid
program. Any overlaid program that would want to work on DOS 2.10 must
have this file linked with it. OVLDOS21 is not needed (and should not
be used) if the program is not overlaid or if it is a protected mode
program. The stub file does not remove code, but always adds code and
functionality (about 500 bytes).
When to Use NOFLTIN.OBJ
-----------------------
Replaces the INPUT code with an "integer only" version. If you link
with this stub file, all forms of numeric input (INPUT, INPUT #, VAL,
The QBNews Page 15
Volume 3, Number 1 March 29, 1992
and READ) will have the following restrictions:
1. READ, INPUT, INPUT #, and VAL will no longer recognize leading base
specifiers on numbers. The following specifiers are illegal:
&H &O, &
2. READ, INPUT, INPUT #, and VAL will no longer recognize trailing
type specifiers on numbers. The following specifiers are illegal:
!, %, #, & and @
3. READ, INPUT, INPUT #, and VAL will no longer parse a number with
either a decimal point, E, or D in them. Thus, while 1E3 is a legal
BASIC integer, it will not be recognized.
4. Using a SINGLE precision, DOUBLE precision, or CURRENCY variable
with READ, INPUT, INPUT #, and VAL will cause the math support to
be linked in. The restrictions in points 1-3 above will still hold.
Also, using any other math related operation will pull in the
support pack without lifting the restrictions of 1-3.
The main size advantage to using this stub file occurs when READ,
INPUT, INPUT#, or VAL are the only statements that use the math
package. This stub file will then eliminate at least 11K of code. If
some other statement also needs the math package, the savings will be
less than 2K.
When to Use NOEDIT.OBJ
----------------------
This stub file replaces the editor used with the INPUT and LINE INPUT
statements. It removes the following functions from the editor:
1. No control character commands are recognized except for ENTER (done
editing) and BACKSPACE (removes the last character). All other
control characters are ignored, as are INS, DEL, HOME, END, and the
arrow keys. Function keys will still expand because this
functionality is performed outside the INPUT editor.
2. If output is redirected (using >) and input is not redirected (no
<), no characters will be echoed to the screen. The normal INPUT
editor will print the characters as you types them in this
situation.
3. No characters will be echoed to the line printer even if line
printer echoing is turned on.
You can obtain a 1K reduction in .EXE size using this stub file.
Linking with this file could increase program size if the program
never uses INPUT, LINE INPUT, LINE INPUT #, RANDOMIZE. If the program
does not have INPUT or LINE INPUT statements but does have LINE INPUT
The QBNews Page 16
Volume 3, Number 1 March 29, 1992
# or RANDOMIZE (with not parameters), there will still be some
savings.
When to Use the TSCNIOxx.OBJ Stub Files
---------------------------------------
Note: The statements affected by this stub file are subject to change
in future versions.
The TSCNIOxx.OBJ file provides a smaller, simpler text output package.
When it is linked in, the following differences from standard BASIC
will occur:
1. No graphics statements are supported. All the following statements
and functions will generate an illegal function call:
CIRCLE, POINT statement, POINT function, PAINT, PSET, VIEW,
VIEW SCREEN, WINDOW, PALETTE, PALETTE USING, DRAW,
PUT (graphics), LINE, PCOPY, PMAP, GET (graphics)
2. VIEW PRINT will not be supported. All programs will have an
implicit VIEW PRINT 1 TO <screen-size - 1> as is the normal
default. For programs linked with this stub file, the only way to
reach the bottom screen line is with the LOCATE statement, since
the VIEW PRINT statement is not available.
3. There will be no support for function key display. The KEY
ON/OFF/LIST statements will generate an illegal function call.
CTRL+T to an INPUT statement will be silently ignored. Softkey
definition and expansion will still be supported.
4. The COLOR statement will not accept a border parameter. Also, the
color parameters are sent directly to the hardware. Thus, on an
EGA or VGA card with a monochrome monitor, many values for COLOR
will cause text to not be visible.
5. Embedded control characters will not be supported for PRINT.
Currently, the following features (which need to be added to the
manual) are supported for the nonstubbed version of the PRINT
code:
Control
Character Description
--------- -----------
CTRL+G Beeps the speaker
The QBNews Page 17
Volume 3, Number 1 March 29, 1992
CTRL+I Moves the cursor to the next tab position, erasing
characters
CTRL+J Moves the cursor to the beginning of the next line
CTRL+K Moves the cursor to the top-left corner of the current
VIEW PRINT window
CTRL+L Clears the VIEW PRINT window, homes the cursor within
it
CTRL+M Moves the cursor to the beginning of the next line
CTRL+\ Moves the cursor to the right one space, stopping at
the end of the line
CTRL+] Moves the cursor to the left one space, stopping at
the beginning of the line
CTRL ^ Moves the cursor up one line, stopping at the top of
the VIEW PRINT window
CTRL_ Move the cursor down one line, stopping at the bottom
of the VIEW PRINT window
6. The SCREEN and WIDTH statements will not be supported. The program
will use whatever screen mode was available on start-up, unless it
is a graphics mode, in which case an attempt will be made to
determine if any text mode can be run in that graphics mode. The
screen will always be 80 columns, displaying on video page 0. The
number of lines will be determined by start-up conditions. The
screen state will not be restored when the program terminates.
7. CLS will not accept any parameters.
8. Underline cursors on an EGA card not in 25-line mode may not be
handled properly.
9. This stub file may not be used to build a customized run-time
module. It may not support the CHAIN statement.
The QBNews Page 18
Volume 3, Number 1 March 29, 1992
10. This stub file does not support CGA snow elimination during screen
output.
This "set" of stub files is dependent upon operating system and
near/far string support. Thus, there are four different versions of
the file:
File Description
---- -----------
TSCNIONR.OBJ Near string DOS version
TSCNIOFR.OBJ Far string DOS version
TSCNIONP.OBJ Near string OS/2 version
TSCNIOFP.OBJ Far string OS/2 version
Any program linked with one of these stub files should decrease in
size. The size decrease should be between 1.3K and 4.4K depending on
the statements used in the program and the library being linked with.
When to Use the NOTRNEMx.LIB Stub File
--------------------------------------
NOTRNEMR.LIB and NOTRNEMP.LIB remove support for transcendental
operations, including: SIN, COS, TAN, ATN, LOG, SQR, EXP, ^ (the
exponential operator), a CIRCLE statement with a start or stop value,
and the DRAW statement with the A or T commands.
When to Use the NOISAM.OBJ Stub File
------------------------------------
NOISAM.OBJ removes ISAM functionality from customized BASIC run-time
modules. NOISAM.OBJ is not useful when linking stand-alone (BC /O)
BASIC executable programs.
======================================================================
David Cleary is a software engineer for Vectron Laboratories in
Norwalk, CT and is also the author of Crescent Software's PDQComm. He
can be reached in care of this newsletter, on Compuserve as
76510,1725, on Prodigy as HSRW18A, on Fidonet at 1:141/777, and on the
Crescent Software Support BBS at 203-426-5958.
======================================================================
The QBNews Page 19
Volume 3, Number 1 March 29, 1992
Using Overlays in Microsoft BASIC PDS 7.1
The following information comes directly from The Microsoft Knowledge
Base. The Microsoft Kwowledge Base is a huge database of information
on all Microsoft products. Microsoft technical support uses the
Knowledge Base to help answer your questions. You can access the
Knowledge Base yourself through Compuserve. Just type GO MSDS at any !
prompt.
Title: How to Use Link Overlays in Basic PDS Versions 7.0 and 7.1
Document Number: Q51416
Publ Date: 7-OCT-1991
Product Name: Microsoft BASIC Compiler Product Version: 7.00 7.10
Operating System: MS-DOS
Summary:
When using the linker (LINK.EXE) to generate code overlays for
Microsoft Basic Professional Development System (PDS) version 7.0 or
7.1 under MS-DOS, you must put the modules you want to overlay in
parentheses on the LINK command line. The modules that make up one
overlay must be compiled with the same switches. Code is the only part
of the program that is overlaid. Data is not overlaid. Examples and
further restrictions for using linker overlays are given below. This
information applies to Microsoft Basic PDS versions 7.0 and 7.1 for
MS-DOS (but does NOT apply to earlier Basic compiler versions). Note
that link overlays are not needed and not supported under OS/2
protected mode, because OS/2 itself automatically provides a similar
feature to support swapping of very large .EXE programs in OS/2
extended and virtual memory.
More Information:
The following is an example of how to produce code overlays:
LINK test1+(test2+test3)+test4+(test5)+(test6),TEST1.EXE,TEST1.MAP;
where the following apply:
1. test1 (TEST1.OBJ) is the main module.
2. test2 and test3 (TEST2.OBJ and TEST3.OBJ) are separately compiled
modules that make up one overlay.
3. test4 (TEST4.OBJ) stays resident in memory along with the main
module (test1) at run time and is not swapped out of memory to
disk.
4. test5 and test6 (TEST5.OBJ and TEST6.OBJ) are two separate
overlays.
5. TEST1.EXE is the executable overlaid program created by this LINK.
6. TEST1.MAP is a text file (created by the above LINK) that tells
you the code sizes of all overlays and procedures.
To invoke an overlay, you call a SUB or FUNCTION in a module contained
in that overlay, and the Overlay Manager automatically moves the
overlay (if it is not already loaded) into DOS memory, overlaying any
previous overlay in memory.
You can call any module or overlay from any other module or overlay.
The QBNews Page 20
Volume 3, Number 1 March 29, 1992
Overlays provide an alternative to CHAINing when a program is too
large to fit into memory all at once. An overlaid program is made up
of a single .EXE file (which can be an advantage in some cases),
unlike CHAINed programs, which are composed of several .EXE files.
Restrictions on Using Overlays
------------------------------
The restrictions on using overlays in Microsoft Basic PDS versions
7.0 and 7.1 for MS-DOS are as follows:
1. Each Microsoft Basic overlay cannot exceed 256K in code (see LINK
.MAP for size of each overlay). You can have up to 64 overlays
per .EXE program. This means you may be able to make .EXE programs
up to 16 MB in code size under MS-DOS.
2. The main module must be the first module in the LINK command line,
and it must NOT be specified as an overlay. If you incorrectly make
the first module in the LINK command line an overlay, the machine
will hang when the program first loads.
3. When you create an overlaid version of a program, make sure that
each module contained in the program is compiled with the same
options.
4. You cannot use the LINK /PACKCODE or /EXEPACK option when linking a
program that uses overlays.
5. You cannot have a stub file as an overlay. Do not specify stub
files (NOxxx.OBJ) in the parentheses for link overlays, or the
program will hang. Stub files may only be specified outside
parentheses in the LINK command line.
Using Expanded Memory with Overlays
-----------------------------------
386Max (386MAX.SYS) from Qualitas, Inc. is an example of an expanded
memory driver that can be used with Basic PDS 7.0 and 7.1. Basic PDS
7.0 and 7.1 require an expanded memory driver that uses the
Lotus-Intel-Microsoft (LIM) version 4.0 Expanded Memory Specification
(EMS).
If you have loaded an expanded memory driver, and if all the overlays
can fit together at one time in expanded memory, and if each overlay
has less than 64K of code, then overlays are loaded from expanded
memory. Otherwise, overlays are swapped from disk, which is slower
than loading from expanded memory.
Assume that the overlaid program satisfies the above conditions for
using expanded memory. Note that the overlaid modules are not loaded
when the .EXE file is first invoked. They remain on disk until the
first overlay is called. When this occurs, all the overlaid modules
are loaded at once from disk into expanded memory. From then on, the
overlays are swapped from expanded memory into DOS memory, and the
disk is no longer used for loading overlays.
The overlay manager in Basic 7.0 and 7.1 requests expanded memory in
16K pages (blocks). The overlay manager only knows the size of the
largest overlay, and must make a "best guess" at the size of the
The QBNews Page 21
Volume 3, Number 1 March 29, 1992
smaller overlays. When the overlay manager estimates how many 16K
pages are necessary to hold all overlays at once in expanded memory,
the estimate could be over or under the actual number of pages needed.
If your overlays are all between 16K and 64K in size (according to the
LINK .MAP file), and if the estimated or actual size of all overlays
together exceeds the available expanded memory, the following
initialization error occurs when the first overlay is called at
run-time:
Insufficient EMS to load overlays
Note: This error is documented on page 656 of the "Microsoft Basic
7.0: Language Reference" manual for versions 7.0 and 7.1. You will
never see this error if all your overlays are smaller than 16K each.
If you want to force loading overlays from disk, thus avoiding the
possibility of this overlay initialization error in expanded memory,
you must link with the stub file NOEMS.OBJ (with no parentheses around
NOEMS.OBJ on the LINK command line). Alternatively, you can try
reconfiguring expanded memory so more of it is available for Basic
overlays. Another alternative is to make overlays similar in size.
DOS Memory Map When Using Overlaid .EXE Program
------------------------------------------------
[Low Memory]
- MS-DOS
- Main program and non-overlaid modules
- Contiguous overlay memory area, equal to the size of biggest
overlay
- DGROUP (default data segment, which is shared by all routines)
- Far heap (dynamic non-variable-length-string arrays)
- Basic's run-time support module if .EXE not compiled stand-alone
(BC /O)
[High Memory]
For more information on using overlays, see the following:
"Microsoft Basic 7.0: Programmer's Guide." pages 612-614.
Additional reference words: 7.00 7.10
COPYRIGHT Microsoft Corporation, 1991.
The QBNews Page 22
Volume 3, Number 1 March 29, 1992
----------------------------------------------------------------------
T h e Q B N e w s P r o f e s s i o n a l L i b r a r y
----------------------------------------------------------------------
Thanks for the Memories by Robin Duffy
For years QuickBASIC programmers have done some pretty incredible
things when it comes to using all the resources available on a PC. Of
all the things accomplished, the ability to use expanded memory was
heralded as a major accomplishment (at least I thought it was!). Now
QB programmers had oodles more of that precious commodity, RAM! Why,
several meg of RAM could now be used by programmers without thinking,
allowing them to create the most powerful of applications.
Without thinking? Well, not really. Expanded memory has its drawbacks,
one of which is the concept of bank switching blocks of this memory in
and out of the processor's addressable space. Also there was no
management of these blocks available to the programmer other than what
he could muster up for himself. He had to keep track of what data was
in what page and which pages were loaded where in the page frame.
Without some careful advanced planning it would be easy to get things
all mixed up beyond any hope of survival.
Another disadvantage I saw was the difficulty in saving a huge array
into this 64K page frame. A huge array by definition is larger than
the page frame itself. So, one would have to save the first 64K of the
array into the four available pages, swap pages, and then save another
64K chunk. I think there is a term for this sort of work around
programming - kludge! Why would you want to have all this beautiful
streamlined code in your program and then rely on a kludge?
Well, my thoughts took a different course after I tried programming
for expanded memory. I knew there was a different sort of memory
native to AT machines called extended memory. Extended memory differed
from expanded memory in several different ways, the most attractive of
which was the fact this memory was continuous for meg after meg. The
only problem with this memory was it was only available from the
processor's protected mode of operation. Now, I thought, how can I get
to this memory from a platform I am comfortable with? The answer was
obvious, but somewhat frightening!
Now enter a rather mysterious little device driver supplied with many
versions of DOS named HIMEM.SYS. HIMEM.SYS was barely documented (if
at all) as an extended memory manager, but precious little else could
be found out about it. Now here was something that could manage
extended memory for me, if only I could find out how to make this
thing work! Expanded memory has this dedicated interrupt (Int 67h)
that made interface simple, but HIMEM was written differently.
Instead of a clean system of interrupt function calls, or even
invoking a device name, HIMEM.SYS is used by calling the driver
directly as a procedure call! While direct calls to device drivers
can be done directly from QB with CALL ABSOLUTE, not every aftermarket
runtime library supported this QB keyword. Setting up the required
structures was also somewhat of a pain. The idea for an assembly
The QBNews Page 23
Volume 3, Number 1 March 29, 1992
interface to HIMEM.SYS was born!
HIMEM.SYS provides a variety of functions for managing extended
memory, the high memory area (1M + 64K) and the upper memory area
(memory between A000:0000 and 1M). It is important for user programs
NOT to issue calls for managing the high and UMB memory areas if some
other program is already managing those areas, especially DOS. The
popularity of DOS 5.0 meant I would have to be careful which functions
I chose to implement. After consideration I chose only those functions
that allocate, deallocate, move,
and report on extended memory. HIMEM
would perform a move to and from conventional memory, so I did not
require the use of the other functions.
I was pleasantly surprised when I learned HIMEM uses a handle based
system for managing blocks of memory instead of a more bulky system
such as page frames. For each block of XMS you allocate HIMEM assigns
a handle to reference the block by. This allows HIMEM to manage the
actual locations any way it pleases in a transparent manner - so if I
wanted to allocate a 1.5 meg block of XMS memory (certainly possible)
I could reference it at anytime with a single handle. Certainly an
improvement over paging! Another advantage of handles is a program
can use several blocks of XMS memory of varying sizes without regard
to the physical location of the memory or what's in it. Just use the
handle much like you would a DOS file handle and let it go at that.
There is one responsibility you as programmer must undertake when
deciding to use extended memory in your program. You must make sure to
release any XMS memory you allocate before your program ends its
execution. This memory is not managed by DOS at all, so DOS can not
automatically release XMS on program termination as it does for
conventional memory. If a program exits without releasing it, the
memory remains allocated until the next time the computer is booted!
Although the demo program I have included does not do this, you should
trap all possible means by which your program can be terminated.
Included with this text is my extended memory interface for
QuickBASIC, the XMS driver. When designing XMS I had considered using
a system of pointers to emulate a block storage device, and using it
like a disk drive. However, after some consideration I decided to
implement it similar to the manner Ethan Winer had implemented his
expanded memory interface for QuickPak Professional. The major reason
for this design decision is simulation of a block device would not
remove enough of the management required by the programmer. I think
that although somewhat limited, the XMS driver provides a good amount
of flexibilty while insulating the programmer from much of the work
involved.
Let's now take a look at the ten procedures that make up the XMS
driver for QuickBASIC. I won't get into the calling syntax here (it is
included as part of the ZIP file in XMS.DOC) but will instead provide
some comment on the operation of each. If you wish to see these
routines in action just run the small demo program included with the
driver package.
The QBNews Page 24
Volume 3, Number 1 March 29, 1992
INITXMS is the procedure to get the ball rolling. This procedure
checks for the presence of HIMEM.SYS and determines the availability
of XMS memory. This procedure returns the availability and size of any
XMS memory on the machine in two integers. The size returned is the
actual XMS available in K bytes (that is, this number times 1024 is
the actual size).
GETXMS is a function that allocates a block of XMS memory and returns
its handle. The only parameter for this function is the size of the
memory block you are requesting, in K bytes (1024 bytes is the
smallest increment in which HIMEM.SYS will allocate XMS memory). You
may specify a block of any size up to and including all available
memory! Block sizes of several meg are commonplace. If desired, you
may specify a number of different blocks for different purposes.
FREEXMS will deallocate (free up) memory that was allocated using
GETXMS. Simply call it with the handle of the block you wish to
release. See the above paragraphs for the importance of using this
call.
ARRAY2XMS is a procedure that will copy any continuous block of
conventional memory to an allocated block of XMS. This procedure will
copy the block of conventional memory into the XMS block at offset
zero into the block. One interesting use of this procedure is saving
huge arrays to XMS with one call. In fact, given enough extended
memory, you could conceivably copy the entire contents of conventional
memory to XMS! You can use this call with any far array. The only
limitation posed by this procedure is the number of bytes to move must
be an even number. Odd numbers are forced even without comment or
error.
XMS2ARRAY is the compliment routine to ARRAY2XMS. Its function is to
copy a block of memory from XMS to conventional memory. I have used
these two routines to save and restore the screen directly from XMS.
The only drawback to using this method to save and restore screens is
HIMEM.SYS knows nothing of retrace checking for CGA monitors, and may
cause some snow. Other uses include restoring huge arrays with one
call and loading code stored in XMS.
XGETELEMENT is one of those afterthought routines. If you know the
size of the array elements you have stored in an XMS block (and you
should), this procedure will allow retrieving a single element from
that block. The demo program uses this routine to display any random
element the user chooses. The procedure uses your element size and an
element number to determine where in the XMS block to start reading.
Please note this procedure assumes the first element of your stored
array is item number one, not zero. Also, your element size must be an
even number.
XSETELEMENT is the compliment procedure to XGETELEMENT and has
identical syntax. This procedure will allow the setting of any
individual element stored in XMS memory. The demo program uses this
procedure to change any chosen element to a new value of the user's
choice. These two routines can let you set up a "virtual" array in
The QBNews Page 25
Volume 3, Number 1 March 29, 1992
extended memory of any element size, up to and including all installed
XMS!
Next come three procedures that deal with error handling. These
procedures were inspired by Ethan's QuickPak Professional and really
bind the whole thing together. My personal salute to Ethan Winer for
such insightful design!
XMSERROR is a function that will return the current state of error,
but not the specific error code. This is extremely handy when you wish
to test for an error condition, but don't care what error has
occurred. Very neat code can be written for error handling as so:
.
.
CALL Array2XMS(SEG Array%(start%), XHandle%, NumBytes&)
IF XMSError% THEN
PRINT "Error transferring array to XMS"
(branch to error handling code here)
ELSE
PRINT "Array transferred"
END IF
.
.
The status of errors is updated after every call in this driver except
for INITXMS. Thus, any sucessful operation will clear the value of any
previous error.
It should be noted that if XMS memory is not available for any reason
(such as HIMEM not installed, extended memory not installed or none
available) this function will always show an error condition. This
way programming logic will not have to adapt much to the presence or
lack of XMS memory.
WHICHXERROR is a function that will return the actual code of an error
reported by XMSError. This routine would most likely be used inside an
error handling routine to determine the course of action required by
the program. If there is no outstanding error condition WhichXError
will return a zero.
WhichXError is designed so if XMS memory is not available for any
reason this function will always return a "Function not supported"
error. I thought it might cause some confusion if a call to a routine
in this driver fails because XMS is not available and the reported
error was "No Error"!
SETXERROR is a sub you can use to set the error code returned by
WhichXError. This sub will allow setting error codes in the range of 0
to 255 inclusive. I thought for completeness this procedure should be
included. I also thought about allowing this sub to work if no XMS is
installed but then decided against it. Again, some confusion could
result if you set the error code to zero when no XMS was installed.
So, if XMS is not available to the driver, this sub will have no
The QBNews Page 26
Volume 3, Number 1 March 29, 1992
effect on anything.
Well, that pretty much wraps it up. Included with the XMS package is a
sample program and source code that demomstrates use of most of the
routines in this package. One glaring error that stands out is a
CRTL-C will abort this program prematurly (it uses standard DOS I/O so
it can be interrupted easily) and lose the allocated memory until next
reboot. I did this intentionally so you could see the results of such
a programming practice. If you experiment, you'll see that when you
try to run the demo again, it will tell you there is no available XMS
memory!
These routines have been tested pretty thoroughly, but not completely.
It is after all just a prototype for something normally not possible
within a QuickBASIC program. I hope it provides you with many hours of
entertainment just pushing the driver to the limits!
I have only scratched the surface of the potential of this driver. I
am sure there are hundreds (perhaps thousands) of practical
applications for blocks of memory larger than those you can access by
any other means except straight protected mode programming. I would
be interested to learn just what feats can be accomplished using this
code as a starting point.
If you have any comments concerning the XMS driver package or would
like to ask me a question concerning it, feel free to contact
Sequental Software's support BBS at (606) 561-5766 24 hours daily.
There's no registration fee and you get full privs on the first call.
I'm usually on it every day, so your question should be answered in
about 24 hours or so. If you are more inclined to write, send your
response to:
Sequential Software Inc.
P.O. Box 53
Somerset, KY 42502-0053 USA
Make sure to put it to my attention. I will answer as soon as possible
by mail.
Have fun and good luck!
SOURCE CODE FOR THIS ARTICLE CAN BE FOUND IN XMS.ZIP
The QBNews Page 27
Volume 3, Number 1 March 29, 1992
----------------------------------------------------------------------
Q B A S I C C o r n e r
----------------------------------------------------------------------
Extending the QBasic Interpreter by Brent Ashley
With the widespread acceptance of MS-DOS 5.0, many people are
discovering and rediscovering the power of modern, structured BASIC.
This is evidenced especially in the various BBS network programming
echoes, where very often a reply is now prefaced with:
"Well, if by QBasic you mean the one that came with DOS 5.0 then
I'm afraid that can't be done; but if you mean the QuickBASIC
compiler, well then you simply..."
QBasic (the interpreter) differs from QB (the QuickBASIC compiler) in
a few ways, but mostly in its extensibility, or more to the point,
lack of it. Keen QBasic programmers soon run up against the
language's limitations, mostly as regards system-level programming.
While the obvious solution would be to buy QuickBASIC for its access
to DOS and BIOS interrupts and its easy extensibility via code
libraries, in many situations this is impractical. Perhaps your
company MIS department disallows language purchases by "common users"
(I hear bells ringing in heads all over the continent as you read
this!), or your personal budget doesn't allow for it yet. It would be
best to use a company-sanctioned tool, or one you already have, if
only it provided the functionality you needed.
One advanced feature Microsoft "left in" the QBasic interpreter is the
CALL ABSOLUTE statement. This statement allows you to call a
machine-language routine at a known place in memory, and to pass it a
list of arguments. At first glance it doesn't seem to be of much use,
but with a little imagination, you can use this feature to extend the
use of QBasic far into QB's realm.
I have written three assembly-language routines which, together with
their BASIC support routines, add the following to the QBasic arsenal:
o DOS and BIOS Interrupt calls
o Almost instant memory block copies
o Fast colour single-line box drawing
You will find these routines with ASM source, along with a demo
program containing many sample QBasic support routines, in QBASIC.ZIP.
Meanwhile, I'll explain here the methods I use to load and call binary
routines and some of the further-reaching implications. Keep in mind
that all of these routines work just as well with the QuickBASIC
compiler, as long as the CALL ABSOLUTE routine from QB.LIB is
available.
I'll try to encapsulate the essence of loading and calling a BIN file
from QBasic in a short example. This example program uses the
MEMCOPY.BIN file to quickly copy a block of memory so screen saves can
be done without PCOPY, which isn't supported by monochrome adapters.
The QBNews Page 28
Volume 3, Number 1 March 29, 1992
The source is followed by a discussion of its innards.
-------------- ASM Source ---------------------------------------
; MemCopy.ASM - by Brent Ashley
; Copies blocks of memory quickly
; - to be used primarily for screen saves.
;
.MODEL medium, BASIC
.CODE
MemCopy PROC USES si di ds es, \
FromSeg:PTR WORD, FromOfs:PTR WORD, \
ToSeg:PTR WORD, ToOfs:PTR WORD, \
Count:PTR WORD
; load ds:si with source, es:di with destination
mov bx,FromOfs
mov si,[bx]
mov bx,ToSeg
mov es,[bx]
mov bx,ToOfs
mov di,[bx]
mov bx,Count
mov cx,[bx]
; ds last (used to access data)
mov bx,FromSeg
mov ds,[bx]
; do the copy
cld
rep movsb
ret
MemCopy ENDP
END
--------------- QBasic code --------------------------------------
DEFINT A-Z
DECLARE FUNCTION LoadBin$ (BinFileName$)
CLS
FOR i = 1 TO 24 ' fill screen with letters
PRINT STRING$(80, 64 + i);
NEXT
ScrnSave 1 ' save screen
SLEEP 1 ' wait a second for user to see screen
CLS
PRINT "That screenful of letters has been erased."
PRINT : PRINT "Press a key to restore screen..."
DO: LOOP UNTIL LEN(INKEY$) ' wait for key
ScrnSave 0 ' restore screen
END
SUB ScrnSave (SaveRestore) STATIC
' save/restore a text screen
' save = nonzero, restore = 0
STATIC InitDone, ScrnBuf, VidSeg ' ensures local scope
IF NOT InitDone THEN
The QBNews Page 29
Volume 3, Number 1 March 29, 1992
REDIM ScrnBuf(1 TO 2000) ' 4000 bytes (80x25x2)
DEF SEG = 0
IF PEEK(&H463) = &HB4 THEN ' determine mon/colour
VidSeg = &HB000 ' mono
ELSE
VidSeg = &HB800 ' colour
END IF
DEF SEG
InitDone = -1
END IF
IF SaveRestore THEN ' save
BlockCopy VidSeg, 0, VARSEG(ScrnBuf(1)), VARPTR(ScrnBuf(1)), 4000
ELSE ' restore
BlockCopy VARSEG(ScrnBuf(1)), VARPTR(ScrnBuf(1)), VidSeg, 0, 4000
END IF
END SUB
SUB BlockCopy (FromSeg, FromOfs, ToSeg, ToOfs, Count)
' copy a block of memory
STATIC MemCopy$ ' ensure local scope
IF NOT LEN(MemCopy$) THEN MemCopy$ = LoadBin("MemCopy.BIN")
DEF SEG = VARSEG(MemCopy$) ' point to routine's segment
CALL Absolute(FromSeg, FromOfs, ToSeg, ToOfs, Count, SADD(MemCopy$))
END SUB
FUNCTION LoadBin$ (BinFileName$)
' Loads a binary file as a string
STATIC FileNum, Buf$
FileNum = FREEFILE
OPEN BinFileName$ FOR BINARY AS FileNum
IF LOF(FileNum) = 0 THEN ' file didn't exist
CLOSE FileNum
KILL BinFileName$
CLS : PRINT "Can't find "; BinFileName$; " - aborting."
END
END IF
Buf$ = SPACE$(LOF(FileNum)) ' size buffer
GET FileNum, , Buf$ ' load BIN routine
CLOSE #FileNum
LoadBin$ = Buf$
END FUNCTION
--------------------- end of example --------------------------------
The Assembly routine was written with Microsoft's QuickAssembler. I
used some of its advanced segment directives and high-level language
interface capabilities, but knowledgeable (read:masochistic)
programmers could generate similar .BIN files with DEBUG as long as
they were familiar with accessing stack parameters and cleaning up the
stack on return. All it does is to load DS:SI and ES:DI with the
source and destination and then copy the number of bytes specified by
Count, which is in the range 0 to 65535. The routine is assembled and
then converted to binary image with EXE2BIN. The resulting file is
called MEMCOPY.BIN.
The QBNews Page 30
Volume 3, Number 1 March 29, 1992
The QBasic code consists of a short main module which fills the
screen, saves it, erases it, and restores it, using our routine.
While only the ScrnSave procedure is called by the demo, ScrnSave
relies on BlockCopy, which in turn relies on LoadBIN$.
ScrnSave saves and restores the screen by reserving a block of memory
to use as a buffer. This allows fast screen saves on monochrome
adapters, which do not have extra video pages as do colour adapters.
The first time the routine is called, it dimensions the buffer array
and determines the adapter type and therefore the address of the
screen page. Then, and on any subsequent calls, it copies the the
screen contents between the buffer and screen memory, depending on the
value of SaveRestore.
The BlockCopy routine performs the copy requested by ScrnSave. On
first pass, it loads the ASM routine from its .BIN file on disk into
the string MemCopy$, which has been declared as STATIC. The STATIC
declaration causes it to retain its value between calls ensures it
isn't affected by any module-level variable of the same name which may
have been declared with the SHARED attribute. It then uses the CALL
ABSOLUTE statement to call the BIN routine. This is done by setting
BASIC's current DEF SEG to the routine's segment and then passing the
address of the routine to run, along with the parameters to pass. It
is interesting to note that CALL ABSOLUTE takes a variable number of
parameters, depending on the requirements of your routine. Note that
SADD is used to determine the address of the routine, since it is
stored in a string variable.
LoadBin$ is a general-purpose function to load these .BIN files from
disk into a string. It assumes the file is in the current directory
or that the path is specified in BinFileName$. The file is loaded
into a string which is then returned by the function, to be called
with CALL ABSOLUTE by your QBasic-level support routine.
Using the methods demonstrated in this example, it is possible to
extend QBasic's power as far as your assembly skills allow. It is
even possible to write support routines which would allow the creation
and use of BIN libraries. I had contemplated doing this but decided
that interest wouldn't be high enough due to the availability of the
QuickBASIC compiler, and the fact that multiple BIN files in a
"library" directory would be simple enough to implement under the
scheme outlined above.
There are some details and implications of the BIN routine methods
described above which aren't readily apparent.
Firstly, in exploring the CALL ABSOLUTE assembly interface, one will
soon discover that FUNCTIONs are not readily supported. The simple
solution to this will serve to exemplify an important aspect of
QBasic/BIN programming - the QBasic "front-end" routine.
We met the front-end routine in our example program, in the guise of
the BlockCopy routine. This routine served to insulate our main
The QBNews Page 31
Volume 3, Number 1 March 29, 1992
program from the details of loading and calling the BIN file. It was
called with only the parameters relevant to the task at hand, and in
turn called the ABSOLUTE routine with the additional BIN-file specific
parameters.
Since the front-end file takes care of some of the dirty details of
BIN file calls in easy-to-code-and-maintain QBasic, we can simplify
the assembly routine, often the hardest to write and most difficult to
maintain part of the hybrid program.
Take the example of a routine which uses the BIOS to print a
character. In QBasic, we would like to pass to the routine the
character, its positional row and column on the screen, and the
foreground and background colours in which to print the character.
Our calls to this routine might look like this:
BIOSPrint Char$, Row%, Col%, Fore%, Back%
Anyone who has written assembly routines for BASIC will attest to the
hassles involved in accessing BASIC's dynamic strings. It would be
nice to write the routine to receive the ASCII value of the character
instead as an integer. Furthermore, the BIOS routines use 0-based
screen positioning, as opposed to the 1-based positioning used in
QBasic. To insulate the user from confusion, the routine should
adjust QBasic row and column values to BIOS values, and even build
them into a single integer to be loaded into a register for the BIOS
call. Lastly, the BIOS routine will want a single integer colour
attribute, meaning you will have to program the conversion routine if
the separate colours are sent. Really, then, the BIN routine really
wants the parameters sent like this:
CALL ABSOLUTE(AsciiValue%, BIOSPosition%, Attribute%, BINAddress%)
Your front-end routine, then, can take care of all of these
conversions, thus minimising the assembly code so it performs only
that which QBasic can't do for itself:
SUB BIOSPrint (Char$, Row%, Col%, Fore%, Back%)
STATIC BINFile$
IF BINFile$ = "" THEN BINFile$ = LoadBinFile("BIOSPRT.BIN")
AsciiValue% = ASC(Char$)
BIOSPosition% = (Row% - 1) * 256 + (Col% - 1)
Attribute% = (Fore% AND 16) * 8 + (Back% AND 7) * 16 + (Fore% AND 16)
DEF SEG VARSEG(BINFile$)
CALL ABSOLUTE(AsciiValue%, BIOSPosition%, Attribute%, SADD(BINFile$))
END SUB
The front-end routine also answers the FUNCTION problem. Here is the
code for a fictitious CurDrive function which would act identically to
the one in the QBIN demo program:
FUNCTION CurDrive%
STATIC BinFile$
' returns logged drive (a=1, b=2, etc)
The QBNews Page 32
Volume 3, Number 1 March 29, 1992
IF BinFile$ = "" THEN BINFile$ = LoadBinFile("CurDrv.BIN")
AXReg% = 0
DEF SEG VARSEG(BinFile$)
CALL ABSOLUTE(AXReg%, SADD(BinFile$))
CurDrive% = AXReg% MOD 256 + 1
END FUNCTION
Since you can't return values to CALL ABSOLUTE in the same way you
would when writing assembly FUNCTIONs for compiled QuickBASIC, you
have to provide your assembly routine with references to variables to
be changed and then use the front-end routine to pass them to the
caller via a FUNCTION.
The second point I'd like to make is more far-reaching and has much
more potential for power - the use of strings containing BIN files as
parameters to your BASIC routines.
Anyone who has used Nantucket's Clipper 5.x product will know the
power of "code blocks". These are sections of code which can be
assigned to a variable and passed between routines like data.
Actually, the code is static in memory and the routines receive
references, but knowledge of these details is not necessary. In this
way (among others), the Clipper implementation differs from that of C
and PASCAL, for instance, where you use "pointers to functions", which
demand that you dwell on some of these details directly.
Let's say you want to write a generic sort routine. You want it to
support ascending and descending sorts, as well as sorting starting at
a certain column of the input strings.
The normal way to do this would be to provide a passed argument
specifying which of the hard-wired methods to use, for example:
CALL SortArray ( Array$(), TypeOfSort% )
Deeper inside the routine, you would have code similar to:
SUB SortArray (...
...
SELECT CASE TypeOfSort% ' choose hard-wired method
CASE 1 ' ascending
IF Array$(i) < Array$(j) THEN SWAP Array$(i), Array$(j)
CASE 2 ' descending
IF Array$(i) > Array$(j) THEN SWAP Array$(i), Array$(j)
CASE 3 ' sort from column 5 ascending
IF MID$(Array$(i),5) < MID$(Array$(j),5) THEN SWAP ...
...etc
If you were to write a series of ASM routines, however, each of which
took two string parameters, performed a comparison according to your
latest whim, and returned a true-or-false value, then saved these as
BIN files, you could simplify your routine to:
Compare$ = LoadBINFile( "MyAsmFn.BIN" )
The QBNews Page 33
Volume 3, Number 1 March 29, 1992
CALL SortArray ( Array$(), Compare$ )
SUB SortArray (...
...
IF CallBINFunc(Compare$, Array$(i), Array$(j)) THEN SWAP ...
You and your users can now write ASM modules yourselves to your specs
and extend the functionality of your routine without touching its
innards.
You could also use this method to send a user-defined filter condition
to your display routine, or to tell an event handling routine what to
do when it is triggered - all completely extensible without
recompiling your main code or even having access to source!
Unfortunately, the kind of flexibility that would really make these
methods shine (access to QBasic variables, definition of code blocks
in QBasic itself, pointers to functions...) isn't available with
external BIN files. Perhaps Microsoft has been thinking of something
like this for the future? I would be interested in anyone's ideas on
how to expand on these concepts.
I can be found lurking about many QuickBASIC conferences on the
various BBS networks, including Fido's QUIK_BAS echo, ILink, RelayNet
(RIME), and NorthAmeriNet (NANET). Feel free to drop by and say hello.
SOURCE CODE FOR THIS ARTICLE CAN BE FOUND IN QBASIC.ZIP
======================================================================
Brent Ashley is a Technical Support Analyst for the Ontario
Government, troubleshooting a province-wide data communications
network and providing hardware and software support to a 24-hour
micro/mainframe helpdesk operation. He can be reached in care of this
newsletter.
======================================================================
The QBNews Page 34
Volume 3, Number 1 March 29, 1992
----------------------------------------------------------------------
S w a p S h o p - Q B S o u r c e C o d e E x c h a n g e
----------------------------------------------------------------------
Creating Vertical Menus by Bernard Veerman
You don't always need a complex set of routines to perform WINDOW like
techniques. To avoid confusion with the word WINDOWS, from hereon I'll
use the buzzwords TABLES and PAGES. As a matter of fact, the basics do
have things in common, but I prefer to keep things clear (and fast). I
need tables in my programs like files, text and directories. These I
want to display, move forwards and backwards through it, select and
pick an item and that's it. The programming for that I did myself, be-
cause I couldn't find any flexible and uncomplicated software. What is
left, are some powerful subprograms that might be used by itself or
may be added to a (personal) library. The "tables" are made reentrant,
that means: use the table as you wish, destroy the existing screen and
recall the table any time you need it. The advantage is, the table
attributes and pointers are popped from a stack and allow you to con-
tinue where you left off. Want to relocate the table, just open it
again and tell it where to pop up. Basically there is nothing more than
2 calls:
TABLOPEN, pushes attributes and pointers to an internal stack;
TABLSLCT, displays the table and handles keystrokes.
the syntax of both functions is:
TABLOPEN TNR, ROW, COL, HGT, WID, SF, SB, BF, BB, TY$
TNR = table number, in this example valid between 1 and 6.
Array TablDefs could be part of your library.
ROW = row where table is to be displayed on the screen. If you intent
to use a frame around your tablepage, ROW is the display line
where the frame will start. Height and Width are adjusted by the
function.
COL = column where table is to be displayed on the screen. See ROW for
comments on Height and Width.
HGT = is tableheight in lines. Validation is left out the program to
keep the coding simple and clear. You may add validation if you
wish, it won't be difficult. HGT will be 2 less if a frame is
used.
WID = is tablewidth in characters. Also no validation, same as HGT.
WID also will be 2 less if a frame is used.
FS = foreground color of screen. See COLOR instructions as explained
in your DOS manual. VZCOLORS.BAS includes the dutch names for
colors, brightness and blinking. No validation is done on colors
escpecially equal fore- and background colors might cause confu-
sion. Something like black characters on a black background. If
The QBNews Page 35
Volume 3, Number 1 March 29, 1992
you do this careful, you will have no problems.
BS = background color of screen. See FS parameter.
FB = foreground color of bar. The bar will run up and down over the
table entries and is advised to have a different color than the
screen to make it visible.
BB = background color of bar. See FB parameter.
TY$ = type of frame, if you need one. "" (null string or character)
means that you don't want a frame. "S" will create a single
line frame, "D" a double. Lowercase is allowed. In the coding
you find a routine called DRAWBOX as you'll find in any library,
so if you have one of your, than use it.
After declaration of your table(s) nothing happens until you call the
table handler TABLSLCT. Since all attributes and pointers are pushed
on the stack TablDefs, it simply uses the table number to pop them
back to where you need them. All, except two (PTR and CUR), are
treated as CONSTANTS until you change them. PTR and CUR are saved as
soon as you leave the table handler for further use. The table handler
returns them when you access the table again. This is one of the nicer
features, because in this way tables are reentrant. For a good impres-
sion of how things work, look in the example program where you find
the 3 OPEN's and then how they are used.
The full syntax of the table handler is:
TABLSLCT TNR, Table$(), Entry$
TRN = table number, between 1 and 6, by using this number you will
make the table handler refer to the stack entry where attri-
butes and pointers for this table are stored.
Table$() = name of the table you want to use. The table must be decla-
red with a DIM statement and filled with the data you want
to be handled by the table handler.
Entry$ = will return your pick from the table or "<ESCAPE>" if you
used the escape key. This is very convenient if you need
to know if an escape was used.
The table handler uses a couple of functions and a stack to store the
attributes and pointers. The stack and the internal subprograms are
strongly advised to integrate in a (personal) library so that you
don't have to worry about these things when you're using the table
handler. So again convenience is very important. Just fancy this:
DIM Titles$(250)
now fill array with data
TABLOPEN 1, 250, 6, 60, 16, 20, WT, ZW, ZW, WT, "S"
The QBNews Page 36
Volume 3, Number 1 March 29, 1992
TABLSLCT 1, Titles$(), Book$
now, talking about powerful programming! To explain these statements
in brief:
DIM Titles$(250) allocate array for 250 titles
fill array with titles
TABLOPEN 1, 200, 6, 60, 16, 20, WT, ZW, ZW, WT, "S"
| | | | | | | | | --- single line frame
| | | | | | | | +----- bar: black on white
| | | | | | | +----- screen: white on black
| | | | | | +--- table with 20, including frame
| | | | | +--- table height 16, including frame
| | | | +--- column to display table
| | | +--- row to display table
| | +--- actual number of entries used in array Titles$
| +--- table number in stack TablDefs
+--- call to declare table
TABLSLCT TNR, Titles$(), Book$
| | | ------- returns your pick or "<ESCAPE>"
| | +--- tell table handler to pick from array Titles$
| +--- use attributes and pointers as declared for table 1
+--- call table handler
In a matter of facts, this is all you have to do. The demo-program
shows how you can use the table handler. To summarize, for the user
two sub programs are called to handle tables:
1. TABLOPEN
2. TABLSLCT
the table handler itself uses some internal subprograms and needs a
stack to store the attributes an pointers, they are:
1. TablDefs(), reasonable dimension is (6, 12).
2. DRAWBOX or any other similar function.
3. TABLDISP, this one displays a table page.
4. TABLLINE, this one switches lines from normal to reversed video
and back.
5. TABLLOAD, this copies the attributes and pointers to the handler.
SOURCE CODE FOR THIS ARTICLE CAN BE FOUND IN TABLE.ZIP
======================================================================
Bernard Veerman is a professional IT staff member at Amsterdam
Schiphol Airport in the Netherlands. He has been using QuickBASIC
since version 2.0, and has a number of shareware utilities available.
He can be reached at the following address:
Bernard Veerman
Donizettihof 5
2402 EH ALPHEN ad RIJN
NETHERLANDS
======================================================================
The QBNews Page 37
Volume 3, Number 1 March 29, 1992
Windowing in BASIC by Mark Butler
Preface by David Cleary
The last issue of The QBNews contained an assembly language windowing
library written by Christy Gemmel. This proved to be on of the most
popular articles ever in The QBNews. However, some people said "The
ASM routines are great, BUT, I program in BASIC and I want to see
BASIC routines to do that." You've got your wish. A little while ago,
Mark Buttler posted this code in the Fidonet QuickBASIC echo, and I
was quick to capture it. It is comprised of three routines. They are:
Explode (UpRow%, LCol%, LoRow%, RCol%)
Expand (UpRow%, LCol%, LoRow%, RCol%)
ScreenClear (LineColor%)
They are contained in WINDOW.BAS. Explode will pop a window on the
screen instantly. Expand will create a window that expands little by
little. ScreenClear is a neat little special effect for clearing the
screen. Load WINDOW.BAS up in your QB editor and enjoy.
----------------------------------------------------------------------
Viewing Files in BASIC by Matt Hart
This is another gem that was posted in the Fidonet QuickBASIC echo by
Matt E. Hart, QB Guru (echo joke). It is a complete routine that
allows viewing of a text file of up to 16384 lines without the use of
temporary files. The routine supports the arrow keys, page up and
down, home and end, and escape.
' View any size text file without
any temporary files. ' Keeps the SEEK position of each line in a long
integer array - ' which does limit this to 16,384 lines of text (and
makes this ' program easy, small, and fast.) Key controls are up,
down, ' left, right, page up, page down, end, home, and escape.
Although the program is laid out as a stand alone application, you
shouldn't have too much trouble integrating it into your own programs.
The code is contained in VIEWFILE.BAS.
The QBNews Page 38
Volume 3, Number 1 March 29, 1992
----------------------------------------------------------------------
A l g o r i t h m s
----------------------------------------------------------------------
QuickInsert Sort Algorithm - a push from B$ASSN by Larry Stone
One of the fastest, all purpose sort algorithms, is QuickSort.
QuickSort is one of the sort routines supplied with the Microsoft
program, "DEMOSORT.BAS". Speed is achieved by picking a random pivot
point then moving every element bigger to one side of the random point
and every value smaller to the other side. QuickSort then recursively
calls itself from within its two areas of code that deal with those
elements greater or smaller than the pivot point.
I like QuickSort but, alas, there are a couple of limitations that
prevent me from incorporating into my code. The first is the fact
that the pivot point is randomly selected. This means that the
floating point library is loaded into the program. This is no small
matter. The floating point library can add upwards of 10,000 bytes to
one's final EXE size and, if the program is designed to avoid using
floating point routines, this then becomes a prohibitive cost.
The floating point library can be avoided by substituting a "homemade"
random routine - one that uses LONG integers in lieu of real numbers.
An outstanding replacement one could use is found in the book,
"Microsoft QuickBASIC Programmer's Toolbox", by John Clark Craig.
Craig's random generator is a QB version of two routines described in,
"The Art of Computer Programming", Vol. 2, "Seminumerical Algorithms",
by Donald Knuth. The random generator is an excellent replacement for
QB's because it not only doesn't use floating point but also, it has a
sequence length greater than 2^55 with a possible 256^83 possible
sequences. That's an awful lot of random numbers!
The real disadvantage to the QuickSort is the fact that it uses
recursion. If there is a lot of data to sort, this recursive routine
will blow the top of the stack. This can be overcome by setting a
larger stack. Placing the statement, "CLEAR,,16384" at the top of the
code will establish 16K of stack space. Conversely, "STACK 16384&"
will do the same with PDS and the linker option, "/ST:16384", will do
it if one compiles using PDQ. However, there is no free lunch.
Increasing the stack size is accomplished by a comparable reduction in
code and string space in DGROUP.
Two other, quick sort routines may offer relief. The WAVE sort,
developed by Richard F. Ashwell for GW-BASIC is somewhat slower than
the QuickSort but on large sorts, it really shines. Another extremely
fast sort that on average, is just a smidgen slower than the
QuickSort, is the ripple sort algorithm that MicroHelp supplies with
some of their tools. However, it seems logical that the absolute
fastest sort should be an insertion sort - ie, sorting the data while
it is gathered, intuitively, is faster than other techniques that
requires two separate steps, a gathering followed by sorting.
Unfortunately, BASIC insertion sorts are notoriously slow. They are
The QBNews Page 39
Volume 3, Number 1 March 29, 1992
slow for two, related reasons. They require loops that must touch and
compare array elements, one at a time, until the insertion point is
located. This is generally accomplished by STEPping a FOR...NEXT loop
in a negative direction, pushing each element "up the ladder" until
the appropriate element is freed for insertion with new data. In three
words, slow, slow, slow.
"I-INSERT.BAS" overcomes the, up-to-now, inherent slowness of BASIC
insertion sorts by incorporating two separate processes into its
algorithm. The first part of the algorithm uses a modified binary
search to quickly locate the appropriate insertion point. The binary
search algorithm is not the generic binary search. Although, like any
binary search, it looks for a match between an array elements data and
the data to be inserted, it also looks for the appropriate spot where
the existing array data has greater value on the up-side and lesser
value on the down-side. The test data used by I-INSERT contains 150
random integers. On average, the binary search requires 5 steps into
the array to locate the appropriate insertion point for each value
inserted. The maximum number of steps required (for this data group)
is seven and the minimum is one.
The binary search is fast, not only because it minimizes the number of
steps needed to locate the insertion point but also speeds along due
to the nature of its architecture. If you look at the code, you will
note that mathematics are limited to a single expression that adds the
begin value to the ending value. Although the result of this is
divided by two, the division is integer division which QB will compile
as a shift instruction - "middle% = (begin% + ending%) \ 2". The math
like instructions, "begin% = middle% + 1" and "ending% = middle% - 1"
are compiled as INC and DEC instructions to the CPU - again, very
fast. The search performs five tests. The first test is the
conditional entry into the loop, "DO WHILE begin% <= ending%". Two of
the tests are simple comparisons. One test isn't even a test but,
rather, a fallthrough if the previous three tests within the loop are
false. The slowest portion of the search is the first test. It tests
two conditions and if the condition is met, then tests whether the
insertion point is located.
The second algorithm that comprises I-INSERT is the code that moves
the existing data upwards in order to free the appropriate element for
data insertion. It too, contains a single mathematic expression
composed of a compiled SUB and IMUL instruction:
"MoveBytes% = (LastElement% - middle%) * LEN(Arry%(Low%))"
The actual moving of the array's elements is performed by a call to
the routine, "QBMemCopy". This routine is an ALIAS for the QB
procedure, "B$ASSN". B$ASSN copies a specified number of bytes from
one memory location to another memory location in one, very quick
move. B$ASSN requires six parameters: FromSegment, FromOffset,
BytesToCopy, ToSegment, ToOffset, and BytesToTransfer. All are
integers and all must be passed by value. Well, to speed things up
just a wee bit more, the ALIAS for B$ASSN, "QBMemCopy", was declared
using only four arguments: FromAddress, BytesFrom, ToAddress, and
The QBNews Page 40
Volume 3, Number 1 March 29, 1992
BytesTo. Reduction in the number of arguments was accomplished by
using the "SEG" directive which will push the segment and offset onto
the stack. Although the stack still has the same number of arguments,
execution time is again improved because the code does not require a
VARSEG and VARPTR instruction (QB is already aware of the variable's
address so a simple SEG directive suffices). BytesFrom and BytesTo are
still passed by value.
I-INSERT does have some limitations. The first is that B$ASSN can only
move 64K bytes at a time. And, as presently written, it can only move
32K bytes. If you need to move more than 32K but less than 64K then
make the following modification to the code that establishes MoveBytes:
M& = 1& * (LastElement% - middle%) * LEN(Arry%(Low%))
MoveBytes% = M& - 65536 * (M& > 32767)
If you need to move more than 64K bytes then you must do it in
"chunks".
Because B$ASSN performs its copy in a forward direction, you must DIM
another array of equal size to the array you will be inserting into
(or equal to your largest "chunk"). QBMemCopy, the ALIAS for B$ASSN,
first copies a block of memory, bounded by the insertion point to the
last existing array element, to the scratch buffer or working array.
From there, it copies back to the original array but places the data
up one element from their original positions. Once this is
accomplished, the new value is then inserted.
A speed improvement and memory reduction can be achieved using the
MicroHelp routine, MhMove in lieu of B$ASSN. MhMove is smart enough to
realize that data is being moved within the same segment. When MhMove
"sees" this, it reverses the direction flag thereby, allowing for the
copy to be performed only once. As a consequence, MhMove does not
require the work array as a temporary scratch buffer which means that
the memory allocated for B$ASSN to make its first copy to does not
have to be allocated - hence, both a speed and memory improvement.
Using I-INSERT's QuickInsert routine is as easy as eating apple pie.
As your code reads in data, pass QuickInsert the value, the next array
element that is available (LastElement%), and the array in which to
insert the data. The work array or scratch buffer is DIM SHARED as
TempSortArray%() and is not passed in the arguments list (If you use
MhMove or a similar ASM routine then TempSortArray does not even need
to be created.) That's all there is to it.
It needs to be noted that the QuickInsert routine will not execute
from within the QB or QBX environment. This is because neither
environments will recognize the ALIAS for B$ASSN. You must compile it
to run it. Also, if you desire to test its speed against other sort
procedures, to be fair, these procedures need to be timed from the
point in which data is first copied into an array because QuickInsert
is sorting while the array gets filled.
By-the-way, B$ASSN, among other things, is used by QB to copy data
The QBNews Page 41
Volume 3, Number 1 March 29, 1992
from TYPE to TYPE and fixed-length strings to variable length strings.
As a consequence, a lot of QB internal string handling code will be
included with your program if you use this routine. This won't be very
noticeable if your program already uses string handling routines. But
if it doesn't use strings then you should be aware that your EXE size
will substantially increase by declaring and using B$ASSN.
Two final notes. I was originally going to name the routine the "Stone
Insert Sort" but false modesty prevented that. The second is a
challenge. I challenge you, the reader, to discover other QB internals
that can be applied in ways to perform insert sorts on strings and
string arrays.
SOURCE CODE FOR THIS ARTICLE CAN BE FOUND IN I-INSERT.ZIP
======================================================================
Larry Stone is the author of the shareware file manager "SERVICES" and
is also a frequent contributor to The QBNews. He can be contacted in
care of this newsletter.
======================================================================
The QBNews Page 42
Volume 3, Number 1 March 29, 1992
----------------------------------------------------------------------
F u n a n d G a m e s
----------------------------------------------------------------------
Having A Ball - Solution to 12 Ball Problem
I've received exactly one entry into our little 12 ball problem
contest. Luckily, it was correct. A hearty congratulations goes out to
Jim Eccleston of North Vancouver, BC Canada. He wins our grand prize
of a one year subscription to The QBNews. Here is how Jim did it.
----------------------------------------------------------------------
Not very elegant but functional solution to "BALLS" in BALLS.BAS from
Jim Eccleston
North Vancouver, BC
Accompanying info for solution program (in .BAS file also)
Flowchart for weighing sequence structure above follows, with balls
represented by alpha characters A thru L. ( I was less confused! )
Letters shown in the balance pans. Outcome is Left, Balanced, Right
L suffix in letter pairs = underweight, H suffix = overweight
1st Level Weighing
+------+------+
| EFGH | IJKL |
+------+------+
|
+-------------------+---------------------+
2nd Level | | |
+------+------+ +-----+-----+ +------+------+
| IJKE | LABC | | BCD | JKL | | EFGI | HABC |
+------+------+ +-----+-----+ +------+------+
| | | | | | | | |
3rd Level | | | | | | | / |
+---+---+ | +---+---+ | | | +---+---+ | +---+---+
| J | K | | | E | A | | | | | F | G | | | I | A |
+---+---+ | +---+---+ | | | +---+---+ | +---+---+
KL IL JL | EH LL * | | | GL EL FL | IH HL *
| / | \ \
+---+---+ / | \ +---+---+
| G | H | / | \ | K | L |
+---+---+ / | \ +---+---+
GH FH HH | | | KH JH LH
+---+---+ +---+---+ +---+---+
| C | D | | A | L | | C | D |
+---+---+ +---+---+ +---+---+
CH BH DH AH * AL DL BL CL
* = Innaplicable
The QBNews Page 43
Volume 3, Number 1 March 29, 1992
Find above a solution to the Having a Ball problem which I'm sure
will arrive far too late from the frozen north to stand a chance at
the prize unless there's a Canadian section :) , but the feature
is a great addition and I hope it is continued. The problem reminds
me of one I saw in the 60's that used a set of base 3 weights.
Am sending also a small piece of video chewing gum you may want to
use for entertainment purposes or your readers might enjoy.
Best Wishes for this New Year and many thanks for a job
exceedingly well done.
Jim Eccleston.
----------------------------------------------------------------------
All files are contained in the file BALLS.ZIP. Jim's solution is in
the file WINNERS.BAS while Charles Graham's solution (originator of
the problem) is in the file BALLS.BAS. I've also included a small
program Jim sent in with his entry that I think is quite interesting.
It is in the file WORMS.BAS. Load it into QB and enjoy.
The QBNews Page 44
The QBNews Master Index for Volume 2 March 28, 1992
Article Name Vol Issue
======================================================================
Algorithms
Cardan's Method for Solving Cubes...................... 2 3
Improved Cloning Algorithm............................. 2 2
Playing Around with Random Numbers..................... 2 1
Reversing Color Attributes............................. 2 1
Assembler
Event-Driven Mouse Support Library..................... 2 3
Fast Screen Printing................................... 2 2
Pop-Up Windows......................................... 2 4
Setting Error Levels with QB........................... 2 1
CALL INTERRUPT
A Bug Free CALL INTERRUPT.............................. 2 3
Add BASIC 7's DIR$ Routine to your QB Programs......... 2 2
Everything You Wanted To Know About a Program.......... 2 1
How to Copy Files with QB.............................. 2 2
Charles Graham
ASCII Art -- A Piece of Computer History............... 2 2
Having a Ball.......................................... 2 4
How I Came to Know and Love ANSI.SYS................... 2 1
Lines with Style....................................... 2 3
Christy Gemmel
Fast Screen Printing................................... 2 2
Pop-Up Windows......................................... 2 4
Communications
A Look at Crescent Software's PDQComm.................. 2 2
PDQComm 2.5 from Crescent Software..................... 2 1
Using COM3 and COM4 with QB............................ 2 4
Copyrights
Intellectual Property Protection....................... 2 1
Cornel Huth
A Bug Free CALL INTERRUPT.............................. 2 3
Daniel R. Berry
Working with the Rodent................................ 2 2
David Cleary
Add BASIC 7's DIR$ Routine to your QB Programs......... 2 2
Having a Ball.......................................... 2 4
How to Copy Files with QB.............................. 2 2
Setting Error Levels with QB........................... 2 1
Special Preview of Visual Basic........................ 2 2
David Postler
Intellectual Property Protection....................... 2 1
The QBNews Master Index for Volume 2 March 28, 1992
Article Name Vol Issue
======================================================================
David Rice
Create Bar Charts in Text Mode with QB................. 2 2
Create Pie Charts with QB.............................. 2 2
Dick Dennison
Using COM3 and COM4 with QB............................ 2 4
Ethan Winer
QB's Hidden Data Copying............................... 2 3
File IO
Add BASIC 7's DIR$ Routine to your QB Programs......... 2 2
Getting and Setting File Attributes.................... 2 1
How to Copy Files with QB.............................. 2 2
Fred Sexton Jr.
Manipulating Sprites in SCREEN 13...................... 2 3
Fun and Games
ASCII Art -- A Piece of Computer History............... 2 2
Having a Ball.......................................... 2 4
Lines with Style....................................... 2 3
Graphics
A Graphics Mouse Cursor Design System.................. 2 2
Create Pie Charts with QB.............................. 2 2
Fonts in a Can......................................... 2 3
Lines with Style....................................... 2 3
Manipulating Sprites in SCREEN 13...................... 2 3
Reading Print Shop Graphics in QB...................... 2 1
J. D. Hildebrand
Spill the Wine......................................... 2 3
James Young
Playing Around with Random Numbers..................... 2 1
Jim Harre
A Look at Crescent Software's PDQComm.................. 2 2
John Richard De Palma
BASICZen............................................... 2 2
Keith Rolland
Everything You Wanted To Know About a Program.......... 2 1
Larry Stone
Fonts in a Can......................................... 2 3
Improved Cloning Algorithm............................. 2 2
The QBNews Master Index for Volume 2 March 28, 1992
Article Name Vol Issue
======================================================================
Larry Stone
Lines with Style....................................... 2 3
Mike Welch
Introduction to QuickSHARE............................. 2 1
Reading Print Shop Graphics in QB...................... 2 1
Monte Ferguson
Detecting Desqview from
QB............................. 2 1
Mouse
A Graphics Mouse Cursor Design System.................. 2 2
Event-Driven Mouse Support Library..................... 2 3
Working with the Rodent................................ 2 2
QBNews Professional Library
Event-Driven Mouse Support Library..................... 2 3
Fast Screen Printing................................... 2 2
Pop-Up Windows......................................... 2 4
Ray Crumrine
The UEVENT Bug......................................... 2 4
Richard Jones
Cardan's Method for Solving Cubes...................... 2 3
Richard Randles
Getting and Setting Bits............................... 2 1
Rick Cooper
Getting and Setting File Attributes.................... 2 1
Reversing Color Attributes............................. 2 1
Screen IO
Create Bar Charts in Text Mode with QB................. 2 2
Fast Screen Printing................................... 2 2
How I Came to Know and Love ANSI.SYS................... 2 1
Pop-Up Windows......................................... 2 4
Reversing Color Attributes............................. 2 1
Shareware
Introduction to QuickSHARE............................. 2 1
Source Code
A Bug Free CALL INTERRUPT.............................. 2 3
Add BASIC 7's DIR$ Routine to your QB Programs......... 2 2
Cardan's Method for Solving Cubes...................... 2 3
Create Bar Charts in Text Mode with QB................. 2 2
Create Pie Charts with QB.............................. 2 2
The QBNews Master Index for Volume 2 March 28, 1992
Article Name Vol Issue
======================================================================
Source Code
Creating Smaller QB EXEcutables........................ 2 1
Detecting Desqview from QB............................. 2 1
Event-Driven Mouse Support Library..................... 2 3
Everything You Wanted To Know About a Program.......... 2 1
Fonts in a Can......................................... 2 3
Getting and Setting Bits............................... 2 1
Getting and Setting File Attributes.................... 2 1
How I Came to Know and Love ANSI.SYS................... 2 1
How to Copy Files with QB.............................. 2 2
Improved Cloning Algorithm............................. 2 2
Lines with Style....................................... 2 3
Manipulating Sprites in SCREEN 13...................... 2 3
Playing Around with Random Numbers..................... 2 1
Reading Print Shop Graphics in QB...................... 2 1
Reversing Color Attributes............................. 2 1
Setting Error Levels with QB........................... 2 1
Using COM3 and COM4 with QB............................ 2 4
Working with the Rodent................................ 2 2
T. G. Muench
Creating Smaller QB EXEcutables........................ 2 1
Tony Elliot
Event-Driven Mouse Support Library..................... 2 3
Tools
A Look at Crescent Software's PDQComm.................. 2 2
Custom Control Factory for MS Visual Basic............. 2 2
PDQComm 2.5 from Crescent Software..................... 2 1
Tricks and Tips
Creating Smaller QB EXEcutables........................ 2 1
QB's Hidden Data Copying............................... 2 3
The UEVENT Bug......................................... 2 4
View Print
BASICZen............................................... 2 2
Spill the Wine......................................... 2 3
Visual Basic
Custom Control Factory for MS Visual Basic............. 2 2
Special Preview of Visual Basic........................ 2 2
Warren G. Lieuallen
A Graphics Mouse Cursor Design System.................. 2 2