2657 lines
108 KiB
Plaintext
2657 lines
108 KiB
Plaintext
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
**************************************************
|
||
* *
|
||
* QBNews *
|
||
* *
|
||
* International QuickBASIC Electronic *
|
||
* Newsleter *
|
||
* *
|
||
* Dedicated to promoting QuickBASIC around *
|
||
* the world *
|
||
* *
|
||
**************************************************
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews is an electronic newsletter published by Clearware
|
||
Computing. It can be freely distributed providing NO CHARGE is charged
|
||
for distribution. The QBNews is copyrighted in full by Clearware
|
||
Computing. The authors hold the copyright to their individual
|
||
articles. All program code appearing in QBNews is released into the
|
||
public domain. You may do what you wish with the code except
|
||
copyright it. QBNews must be distributed whole and unmodified.
|
||
|
||
You can write The QBNews at:
|
||
|
||
The QBNews
|
||
P.O. Box 507
|
||
Sandy Hook, CT 06482
|
||
|
||
Copyright (c) 1989 by Clearware Computing.
|
||
|
||
|
||
|
||
The QBNews Page i
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
|
||
|
||
----------------------------------------------------------------------
|
||
|
||
T A B L E O F C O N T E N T S
|
||
|
||
|
||
1. From the Editors Desk
|
||
From the Editor .............................................. 1
|
||
|
||
2. Mail Bag
|
||
QBNews in Europe ............................................. 2
|
||
|
||
3. Beginners Corner
|
||
BASIC Menuing and Graphics by Ryan Snodgrass ................. 4
|
||
|
||
4. Who ya gonna call? CALL INTERRUPT
|
||
Directory Swapping by Hector Plasmic ......................... 6
|
||
|
||
5. The Tool Shed
|
||
P-Screen+ and P-Screen Professional by David Cleary .......... 8
|
||
Index Manager - B-Tree indexing for QB by David Cleary ....... 10
|
||
|
||
6. Product Announcements
|
||
P-Screen, P-Screen Professional, P~F Presents ................ 12
|
||
|
||
7. Under The Hood
|
||
Fast File I/O in QuickBASIC by Ethan Winer ................... 16
|
||
|
||
8. Power Programming
|
||
How to Make a Self-Cloning Exe in QuickBASIC by Larry Stone .. 19
|
||
Programming UEVENT by Jim Mack ............................... 23
|
||
|
||
9. Some Assembly Required
|
||
Assembler Programming for QuickBASIC by Tom Hanlin ........... 26
|
||
|
||
10. And I Heard it Through the Grapevine
|
||
Exerpts from the QUIK_BAS echo ............................... 29
|
||
|
||
11. Swap Shop
|
||
Screen Scrolling with Call Interrupt ........................ 33
|
||
Getting the Day of the Week with Call Interrupt ............. 35
|
||
Yes/No Response DEF FN ...................................... 37
|
||
A Replacement for INPUT with MUCH MORE programmer control. .. 39
|
||
Windowing Routines with Shading ............................. 41
|
||
|
||
12. Input Past End
|
||
Get the QBNews on Disk ...................................... 42
|
||
Contacting the QBNews ....................................... 43
|
||
|
||
The QBNews Page ii
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
|
||
----------------------------------------------------------------------
|
||
F r o m t h e E d i t o r s D e s k
|
||
----------------------------------------------------------------------
|
||
|
||
From the Editor
|
||
|
||
Welcome to the third issue of The QBNews. I know it has been a
|
||
while coming but I hope it was worth the wait. There are some big
|
||
changes in store for the news. I have realized that putting out an
|
||
issue every 2 months is impractical. Therefore, The QBNews will be
|
||
published quarterly. Expect issues around these dates:
|
||
|
||
May 30
|
||
August 30
|
||
November 30
|
||
February 28
|
||
|
||
I have also received alot of requests for the news on disk. You
|
||
can now receive the QBNews on disk. Information on this service is
|
||
available in the back of this issue.
|
||
|
||
The QBNews is distributed through SDS on Fidonet. It seems that
|
||
SDS is not as far reaching as I had thought. In order that everybody
|
||
knows that the can get the news reasonably close to them, I would like
|
||
to set up distribution hubs around the country. I am looking for BBS's
|
||
in these areas who would like to be QBNews hubs: Baltimore/Washington,
|
||
Charlotte NC, Atlanta, Orlando, Memphis, New Orleans, Chicago,
|
||
Cincinnati, Minneapolis, Kansas City MO, Dallas, Denver, Phoenix, Los
|
||
Angeles, San Francisco, and Portland. I do require a few things in
|
||
order to be a hub. First, first time callers must be granted limited
|
||
download privledges. Second, you must accept file requests from Point
|
||
systems. Last, you must be willing to send the news down the line to
|
||
the next hub. If you meet these conditions and are interested in being
|
||
a hub, write me.
|
||
|
||
I want to hear from you. After the first issue, I received quite
|
||
a bit of feedback. I wasn't too happy with that issue. I thought the
|
||
second issue was really good. I didn't receive as much feedback on it
|
||
as the first though. It was kind of disappointing. Let me hear your
|
||
complaints, suggestions, coding tips, or whatever. It always helps to
|
||
know people are interested.
|
||
|
||
Thanks and enjoy.
|
||
David Cleary
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 1
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
|
||
----------------------------------------------------------------------
|
||
M a i l B a g
|
||
----------------------------------------------------------------------
|
||
|
||
|
||
Hello David,
|
||
|
||
Today I've picked up 2 QBNews files and I've read them both. Most
|
||
interesting stuff! Just the electronic magazine I need! Coming from
|
||
the TRS80 Model I computer on which I've learned basic and wrote my
|
||
own BBS and videotext systems in basic (the system is still online)
|
||
I've entered the PC community and started with RBBS-PC which is, as
|
||
you would know, almost completely written in QuickBasic. I've
|
||
purchased the package a few years ago and developed a few
|
||
administrative applications in it for a friend his firm. At the
|
||
moment, due to lack of time, I'm only do a little debugging and
|
||
modifying RBBS-PC. I recently discovered a bug (well, I think it is a
|
||
bug) which I will give you here:
|
||
|
||
DEFINT A-Z :' so every variable is by default integer
|
||
Single precision! = 3600 * Hour
|
||
|
||
The maximum value of an integer is 32767 and when you expect
|
||
"Hour" can have a maximum value of 24, then the receiving variable
|
||
must be a single precision variable 'cause by example 20 * 3600 =
|
||
72000. So the construction above looks good but isn't. QuickBasic will
|
||
evaluate "3600 * Hour" as an integer expression 'cause both variables
|
||
are integers. The result will be an overflow error. I've tested the
|
||
same construction on my TRS80 and on the PC in GWBASIC and they both
|
||
work fine!!
|
||
|
||
The solution for this problem is very simple. The technique is called
|
||
typecasting.
|
||
|
||
Single precision! = 3600.0 * Hour :' 3600.0 is of type single
|
||
precision
|
||
|
||
When you enter this in the QB environment, QB will change 3600.0 in
|
||
3600! which is the same.
|
||
|
||
Some undocumented META statements, nice to know:
|
||
' $LINESIZE:132
|
||
' $PAGE
|
||
' $TITLE: 'put the main title here'
|
||
' $SUBTITLE: 'put the sub-title here'
|
||
|
||
Anyway, I hope this is some contribution to the magazine. From
|
||
now on I will put the QBNews files in my two BBS systems and will
|
||
upload them to some other systems here in Holland. I hope more QBNews
|
||
will come from the other side of the ocean. Please respond through
|
||
Fidonet if you receive this message. Where I living, well, in a city
|
||
called Amsterdam, that's in Holland or The Netherlands and that is in
|
||
Europe ('cause many Americans don't know what's on the other side of
|
||
the ocean ;-)
|
||
|
||
|
||
The QBNews Page 2
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
Cu, Kim Kodde (2:500/41.1433) Holland
|
||
|
||
|
||
|
||
Hello David,
|
||
|
||
A very good initiative! I give my full support for whit it's
|
||
worth. I am not a professional programmer and I have no education in
|
||
this area, but I have been programming in BASIC for some years for fun
|
||
and during that time gone from an VIC64 to an AMSTRAD 6128 to an
|
||
Artech 286/AT (and IBM ps 20). I started out with QB 2.00 a couple of
|
||
years ago but recently upgraded to 4.50. It is a marvelous difference.
|
||
|
||
I have also included an extract from a program I have written for
|
||
my work. I am a journalist and the program is used to store things we
|
||
are to check or cover in the future. Certain things come back
|
||
regularly on certain weekdays no matter which date it is. I therefore
|
||
needed a simple routine to check which weekday a certain date is so
|
||
when the agenda for that date is printed out the correct items
|
||
depending on the weekday is included. I found my answer in interrupt
|
||
33, function 2a00. The low part of register AX returns a number for
|
||
the weekday. 0 for Sunday to 6 for Saturday. This is very good for
|
||
the future. If you are interested in checking which day you were born
|
||
for example you need something else because the computer only covers
|
||
dates from the early 80-ies. I have seen programs in genealogy-
|
||
packages which covers this part.
|
||
|
||
Johan Lindgren
|
||
Sundsvall, Sweden
|
||
|
||
|
||
I would be interested in hearing from you. Please write with
|
||
comments, suggestions, complaints, or whatever you feel like talking
|
||
about. Send it to:
|
||
|
||
The QBNews
|
||
P.O. Box 507
|
||
Sandy Hook, CT 06482
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 3
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
|
||
----------------------------------------------------------------------
|
||
B e g i n n e r s C o r n e r
|
||
----------------------------------------------------------------------
|
||
|
||
BASIC Menuing and Graphics by Ryan Snodgrass
|
||
|
||
This section of QB News is dedicated to the readers who are
|
||
novices to Quick BASIC. In this issue we will talk about creating and
|
||
editing simple menu programs and about some of the elementary commands
|
||
used in making computerized graphics. The first thing we talk about
|
||
is making simple menus. The first step you take in making a menu is
|
||
to plan what selections you will have. In our example we will use the
|
||
following selections: DIR, make the computer beep, and quit. The next
|
||
step is to plan whether to use numbers, letters, or both. In our
|
||
example we will use both numbers and letters. The following is an
|
||
example program; you may edit it as much as you like.
|
||
|
||
Menu:
|
||
PRINT "(1) - DIR" 'Shows the first selection (DIR)
|
||
PRINT "(2) - BEEP" 'Shows the second selection (BEEP)
|
||
PRINT "(Q) - QUIT" 'Shows the third selection (QUIT)
|
||
MenuInput:
|
||
A$=INPUT$(1) 'Waits for the input from the keyboard
|
||
IF A$="1" THEN GOTO Selection1 'See if one was pressed
|
||
IF A$="2" THEN GOTO Selection2 'See if two was pressed
|
||
IF A$="Q" OR A$="q" THEN CLS:END 'See if Q was pressed
|
||
GOTO MenuInput 'Go back and wait for another key
|
||
|
||
Selection1:
|
||
SHELL"DIR" 'Do a DIR of the current directory
|
||
GOTO Menu 'Redisplay the menu
|
||
Selection2:
|
||
BEEP 'Produce a beep
|
||
GOTO Menu 'Redisplay the menu
|
||
|
||
-+* To edit selections on this menu do the following: *+-
|
||
|
||
1) Change the menu listing by replacing one of the selections by
|
||
another (i.e. PRINT "(1) - DIR" replace with the following:
|
||
PRINT "(1) - DIR/P")
|
||
|
||
2) Change the selection commands (i.e. change the Selection1 commands
|
||
to:
|
||
Selection2:
|
||
SHELL"DIR/P"
|
||
GOTO Menu
|
||
|
||
-+* To add selections to the menu do the following: *+-
|
||
|
||
1) After the PRINT "(2) - BEEP" add PRINT "(3) - Your Selection"
|
||
|
||
2) After IF A$="2" THEN... add IF A$="3" THEN GOTO Selection3
|
||
|
||
3) After the GOTO Menu on Selection2 add:
|
||
Selection3:
|
||
|
||
The QBNews Page 4
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
'Your command
|
||
GOTO Menu
|
||
|
||
|
||
The next subject we will discuss is elementary commands for
|
||
creating graphics screens. A graphics screen is represented by
|
||
a number of pixels or points on the screen, which is referred to as
|
||
the resolution of your screen. The first step we must do is select a
|
||
screen number which corresponds to your resolution or any other
|
||
resolution you can use. The following is a list of screen number and
|
||
their attributes:
|
||
|
||
+-----------+------------------+-------------+------------------+
|
||
|Screen #: | # of colors: | Resolution: | Width of Screen:|
|
||
+-----------+------------------+-------------+------------------+
|
||
| 1 (CGA) | 4 out of 16 | 320x200 | 40 Characters |
|
||
| 2 (CGA) | 2 out of 2 | 640x200 | 80 Characters |
|
||
| 7 (EGA) | 16 out of 64 | 320x200 | 40 Characters |
|
||
| 8 (EGA) | 16 out of 64 | 640x200 | 80 Characters |
|
||
| 9 (EGA) | 16 out of 64 | 640x350 | 80 Characters |
|
||
| 10 (MONO) | 9 grays | 640x350 | 80 Characters |
|
||
| 11 (VGA) | 2 out of 2 | 640x480 | 80 Characters |
|
||
| 12 (VGA) | 16 out of 256000| 640x480 | 80 Characters |
|
||
+-----------+------------------+-------------+------------------+
|
||
|
||
The next step is to type: SCREEN (and then the type of graphics
|
||
you want). The first and easiest command is LINE. The usage is LINE
|
||
(X,Y)-(X,Y),Color (i.e. LINE (100,100)-(200,200),1 would draw a line
|
||
from 100,100 to 200,200 using the color 1). Using that in an example
|
||
program would be as follows:
|
||
|
||
SCREEN 1
|
||
LINE(100,100)-(200,200),1
|
||
END
|
||
|
||
You can also draw an open rectangle by using LINE (X,Y)-
|
||
(X,Y),Color,B or a solid rectangle by using LINE (X,Y)-(X,Y),Color,BF.
|
||
The next command we will go into is the DRAW command. The usage is
|
||
DRAW "(Attributes)" (i.e. DRAW "U4 R4 D4L4"). The attributes are as
|
||
follows: C#=Color Number, U#=Up a number of pixels, D#=Down a number
|
||
of pixels, L#=Left a number of pixels, R#=Right a number of pixels,
|
||
E#=Up and to the right a number of pixels, F#=Down and to the right a
|
||
number of pixels, G#=Down and left a number of pixels, H#=Up and left
|
||
a number of pixels, M X,Y=Moves to a certain pixel (i.e. DRAW "M
|
||
100,100"). Our example program draws a 3-D box:
|
||
|
||
SCREEN 1
|
||
DRAW "M 100,100 C1 U10 R10 D10 L10 H10 U10 F10 R10 H10 L10"
|
||
END
|
||
|
||
If you have any suggestions as to what you would like to see in
|
||
this column, please send them to the QBNews at the address in the
|
||
back.
|
||
|
||
|
||
The QBNews Page 5
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
|
||
----------------------------------------------------------------------
|
||
W h o y a g o n n a c a l l ? C A L L I N T E R R U P T
|
||
----------------------------------------------------------------------
|
||
|
||
Directory Swapping by Hector Plasmic
|
||
|
||
You've all seen professional programs that let you Shell to DOS
|
||
and always return you to the proper drive and subdirectory when you
|
||
Exit. It's not too hard to implement something similar for your own
|
||
QuickBASIC programs. QB doesn't have all the functions you need to do
|
||
it, but DOS can lend a hand via Interrupt.
|
||
|
||
What we need to do is handle all SHELL calls from a common point
|
||
(Sub). In this Sub, we'll determine the current drive and
|
||
subdirectory, perform the SHELL, then restore the old drive and
|
||
subdirectory before Exitting the Sub.
|
||
|
||
Interrupt 21h function 19h returns the number of the current disk
|
||
drive in register .al as a number (0=A, 1=B, etc.).
|
||
|
||
Interrupt 21h function 47h copies the current directory of the
|
||
drive # in .dl (0=default, 1=A, 2=B, etc.) as an ASCIIZ (null
|
||
terminated) string into a buffer pointed to by .ds:.si. The pathname
|
||
does not include the drive identifier or a leading backslash. An
|
||
error can occur if you use an invalid drive specification; this is not
|
||
likely since we are using the default drive, but if you are using this
|
||
function to attempt to read the default directory on a drive that may
|
||
not exist, check the carry flag (IF OutReg.FLAGS AND 1
|
||
THEN...oops!). .ax will contain 0Fh (invalid drive spec) if the error
|
||
occurs.
|
||
|
||
Finally, Interrupt 21h function 0Eh sets the default drive to the
|
||
drive number passed in register .dx (0=A, 1=B, etc.).This completes
|
||
the list of DOS functions we'll need to perform our switching. What
|
||
follows is some sample code to show a practical application of these
|
||
interrupt functions:
|
||
|
||
DEFINT A-Z
|
||
|
||
TYPE RegType2
|
||
AX AS INTEGER
|
||
BX AS INTEGER
|
||
CX AS INTEGER
|
||
DX AS INTEGER
|
||
BP AS INTEGER
|
||
SI AS INTEGER
|
||
DI AS INTEGER
|
||
Flags AS INTEGER
|
||
DS AS INTEGER
|
||
ES AS INTEGER
|
||
END TYPE
|
||
|
||
'You must link with QB.LIB (QB.QLB) to use Interrupt functions
|
||
|
||
DECLARE SUB InterruptX (Intr%, InReg AS RegType2, OutReg AS RegType2)
|
||
|
||
The QBNews Page 6
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
DECLARE SUB DoShell (Before$, Args$, After$)
|
||
|
||
DoShell "Type EXIT to return", "", "Welcome back" 'Just to test it
|
||
END
|
||
|
||
SUB DoShell (Before$, Args$, After$)'Declare some stuff to use
|
||
|
||
DIM InReg AS RegType2
|
||
DIM OutReg AS RegType2
|
||
DIM CurrentDrive AS INTEGER
|
||
DIM CurrentDir AS STRING * 64
|
||
|
||
'Get current disk drive
|
||
|
||
InReg.AX = &H19 * 256
|
||
InterruptX &H21, InReg, OutReg
|
||
CurrentDrive = OutReg.AX MOD 256
|
||
|
||
'Get current directory
|
||
|
||
InReg.AX = &H47 * 256
|
||
InReg.DX = CurrentDrive + 1 'Note adding one to drive for this, or
|
||
'could use 0 for default drive
|
||
InReg.DS = VARSEG(CurrentDir)
|
||
InReg.SI = VARPTR(CurrentDir)
|
||
InterruptX &H21, InReg, OutReg
|
||
|
||
'Do the shell
|
||
IF Before$ <> "" THEN CLS : PRINT Before$ 'Optional
|
||
SHELL Args$
|
||
IF After$ <> "" THEN CLS : PRINT After$ 'Optional
|
||
|
||
'Change to old disk drive
|
||
InReg.AX = &HE * 256
|
||
InReg.DX = CurrentDrive
|
||
InterruptX &H21, InReg, OutReg
|
||
'(InReg.AX MOD 256 is the # of logical drives in the
|
||
'system if anyone is interested)
|
||
|
||
'Change to old subdirectory (Could use Int &H21 func &H3B instead)
|
||
ToDir$ = CHR$(ASC("A") + CurrentDrive) + ":\" + LEFT$(CurrentDir,_
|
||
INSTR(CurrentDir, CHR$(0)))
|
||
CHDIR ToDir$
|
||
|
||
END SUB
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 7
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
|
||
----------------------------------------------------------------------
|
||
T h e T o o l S h e d
|
||
----------------------------------------------------------------------
|
||
|
||
P-Screen+ and P-Screen Professional by David Cleary
|
||
|
||
*** IMPORTANT ***
|
||
It took me a while to write this review. As you read it, you will
|
||
see I have two major complaints concerning these programs. They are
|
||
lack of mouse support and an easier user interface. These problems
|
||
have been corrected in the latest release. Please see the product
|
||
announcement for the new version in this issue.
|
||
|
||
A program's user interface can be the difference between success
|
||
and failure. You could have the best program in the world but if
|
||
people don't like using it, it won't succeed. The user interface is
|
||
also the part of a program I hate doing the most. I know what I like
|
||
in a user interface but I have a hard time translating it into my
|
||
programs. I also find the coding of user interfaces very tedious. So,
|
||
in this issue, I will review a tool that helps you design user
|
||
interfaces quickly and easily.
|
||
|
||
The product is called P-Screen and is from Pro~Formance. P-
|
||
Screen+ is a shareware program while P-Screen Professional is
|
||
commercial. This program combines a screen drawing utility, a screen
|
||
storage and display utility, and the Professional version adds a
|
||
QuickBASIC 3 and 4 code generator and a variety of user input
|
||
routines. These programs allows you to create screens and forms, store
|
||
them in libraries, and access them from your QuickBASIC programs. We
|
||
will examine these features individually.
|
||
|
||
As a screen generator, I feel that P-Screen has one major flaw.
|
||
It lacks mouse support. Personally, I like mice and I don't like
|
||
having to navigate the screen with the cursor keys. When you start up
|
||
P-Screen Professional, you get a nice title screen that tells you your
|
||
options and waits for you to press a key. After you press a key, you
|
||
are left with a blank screen and a "What do I do now?" look on your
|
||
face. Pressing F1 for help shows you 2 screens of commands but that is
|
||
all. To learn how to use P-Screen, you will need a copy of the printed
|
||
documentation next to you.
|
||
|
||
After you start using the commands and learn what they do, P-
|
||
Screen is a pleasure to use. It allows you to draw your screens and
|
||
store them in either ASCII or a compressed format. P-Screen also
|
||
allows you to load screens saved in QB's BSAVE format but won't let
|
||
you save them that way. If P-Screen had mouse support and better on
|
||
line help, it would be one of the best screen designers available.
|
||
Without it though, it still is very good.
|
||
|
||
Next comes the screen storage and display utility. P-Screen
|
||
stores screens on disk in a compressed screen format. The savings in
|
||
size is very noticeable the more screens you have in a library. P-
|
||
Screen then has two routines that load the screens into an array and
|
||
display them. They are written in Assembler and are very fast. These
|
||
routines allow you to display full or partial screens anywhere you
|
||
|
||
The QBNews Page 8
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
want. I couldn't find anything to complain about. They are nicely done
|
||
and will add a professional look to your programs.
|
||
|
||
Now to what I think is the best part of P-Screen. The
|
||
Professional version comes with a form generator. P-Screen
|
||
Professional comes with the ability to create forms and it generates
|
||
code that handles user input on these forms. See the program Index.Bas
|
||
for an example of the code P-Screen Professional generated for a small
|
||
index card screen I created. The user input routine is nicely done in
|
||
Assembler and includes a variety of formatting options and masks. Some
|
||
of these include Date, Phone Number, Zip Code, Social Sec. Number, and
|
||
Currency. With these options, your program makes sure that the user
|
||
types in only valid keys and in the format you want. The code that P-
|
||
Screen Professional generates is then inserted into your program. This
|
||
allows you to create professional looking documents with very little
|
||
effort. I am very impressed with these capabilities in P-Screen
|
||
Professional.
|
||
|
||
Two shareware programs you should be aware of are P-Screen and
|
||
P~F Presents. P-Screen is the screen drawing and library utility
|
||
portion of P-Screen Professional. Gone are the code generator and form
|
||
utilities and the ability to display partial screens. My advice to you
|
||
is to get the shareware version and try out the screen generator. If
|
||
you like using it to create your screens, then you should certainly
|
||
buy the professional version. You won't be disappointed.
|
||
|
||
P~F Presents is a screen presentation system. It lets you take
|
||
screens created with P-Screen and create slide shows out of them. This
|
||
is great for presentations or prototyping applications before you get
|
||
down to writing code. With it, you can create your whole user
|
||
interface and let the users give you there comments on it BEFORE you
|
||
write any code. This saves a lot of headaches from having to rewrite
|
||
your programs when your views on how the program should operate are
|
||
different from the intended users.
|
||
|
||
P-Screen Professional is available from:
|
||
|
||
Pro~Formance
|
||
132 Alpine Terrace
|
||
San Francisco, CA 94117
|
||
(415) 863-0530
|
||
|
||
The cost is $49 plus $3 shipping and handling. You also can
|
||
download the shareware version of P-Screen and P~F Presents from Peter
|
||
Tiffany's BBS, (415) 458-6404 or on CompuServe in the IBMPro and
|
||
IBMApp areas. The filenames are PSCRN35.ZIP and PFPRES35.ZIP.
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 9
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
Index Manager - B-Tree indexing for QB by David Cleary
|
||
|
||
Databases are an important part of computers and computer
|
||
programming. QuickBASIC has built in capabilities that make it easy to
|
||
write a simple database. The problem is, as your database gets larger
|
||
and larger, it takes longer to find the information you need. That is
|
||
where Index Manager helps out.
|
||
|
||
Index Manager allows you to build single user ISAM (Indexed
|
||
Sequential Access Method) databases using a B+ Tree index. A B+ Tree
|
||
is a data structure that allows you to find information quickly
|
||
without searching something from start to finish. All Index Manager
|
||
does is handle the index of your database allowing you to handle your
|
||
datafile as you please. All you do is to associate a unique "Key" with
|
||
each record and Index Manager does the rest. This key could be a name
|
||
or customer number or what have you. The only thing you have to be
|
||
sure of is that each record in your database has it's own unique key.
|
||
|
||
The specifics of Index Manager are as follows:
|
||
|
||
1. Create an indexed-access file using the key of your choice.
|
||
|
||
2. Read any record on you indexed-access files by specifying it's
|
||
key.
|
||
|
||
3. Browse through your indexed-access file by specifying a partial
|
||
key.
|
||
|
||
4. Read your indexed-access file sequentially sorted by key either
|
||
forward or backward.
|
||
|
||
5. Work with up to ten indexed-access files at the same time.
|
||
|
||
All of Index Manager's functions are incorporated into one call
|
||
making it very easy to use. It is also written in assembly language
|
||
making it extremely fast and small. It only adds 5k of code size to
|
||
your QB programs. It utilizes a large cache buffer to cut down on disk
|
||
accesses when searching for a key. This makes it very fast but also
|
||
introduces one of it's drawbacks. It uses 24k of string space for it's
|
||
buffers. This makes string space kind of tight on large applications.
|
||
I would like to see some sort of variable buffer allocation so you
|
||
could reclaim the string space while sacrificing some speed.
|
||
|
||
Although Index Manager is very easy to use and comes with
|
||
examples showing how to use every function, it doesn't teach you
|
||
database principles. If you know nothing of how to set up good
|
||
databases, you could find yourself making errors that could cause your
|
||
program to not be as useful as it can. The example programs show you
|
||
how the functions work but they are not real world applications. I
|
||
would like to see some examples of things like a small phone
|
||
directory, ect. that will help someone not familiar with database
|
||
programming go in the right direction.
|
||
|
||
Aside from the string space problem and the lack of good database
|
||
examples, I love this program. I received my copy of Index Manager
|
||
|
||
The QBNews Page 10
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
free for the purpose of doing this review. At the time, I had never
|
||
written a database program before. As luck would have it, a database
|
||
programming application had just come up where I work. I decided that
|
||
I would give Index Manager a try in helping me with this project. The
|
||
project turned out so well that my company decided to pay for this
|
||
copy.
|
||
|
||
Index Manager is for those people who just want to add fast
|
||
indexing to their QB programs. It is an alternative to going out and
|
||
spending more money on products like DB-Lib or B-Trieve when you don't
|
||
need all the functions of these products. Index Manager is also alot
|
||
easier to use than those products and allows you to handle your
|
||
datafiles anyway you choose.
|
||
|
||
Index Manager costs $59 and is compatible with QB 2 to 4.5 and
|
||
Bascom 6. A Basic 7 PDS version that supports far strings is in the
|
||
works. You can get Index Manager by contacting:
|
||
|
||
CDP Consultants
|
||
1700 Circo del Cielo Drive
|
||
El Cajon, CA 90202
|
||
|
||
619-440-6482
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 11
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
|
||
----------------------------------------------------------------------
|
||
P r o d u c t A n n o u n c e m e n t s
|
||
----------------------------------------------------------------------
|
||
|
||
P-Screen, P-Screen Professional, P~F Presents
|
||
|
||
Rob W. Smetana (415) 863 - 0530
|
||
Pro~Formance 132 Alpine Terrace San Francisco Ca 94117
|
||
|
||
Program Name Cost Summary
|
||
--------------------- ---- -----------------------------------
|
||
P-Screen "Plus" $ 29 Screen Design, Display, Library
|
||
system for QuickBASIC 3.0 - 4.x.
|
||
|
||
P-Screen "Professional" $ 49 PS Pro writes programs for you! and
|
||
includes other CALLable routines.
|
||
|
||
P~F Presents $ 49/$ 79 Presentation system to display
|
||
P-Screen's "text" screens -or-
|
||
BSAVEd "graphics." See below for
|
||
many "uses" for presentations.
|
||
|
||
P-Screen "Pro" AND Enhanced versions of BOTH.
|
||
P~F Presents ($79 ver.) $110
|
||
|
||
NOTE: P-Screen and P~F Presents are "shareware." Registered
|
||
versions cost 1/2 to 2/3 LESS than commercial examples.
|
||
Yet they're finely tuned, professional quality programs
|
||
that'll save you enormous amounts of time, and give your
|
||
programs a professional appearance -- f-a-s-t, easily.
|
||
|
||
P-Screen and P-Screen Professional are among the most sophisti-
|
||
cated "screen management systems" available. They were written
|
||
BY Quick- BASIC programmers FOR QuickBASIC programmers (we
|
||
support QB 3.0-4.x). P-Screen "+" and P-Screen Pro share most
|
||
features. These are described immediately below. Later we'll
|
||
explain features that PS Pro adds.
|
||
|
||
DESIGNING help screens, menus, data entry screens, etc. is a snap.
|
||
* Use a mouse or fast keyboard "hot keys" (eg., alt-B = Box).
|
||
* Choose options using hot keys or pull down menus.
|
||
* Many design options: Boxes, lines, "auto-joining" of lines
|
||
and boxes, text, Big! Font text (tm), clipboard, paint,
|
||
center, copy, move, erase, WalkAbout, re-color, repeat, add
|
||
any Ascii character, view in Monochrome, UnDo, and much more.
|
||
|
||
LOAD screens for editing from Screen Libraries, ASCII or BSAVE files.
|
||
* A RAM-resident program is included letting you: 1) "Capture"
|
||
screens from other applications (to later load and edit); and
|
||
2) Save ANY text screen in BSAVE format when you need them.
|
||
|
||
SAVE screens to Screen Libraries, ASCII or "Com" files.
|
||
* Screens saved to libraries or Com files are COMPRESSED,
|
||
saving disk space and RAM. Libraries store 1-100 screens;
|
||
libraries "index" screens, letting us display or edit them fast.
|
||
|
||
The QBNews Page 12
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
* Com screens are "executable!" Run them from batch files or DOS
|
||
for instant screens -- complete with color, lines, shading, etc.
|
||
|
||
DISPLAY screens from your programs fast and easily -- just CALL
|
||
two routines we include.
|
||
|
||
OTHER FEATURES
|
||
* Blazing speed! Assembler language routines plus "indexed"
|
||
screen libraries mean your programs display screens f-a-s-t!
|
||
10-20 screens per second is typical. We've seen 75 per second!
|
||
- We've eliminated the disadvantages of storing screens on disk.
|
||
- Screen libraries let you keep "screen text" OUT of your
|
||
programs, preserving string space and memory. And you can
|
||
edit screens WITHOUT changing your programs.
|
||
- And there are NO RAM-resident screen loaders to worry about!
|
||
|
||
* Big! Font (tm) lets you easily add large-character messages.
|
||
We include several Big! Fonts. You can create your own Big!
|
||
Fonts, or customize them "on the fly."
|
||
|
||
* Supports 25, 43 or 50 line screen modes.
|
||
|
||
=================================================================
|
||
P-Screen Professional ($ 49)
|
||
=================================================================
|
||
|
||
P-Screen Professional (PS Pro) has all the features of P-Screen
|
||
described above, but also saves you enormous amounts of time by:
|
||
|
||
* Writing your QuickBASIC 4.x programs for you!
|
||
|
||
* Including several other subprograms you can use in ANY Quick-
|
||
BASIC 4.x program you write (most also work with QB 3.0).
|
||
|
||
In short, you focus on what your programs "look like." Once
|
||
you have your screen designed, PS Pro can write your BASIC code.
|
||
Just add any routines you need for printing or database manage-
|
||
ment. Then compile your programs and away you go.
|
||
|
||
|
||
PS Pro writes your data entry programs for you! Just "mark" a
|
||
"field" on your screen and tell PS Pro what "type" of field it is.
|
||
* You can create fields with are "editable," and fields which
|
||
are "calculated." For calculated fields, enter ANY Quick-
|
||
BASIC formula, and PS Pro will handle the calculations for
|
||
you and print their results.
|
||
|
||
* And you can link "help screens" to each field if you like.
|
||
|
||
* Once you've "formatted" each field on your screen just press
|
||
a key. PS Pro writes your program in about 2-3 seconds!
|
||
|
||
|
||
PS Pro lets you choose from among 13 field types.
|
||
* Choose a field type and PS Pro formats editing, printing,
|
||
|
||
The QBNews Page 13
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
and displaying the results of "calculated fields" for you.
|
||
|
||
* Choose field types from among: string, upper case, proper
|
||
name, date, phone number, Zip Code, Social Security number,
|
||
numeric string, integer, long integer, single precision,
|
||
currency and double precision.
|
||
|
||
PS Pro comes with several subroutines you can use in any program.
|
||
These include: rsMinput, OneKey, Mask/StripMask, FormatUsing,
|
||
ProperName, rsQprint, Exists, and StripTail. Use them to:
|
||
* Handle ALL user input (text, extended keys, printer codes).
|
||
Get a single key, or a full line of text. rsMinput offers
|
||
the full array of editing features, includes UnDo, AND
|
||
offers "masked" input for easy, accurate editing of fields
|
||
like Phone Numbers [(...) ...-....] or Zip Codes [.....-....].
|
||
|
||
* Format text and numbers for easy editing or printing
|
||
|
||
* Print with assembler speed
|
||
|
||
* Convert all lower case text to "proper name" format
|
||
|
||
* Determine if files exist (before you try to open them)
|
||
|
||
=================================================================
|
||
Product Announcement: P~F PRESENTS
|
||
=================================================================
|
||
|
||
P~F Presents (PFP) is our desktop presentation system. It dis-
|
||
plays screens from P-Screen's screen libraries. It also displays
|
||
BSAVED "graphics" screens. Text, graphics or both; it's your call.
|
||
|
||
Presentations (or slide shows) can include, among other things:
|
||
* Full- or Sub- screen displays.
|
||
* Menus, in 3 different styles.
|
||
* Display and sound effects.
|
||
* Special options including: "If x Goto," "Gosub", "Loop,"
|
||
"Pause," "MakeMono" (to display colored screens on
|
||
monochrome monitors).
|
||
* Timed slides (which pause as long as you want between slides),
|
||
-or- slides which wait for the viewer to press a key.
|
||
|
||
And you can create self-running presentations, or run 'em yourself.
|
||
|
||
Why would a programmer be interested in a presentation system?
|
||
For many of the same reasons programmers like Dan Bricklin's DEMO
|
||
program (at about 1/4 the cost)! Plus, P~F Presents offers
|
||
many other opportunities as well. Consider these:
|
||
|
||
PROGRAM PROTOTYPES
|
||
* You can create "working prototypes" of programs in minutes or
|
||
just a few hours.
|
||
* Since presentations can include menus (3 types), display effects,
|
||
sound effects, etc. your prototypes can have the "look and feel"
|
||
of your actual program.
|
||
|
||
The QBNews Page 14
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
* Letting your clients, customers or potential users see how your
|
||
program will look and feel (BEFORE you've written a line of code):
|
||
1) Helps you "beta test" your ideas; 2) Helps eliminate time-
|
||
consuming re-writes; and, 3) Speeds up program development.
|
||
* And creating "mock ups" helps you think through a program's
|
||
logic before you write any code.
|
||
|
||
PROGRAM: DEMOS, MARKETING TOOLS, TUTORIALS
|
||
* You can easily and quickly create demos, marketing tools or
|
||
program tutorials -- using many of the SAME SCREENS your
|
||
programs will display.
|
||
|
||
As an example, we recently used PFP to create, in 2 hours, a
|
||
working prototype of a new program. We had it back to a
|
||
prospective client the day after we first talked to him. It
|
||
had the complete "look & feel" of the program he wanted. And
|
||
creating it helped us think through our program design.
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 15
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
|
||
----------------------------------------------------------------------
|
||
U n d e r T h e H o o d
|
||
----------------------------------------------------------------------
|
||
|
||
Fast File I/O in QuickBASIC by Ethan Winer
|
||
|
||
[EDITOR'S NOTE] This article first appeared in the March 1990 issue of
|
||
Programmer's Journal. Back issues can be ordered by calling
|
||
1-800-234-0386.
|
||
|
||
Without doubt, one of the slowest operations a program can
|
||
perform is saving and loading disk data files. In many cases, this is
|
||
dictated by the physical access delay of the disk device, and the time
|
||
required to transfer data based on its rotation speed. One exception,
|
||
however, is when many reads or writes must be performed on small
|
||
pieces of data. For example, it is quite common to save or load an
|
||
entire numeric array. In the case of an integer array that contains,
|
||
say, ten thousand elements, that many individual calls to the DOS file
|
||
I/O services will be needed. Even though DOS is written in assembly
|
||
language, it still takes a fair amount of time to process each read or
|
||
write request.
|
||
|
||
One obvious solution is to process the file operation as a single
|
||
large read or write. Indeed, I have written assembly language
|
||
routines to do just that for use in company's QuickPak Professional
|
||
add-on library product. But it is also possible to call QuickBASIC's
|
||
internal PUT and GET routines directly. By bypassing the QuickBASIC
|
||
compiler and its syntax checking, you can coerce it to read and write
|
||
up to 64K of data in a single operation. Larger files can be
|
||
accommodated by processing the file in pieces. The trick is to
|
||
determine the names of these routines, and the number and type of
|
||
parameters they expect to receive.
|
||
|
||
QuickBASIC versions 4.0 and later contain four different internal
|
||
routines for reading and writing binary data. Two of these are meant
|
||
for reading data from a file, with one using the current DOS SEEK
|
||
location and the other accepting a long integer SEEK argument.
|
||
Similarly, there are two separate routines for writing data to disk.
|
||
|
||
Most of QuickBASIC's internal routines begin with the characters
|
||
"B$", which are illegal in a subroutine name. Fortunately, the ALIAS
|
||
keyword allows you to declare a procedure with two different names --
|
||
the name you will use when calling it from the program, and the actual
|
||
name that is made public for the linker. When Microsoft introduced
|
||
inter-language calling capabilities in QuickBASIC version 4.00, it
|
||
needed a way to allow access to routines written in C. These routines
|
||
always start with an underscore character, which is also illegal as a
|
||
QuickBASIC procedure name.
|
||
|
||
The example program shown in Figure 1 declares the four internal
|
||
routines as follows: BigSave writes data using the current DOS file
|
||
pointer position, and BigSaveS expects a SEEK argument. Likewise,
|
||
BigLoad reads from the current file position, and BigLoadS requires an
|
||
offset to SEEK to before reading. All four of these routines require
|
||
the parameters to be passed "by value", as opposed to "by address"
|
||
|
||
The QBNews Page 16
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
which is BASIC's usual method of passing parameters. This results in
|
||
code that is both faster and smaller, because an extra level of
|
||
indirection is avoided. That is, the routines can obtain the values
|
||
directly from the stack, rather than having to first determine an
|
||
address, and then go to that address for the actual value. Even
|
||
though BYVAL and SEG *look* like they would result in additional code
|
||
being added to a program, they are really just directives to the
|
||
compiler.
|
||
|
||
Before any of these routines may be called, you must open the
|
||
file to be read or written for BINARY operation. Then, the first
|
||
parameter that each routine expects is the BASIC file number that was
|
||
used to open the file. The address parameter is passed as a SEG
|
||
value, which means that both a segment and offset are required.
|
||
Notice that a file may be loaded to or saved from any area of memory,
|
||
by replacing [SEG Address] with [BYVAL Segment, BYVAL Address]. When
|
||
SEG is used as part of a CALL statement, the "value" of the variable's
|
||
segment is pushed on the stack, followed by the value of its address.
|
||
Substituting two separate arguments "by value" is functionally the
|
||
same thing as far as the routines are concerned. Also notice that the
|
||
internal routine names are not available within the QuickBASIC editing
|
||
environment. Therefore, this example program must be compiled to disk
|
||
before it may be tested.
|
||
|
||
In my own informal tests, I have found this technique to be as
|
||
much as ten times faster than reading or writing individual array
|
||
elements using a BASIC FOR/NEXT loop. The actual savings will of
|
||
course depend on the number of elements being processed and their
|
||
length in bytes. Unfortunately, this method cannot be used with
|
||
QuickBASIC string arrays, because they are not kept in consecutive
|
||
memory locations. However, numeric arrays may be accommodated, as
|
||
well as any fixed-length or user-defined TYPE array.
|
||
|
||
It is important to understand that when manipulating a fixed-
|
||
length string array, the SEG operator must not be used. Whenever a
|
||
fixed-length string or array element is used as an argument to an
|
||
external routine, QuickBASIC first makes a copy of it into a regular
|
||
string variable. Then, the address of the copy is passed instead.
|
||
Since the address of a copy of an array element has no relevance to
|
||
the address of the actual array, we must use a different approach. In
|
||
fact, there are two possible solutions.
|
||
|
||
One is to create a TYPE definition that is comprised solely of a
|
||
fixed-length string portion. Although the example below assumes a
|
||
string length of twenty characters, you would of course use whatever
|
||
is appropriate for your program.
|
||
|
||
TYPE FLen
|
||
S AS STRING * 20
|
||
END TYPE
|
||
|
||
DIM Array(1 TO 10000) AS FLen
|
||
|
||
The second solution is to use a combination of BYVAL VARSEG and
|
||
BYVAL VARPTR, to pass the segment and address of the starting array
|
||
|
||
The QBNews Page 17
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
element directly. When QuickBASIC sees VARSEG or VARPTR, it realizes
|
||
that you do in fact want the actual segment and address of the
|
||
specified array element. Thus, you would use the following syntax
|
||
when calling BigSave to save a fixed-length string array:
|
||
|
||
CALL BigSave(FileNumber, BYVAL VARSEG(Array(First)), BYVAL _
|
||
VARPTR(Array(First)), NumBytes)
|
||
|
||
One final note concerns saving or loading more than 32767 bytes.
|
||
QuickBASIC does not support unsigned integers, so you must instead use
|
||
an equivalent negative value. This is quite easy to determine, by
|
||
simply subtracting 65536 from the required number of bytes. It is a
|
||
common trick to avoid negative numbers when calling assembly language
|
||
routines by instead substituting a long integer number or variable.
|
||
However, that will not work in this case, because two extra bytes will
|
||
be pushed onto the stack by the use of BYVAL. Therefore, it is
|
||
essential that you specify the correct type of parameters when calling
|
||
these routines.
|
||
|
||
**********************************************************************
|
||
Ethan Winer is the president of Crescent Software, and the author
|
||
of QuickPak Professional and P.D.Q. He can be reached by calling
|
||
Cresent Software at (203) 846-2500.
|
||
**********************************************************************
|
||
|
||
[EDITOR'S NOTE] Source code for this article is contained in
|
||
FASTFILE.ZIP.
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 18
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
|
||
----------------------------------------------------------------------
|
||
P o w e r P r o g r a m m i n g
|
||
----------------------------------------------------------------------
|
||
|
||
How to Make a Self-Cloning Exe in QuickBASIC by Larry Stone
|
||
|
||
[EDITOR'S NOTE]
|
||
All extended ASCII codes have been replaced in the following
|
||
article.
|
||
|
||
Have you ever had the need to create a program that holds a
|
||
password away from prying eyes of others? Or, maybe you have
|
||
discovered that writing shareware rewards your ego by making your name
|
||
familiar to the PC world, but doesn't reward your pocket-book because
|
||
most people will register their programs when they get around to it,
|
||
which, often-times, is never. Or, maybe you just wish to write a
|
||
program that holds it's configuration without having to create a
|
||
configuration file.
|
||
|
||
One of the easiest methods to accomplish the above listed tasks
|
||
is to create an EXE file that "clones" information to itself. The
|
||
trick is to create a "recognizable" area inside of the EXE itself that
|
||
can be quickly read and modified.
|
||
|
||
What makes this such an easy trick? Well, have you ever used
|
||
Vernon D. Buerg's LIST utility to list your EXE's? If you do, you
|
||
will notice that towards the end of the program, every string that you
|
||
have defined within your program is CLEARLY VISIBLE! What you are
|
||
viewing is the EXE's token definition area. When you compile and link
|
||
your programs, a token is defined for every string used. For example,
|
||
your program might have the code, Strike$ = "Strike any key". When
|
||
you list the EXE, it may show something like, 0TStrike any key. The
|
||
symbols 0T would be the programs marker to the definition, "Strike any
|
||
key". Under no circumstance do you want to change this marker because
|
||
really weird results could ensue. However, you can create a string
|
||
that contains a marker that is exclusive to your use, i.e.,
|
||
|
||
Special$ = "<*!@#%>This is my special string"
|
||
|
||
In the above example, <*!@#%> then becomes your special marker to
|
||
the data that immediately follows. Then, all your program has to do
|
||
is to look for your special marker and modify the next 25 characters
|
||
as needed!
|
||
|
||
CAUTION! Never, never, never try to reserve a data area for
|
||
cloning by defining a string as:
|
||
|
||
Special$ = "<*!@#%>" + SPACE$(25)
|
||
Special$ = "<*!@#%> "
|
||
|
||
Both of the above examples will *NOT* create the 25 character
|
||
data area desired because BC will optimize the SPACE$(25) as a two
|
||
byte token!
|
||
|
||
Let's assume that we need to build a program that needs to hold a
|
||
|
||
The QBNews Page 19
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
user-defined, sixteen character password and a token that determines
|
||
whether the EXE is shareware (limited in scope) or registered. Let's
|
||
further say that when a registration is received by you, the author,
|
||
you then mail that person a key which redefines the definition of a
|
||
token so that features not available to the shareware user now become
|
||
available. Let's further state that your program is going to hold
|
||
configuration information within a 13 byte string.
|
||
|
||
The first thing to do is to create a unique string inside of the
|
||
program itself, as well as, two or three variables shared within the
|
||
program. At the top of the program, do something like the following:
|
||
|
||
DIM SHARED StoredData$, BytesToData&
|
||
|
||
Now, if your program does not "clone" configuration information
|
||
or passwords, then BytesToData& does not need to be SHARED. Rather,
|
||
in this case, only the information itself (Shareware/registration key)
|
||
needs to be shared. However, for this discussion, we're going for the
|
||
entire pie.
|
||
|
||
Next, someplace within your initialization subprogram (or in your
|
||
main module), you should place code such as the following:
|
||
|
||
SpotForKey$ = "<%*@#!>123456789012345678901234567890"
|
||
|
||
Now, because your program needs to read itself, modify itself
|
||
and, at the same time, hold part of the original string as your
|
||
special marker, we need to do the following:
|
||
|
||
tempKey$ = LEFT$(SpotForKey$, 6)
|
||
|
||
In this way, no matter what we do to the following 30 character
|
||
spaces, <%*@#!> will always remain our special marker that the program
|
||
looks for.
|
||
|
||
Let's build the routine that reads in this data.
|
||
|
||
'--------------------- Get Special Data Routine ---------------------
|
||
|
||
DIM SHARED StoredData$, BytesToData&
|
||
|
||
SpotForKey$ = "<%*@#!>123456789012345678901234567890"
|
||
|
||
tempKey$ = LEFT$(SpotForKey$, 6) 'Our special marker.
|
||
|
||
'The Bytes% variable is the number of bytes to read.If your program is
|
||
'less than 16000 bytes then this routine adjusts accordingly. Also, if
|
||
'a 16K byte "GET" cuts the marker field in two then you need to change
|
||
'it to another value, such as 15550.
|
||
|
||
Bytes% = 16000
|
||
BytesToData& = 0
|
||
portion& = 1
|
||
countToKey% = 0
|
||
StoredDataLen% = 30
|
||
|
||
The QBNews Page 20
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
OPEN MyProg$ FOR BINARY AS #1 FiSize& = LOF(1)
|
||
'Get the size of the file
|
||
DO WHILE NOT EOF(1)
|
||
IF Bytes% > FiSize& THEN Bytes% = FiSize&
|
||
IF Bytes% + portion& > FiSize& THEN Bytes% = FiSize& - portion&
|
||
A$ = INPUT$(Bytes%, 1) 'Read Bytes% number of characters.
|
||
countToKey% = INSTR(A$, tempKey$) 'Look for our special marker.
|
||
IF countToKey% THEN 'If we found it then process it.
|
||
BytesToData& = portion& + countToKey% + 5 'Get past our marker.
|
||
SEEK #1, BytesToData& 'Get the data from the file.
|
||
StoredData$ = INPUT$(StoredDataLen%, 1)
|
||
EXIT DO 'We found it so out of the DO LOOP
|
||
END IF
|
||
|
||
portion& = Bytes% + portion& 'Determine where the next SEEK is.
|
||
|
||
'If we're within 800 bytes of the end of the EXE then we are past the
|
||
'token definition area of the QB program. In this case, we're done.
|
||
|
||
IF portion& >= FiSize& - 800 THEN EXIT DO
|
||
|
||
'Move pointer to the next 16000 byte block to read from the file.
|
||
|
||
SEEK #1, portion&
|
||
|
||
LOOP
|
||
CLOSE #1
|
||
|
||
'--------------------- End Special Data Routine ---------------------
|
||
|
||
Now, whenever our program needs to look for a password, a
|
||
registration key value, or it's configuration information, it need
|
||
only do the following:
|
||
|
||
Password$ = LEFT$(StoredData$, 16)
|
||
RegisValue = VAL(MID$(StoredData$, 17, 1))
|
||
|
||
IF RegisValue = 7 THEN
|
||
PRINT "Shareware Edition"
|
||
ELSE
|
||
PRINT "Registered Edition"
|
||
END IF
|
||
|
||
ConfigData$ = MID$(StoredData$, 18)
|
||
|
||
To prove this works, snip out the special routine and add the
|
||
following statement at the end of the routine: PRINT StoredData$
|
||
Next, compile and link it, then run it. You will see the above string
|
||
printed (you will also notice just how fast QB's INSTR function really
|
||
is! - It's blazingly fast! - Couple this with BINARY access and you'll
|
||
discover that load time is not appreciably degredated). Don't forget
|
||
to define MyProg$ as something or you'll get a nasty error message!
|
||
|
||
Okay, okay, so how do we write new information to our special
|
||
|
||
The QBNews Page 21
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
data area? Simple - just do the following:
|
||
|
||
Password$ = "Lawrence Stone "
|
||
RegisValue$ = "0"
|
||
ConfigData$ = "Config Area 1"
|
||
|
||
OPEN MyProg$ FOR BINARY AS #1
|
||
PUT #1, BytesToData&, Password$ 'To write the new password.
|
||
RegisValue$ = "0"
|
||
PUT #1, BytesToData& + 16, RegisValue$'To create a registered version.
|
||
PUT #1, BytesToData& + 17, ConfigData$ 'To clone configuration data.
|
||
CLOSE #1
|
||
|
||
Now, re-run your compiled program and have these values print to
|
||
the monitor. Notice how easy it was to change the data?
|
||
|
||
If you are going to have an external "key" program that "turns
|
||
on" the registered version then it needs to simply read in the data
|
||
using the same special marker that we created as a marker to search
|
||
for. Also, you might wish to make another small program that converts
|
||
your pre- defined password and configuration space to spaces.
|
||
Otherwise, you need to run your program before you distribute it so
|
||
that you can change the password (which is equal to
|
||
"1234567890123456") to something like SPACE$(16). In other words,
|
||
nullify the temporary string used by our program that forced BC to
|
||
give us the data space we needed in the first place.
|
||
|
||
Now, for demonstration purposes, we have used the default "7" for
|
||
indicating that the program is shareware and "0" for registered. I
|
||
would recommend that you reserve at least 8 character spaces for this
|
||
field because then you can create unique codes for every key and every
|
||
user. In this way, your program can look for the key in both itself
|
||
and within the key program as well. This would also offer one more
|
||
level of safeguards for you.
|
||
|
||
One final word: Any casual hacker can use LIST to find your
|
||
password if you leave it in it's native ASCII. You should consider a
|
||
routine that converts the appearance of your data so that it looks
|
||
like the rest of the binary code. Routines can be as simple as taking
|
||
each character in the strings and adding 100 to their ASCII value for
|
||
writing, then, subtracting 100 from their ASCII value for reading, to
|
||
some truely cryptive procedure, depending on how sensitive you want
|
||
the information contained therein to remain.
|
||
|
||
**********************************************************************
|
||
Larry Stone is President of LSRGroup and is involved in writing
|
||
software for marine and aquatic research. He can be reached at
|
||
LSRGroup, P.O. Box 5715, Charleston, OR 97420, or in care of this
|
||
newsletter.
|
||
**********************************************************************
|
||
|
||
[EDITOR'S NOTE] The file CLONE.BAS contains a slightly modified
|
||
version of Larry's code above. I have modified it to make it easier to
|
||
add to your program. It is contained in CLONE.ZIP.
|
||
|
||
The QBNews Page 22
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
In Search of the Elusive UEVENT by Jim Mack
|
||
|
||
QB allows you to trap a number of different "events", such as the
|
||
TIMER tick, the arrival of a byte in a COM buffer, the press of a
|
||
specific KEY, and so on. It does so by adding extra code after
|
||
each statement (/V) or each line (/W) which checks the state of flags
|
||
associated with enabled events. Special handlers deal with the
|
||
actual interrupt and set these internal flags as appropriate.
|
||
|
||
This is a three-stage process: first, an interrupt (an event)
|
||
occurs and is handled quickly by the QB runtime, which sets the flag
|
||
and variables associated with the event. This happens behind your
|
||
program's back, as it were. Second, when the current line or
|
||
statement completes, QB checks the flags to see if any active events
|
||
(those for which you have executed "ON xxx GOSUB" and "xxx ON"
|
||
commands) have occurred. Third, on discovering such a condition QB
|
||
executes the GOSUB code you wrote to deal with it.
|
||
|
||
The only area where UEVENT differs from events like KEY is in the
|
||
first part of the first step. In defining a UEVENT, _you_ take
|
||
responsibility for dealing with the interrupt, and for notifying the
|
||
QB runtime that such an event has occurred. From that point on, the
|
||
action is exactly the same.
|
||
|
||
The difference between invoking a GOSUB via SetUEvent (or any
|
||
trap) and calling it directly is that when you invoke it, it's
|
||
executed only when QB gets around to it, and only if UEVENT ON is
|
||
currently in effect. A side effect of this is that you may "lose"
|
||
events if more than one occurs between occasions when QB checks its
|
||
internal flags.
|
||
|
||
This whole business of interrupts can be broken down in several
|
||
ways: shared vs. exclusive vs. chained, or software vs. hardware, and
|
||
so on. The code packages included here give examples of two common
|
||
combinations.
|
||
|
||
You can trigger a UEvent in QB with no interrupt at all, by just
|
||
saying "CALL SetUEvent". In MASM, declaring SetUEvent as an EXTRN far
|
||
procedure lets you do the same thing: CALL SetUEvent. In C, you'd
|
||
declare "setuevent" as a void far external function and then reference
|
||
"setuevent()" to cause your QB handler to be invoked. Simple... and
|
||
practically useless by itself. You need to combine this with a
|
||
software or hardware interrupt.
|
||
|
||
>> "Software interrupts" are really misnamed: they have more in
|
||
>> common with a subroutine call than with a hardware interrupt.
|
||
>> Since they occur under direct program control, there's nothing
|
||
>> unexpected or asynchronous about them. They do however use
|
||
>> the same table of vectors that the hardware interrupts use.
|
||
|
||
A small step up is the exclusive "true" software interrupt. This
|
||
involves taking over an unused interrupt vector, writing a tiny MASM
|
||
routine which intercepts INTs directed at this vector and performs a
|
||
CALL SetUEvent. There's no reason to take this extra step unless
|
||
you're working with a canned other-language program which must use a
|
||
|
||
The QBNews Page 23
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
pre-defined INT to access your code. If you're using DOS 3.x, this
|
||
can be done in exactly the same manner as the "chained" software
|
||
interrupt described below, since what you're chaining onto is a
|
||
pre-defined Dismiss This Interrupt routine.
|
||
|
||
>> A "vector" in this context is a memory location reserved by
|
||
>> the computer as a pointer: it contains the address of a routine
|
||
>> intended to service an interrupt. There are 255 such vectors in
|
||
>> the PC, occupying the memory from 0000:0000 through 0000:03FF.
|
||
>> Eight of these (sixteen in the AT) are reserved for use by the
|
||
>> hardware Interrupt ReQuest lines, or IRQs. When an enabled
|
||
>> interrupt occurs, the PC stops what it's doing and executes the
|
||
>> routine whose address is stored in the appropriate vector.
|
||
|
||
Next most complicated is the chained software interrupt. One
|
||
example of an existing software interrupt is the BIOS disk service,
|
||
which uses INT 13H. If you wanted your handler to be invoked whenever
|
||
disk activity occurred, you'd chain onto this interrupt vector and
|
||
monitor the registers using MASM. When an event of interest occurred,
|
||
you'd "CALL SetUEvent" to notify QB. In any case, you'd pass the
|
||
interrupt along to the original INT 13H handler. Closely related to
|
||
this is the chained hardware interrupt. The setup is exactly the
|
||
same: hook the interrupt vector, monitor the registers, etc. All
|
||
other details are taken care of by an existing handler.
|
||
|
||
The code in CHNEVENT.BAS is an example of a chained handler which
|
||
will work for any hardware or software interrupt. The assumption is
|
||
that you're just monitoring existing events (and sometimes activating
|
||
SetUEvent), but not touching any hardware. In the example we monitor
|
||
INT 9, the keyboard interrupt, but you can monitor almost any of
|
||
the256 vectors by replacing "9" with the appropriate number. Try an
|
||
experiment: replace the INKEY loop with a LINE INPUT statement. If
|
||
you can explain what happens, you've grasped the essentials of QBevent
|
||
handling.
|
||
|
||
>> "Hooking" a vector means only that you store the address of your
|
||
>> own service routine in the vector. To facilitate cleanup, it's
|
||
>> usual to first retrieve and store the existing contents of the
|
||
>> vector so that they can be replaced on exit. If you're "chaining"
|
||
>> onto this vector, then you'll also use that original address when
|
||
>> your routine is finished, by performing a JMP directly to it.
|
||
>> Since this can happen to several routines in sequence, it's easy
|
||
>> to see why it's known as chaining.
|
||
|
||
The next step up in complexity (and it's a pretty big step) is
|
||
the exclusive hardware interrupt. Here, you're responsible for all of
|
||
the nitty-gritty of the PC hardware, in addition to any details
|
||
associated with the hardware device. You must program the 8259A
|
||
Programmable Interrupt Controller to allow interrupts on your IRQ
|
||
level, then issue a command to clear the PIC when you service an
|
||
interrupt. These must be done in MASM, as your QB event handler will
|
||
not be executed in a timely fashion and so cannot be relied on to take
|
||
care of these high-speed events. The code in EVENTHDW.ASM shows how
|
||
to deal with an event occurring on an arbitrary IRQ line (determined
|
||
at install time), but because we aren't dealing with a real device
|
||
|
||
The QBNews Page 24
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
here, the specific instructions for the interrupting hardware can only
|
||
be hinted at.
|
||
|
||
>> Each hardware IRQ line is intimately tied to a vector: in the
|
||
>> case of the lower IRQs (0-7) the INT number (the vector number) is
|
||
>> simply the IRQ number plus 8. That's why the KB interrupt, which
|
||
>> uses IRQ 1, is vectored through INT 9.
|
||
|
||
Slightly more complicated is the shared hardware interrupt. In
|
||
order for two hardware devices to share an IRQ line, there must be
|
||
away to determine which device requested service by interrupting. An
|
||
example of sharing an interrupt might be COM1 and COM3, which both use
|
||
IRQ4 and hence INT 0CH. When an interrupt occurs on IRQ4, the COM3
|
||
service routine gains control and examines a register in the UART it's
|
||
responsible for to see if that UART caused the interrupt. If it
|
||
didn't, control is passed to the COM1 service routine. I haven't
|
||
included a specific example of adding a shared handler, but if you
|
||
need one and can't figure it out from the code shown, you can contact
|
||
me and I'll try to help.
|
||
|
||
In addition to the above, whenever you take over an interrupt
|
||
vector you must somehow put things back in order when your program
|
||
terminates. At a minimum this means restoring the original contents
|
||
of the vector; for hardware interrupts, you must also restore the
|
||
8259A Interrupt Mask Register bit to the state in which you found it.
|
||
|
||
To make this process a bit more automatic, QB includes the
|
||
B_OnExit routine. Any running BC program takes over a number of
|
||
interrupt vectors for its own use (for example, BC math functions
|
||
invoke INT 04H whenever an overflow occurs) which must be restored on
|
||
any exit, normal or abnormal. BC and QB provide B_OnExit as an
|
||
extension of this internal cleanup. You still must write the code to
|
||
do the actual restoring of vectors, etc., but BC can call that code
|
||
automatically on *any* exit, even an error crash, if you "register
|
||
"your routine via B_OnExit. Each of the included code packages uses
|
||
B_OnExit in this way.
|
||
|
||
**********************************************************************
|
||
Jim Mack is a programmer specializing in real-time systems for the
|
||
entertainment industry. He can be reached via CIS ID 76630,2012 on
|
||
the MSSYS forum in the BASIC or MASM sections, or at Editing Services
|
||
Co., PO Box 599, Plymouth MI 48170, (313) 459-4618
|
||
**********************************************************************
|
||
|
||
[EDITORS NOTE]
|
||
For some reason, the program CHNEVENT.BAS will cause my computer
|
||
to crash when run in the QB 4.5 enviroment. This is not the case when
|
||
run in the QBX (BC7) enviroment. Caution is advised if you try to run
|
||
this in the enviroment. Source code for this article is contained in
|
||
UEVENT.ZIP.
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 25
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
|
||
----------------------------------------------------------------------
|
||
S o m e A s s e m b l y R e q u i r e d
|
||
----------------------------------------------------------------------
|
||
|
||
Assembler Programming for QuickBASIC by Tom Hanlin
|
||
|
||
Perhaps you already know a little bit about programming in
|
||
assembly language, or perhaps you've never given it much thought.
|
||
After all, it's supposed to be frighteningly difficult to write
|
||
assembler programs, and you've already got QuickBASIC anyway.
|
||
|
||
Well, it's true that there's a lot of work involved in writing
|
||
large programs in assembly language. If you keep to the small stuff,
|
||
however, there's actually very little to it. One of the easiest and
|
||
most rewarding uses for assembly language lies in writing routines
|
||
that can be called from a higher-level language like QuickBASIC. This
|
||
can give you entirely new capabilities or make your existing programs
|
||
smaller and faster. By mixing the capabilities of a low-level
|
||
language like assembler with a high-level language like QuickBASIC,
|
||
you can gain a lot of flexibility when you need it, without
|
||
sacrificing the ease of use of good ol' BASIC.
|
||
|
||
Microsoft's documentation on mixed-language programming is rather
|
||
daunting. It's not exactly clear and the examples never seem to cover
|
||
quite what you had in mind. Once you understand a few simple rules,
|
||
though, you'll see that adding assembler routines to your QuickBASIC
|
||
programs can be readily accomplished.
|
||
|
||
I'm going to assume you have some notion of how to program in
|
||
both QuickBASIC and assembly language, since explaining an entire
|
||
language would be a bit more than a single article could cover! With
|
||
that in mind, let's take a look at the basic rules of writing assembly
|
||
routines for QuickBASIC and follow that up with the code for a working
|
||
routine.
|
||
|
||
The first thing you need to know is which registers you can use.
|
||
The answer is, "all of them." However, certain registers must be
|
||
preserved for BASIC, so if you use them, you must restore their
|
||
original values before returning to the main BASIC program. The
|
||
registers that must be preserved are SI, DI, BP, and DS. You also
|
||
need to preserve the stack (SS and SP) and direction flag. The
|
||
direction flag must always be "forward" when you exit, so if you
|
||
change it using the "STD" instruction, be sure to restore it using the
|
||
"CLD" instruction.
|
||
|
||
Believe it or not, that's most of what you need to know right
|
||
there. The other important thing to know is how to pass parameters to
|
||
or from the assembler routine. I'll keep it simple by assuming you
|
||
use the standard convention, which is "pass by reference", rather than
|
||
"pass by value", which has to be explicitly declared.
|
||
|
||
What do I mean by "pass by reference?" I mean that, instead of
|
||
getting the actual value of a parameter, your routine gets the address
|
||
of that parameter and has to look up the value. It's useful to have
|
||
the address of the parameter, since that means you can return a value
|
||
|
||
The QBNews Page 26
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
by storing it in the parameter's address.
|
||
|
||
Integral numbers are stored simply. For integers, the address
|
||
you are given points directly to the integer (a word). If you use
|
||
long integers, the address points to the long integer (a doubleword).
|
||
|
||
Strings are stored in a slightly more complex fashion. The
|
||
address you are given points to a "string descriptor". This
|
||
descriptor is composed of two words, with the first giving the length
|
||
of the string and the second the address of the string. You are not
|
||
allowed to change the length or address of the string in your
|
||
assembler routine, although you may change the string itself.
|
||
|
||
I won't go into single precision or double precision numbers,
|
||
because they are rather tricky to handle in assembler. I won't go
|
||
into arrays, TYPEd values, or fixed-length strings here either, to
|
||
keep it reasonably brief. Perhaps in a later article...
|
||
|
||
Parameters are passed on the stack, starting at offset 6 (six)
|
||
for the -last- parameter and going up by two as you move towards the
|
||
first parameter.
|
||
|
||
Finally, you need to end your routine with a special "RET" opcode
|
||
that will clean the parameters off the stack for QuickBASIC. The RET
|
||
must have a number after it which is twice the number of parameters
|
||
passed to the routine.
|
||
|
||
Clear as mud? Well, perhaps the example routine will help show
|
||
what I'm talking about. The DOSVER.ASM file contains the source code.
|
||
To assemble it just type: ASM DOSVER; (where "ASM" is the name of your
|
||
assembler: MASM, TASM, or OPTASM)
|
||
|
||
Convert the resulting DOSVER.OBJ file to a library so you can
|
||
easily use it both from the command line and QB environment:
|
||
LIB DOSVER; (this creates DOSVER.LIB)
|
||
LINK DOSVER/Q,,NUL,BQLB45; (this creates DOSVER.QLB)
|
||
|
||
If you are using QuickBASIC 4.0, change the BQLB45 to BQLB40. If
|
||
you are using QuickBASIC 4.0a or 4.0b, change it to BQLB41.
|
||
|
||
You can now use the DOSVER routine from the QB environment by
|
||
specifying the library name when you start QuickBASIC: QB /L DOSVER
|
||
|
||
Use of the DECLARE statement is optional, but it will help catch
|
||
any errors you might make when calling DOSVER. Use this: DECLARE SUB
|
||
DOSVER(VERSION$, MAJORV%, MINORV%)
|
||
|
||
Before calling the routine, you must set the VERSION$ string to
|
||
at least four characters, since the routine is not allowed to change
|
||
the length of the string. Call the routine like this:
|
||
VERSION$ = SPACE$(4)
|
||
CALL DOSVER(VERSION$, MAJORV%, MINORV%)
|
||
|
||
Typical results will be "3.11" for VERSION$, 3 for MAJORV%, and
|
||
11 for MINORV%.
|
||
|
||
The QBNews Page 27
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
In later articles, if there is any interest in it, I'll explain
|
||
how to handle arrays, TYPEd variables, and fixed-length strings, and
|
||
also how to pass values back from functions rather than using
|
||
subprograms.
|
||
|
||
**********************************************************************
|
||
Tom Hanlin is the author of the very popular ADVBAS library for
|
||
QuickBASIC. His new shareware library is called BASWIZ. He can be
|
||
reached through the QUIK_BAS echo on Fidonet or in care of this
|
||
newsletter.
|
||
**********************************************************************
|
||
|
||
[EDITOR'S NOTE]
|
||
The archive ASMREQ.ZIP contains the assembler source code plus an
|
||
assembled .OBJ file for the routine contained in the article.
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 28
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
|
||
----------------------------------------------------------------------
|
||
A n d I H e a r d i t T h r o u g h t h e G r a p e v i n e
|
||
----------------------------------------------------------------------
|
||
|
||
|
||
From: Mike Sinak
|
||
To: All
|
||
Subj: PEEK & POKE
|
||
|
||
I am just beginning to study DOS and BIOS calls and don't understand
|
||
how to do it at all. Does anybody have any info on the PEEK and POKE
|
||
usage? Like if you want to peek and poke to turn caps lock on and
|
||
off, how in the world do you know what address to peek and poke? I'm
|
||
lost! I would like to learn more about this stuff and get some kind
|
||
of comprehensive list of peeks and pokes.
|
||
|
||
Also I learned that at DEF SEG 0 you can turn on and off caps lock by
|
||
POKE &H0417, PEEK &H0417 OR &H40 (to turn on)
|
||
|
||
and
|
||
|
||
POKE &H0417, PEEK &H0417 AND &HBF (to turn off)
|
||
|
||
Now how in the world did they know that? The AND and OR statments are
|
||
supposed to be turning on and off bit 6 of the &H0417 address. How
|
||
did they know these particular numbers turn on and off bit 6? Better
|
||
yet, how did they know that bit 6 had to be turned on and off at this
|
||
particular address to turn caps lock on and off. Is there a pattern?
|
||
|
||
Obviously my ignorance is being displayed. Go ahead and laugh <grin>
|
||
but I would sure like to know more about this.
|
||
|
||
ANY HELP?
|
||
|
||
|
||
From: Robin Hunziker @ 965/1
|
||
To: Mike Sinak
|
||
Subj: Re: PEEK & POKE
|
||
|
||
Perhaps your best bet for figuring out how DOS operates is by
|
||
purchasing the following book:
|
||
|
||
Advanced MSDOS Programming
|
||
2nd Edition
|
||
Ray Duncan
|
||
Microsoft Press
|
||
ISBN 1-55615-157-8
|
||
|
||
For example, on page 582 the book discusses exactly your area of
|
||
question in easy-to-understand tabular format. It discusses how to
|
||
call Int 16H Function 02H to "get keyboard flags". Although the front
|
||
cover states that it is "The Microsoft guide for Assembly Language and
|
||
C programmers", it is very relevant to much of the discussion in this
|
||
echo.
|
||
|
||
|
||
The QBNews Page 29
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
From: David Martin
|
||
To: Mike Sinak
|
||
Subj: Peek & Poke
|
||
|
||
A better way to set upper and lower case is the following:
|
||
Lower Case: POKE 1047, PEEK(1047) AND 191
|
||
Upper Case: POKE 1047, PEEK(1047) OR 64
|
||
Lots of stuff can be done with poke such as disable the CTRL-BREAK,
|
||
turn number lock key on and off, read hardware configurements, read
|
||
size of RAM. The list goes on and on. If you want a list of the
|
||
commands let me know. These commands must be preceded by: DEF SEG =
|
||
0. Let me know what kind of stuff you are working with so I can give
|
||
you the commands.
|
||
|
||
|
||
From: Tom Hanlin
|
||
To: Mike Sinak
|
||
Subj: Re: PEEK & POKE
|
||
|
||
In order to understand bit numbering, you need to convert the
|
||
number to binary. Bits are numbered from right to left, with the
|
||
lowest bit being number zero. So:
|
||
&H40 = 64 = 0100,0000b (note that bit 6 is turned on)
|
||
&HBF =191 = 1011,1111b (note that all bits except 6 are turned on)
|
||
when you OR a number with another number, the result contains all of
|
||
the bits that were turned on in the first number OR in the second
|
||
number. When you AND two numbers, the result contains all of the bits
|
||
that were turned on in the first number AND in the second number. So,
|
||
to turn on a specific bit, you OR with a number that has only that bit
|
||
turned on (which leaves the other bits in the original number alone).
|
||
To turn a specific bit off, you AND with a number that has only that
|
||
bit turned off (which leaves the other bits in the original number
|
||
alone). See?
|
||
|
||
Knowing which memory locations have special purposes, such as
|
||
keeping track of Caps Lock and Num Lock, comes from (mostly) IBM's
|
||
listing of the system BIOS. Many reference books contain the
|
||
information in a decoded format, so you can use it without having to
|
||
understand the BIOS at all. If you can find a copy, COMPUTE!'s
|
||
"Mapping the IBM PC and PCjr" is an excellent guide to this sort of
|
||
thing, although there are many others.
|
||
|
||
You may also want something like Norton's guide to assembly
|
||
language, to give you some idea about converting numbers between hex,
|
||
decimal and binary, and how PC memory mapping works. Things like...
|
||
DEF SEG=0:PRINT PEEK(&H417)
|
||
is the same as
|
||
DEF SEG=&H40:PRINT PEEK(&H17)
|
||
|
||
|
||
From: David Martin
|
||
To: Mike Sinak
|
||
Subj: Peek & Poke
|
||
|
||
|
||
The QBNews Page 30
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
The following list is some things that can be done with peek & poke.
|
||
KEYBOARD KEYS:
|
||
PEEK (1047) AND 8: value 8 if ALT is pressed.
|
||
4: CTRL
|
||
2: 2 LEFT SHIFT.
|
||
1: 1 RIGHT SHIFT.
|
||
3: 3 NIETHER SHIFT.
|
||
PEEK (1048) AND 4: 4 PRINT SCREEN KEY.
|
||
PEEK (1047) AND 64 0 if in LOWER CASE.
|
||
64 UPPER CASE.
|
||
POKE 1047, PEEK(1047) AND 191 specify LOWER CASE.
|
||
OR 64 specify UPPER CASE.
|
||
FOR J=0 TO 3:POKE (108+J),PEEK(112+J):NEXT: DISABLE CTRL-BREAK
|
||
CONFIGURATION OF COMPUTER:
|
||
(PEEK(1041) AND 192)/64: number of PRINTER ADAPTERS.
|
||
(PEEK(1040) AND 1)*(1+PEEK(1040)/64 number of DISK DRIVES.
|
||
(PEEK(1041) AND 14)/2 number of RS232 ports.
|
||
PEEK(1043)+256*PEEK(1044) size of RAM.
|
||
NUMBER LOCK KEY:
|
||
PEEK(1047) AND 32 0 if OFF, 32 if ON.
|
||
POKE 1047,PEEK(1047) AND 223: turn NUM LOCK key OFF.
|
||
32: turn NUM LOCK key ON.
|
||
Alot of these commands are abreviated. If nothing appears below a
|
||
line just type in the line on top of what you want along with what is
|
||
changed. Got it? Let me know if you have any questions. Glad to help!
|
||
All lines must be preceded by: DEF SEG =0 (Only one DEF SEG = 0 at
|
||
the beginning of the program)
|
||
|
||
|
||
From: Ronny Ong
|
||
To: Mike Sinak
|
||
Subj: Re: PEEK & POKE
|
||
|
||
Mike, I also have Duncan's book and find it useful, but I do happen to
|
||
use a number of languages including assembler, C, and QuickBASIC.
|
||
|
||
Let me suggest "DOS Programmer's Reference" (2nd Edition), by Terry
|
||
Dettmann, Revised by Jim Kyle. It is published by Que
|
||
ISBN 0-88022-458-4. List price is $27.95 U.S. This book contains
|
||
roughly the same type of information as Duncan's, but it has specific
|
||
QuickBASIC 4.xx examples, so it's probably easier to use for the
|
||
QuickBASIC programmer with less experience in assembler and C.
|
||
|
||
|
||
|
||
From: Ronny Ong
|
||
To: Mike Sinak
|
||
Subj: Re: Peek & Poke
|
||
|
||
Hi, Mike. You might try getting a general intro/computers type of
|
||
book and brushing up on binary numbers. All digital computers of
|
||
today do everything in binary, or base 2. In others words, computers
|
||
are simply made up of billions of tiny on/off switches. "On"
|
||
represents the binary digit (or "bit" for short) of "1" and "off"
|
||
represents "0."
|
||
|
||
The QBNews Page 31
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
When you see "POKE xxx, PEEK(xxx) AND 64," here's what happens (I've
|
||
simplified this slightly):
|
||
Let's say that PEEK(xxx) currently contains the byte value 98. In
|
||
binary, that's 01100010. The decimal number 64 is 01000000 in binary.
|
||
The "AND" operator means to produce a result which has a "1" in every
|
||
position which is "1" in both of the operands and has a "0" for all
|
||
other positions.
|
||
|
||
01100010 <--- 98
|
||
01000000 <--- 64
|
||
--------
|
||
01000000 <--- Result of 64, to be POKE'd back into memory location xxx
|
||
|
||
The end result is that all bits were turned "off" (set to 0) except
|
||
that one bit which corresponded to 64. So, essentially, the AND 64
|
||
"stuff" you see is manipulating individual on/off switches inside the
|
||
computer.
|
||
|
||
A good book will walk you through conversion between binary and
|
||
decimal. Also, you'll see that hexadecimal ("hex") numbers which
|
||
you've probably come across, are shorthand forms of binary. Good
|
||
luck!
|
||
|
||
|
||
[EDITOR'S NOTE]
|
||
The purpose of this conference is to discuss Microsoft QuickBASIC
|
||
and related applications and utilities. SysOps looking for a Group
|
||
Mail or EchoMail link into QUIK_BAS should contact the Alliance node
|
||
known as 520/323, the FidoNet node known as 107/323, or the Good Egg
|
||
Net Node known as 9230/323, or simply 1-201-247-8252 for information
|
||
on local feeds.
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 32
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
|
||
----------------------------------------------------------------------
|
||
S w a p S h o p
|
||
----------------------------------------------------------------------
|
||
|
||
***** Screen Scrolling with Call Interrupt
|
||
|
||
DECLARE SUB scroll.ner (rader!, left!, up!, right!, down!)
|
||
DECLARE SUB scroll.up (rader!, left!, up!, right!, down!)
|
||
|
||
'To demonstrate the use of interrupt 10H ah=06
|
||
'To scroll any part of the screen up or down
|
||
'QB must be invoked with the /l switch. In QB.BI the RegType is
|
||
'defined and the INTERRUPT-Call set up.
|
||
'By Johan Lindgren (BBS:+46 60115371)
|
||
|
||
'$INCLUDE: 'QB.BI'
|
||
|
||
DIM SHARED inregs AS RegType, outregs AS RegType
|
||
|
||
'---------------------------------------------------------------------
|
||
' Fill the screen with numbers to indicate where scrolling takes place
|
||
'---------------------------------------------------------------------
|
||
|
||
FOR i = 1 TO 24
|
||
FOR j = 1 TO 40
|
||
|
||
PRINT USING "##"; i;
|
||
|
||
NEXT j
|
||
NEXT i
|
||
|
||
'----------------------------------------------------------
|
||
|
||
' Do one scroll up first. Give values and call the sub
|
||
'----------------------------------------------------------
|
||
|
||
rader = 2: up = 5: left = 5: down = 10: right = 20
|
||
|
||
scroll.up rader, left, up, right, down
|
||
|
||
'------------------------------------------------------------
|
||
|
||
' Do a scroll down. Give values and call the sub
|
||
'------------------------------------------------------------
|
||
|
||
rader = 3: up = 10: left = 35: down = 15: right = 70
|
||
|
||
scroll.ner rader, left, up, right, down
|
||
|
||
|
||
'END of demo.
|
||
|
||
SUB scroll.ner (rader, left, up, right, down)
|
||
|
||
'-----------------------------------------------------------
|
||
|
||
The QBNews Page 33
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
'First put up and down in right hexadecimal postion
|
||
'Then enter the values into the registers and call interrupt
|
||
'------------------------------------------------------------
|
||
|
||
up = up * 256
|
||
down = down * 256
|
||
|
||
inregs.ax = &H700 + rader
|
||
inregs.cx = up + left
|
||
inregs.dx = down + right
|
||
|
||
|
||
CALL INTERRUPT(16, inregs, outregs)
|
||
|
||
|
||
END SUB
|
||
|
||
SUB scroll.up (rader, left, up, right, down)
|
||
|
||
'-----------------------------------------------------------
|
||
'First put up and down in right hexadecimal postion
|
||
'Then enter the values into the registers and call interrupt
|
||
'------------------------------------------------------------
|
||
|
||
|
||
up = up * 256
|
||
down = down * 256
|
||
|
||
inregs.ax = &H600 + rader
|
||
inregs.cx = up + left
|
||
inregs.dx = down + right
|
||
|
||
|
||
CALL INTERRUPT(16, inregs, outregs)
|
||
|
||
|
||
END SUB
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 34
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
***** Getting the Day of the Week with Call Interrupt
|
||
|
||
DECLARE FUNCTION dag$ (nr!)
|
||
|
||
' This is just an example to illustrate the use of an interrupt
|
||
' to get the day of any date.
|
||
' By Johan Lindgren (+46 60-121497 (BBS System))
|
||
|
||
'$INCLUDE: 'QB.BI'
|
||
|
||
DIM inregs AS RegType, outregs AS RegType
|
||
|
||
inregs.ax = &H2A00
|
||
|
||
spardat$ = DATE$
|
||
|
||
CLS
|
||
PRINT
|
||
PRINT "This is just to show the function of interrupt 33,function 2a"
|
||
PRINT "It works well for our time and the future."
|
||
PRINT "If you need this function for old dates, you have to use"
|
||
PRINT "something else."
|
||
|
||
ON ERROR GOTO fel.datum 'In case you enter a bad date
|
||
|
||
main:
|
||
|
||
svar$ = " "
|
||
DO UNTIL svar$ = ""
|
||
INPUT "Input the date to check in the format MM-DD-YEAR"; svar$
|
||
IF svar$ <> "" THEN
|
||
DATE$ = svar$ 'Set the date we want to check
|
||
'Call the interrupt to get the day
|
||
CALL Interrupt (33, inregs, outregs)
|
||
dagnr = outregs.ax MOD 256 'Extract the daynumber returned
|
||
DATE$ = spardat$ 'Restore proper date
|
||
|
||
SELECT CASE dagnr
|
||
CASE 0
|
||
dag$ = "Sunday"
|
||
CASE 1
|
||
dag$ = "Monday"
|
||
CASE 2
|
||
dag$ = "Tuesday"
|
||
CASE 3
|
||
dag$ = "Wednesday"
|
||
CASE 4
|
||
dag$ = "Thursday"
|
||
CASE 5
|
||
dag$ = "Friday"
|
||
CASE 6
|
||
dag$ = "Saturday
|
||
END SELECT
|
||
|
||
PRINT "The day of the week for ";svar$;" is ";dag$
|
||
|
||
The QBNews Page 35
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
PRINT
|
||
END IF
|
||
|
||
|
||
|
||
|
||
|
||
|
||
LOOP
|
||
|
||
CLS
|
||
END
|
||
|
||
fel.datum:
|
||
RESUME main
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 36
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
***** A YES/NO response DEF FN
|
||
|
||
' TO: DAVID CLEARY 76510,1725
|
||
' FROM: BEN HARTLEY 70033,2612
|
||
' SUBJECT: For QBNews -- CHOOSE.BAS -- (FUNCTION)
|
||
'===================================================================
|
||
'Dear David,
|
||
'
|
||
' Liked your newsletter, which I downloaded from Exec-PC BBS.
|
||
' I'm not what you might call an experienced programmer, but the
|
||
' enclosed function might be of interest.
|
||
' There are LOTS of routines around that allow selection of
|
||
' a simple "Yes" or "No" response. There are times, however, when
|
||
' the flow of a program is improved if the choices are something
|
||
' other than "Y" or "N". That's where this one comes in. If there
|
||
' are no more than two choices, then they can be explicitly stated.
|
||
' Whether this is any faster, or, heaven save us all, more "elegant"
|
||
' than using SELECT CASE, I haven't the foggiest. I do know that it
|
||
' works!
|
||
' You can load this entire file into your QuickBASIC editor,
|
||
' and run it. It was originally written in QB 3.0, but seems to
|
||
' run fine in QB 4.5 --
|
||
' Hope this is something along the lines of what you're
|
||
' looking for.
|
||
'
|
||
' Ben Hartley
|
||
' Jaffrey, NH
|
||
|
||
'-------------------------------------------------------------------
|
||
DEF FNChoose (prompt$, Response1$, Response2$)
|
||
R1$ = UCASE$(LEFT$(Response1$, 1))
|
||
R2$ = UCASE$(LEFT$(Response2$, 1))
|
||
alpha$ = R1$ + R2$
|
||
|
||
PRINT prompt$; " ("; R1$; " or "; R2$; ") "
|
||
reply$ = ""
|
||
charPos% = 0
|
||
WHILE charPos% = 0
|
||
reply$ = UCASE$(INKEY$)
|
||
IF (reply$ <> "") THEN
|
||
charPos% = INSTR(alpha$, reply$)
|
||
IF (charPos% = 0) THEN BEEP
|
||
END IF
|
||
WEND
|
||
reply$ = UCASE$(MID$(alpha$, charPos%, 1))
|
||
FNChoose = (reply$ = R1$)
|
||
END DEF
|
||
'-------------------------------------------------------------------
|
||
COLOR 15, 1
|
||
beginhere:
|
||
CLS
|
||
LOCATE 10, 5
|
||
PRINT "Which option do you wish..."
|
||
LOCATE 12, 7
|
||
IF FNChoose("...The First or the Second ?", "First", "Second") THEN
|
||
|
||
The QBNews Page 37
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
PRINT
|
||
PRINT TAB(20); "You chose the First Option."
|
||
ELSE
|
||
PRINT
|
||
PRINT TAB(20); "You chose the Second Option."
|
||
END IF
|
||
LOCATE 16, 7
|
||
IF FNChoose("Do It Again or Quit ?", "Again", "Quit") THEN
|
||
GOTO beginhere
|
||
END IF
|
||
PRINT
|
||
PRINT TAB(30); "**** All done! ****"
|
||
END
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 38
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
***** A Powerful Replacement for INPUT
|
||
|
||
'SYNTAX: Enput$(Row%,Col%,FLen%,Default$,Allow$,EndKeys$,ExitKey$)
|
||
'WHERE: Row% & Col% - where input to occur
|
||
' FLen% - Field Length - maximum allowable
|
||
' Default$ - Field's beginning default value
|
||
' Allow$ - Character Set allowable for input
|
||
' EndKeys$ - Keystrokes acceptable for finishing.
|
||
' SUCH: [Enter] is CHR$(13)
|
||
' [Esc] is CHR$(27)
|
||
' [F1] is CHR$(255)+CHR$(59)
|
||
' [Ctrl+PgUp] is CHR$(255)+CHR$(132)
|
||
' ... etc
|
||
' ExitKey$ - The keystroke (from above EndKeys$)
|
||
' which was struck at function end.
|
||
'SIMPLEST USE: A$ = Enput$(0,0,0,"",","",Any$)
|
||
' Will default to cursor's current row/col, length is
|
||
' autoset to right margin, allowable chars are ALL,
|
||
' only ending key is [Enter].
|
||
'==========================================> Frederick Volking
|
||
|
||
FUNCTION Enput$ (Row%, Col%, FieldLen%, Default$, AllowCharsMask$_
|
||
,EndingKeys$, ExitKey$) STATIC
|
||
|
||
SHARED ScreenWidth%, BackSpaceKeyStrokes$, EmptySpaceChar$
|
||
|
||
' verify SHARED globals are set
|
||
|
||
IF ScreenWidth% = 0 THEN ScreenWidth% = 40
|
||
IF BackSpaceKeyStrokes$ = "" THEN BackSpaceKeyStrokes$ = _
|
||
CHR$(8) + CHR$(255) + CHR$(75)
|
||
IF EmptySpaceChar$ = "" THEN EmptySpaceChar$ = CHR$(254)
|
||
|
||
' If not specified then supply defaults to incomming vars
|
||
|
||
IF AllowCharsMask$ = "" THEN AllowCharsMask$ = CHR$(34) +_
|
||
" !#$%&'()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]_
|
||
^_abcdefghijklmnopqrstuvwxyz|~"
|
||
|
||
IF EndingKeys$ = "" THEN EndingKeys$ = CHR$(13)
|
||
IF Row% = 0 THEN Row% = CSRLIN
|
||
IF Col% = 0 THEN Col% = POS(0)
|
||
IF FieldLen% = 0 THEN FieldLen% = ScreenWidth% - Col%
|
||
IF LEN(Default$) > FieldLen% THEN Default$ = LEFT$(Default$_
|
||
, FieldLen%)
|
||
|
||
' define internal defaults
|
||
|
||
CharsCollected% = 0
|
||
ReturnVar$ = ""
|
||
' begin main loop
|
||
DO
|
||
NotDone% = 1
|
||
IF CharsCollected% = 0 THEN
|
||
LOCATE Row%, Col%, 0
|
||
|
||
The QBNews Page 39
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
PRINT Default$ + STRING$(FieldLen% - LEN(Default$), _
|
||
EmptySpaceChar$);
|
||
END IF
|
||
IF CharsCollected% = FieldLen% THEN
|
||
LOCATE Row%, Col% + CharsCollected% - 1, 1
|
||
ELSE
|
||
LOCATE Row%, Col% + CharsCollected%, 1
|
||
END IF
|
||
DO
|
||
KeyStroke$ = INKEY$
|
||
LOOP WHILE KeyStroke$ = ""
|
||
IF LEN(KeyStroke$) = 2 THEN KeyStroke$ = CHR$(255) + _
|
||
RIGHT$(KeyStroke$, 1)
|
||
IF INSTR(AllowCharsMask$, KeyStroke$) > 0 THEN
|
||
IF CharsCollected% < FieldLen% THEN
|
||
IF CharsCollected% = 0 THEN
|
||
PRINT STRING$(FieldLen%, EmptySpaceChar$);
|
||
LOCATE Row%, Col%, 0
|
||
END IF
|
||
ReturnVar$ = ReturnVar$ + KeyStroke$
|
||
CharsCollected% = CharsCollected% + 1
|
||
PRINT KeyStroke$;
|
||
END IF
|
||
ELSE
|
||
IF INSTR(BackSpaceKeyStrokes$, KeyStroke$) > 0 THEN
|
||
IF CharsCollected% > 1 THEN
|
||
CharsCollected% = CharsCollected% - 1
|
||
LOCATE Row%, Col% + CharsCollected%, 0
|
||
PRINT EmptySpaceChar$;
|
||
LOCATE Row%, Col% + CharsCollected%, 1
|
||
ReturnVar$ = LEFT$(ReturnVar$, CharsCollected%)
|
||
ELSE
|
||
CharsCollected% = 0
|
||
ReturnVar$ = Default$
|
||
END IF
|
||
ELSE
|
||
IF INSTR(EndingKeys$, KeyStroke$) > 0 THEN
|
||
ExitKeys$ = KeyStroke$
|
||
NotDone% = 0
|
||
ELSE
|
||
SOUND 500, 1
|
||
END IF
|
||
END IF
|
||
END IF
|
||
LOOP WHILE NotDone%
|
||
Enput$ = ReturnVar$
|
||
END FUNCTION
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 40
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
***** Windowing Routines with Shading
|
||
|
||
'FRAME.BAS test program
|
||
'Lawrence Stone, 1990
|
||
'
|
||
'Purpose: Demonstrate the versitility of the Frame subprogram.
|
||
'Note: I built this routine just for the fun of it. I designed it to
|
||
'be easy to use and versitile. This demonstration program simply makes
|
||
'six calls to the frame subprogram-the subprogram does the rest.
|
||
|
||
|
||
DECLARE SUB Frame (TopRow%, leftCol%, botRow%, rightCol%, boxType%,_
|
||
boxFg%, boxBg%, filFg%, filBg%, fillChar%, shadow%, header$)
|
||
|
||
COLOR 12, 4 'Set a fancy color
|
||
FOR A% = 1 TO 25
|
||
LOCATE A%, 1
|
||
PRINT STRING$(80, 206); 'Draw a complex background
|
||
NEXT
|
||
|
||
'Test the Frame subprogram
|
||
Frame 5, 20, 21, 75, 2, 15, 3, 9, 7, 178, -1, "This is a Test"
|
||
|
||
'Overlay the 1st box with a smaller 2nd box
|
||
Frame 4, 3, 10, 36, 1, 15, 6, 6, 0, 219, -1, "This is Test 2"
|
||
|
||
'What the heck, let's draw another box
|
||
Frame 13, 33, 22, 70, 3, 14, 2, 15, 3, 221, -1, "This is Test 3"
|
||
|
||
'What the heck, draw box #4 without a header
|
||
Frame 15, 5, 19, 65, 4, 13, 0, 0, 7, 32, -1, ""
|
||
LOCATE 17,14:PRINT "Box #4 has a shadow but doesn't have a Header."
|
||
|
||
'What the heck, draw box #5 without a shadow
|
||
Frame 8, 40, 10, 73, 4, 11, 0, 11, 0, 32, 0, ""
|
||
LOCATE 9, 43: PRINT "Box #5 doesn't have a Shadow!"
|
||
|
||
'What the heck, draw a frame around it all
|
||
Frame 1, 1, 25, 80, 2, 15, 0, 0, 0, 32, 0, _
|
||
"Box #6 Frames Without Clearing"
|
||
|
||
COLOR 7, 0 'Restore color before ending
|
||
A$ = INPUT$(1) 'Give a keystroke to end this test.
|
||
END 'We're out of here!
|
||
|
||
[EDITOR'S NOTE]
|
||
Due to the formatting of the FRAME subprogram, it is not printed
|
||
here. You can find the sub program in the file FRAME.BAS
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 41
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
|
||
|
||
----------------------------------------------------------------------
|
||
I n p u t P a s t E n d
|
||
----------------------------------------------------------------------
|
||
|
||
Due to demand, you can now get the QBNews mailed to you on disk for a
|
||
nominal charge. The rates are as follows:
|
||
|
||
United States $3.00
|
||
|
||
North America (outside US) $4.00
|
||
|
||
Outside US $6.00
|
||
|
||
Please add $1.00 if you want it on 3.5" media. Also, you can receive
|
||
it in either ZIP, PAK, or LHZ format. If you don't specify, you will
|
||
receive it in ZIP format.
|
||
|
||
The first time you request the QBNews, you will receive all available
|
||
issues. That way you won't miss any.
|
||
|
||
And of course, you can always download it free from Treasure Island.
|
||
First time callers are granted limited download privlidges so you can
|
||
get it. Treasure Island is 9600 HST, is at FIDO address 1:141/730, and
|
||
its phone is 203-791-8532. To request your copy on disk, send US funds
|
||
to:
|
||
|
||
The QBNews
|
||
P.O. Box 507
|
||
Sandy Hook, CT 06482
|
||
|
||
Remember to specify which archive format you want.
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 42
|
||
Volume 1, Number 3 May 22, 1990
|
||
|
||
WE NEED AUTHORS!
|
||
|
||
If you are interested in writing for the QBNews, you can contact
|
||
me at the address below. I can also be reached on Compuserve as
|
||
76510,1725 or on Prodigy as HSRW18A. If you are submitting articles, I
|
||
ask that they be ASCII text with no more than 70 characters per line.
|
||
As far as reviews go, I am pretty well set so what I really want is
|
||
code.
|
||
|
||
|
||
You can write me at:
|
||
|
||
The QBNews
|
||
P.O. Box 507
|
||
Sandy Hook, CT 06482
|
||
|
||
David Cleary
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
The QBNews Page 43
|
||
|