Copy Link
Add to Bookmark
Report

The BASIC Code Cache issue 1

eZine's profile picture
Published in 
The BASIC Code Cache
 · 28 Dec 2019

Volume 1, Number 1
April 20, 1993

  ************************************************** 
* *
* The BASIC Code Cache *
* *
* International BASIC Electronic *
* Newsletter *
* *
* Dedicated to promoting BASIC around *
* the world *
* *
**************************************************

The BASIC Code Cache is an electronic newsletter published by Communication Techniques. The BASIC Code Cache may be freely distributed provided NO CHARGE is charged for distribution. The BASIC Code Cache is copyrighted in full by Communication Techniques and republication of any material contained in The BASIC Code Cache is the prohibited without the consent of Communication Techniques or the author of the material. The BASIC Code Cache must be distributed whole and unmodified.

You can write The BASIC Code Cache at:

The BASIC Code Cache
P.O. Box 507
Sandy Hook, CT 06482

Copyright (c) 1993 by Communication Techniques.

TABLE OF CONTENTS

  1. From The Editor
    • Welcome to The BASIC Code Cache
    • Subscribing to The BASIC Code Cache

  2. COMMON SHARED
    • A Hexidecimal Primer by Earl Montgomery
    • Learning Assembler by Brian Mclaughlin

  3. Quick BASIC/PDS
    • Detecting if Windows is Running by John Riherd
    • A Fast Windowed Print Library by Brian Mclaughlin
    • Power Menus, Prompts and Messages By Larry Stone
    • A Quick Method of Changing Colors by Lee Herron

  4. PowerBASIC
    • PowerBASIC 3.0 Adds Power to BASIC by Bruce Tonkin
    • Getting Netware Connection Information by Lewis Balentine

  5. Visual Basic
    • SpyWorks-VB from Desaware
    • Tom Hanlin Checks in with PBClone for VB

  6. Access Basic
    • Creating Custom Wizards with Access Basic

  7. The Bug List
    • Buglist for Microsoft Visual Basic

From The Editor

Welcome to The BASIC Code Cache

Welcome to the premiere issue of The BASIC Code Cache. For those of you familiar with The QBNews, you can think of this as version 2.0 of that. When The QBNews first started out, Microsoft QuickBASIC and PDS were the king of the hill. However, during the three years that The QBNews was published, the state of BASIC programming has changed radically.

Microsoft Visual Basic for Windows landed on the scene a short while ago and took the Windows development market by storm. Hey, any BASIC product that can get C programmers to use it must be pretty special. Also more recently, QuickBASIC has gotten some pretty serious competition with the release of PowerBASIC 3.0 by Spectra Publishing. Because of these radical changes in the marketplace, The QBNews has become The BASIC Code Cache. What this means to previous readers of The QBNews is that we will now cover all aspects of BASIC programming in the PC world instead of strictly QuickBASIC.

I'm sure some of you are saying "Great, YAWR (Yet Another Windows Rag)". I can assure you that will not be the case. DOS is still very important out there, and with the arrival of PowerBASIC 3.0, there is some new excitement out there too. However, just because you program in a different environment, I hope you don't quickly dismiss the articles and code that don't pertain to you. After all, this is BASIC and you can probably learn something new regardless of what environment you program for.

For those of you who are new to The BASIC Code Cache, here comes the part where I plead for your support to sustain this newsletter. The BASIC Code Cache is made up strictly of contributions from its readership. Over the course of The QBNews, many programmers have contributed a ton of programming knowledge and has made The QBNews an encyclopedia of information on programming in QuickBASIC. Many times if you have a question on how to do something in QuickBASIC, you can find the answer in The QBnews. Now that we have expanded the scope of BASIC programming in The BASIC Code Cache, I'm sure there is a wealth of programming knowledge out there that can be shared. There are three ways to support The BASIC Code Cache.

  1. Submit well commented code - Part of the problem I had with sustaining The QBNews was not a lack of code, but rather a requirement I had about including an article. No more with The BASIC Code Cache. If you have some interesting code you would like to contribute, but are worried about your writing skills, we will gladly except well commented code. For your troubles you will receive the disk based version of The BASIC Code Cache your code appears in.
  2. Submit an article - One of the biggest requests I got was from beginners who wanted more information tailored for beginners. This was always hard to come by because advanced users may not know what stuff beginners are interested in learning. What may be common knowledge to an advanced user may be the answer to a problem for a beginner. So, if you are a beginner and you learn something new that you didn't know about, write it up and share it with other beginners. After all, if it wasn't common knowledge to you, it probably isn't common knowledge to everybody else either. You will also receive the disk based version of The BASIC Code Cache for your troubles.
  3. Subscribe to The BASIC Code Cache - The BASIC Code Cache offers disk subscriptions for those who are interested. By subscribing, you also get some bonus goodies not available in the electronic version. For instance, the disk based edition of this issue includes a working demo version of PowerBASIC 3.0, a demo of SpyWorks VB, and a full version of Tom Hanlin's entry into the VB shareware market PBCWIN. The cost of downloading these from Compuserve or long distance will more than cover the cost of the subscription, and you will also be supporting the continuation of The BASIC Code Cache to boot. Detailed info on subscribing follows this section.

If the rest of the BASIC community supports The BASIC Code Cache like QuickBASIC programmers supported The QBNews, we can look forward to many years of outstanding contributions of BASIC knowledge being spread around, making everybody better BASIC programmers. I look forward to your comments, contributions, and criticisms and can be reached at the addresses below.

US Mail: The BASIC Code Cache
P.O. Box 507
Sandy Hook, CT 06482

Compuserve: 76510,1725

Fidonet: 1:141/777

Prodigy: HSRW18A

Internet: dave.cleary@f777.n141.z1.fidonet.org

Subscribing to The BASIC Code Cache

Show you support of The BASIC Code Cache by subscribing. The disk based version of The BASIC Code Cache contains extra goodies not available in the electronic version. It will come to you on two 360k floppy disks or one 720k floppy disk. Extras include demos of commercial software reviewed, the latest shareware for BASIC plus much more. It costs only $24 for a one year subscription.

     Name ____________________________________ 

Company _________________________________

Address _________________________________

City ____________ State _____ Zip _______

___ 360k ___ 720k

Orders outside of the United States please add $10 shipping and handling.


SPECIAL OFFER FOR THE QBNEWS!!!!

For a limited time, you can receive the entire three disk collection of The QBNews for just $10. That is twelve issues in all of the best BASIC has to offer. Almost every topic of programming with QuickBASIC is touched upon and is an invaluable reference for any programmer.

COMMON SHARED

A Hexidecimal Primer by Earl Montgomery

While refreshing my memory on Hexadecimal and Binary notations (and the use of the logical operators <AND> <OR>, I found that it helped to take notes. This is a compilation of those notes. Some phrasing is entirely my own. So if you find any mistakes (other than grammar, sentence structure, or spelling! <smile>) please inform me so I can correct my document file. This document should prove useful to the new programmers.

A little info on Hexadecimal notation

Hexadecimal is a numbering system based on 16 elements. Digits are numbered 0 through F as follows:

     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F

Representing the digits 0 through 15.

Hexadecimal system uses powers of 16. For example:
&H19 (hexadecimal) represents 25 decimal. Let's see why.
Starting from the right the power is 1. Therefore 9 X 1 = 9
Moving left the next is power is 16. Therefore 1 X 16 = 16
And 9 + 16 = 25.

Let's try another. This time &HFF (hexadecimal)
Again starting from the right (F=15) 15 X 1= 15
Moving left 15 X 16 = 240.
And 240 + 15 = 255

So far we have looked at single byte hex values. Let's look at a 16 bit hex value. Remember 8 bits to the byte? Now we look at two adjoining bytes, or sixteen bits.
&H1902 (hexadecimal) represents 6402 decimal.
Again starting from the right 2 X 1= 2
Moving left 0 X 16 = 0
Moving left again <16 X 16 =256> 9 X 256 = 2304
Moving left again <16 X 256 = 4096> 1 X 4096 = 4096
And 2 + 0 + 2304 + 4096 = 6402

In basic hex values are preceeded by &H. For example &HFF or &H1902. In basic the decimal value of a hexadecimal number can be determined by the command PRINT &H(hexadecimal number): Example PRINT &HFF. The printed result in this case would be 255.

Decimal to hex is accomplished by PRINT HEX$(255)
The printed result in this case would be &HFF.

Now let's look at the individual bits within a byte.
Remember there are 8 bits to the byte and reading from Right to Left they increase in power by the power of 2.
Binary notation reflects set bits with a 1. Non set bits with a 0.
Let's look at one.

1 0 0 0 1 0 0 1 (This byte represents 137)

As with hex we start at the right.
1 X 1= 1
Moving left 2 X 0 = 0
Moving left again 4 X 0 = 0
Moving left again 8 X 1 = 8
Moving left again 16 X 0 = 0
Moving left again 32 X 0 = 0
Moving left again 64 X 0 = 0
Moving left again 128 X 1 = 128
And 1 + 0 + 0 + 8 + 0 + 0 + 0 + 128 = 137

Logical Operators <AND> <OR>

When you AND two numbers the results are in a new third number.

For example:
a = 137
b = 105
c = a AND b
1 0 0 0 1 0 0 1 This represents A <137>
0 1 1 0 1 0 0 1 This represents B <105>
0 0 0 0 1 0 0 1 This represents C <9>

What occurs when you AND two numbers is that the computer compares the bits within the first number against the bits in the second number. If the bits are the same then they will remain the same in the third number. If they are not the same then the equivalent bits will be 0 in the third number.


Logical OR

What occurs when you OR two numbers is that the computer compares the bits within the first number against the bits in the second number.
If the bits are the same they will remain the same in the third number.
If they are not the same then the bits will be 1 in the third number.

For example:
A=122
B=15
C=A OR B
0 1 1 1 1 0 1 0 This represents A <122>
0 0 0 0 1 1 1 1 This represents B <15>
0 1 1 1 1 1 1 1 This represents C <127>

This quick little reference document composed by Earl Montgomery I hope it proves to be of some use to you.


Learning Assembler by Brian Mclaughlin

My first suggestion if you want to learn to write ASM routines for BASIC is to get some good reference material. The best tutorial available can be found in the last 100 pages of "BASIC Techniques and Utilities" by Ethan Winer. It's aimed directly at those who know BASIC already and want to learn assembly language. The book costs $30, and even if you never get the hang of assembler, you'll get your money's worth from the rest of the book.

Next, get a good reference on DOS/BIOS interrupts. I have heard excellent things about the interrupt list put out by Ralf Brown, and available on many BBSes. I use QUE's "DOS Programmer's Reference" and can also recommend it.

Don't forget the manual/quick reference guide that comes with your assembler. When I get error messages, this is where I turn.

Last, once you have a bit of success and are eager for more I suggest you register for one of the shareware libraries that offers source code to registered users. Having some code that works(!) which you can look at is a great way to learn, IMHO. Until then, you can look at XPRINT.ASM. :->

If you get discouraged, take heart; a year ago I couldn't write a five-line procedure in ASM without an error message!

Quick BASIC / PDS

Detecting if Windows is Running by John Riherd

Sometimes you just need to know if your program is running in a DOS box under Windows. This code will not only tell you this, but will also tell you what version and what mode Windows is operating in.

CHECKWIN.BAS can be found in the file QBCODE.ZIP.

'********************************************************************* 
'* CHEKWIN.BAS *
'* *
'* This program will determine whether Windows is running and, if *
'* so, its operating mode. *
'* QuickBASIC must be loaded, as follows: QB /L QB *
'* Copyright 1993 by John Riherd *
'*********************************************************************
DEFINT A-Z
DECLARE FUNCTION ChekWindows% (Ver1 AS INTEGER, Ver2 AS INTEGER)

'$INCLUDE: 'Qb.bi' 'Include file for interrupt calls

CONST MULTIPLEX = &H2F 'multiplex interrupt number
CONST NOWIN = &H0 'Return for no Windows
CONST WIN386 = &H1 'Return for Windows-386 V2.?
CONST REAL = &H81 'Return for Windows in real mode
CONST STANDARD = &H82 'Return for Windows in standard mode
CONST ENHANCED = &H83 'Return fo Windows in enhanced mode

DIM WellIsIt AS INTEGER
DIM Ver1 AS INTEGER 'Primary version number
DIM Ver2 AS INTEGER 'Secondary version number

WellIsIt = ChekWindows%(Ver1, Ver2) 'Do the test and return values
SELECT CASE WellIsIt
CASE NOWIN
PRINT "Windows is not running"
CASE WIN386
PRINT "Windows-386 V 2.? is running"
CASE REAL
PRINT "Windows is running in real mode"
CASE STANDARD
PRINT "Windows is running in standard mode"
CASE ENHANCED
PRINT "Windows Vers. "; LTRIM$(STR$(Ver1)); ".";
PRINT LTRIM$(STR$(Ver2)); " is running in enhanced mode"
END SELECT

FUNCTION ChekWindows% (Ver1 AS INTEGER, Ver2 AS INTEGER)


DIM Regs AS RegTypeX 'Processor registers for interrupt call

DIM VBuffer AS INTEGER 'To store version number


Ver1 = 0 'Initialize version numbers
Ver2 = 0


Regs.ax = &H1600 'Function number
CALL INTERRUPTX(MULTIPLEX, Regs, Regs)

VBuffer = Regs.ax 'Set regs.AX


SELECT CASE VBuffer MOD 256 'Get the low byte of AX

CASE &H1, &HFF 'Windows-386 running
Ver1 = 2 'Primary version
Ver2 = 0 'Secondary version is unavailable
ChekWindows% = WIN386

CASE &H0, &H80
Regs.ax = &H4680 'Check for real or standard mode
CALL INTERRUPTX(MULTIPLEX, Regs, Regs)

IF (Regs.ax MOD 256) = &H80 THEN 'Check if Windows is running
ChekWindows% = NOWIN 'No
ELSE 'Check for real or standard mode
Regs.ax = &H1605 'Set registers and function
Regs.bx = &H0
Regs.si = &H0
Regs.cx = &H0
Regs.es = &H0
Regs.ds = &H0
Regs.dx = &H1
CALL INTERRUPTX(MULTIPLEX, Regs, Regs)

IF Regs.cx = &H0 THEN 'Check for real mode
ChekWindows% = REAL
ELSE 'Windows in standard mode
ChekWindows% = STANDARD
END IF
END IF

CASE ELSE
Ver1 = VBuffer AND &HF 'Get the low byte for primary version
Ver2 = VBuffer \ 256 'Get the high byte for second. version
ChekWindows% = ENHANCED
END SELECT


END FUNCTION

A Fast Windowed Print Library by Brian Mclaughlin

Here is some assembly language code I've been toying with for a while -- a set of fast-printing routines for QuickBASIC 4.x (and P.D.Q.). I wrote these because at the time, P.D.Q. did not support VIEW PRINT, and by design, outputs all text through DOS instead of printing them directly to video memory.

My answer was to write a group of assembler routines that are (almost) as easy to use as regular QB. These routines do direct-to-screen writing, update the cursor, scroll automatically, allow you to set or change the default colors, and let you set a VIEW PRINT window with parameters for width as well as height. They require almost exactly the same parameters as their QB counterparts (they almost have the same names, even!) and in many programs they will result in a smaller EXE than if you used QB's display commands. Admittedly, they will make for a bigger EXE than straight P.D.Q., but the price is fairly small and the extra convenience is tremendous.

Here's a list of the routines:

     DECLARE SUB XInit (IgnoreSnow%) 
DECLARE SUB XPrint (PrintThis$, NumberOfScrolls%)
DECLARE SUB XCls ()
DECLARE SUB XColor (FG%, BG%)
DECLARE SUB XLocate (Row%, Col%)
DECLARE SUB XCursorOn (BlockOrLine%) 'non-zero value for block cursor
DECLARE SUB XCursorOff ()
DECLARE SUB XViewPort (TopRow%, LeftCol%, BotRow%, RightCol%)
DECLARE FUNCTION XCsrLin% ()
DECLARE FUNCTION XPos% ()

These routines do have some limitations and drawbacks. They ONLY work with near strings. Far strings will choke'em. Plus, you can't do the equivalent of PRINT Num%, instead you must use the equivalent of PRINT STR$(Num%). Because STR$() pulls the entire floating-point emulation library into your EXE this can be considered a genuine drawback. (Fortunately, there are ways to get around this one.)

There is no support for 43/50 line mode. You can only use a 25x80 screen size. Page zero is the only display page supported. You may change the shape of the cursor, but your only choices are a block or an underline or turning it off altogether. There are other quirks. I have tried to identify every quirk, feature and point of interest about how the routines work in the comment header for the code.

The internal variables used by XPrint use 14 bytes in DGROUP. The routines all assemble into a single OBJ file, so calling even one of them will link ALL of them into your EXE file. However, if you can assemble the source code, you can easily remove any unneeded routines from the source and reassemble only the routines you want or need.

If you need capabilities not included in XPrint, use straight QB, or better yet, add them to XPrint!

I have tried to design XPrint to allow the most painless possible conversion from normal BASIC syntax.

Here are some samples:

       In QB:  PRINT X$                   'print, scroll once 
In XP: XPRINT X$, 1 'same

In QB: PRINT X$; 'print, don't scroll
In XP: XPRINT X$, 0 'same

In QB: PRINT: PRINT: PRINT 'scroll 3 times, no printing
In XP: XPRINT "", 3 'same

In QB: LOCATE , B% 'old row, new column
In XP: XLOCATE XCSRLIN%, B% 'same

In QB: LOCATE , , 0 'cursor off
In XP: XCURSOROFF 'same

I know very well that I can't instruct the gurus here, but not everyone is a guru. (Look at me!) And I would like to share around a bit of what I've learned with other folks like me, who haven't been at this so very long.

I did one thing in XPrint that was new to me. XPrint has multiple procedures in one object module, some of which are NEAR for internal use and some of which are FAR, to be called from BASIC. In the past when I wrote something like this I dropped the BASIC option from the .MODEL MEDIUM directive, to avoid making all procedures PUBLIC. That stopped the possibility of accidentally CALLing a NEAR procedure from BASIC, but it made for more work.

Writing XPrint I stumbled onto a way to be lazy and use the BASIC directive with a clear conscience, even when mixing NEAR and FAR procedures. I just used a leading "$" character in the names of all the procedures I declared NEAR. Because such names are illegal in BASIC, I figure this should pretty much kill the problem of accidentally referencing a NEAR procedure.

I did another thing new to me. On 386s and above the MUL and DIV were speeded up considerably, but I work and play on an XT clone with an 8088, so I always try to shift bits instead. In XPrint I finally got around to using multiple shifts and adds to achieve what can't be had by shifts alone. In $SetVideoOffset, I needed to multiply by 160. First I shift-multiplied by 128, then by 32, and added. Imagine my childish delight!

I almost blush to point this out, but this same technique can be used as a fast way to multiply by ten (X*8 + X*2). I hope this tip helps someone who hadn't heard it yet.

The last thing I'll mention today isn't exactly a matter of code, so much as a matter of design. In the XInit procedure I added a way to specify that snow-suppression be ignored on CGAs. It is my fervent wish that this feature will be tied in to a command line option for end-users of the programs you write. I strongly believe in giving end-users a chance to escape from default behavior! We programmers don't always know best!

The assembly language source code for XPrint and XPRINT.OBJ are contained in the file XPRINT.ZIP. Please consult the comments section at the head of it. When I was writing XPrint I dug out the FastPrint routine by Christy Gemmel in the QBNews. and studied its design. I would never have learned assembly language for QB without similar help. Perhaps, this will slightly repay those who have helped me.

Lastly, feel free to contact me on the BAS_NET ASM for QB echo about any bugs or weird behaviors you find in XPrint. I ain't poifect, y'know. In the next issue, we will modify XPrint to work with far strings!


Power Menus, Prompts and Messages By Larry Stone

While building a set of routines for the students of my 'C' course (forgive me, I enjoy programming in 'C' as much as I enjoy QB), I developed a fairly efficient routine for word-wrapping text within a boxed frame. Well, I was so impressed with the speed and versatility of my creation that I immediately coded it for QB.

The routine, BoxDialog(), has six arguments in its parameter list:

         BoxDialog Top%, BoxWidth, Border$, Msg$, MsgClr%, Shadow%

"Top" is an integer defining the top row for the boxed display.
"BoxWidth", another integer, defines the width of the displayed box.
"Msg$" is the string of text to word-wrap inside the display box.
"MsgClr" is the color attribute for the text and box frame and,
"Shadow" is true or false for using a shadow around the box frame.

"Border$" is a string of eight characters defining the upper-left corner, top-side, upper-right corner, left-side, right-side, lower- left corner, bottom-side and lower-right corner of the box, respectively.

BoxDialog() automatically frames, word-wraps and centers your text using the corner and side characters as defined in Border$. Further, BoxDialog() knows if your monitor is in a 40 column or 80 column display mode and centers your message accordingly.

Also, BoxDialog() can be instructed to automatically shadow the boxed message. When Shadow is true, BoxDialog() makes calls to DoShadow().

DoShadow() PEEKs into the appropriate video map at the row, col location for the color attribute at that location. Then DoShadow() calculates the attribute needed for a shadow effect at that location. Finally, DoShadow() sets that new attribute into the video map.

BoxDialog() does not use BASIC's PRINT statement. Instead, it makes calls to WriteStr(). WriteStr() uses four arguments in its parameter list: A$, the string to write; row and col, integer location for the displayed text; and, attr, the color attribute to use.

Note that BoxDialog's MsgClr and WriteStr's attr arguments are color attributes as used by DOS. In BASIC, for an intense white foreground and a red background, you would use the command, "COLOR 15, 4". DOS uses the attribute 79. Because you may prefer to think of color in the BASIC scheme of things, DIALOG.BAS includes the small function, ClrAttr%. You can use this function like any other function:

             attribute% = ClrAttr%(foreground%, background%)

ClrAttr%() is extremely fast and efficient and does not use any float- ing point functions (in fact, none of the DIALOG.BAS routines use the floating point library). ClrAttr() has one line of code:

         ClrAttr% = (fg AND 15) OR (16 * bg - (128 * (fg > 15)))

The code above does not perform any multiplication. The instructions 16 * bg and 128 * (fg...) use even multiples of 2. As, consequence, the BASIC compiler compiles this statement as a speedy shift left 4 and shift left 7 instruction. The instruction (fg > 15) is a Boolean test that evaluates as either -1 (true) or 0 (false).

The heart of all of these routines is VidInfo(). VidInfo uses QB's INTERRUPT routine. The AX register is set to &HF00 and the interrupt used is &H10. This is a query to extract the current video mode from the ROM BIOS. Armed with this information, VidInfo() determines your systems current video map address via a SELECT CASE Vmode. Next, this routine PEEKs into low memory to find out how many rows and columns you system is currently set for.

You might want to add two more pieces of information to the CASEs - the memory required to save a screen and whether the particular screen is interleaved or not. In any case, VidInfo() passes four pieces of information via a COMMON SHARED block named, /VInfo/. This means that whenever you make a call to VidInfo(), Vmode%, VidSeg%, MonRows% and MonCols% are immediately known to all of the routines in DIALOG.BAS, as well as, any other modules that '#INCLUDE: 'DIALOG.BI'.

BoxDialog(), DoShadow() and WriteStr() will automatically initialize with a call to VidInfo() if you haven't already made this call. This is because these routines need to know, at minimum, the number or columns used by your monitor. WriteStr(), for example, has the code:

               offset = MonCols * 2 * (row - 1) + col * 2 - 2

Speaking of WriteStr(), if you are using QBX or compiling with BC7 using far strings then this routine won't work as written. You need to use SSEG in lieu of VARSEG. Also, although the routine will not be fast within the QB environment, compiled, it's lightning. In fact, compiled and run on an older CGA system will guarantee snow. This is because WriteStr() does not pause for the monitor's retrace.

I could ramble on and on about every nuance of the code but the code is rather well commented and speaks for itself. So, the best thing to say is compile it into an exe file and run it - the test driver should give you plenty of ideas on how to use it.

     To compile ->  BC dialog /o; 
BC testdlog /o;

To link -> LINK /e testdlog + dialog, , nul, qb;

Now type, "testdlog" to see the action.

Two things you could do to enhance BoxDialog(). One would be an additional argument to force a upper-left column location. This would allow you to use BoxDialog() for pull-down menus (at present, you can us it for menus but the menu is always centered on the screen).

The other thing you could do to enhance BoxDialog() is the inclusion of another argument to allow the text to have a different color than the box frame.

===================

Larry Stone is the author of ORCA Pacific Software's file manager and archive handler, "Professional SERVICES 4.0". He has produced several shareware products including the "LS-1.00 Plus Scientific Calculator", initially released with The QBNews volume 1, issue 4. Larry is also a consulting programmer and an adjunct professor teaching beginning QuickBASIC and 'C'. He is also a frequent contributor to The QBNews. He can be contacted in care of this newsletter or in care of The ORCA Pacific BBS 1(503)888-6050.

===============

A Quick Method of Changing Colors by Lee Herron

I had to color code about 40 pages of text for an app that needed key words highlighted, this idea I got from a BBS software. This code uses high order ASCII codes to add color information to the text you are printing. ZPRINT.BAS is contained in QBCODE.ZIP. Enjoy.

'********************************************************************* 
'* FileName: ZPrint by Lee Herron @ 1:3612/130 fido *
'* Copyright 1993 by Lee Herron *
'* ----------------------------------------------------------------- *
'* Description: For use in coding color into large text displays, *
'* much quicker method of changing colors than using color ?,? *
'* everytime. I hope you find it of some help. Hint: Don't use zPrint*
'* on every line. *
'* Origin: NightFlight BBS Pensacola,FL 16.8HST/DS (1:3612/130) *
'*********************************************************************
DEFINT A-Z
DECLARE SUB zPrint (z$)

' ASCII TABLE:
'128 Ä black '136 à hblack
'129 Å blue '137 â hblue
'130 Ç green '138 ä hgreen
'131 É cyan '139 ã hcyan
'132 Ñ red '140 å hred
'133 Ö magenta '141 hmagenta
'134 Ü brown '142 é hbrown
'135 á white '143 è hwhite

CLS
LOCATE 11, 6
zPrint "ÇÄThis is a sample string using äÄ<éÄZPrintäÄ>ÇÄ to "
PRINT "Highlight specific words!" ' see Hint !

SUB zPrint (z$) STATIC

y = CSRLIN: x = POS(0): cflag = 0

FOR z = 1 TO LEN(z$)
a = ASC(MID$(z$, z, 1)): m$ = CHR$(a)
IF a = 145 THEN
PRINT
ELSE
IF a < 128 THEN
PRINT m$;
cflag = 0
ELSE
IF cflag THEN
COLOR , a - 128: cflag = 0
'Set background color because previous character was a color.
ELSE
COLOR a - 128: cflag = 1
'Set foreground color because prev. char was a letter.
END IF
END IF
END IF
NEXT z
END SUB

PowerBASIC

PowerBASIC 3.0 Adds Power to BASIC by Bruce Tonkin

Product Name: PowerBASIC 3.0
Available from: Spectra Publishing (408) 730-9291
1030 D East Duane Ave
Sunnyvale CA 94086
Price: $149 ($59 for Basic Code Cache readers until 4/30/93)

PowerBASIC represents a clearly-defined and demonstrably better alternative in the BASIC compiler market. It concedes nothing to other compilers, and extends the range of BASIC in ways that any other compiler vendors might envy.

The envy ought to extend to the former leader, Microsoft. That largest of all software businesses started as a vendor of BASIC, and for years has prided itself on having the best BASIC available. For all those years, that pride has been justified, but no more; the new king is a product called PowerBASIC. To see why this is so, we need to ask just two questions: What do BASIC programmers want? What makes PowerBASIC so good?

The answer to both questions is the same: power. Microsoft BASIC has five numeric data types: integer, long integer, currency, and single and double precision floating-point. PowerBASIC adds single byte integer, unsigned word and long integer, 8-byte (quad-word) integer, BCD fixed and BCD floating-point (instead of just one currency type), and extended-precision real (80-bit real). While BASIC isn't made good or bad solely because of the number of numeric data types supported, more types are a definite help -- and these types have been on most BASIC programmers' wish lists for years.

Further, the BCD types in PowerBASIC are not limited to a single number of decimal places; the programmer can specify (at run-time) how many places are desired. Rather than be limited to four decimal places for all calculations (as with the currency data type), PowerBASIC allows you to set BCD to two decimal places for exact (to the penny) calculations with no need for rounding, or to any number of places from zero to eighteen for any particular need. The result is decreased overhead in each program (no need for rounding), and increased flexibility.

PowerBASIC also implements BCD as scaled integers, rather than the two-digits-per-byte "natural" method. By using scaled integers, PowerBASIC's approach gives increased speed -- ordinary BCD math has a deserved reputation for sluggishness.

PowerBASIC also supports flex strings -- strings with a fixed length, except that the length can be changed under program control -- and fundamental changes in the way programs can be created.

Consider the usual way any program is created. There are several steps; design, code, test, debug, and retest. In practice, the debug and retest steps are repeated indefinitely. No one seems to want to mention the reason for the extended debugging and testing phases, perhaps because the reason is so fundamental: the number of expressions and branches in the code. In other words, code complexity leads directly to coding errors.

From that standpoint, it is clear that the fewer expressions and the fewer branches, the more likely a program will work correctly the first time, and the easier it will be to enhance. This is the big reason for the popularity of toolkits, modular programming, and object orientation. Sure, there are other reasons for each of those things, but reduced complexity is the biggest and certainly easy to defend.

So, how does this apply to PowerBASIC? Simple: PowerBASIC adds functions that would ordinarily be found in a toolkit or written as needed. PowerBASIC adds types to make it easier and more natural to express more programming requirements in fewer statements, fewer lines, and fewer branches. The more power in the language, the better for the programmer -- and the person using the applications. Reliability helps everyone!

Some specific examples are in order. Let's start with some of the array commands and functions.

The Array Sort command allows the programmer to sort any type of array in ascending or descending order, in whole or in part. The sort can simultaneously rearrange the elements in another array (a tag array). It's not so much that the sort command is useful; it's certainly that. It's even more important that it exists; it's such a generally useful command that it's hard to imagine going without it once you've used it. Even a low-level language like C includes a sort command in its standard library. No Microsoft BASIC has a sort command, however.

Equivalently useful are commands like Array Scan (search any array for any value), Array Insert (insert a new element in an array), and Array Delete. Without PowerBASIC, the programmer either must write an equivalent for each, or buy one. It's not as if these commands are terribly complex, so there's not a lot of work involved -- but there is some work, and it is repeated in every program written, and those programs are thus larger and more likely to contain errors, and slower than the PowerBASIC equivalent besides.

In every part of PowerBASIC, the same pattern is repeated. Even mundane matters like compiling are addressed; PowerBASIC supports conditional compilation (making it easier to maintain separate versions of the same program in one source module). PowerBASIC also supports metacommands that eliminates both long and complex command lines and lengthy and error-prone selections from cascading dialog boxes. To force the compiler to create a program that will require an 80386 processor, you would insert the metacommand $cpu 80386 at the start of the program, for example. All executables can be compiled to stand-alone files that need nothing more than MSDOS to run. The other metacommands are also named in easily-remembered ways, making Power BASIC programs almost entirely self-documenting (at least potentially)!

Other notable advances include an in-line assembler with a full knowledge of the environment (use MOV AX,X% to move the value of the BASIC variable X% to the AX register), TSR creation, string memory (in any single array or any number of arrays) up to the full amount of available memory -- not just 64K -- and things like block memory moves, MAX and MIN functions, bit functions (test, set, shift, and rotate), pointers, library support for arbitrary OBJ files, and minor niceties almost everywhere you look.

Consider the INSTR function. In any standard BASIC, INSTR returns the first matching position of one string within another; INSTR("ABC","C") will return the result 3. PowerBASIC adds the ANY keyword for even more power, so the function INSTR("GFDSALK",ANY "QWERTAS") will return the result 4 (S is found before A). The ANY keyword can also be used in commands like LTRIM, RTRIM, REPLACE, and others. Communications capability extends to 115K baud and to other COM ports (to COM4, even all at once). There is a MAP command which allows you to subdivide a flex string into separate parts, similar to a FIELD statement; in effect, you can define a type at run-time! All this isn't just "neat" -- it's good, solid, and genuinely useful stuff.

If you'd like to write TSR programs, PowerBASIC makes it easy; a complete TSR can take as little as five lines, and you don't need a third-party library -- the capability is built into PowerBASIC.

In sum, PowerBASIC was designed from the ground up with a very different agenda than the other BASIC products. PowerBASIC was written in response to BASIC users; nearly every feature that appeared on very many wish lists was included in PowerBASIC. Some products have hidden agendas -- use them and you're buying a vision of the future of programming or computing that may or may not match what you'd like. PowerBASIC is pragmatic; it's what you always wanted in a computer language, and may be far more than you ever expected to get. That strikes me as especially significant. After all, don't you want to encourage a company that actually listens to its customers?

I do. I'm now moving all my BASIC software from the former leader to the new one, and that's not a step I take lightly. After all, I've been using products from the other vendor since 1976, and there's a lot to move. It's nice to discover that my EXE files are smaller and run faster, besides my source files being an average of 25% smaller!

Bruce W. Tonkin
President - T.N.T. Software
34069 Hainesville Road
Round Lake, IL 60073

EDITOR'S NOTE
Disk subscribers to The BASIC Code Cache will find TRYPB3.ZIP on disk number 2. This is a fully functional demonstration version of PowerBASIC 3.0.


Getting Netware Connection Information by Lewis Balentine

This code provides three routines that return information on a work station's netware connections. It is an excellent example of what you can do with some of PowerBASIC's more advanced features. NET001.BAS can be found in the file PBCODE.ZIP.

The functions are:

     DECLARE FUNCTION GetConnectNumber% () 
DECLARE FUNCTION GetConnectInfo% (Con%, Reply AS ConInfoRep)
DECLARE FUNCTION GetNode$ ()

GetConnectNumber% returns the Netware Logical Connection number. This will tell you if you are logged into a server. GetConnectInfo% returns information about your connection and GetNode$ returns the 6 byte Physical Node Address.

GetNode$ takes advantage of PowerBASIC's in-line assember. It also calls the internal PowerBASIC routine GetStrLoc to return address information on a PB string. Be sure to check out the support routines that these functions call for more interesting code.

     ' This FILE: "NET001.BAS" is placed in the public domain by the author 
' Lewis Balentine, 19 March 1993. The author specificly denies all
'warranties, exspressed or implied, of fittness or function.
' ->>>> use or abuse as you see fit <<<<-
'---------------------------------------------------------------------
'PGN PAGE: XXX in this program remarks refers to a page in the book:
'"Programers Guide to Netware", Charles G. Rose, (c) 1990 McGraw Hill.
'=====================================================================

$compile exe
$debug map on
$dim array

DECLARE FUNCTION GetStrLoc&(byval AllocHandle%)' so ASM CALL can find it

'---------------------------------------------------------------------
' Constants for use with PB3's REGS function/statement.
%FLAGS = 0
%AX = 1
%BX = 2
%CX = 3
%DX = 4
%SI = 5
%DI = 6
%BP = 7
%DS = 8
%ES = 9

'---------------------------------------------------------------------
type ConInfoReq ' Connection Information Request Buffer
length as word ' (LoHi) Request buffer length (4 - 2 = 2)
cll as byte ' Set to &H16
con as byte ' logical connection number
end type

type ConInfoRep ' Connection Information Reply Buffer
length as word ' (LoHi) Reply buffer length (64 - 2 = 62)
id as Dword ' (HiLo) Object ID
tipe as word ' (HiLo) Object Type
nam as string * 48 ' Object Name
Yr as Byte ' Log in Year where 0 = 1980
Mo as Byte ' Month (1 to 12)
Dy as Byte ' Day (1 to 31)
Hr as Byte ' Hour (0 to 23)
Mn as Byte ' Minute (0 to 59)
Sc as Byte ' Second (0 to 59)
Wk as Byte ' WeekDay where 0=Sunday
Extra as Byte ' Undefined extra byte
end type

'---------------------------------------------------------------------
' the FourByte, TwoByte types and HiLoWord, HiLoDWord are used in the
' functions SwapBytesW and SwapBytesDW.
Type FourByte
B1 as Byte
B2 as Byte
B3 as Byte
B4 as Byte
end Type

Type TwoByte
B1 as Byte
B2 as Byte
end Type

Union HiLoWord
Wrd as Word
BB as TwoByte
end Union

Union HiLoDWord
DW as Dword
BB as FourByte
end Union

'=====================================================================
' This is the "MAIN" code of the prgram. It prints Netware Connection
' Information about the workstation and logged on user.
'=====================================================================
start:
dim info as ConInfoRep

connect%=GetConnectNumber%

print

if connect%=0 then
print "This workstation is not logged in to the network."
end
end if

errr%=GetConnectInfo%(connect%,info)

if errr%<>0 then
print "Get Netware Connection Information failed."
end
else
Print "Logical Connection number is (DEC): ";connect%
Print " LogIn Name is: "; trim$(info.nam)
print " Netware Object ID is (HEX): "; DWHex$(SwapBytesDW???(info.id))
print " Netware Object Type is (HEX): ";Right$(DWHex$(SwapBytesW??(info.tipe)),4)
print " WorkStation Node is (HEX): "; getnode$
end if
end
'=============================================================================
' Below are the function used by the program.
'=============================================================================
' function to return Netware Logical Connection number
function GetConnectNumber% ' PGN PAGE: 274
' if 0 then not logged in
local c%
!xor AX,AX ' zero AX
!mov AH,&Hdc ' Netware API call for Connect #
!int &H21 ' Call Netware (returns AX=&Hdc32)
!xor AH,AH ' Mask off the high byte
!mov c%,AX ' AL contains connection number
GetConnectNumber%= c%
end function
'----------------------------------------------------------------------------
' function to return info about the Netware object at a specific connection #
' PGN PAGE: 272
function GetConnectInfo% (con%, reply as coninforep) Local
dim request as ConInfoReq
request.length=2
request.cll=&H16
request.con=con%
reply.length=62
reg %ES, varseg(reply)
reg %DI, varptr(reply)
reg %DS, varseg(request)
reg %SI, varptr(request)
reg %AX, &HE300
call interrupt &H21
reply.Extra = Reg(%AX) and &H00FF ' 0 indicates successful call
GetConnectInfo%=reply.extra
end function
'----------------------------------------------------------------------------
' function to return 6 byte Physical Node Address of the requesting workstation
' PowerBasic does not have a 6 byte integer type so we are going to return
' a 12 byte string representation of the unsigned Hexidecimal number.
' There is probably a better way to do this, but ....
function GetNode$ ' PGN PAGE: 276
temp$="000000000000" ' 6 bytes requires 12 characters
! push DI ; save Destination Index
!
! mov AX,&Hee00
! int &H21 ; Call Netware
!
' ! mov AX,&h4321 ; for test of conversion
' ! mov BX,&h8765 ; for test of conversion
' ! mov CX,&hCBA9 ; for test of conversion
!
! push CX ; Node returned in CX,BX,AX
! push BX
! push AX

' setup our working string
! mov AX,temp$ ' string handle
! push AX ' now for location and length
! call getstrloc ' return: location=DX:AX, length=CX
! dec CX ' reduce count by one
! add AX, CX ' we need the end of the string
! mov ES, DX ' store our address of string
! mov DI, AX ' in ES:DI


! std ; set direction flag for decriment
! mov CX,&h0003
GetNodeLoop:
! pop BX ; get word from stack
! mov AH,4 ; (4 nibbles)
! call WHex ; translate
! loop GetNodeLoop

! pop DI ; restore resisters
! cld
GetNode$=temp$
end function
'----------------------------------------------------------------------------
' functions to swap High and Low bytes of a Word/DWord
' Netware was origionally only available on a Motorola 6800 server. Motorola
' stores numbers with the most significant byte first. Intel stores numbers
' with the least significant byte first. This function is use to translate
' the old style unsigned wird values. Note that it does not change the input.
function SwapBytesW?? (wrd??) Local
dim temp as HiLoWord
temp.Wrd=wrd??
swap temp.bb.b1 , temp.bb.b2
SwapBytesW??=temp.Wrd
end function
'----------------------------------------------------------------------------
function SwapBytesDW??? (DW???) Local
dim temp as HiLoDWord
temp.DW=DW???
'print hex$(temp.bb.b1), hex$(temp.bb.b4)
swap temp.bb.b1, temp.bb.b4
swap temp.bb.b2, temp.bb.b3
SwapBytesDW???=temp.DW
end function
'----------------------------------------------------------------------------
' function to return the value of the string representation of Hexidecimal
' number. PB's "&Hxxxx" is limited to compile time and/or two bytes.
' NOTE: This function assumes unsigned strings !
' NOTE: This function ignores the invalid characters!
function DWHexVal???( DW as string) Local
dim temp as string
temp=ucase$(DW)
while len(temp)>0
p= instr("0123456789ABCDEF",left$(temp$,1))
if p>0 then
shift left t???,4
t???=t???+(p-1)
end if
' print p,t???,temp
temp=mid$(temp,2)
wend
DWHexVal???=t???
end function
'----------------------------------------------------------------------------
' function to return a 8 character Hexidecimal string representation of
' a four byte DoubleWord variable. (PB's HEX$ function is limited to 2 Bytes)
function DWHex$ (DW as DWord) Local
temp$="87654321" ' allocate 8 byte character string

' PAGE: 333 of PB3 Programers Guide
' " ... save the SI,DI,BP,DS,SS and SP registers."
' of these we only modify the DI register.
! push DI ; save Destination Index

' setup our working string
! mov AX,temp$ ' string handle
! push AX ' now for location and length
! call getstrloc ' return: location=DX:AX, length=CX
! dec CX ' reduce count by one
! add AX, CX ' we need the end of the string

' setup our DoubleWord Variable
! les di,[bp+6] ' get the address from the stack
! mov BX, es:[di] ' store lo word
! inc di ' move index foward
! inc di ' two bytes
! mov CX, es:[di] ' store hi word
! mov ES, DX ' store our address in of string
! mov DI, AX ' in ES:DI
! std ' set the direction flag
! mov AH,4 ' 1 word = 4 nibbles
! call Whex ' now convert
! mov BX,CX ' get the hi word
! mov AH,4 ' 1 word = 4 nibbles
! call WHex ' convert it
! pop DI ' restore Destination Index
' PAGE: 333 of PB3 Programers Guide
' " ... all these calls also require you clear ... the processor
' direction flag before returning to caller. ..."
! cld
DWHex$=temp$
end function
'----------------------------------------------------------------------------
' This function trims the "white space" from both ends of string.
' It also removes ANY contol characters (0 to 31).
function trim$(t$)
dim temp as string
for i=1 to len(t$)
tt$=mid$(t$,i,1)
if tt$=>" " then temp=temp+tt$
next i
trim$=ltrim$(rtrim$(temp))
end function
'=============================================================================
' below are misc ASSEMBLY soubroutines called from the inline ASM functions
'=============================================================================
' Most, if not all, of this assembly work could have been done in pure Basic.
' The main reason I did it in assembly was to get some idea of what could
' be done (and how) with the INLINE ASM capability of PB3.
' Having gone to the trouble ..... I am going to use it.
'-----------------------------------------------------------------------------
! ; ASM routine converts the WORD in BX to a Hex String representation
! ; on entry
! ; ES:DI = pointer to end of string (works right to left)
! ; BX = value to be converted
! ; AH = number of nibbles (hex digits) to convert (0 to 4)
! ; direction flag = set (decrement)
! ; on exit
! ; BX = undefined (contents rotated, 4 digits->BXin=BXout)
! ; AH = zero
! ; AL = last Hex Character
! ; AX = undefined (AH =0, AL last Hex digit)
! ; ES:DI = byte in front of hex string
! ; The only other register affected is the flag register.
! ; NOTES:
! ; NO ERROR CHECKING, THIS WILL WRITE OVER ANYTHING (or at least try)!!
! ; THIS ROUTINE USES A NEAR RETURN, MUST CALL FROM SAME CODE SEG !!!!
WHex:
! cmp AH,0 ; if 0 then
! jz WHexExit ; out of here
! mov AL, BL ; get value from BX
! and AL, &h0F ; mask off low nibble
! dec AH ; sub one from our counter
! ror BX, 1 ; rotate the next nibble in BX
! ror BX, 1 ; four rotates are used so that
! ror BX, 1 ; this will work on an 8088
! ror BX, 1 ; rotate is used to preserve BX
! cmp AL, &H0009 ; if greater than 9 then
! jg WHexAlpha ; jump to alpha character
! add AL, &h30 ; else add offset for numeric
! stosb ; store val in AL at ES:DI, DI=DI-1
! jmp WHex ; do it again Sam ...
WHexAlpha:
! add AL, &h37 ; add offset for alpha character
! stosb ; store val in AL at ES:DI, DI=DI-1
! jmp WHex ; do it again Sam ...
WHexExit:
! retn ; back to whince we came (I hope)
'-----------------------------------------------------------------------------
' more to come, maybe ....
' End of File <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

Visual Basic

SpyWorks-VB from Desaware

SpyWorks-VB is an advanced programming tool for Microsoft's new Visual Basic for Windows version 2.0. It consists of a set of custom controls, dynamic link libraries and applications that not only significantly extend the power of the Visual Basic language, but provide valuable debugging tools as well.


VISUAL BASIC ENHANCEMENTS

On the enhancement side, SpyWorks-VB provides three custom controls. The SBC.VBX, or generic subclass custom control provides you with complete access to the underlying windows message stream for the controls and forms in your application. The messages that you specify will trigger events in the SBC control. Each message can be processed before or after the default Visual Basic processing for that message, or the event can be simply posted so that your program will know that it occurred. The subclass control can even intercept Visual Basic messages to forms, controls, and VB2 graphical controls.

The CBK.VBX, or generic callback custom control handles those situations where you are accessing a Windows API function or third party DLL function that requires a function address as a parameter. Generic callback provides a pool of "callback" function addresses which are mapped into VB events.

The SBCKBD.VBX, or keyboard custom control allows you to detect all keystrokes before they are sent to your application, or to detect all keystrokes for the entire system.

The DWSPYDLL.DLL dynamic link library not only provides the underlying code used by the controls described previously, but also provides a powerful set of functions for accessing hard to get at Windows API functions (such as those for the printer drivers). It also provides access to many of the Visual Basic API functions which normally cannot be accessed directly.


VISUAL BASIC DEBUGGING TOOLS

SpyWorks-VB provides a set of debugging tools that can shave hours off of the development process.

SpyParam.exe uses the Windows 3.1 built in parameter error detection capability to detect and trap errors that occur while accessing API functions - errors that are often hard to find because they are simple ignored by Windows.

SpyMem.exe is a complete memory/resource/module and task browser. Not only does it provide detailed information on various Windows objects, but you can compare the current state of the system to a saved reference - ideal for determining if you have forgotten to free memory or resources before your program terminates.

SpyMsg.exe is a classing "spy" type program with the ability to record any or all events to one or more Windows in your system. SpyMsg.exe adds a couple of new twists however, with its ability to detect not only Windows and Visual Basic messages, but also Visual Basic events. You can obtain a complete list of every event that occurs during the course of your program. Naturally, SpyMsg works with VB2 graphical controls as well.

SpyWin.exe is a system window browser that lets you examine information about any or all windows, forms and controls in your system. This application is provided with complete source code so that you can learn some of the techniques used.

SpyWorks-VB comes with on-line help, various sample programs, and a 30 day money back guarantee (when you order directly from Desaware - your dealer may have other policies). All this for only $129.

SpyWorks-VB is a powerful and flexible tool - but in order to use it effectively you will need to have access to information about the Windows API such as that included in the Widows Software Development Kit, The Windows Programmer's Reference from Microsoft, or the Visual Basic Programmer's Guide to the Windows API from Ziff-Davis press (written by the author of SpyWorks-VB).

SpyWorks-VB requires Windows 3.1 and Visual Basic 2.0. The runtime custom controls may be distributed with your compiled application without royalties. SBC.VBX and CBK.VBX are Windows 3.0 compatible as well at runtime.

Disk subscribers to The BASIC Code Cache can find a demo of SpyWorks-VB in the file SPYWRK.ZIP. You can order SpyWorks-VB by calling Desaware at (408) 377-4770.


Tom Hanlin Checks in with PBClone for VB

Tom Hanlin, shareware author extraordinaire, checks into the Visual Basic arena with his first offering, PBClone Windows. PBC is a collection of 79 routines callable from Visual Basic, or any language that can call DLLs.

PBC provides a number of low level routines that were left out of Visual Basic, or done more efficiently. Included are routines that interrogate the hardware, calculate checksums and crcs, and perform array operations. Also, routines to PEEK and POKE memory are included.

Some of the routines included are:

  • Hardware:
    • Comports Returns the number of com ports installed
    • GetComAddr Returns address of a comport
    • GetPrtAddr Returns address of a printer port
    • GetTick Returns the current system timer tick
    • PeekI and PeekL Peeks that return an integer or long respectively
    • PokeI and PokeL Pokes that set an integer or long respectively

  • Misc:
    • DateSq and DateUnsq Date compression routines
    • TimeSq and TimeUnsq Time compression routines
    • IsAlNum Checks to see if a character is alphanumeric
    • IsControl Checks to see if a character is a control code

  • Matrix:
    • PtrMatD Initializes a double precision array with increasing values
    • SetMatC Initializes a currency array to a set value

If you have yet to try accessing a third party DLL from your Visual Basic programs, this is a good way to learn. If you have the disk version of The BASIC Code Cache, you can find the full version of PBCWIN in the file PBCWIN10.ZIP. If you have the electronic version, you can find this library as well as all of Tom's other libraries on the following BBSes:

219-696-3415 IN ToolKit (Ken Prevo's) PC-Board net: SourceNet
A programmer and power user board.
1 line, 1.2G disk space, HST Dual Standard modem.
Use the name HANLIN SOFTWARE and password SHAREWARE for access.
Voted 23rd Best BBS in the 1991 Best BBS contest.

301-596-7692 MD Programmer's Corner custom BBS also 301-995-6873
All languages-- your one-stop programming shop.
11 lines, 1.5G disk space, v.32 9600 bps modems (some lines are
2400).

201-334-2555 NJ Hacker Central PC-Board net: ILink
Software and hardware support for serious computer folks. ILink,
Intelec.
2 lines, 930M disk space, 2400 public / 9600 private (HST Dual).

718-837-3236 NY The Consultant BBS PC-Board v14.5a
Programming, Consulting, Tech, Medical, Politics, and more. ASP
hub.
2 lines, 850M, USR HST on Node 1 (listed above), USR DS (v32bis)
on Node 2.
Member of Association of Shareware Professionals. "NYC's best
FREE BBS".

Access Basic

Creating Custom Wizards with Access Basic

The following three articles are part of the Microsoft Knowledge Base that can be found on Compuserve. They detail undocumented functions that are necessary to create Access Wizards. For those not familiar with Wizards, they are programs that automate the creation of new forms or reports. You can access the Microsoft Knowledge Base by typing GO MSDS at any ! prompt. This issue also contains a custom wizard from Microsoft that helps in creating menus for an Access application. In future issues of The BASIC Code Cache we will look into creating our own Wizards.

Using Undocumented CreateForm(),CreateReport() Functions [B_WACCESS]
ID: Q93096 CREATED: 23-NOV-1992 MODIFIED: 15-DEC-1992


Summary

This article discusses the Microsoft Access undocumented functions CreateForm() and CreateReport(). If you intend to write your own FormWizard or ReportWizard, you can use these functions to create and customize a blank form or report to which you can add controls.

This article assumes that you are familiar with Access Basic and designing forms and reports.


More Information

CreateForm()/CreateReport() is roughly equivalent to choosing "New... Form/New... Report" from the File menu at the top of the screen. When the function is executed, a new empty form/report appears in an iconized state.

Both functions return an object value that you can use for further manipulation, and neither function requires parameters.

To use these functions, first define a form or report object variable, then assign the variable to the function name. An example of how to do this is:

        Dim MyForm As Form 
Set MyForm = CreateForm()

After opening the form/report in design mode after executing the commands above, you can bind the form to a table or query by modifying the form's/report's RecordSource property:

        MyForm.RecordSource = "Categories"

With the form/report in design mode, you can access and change any of the other design-time properties of the form/report. You can also access and change properties of each of the form's/report's sections via the Section property. The Section property is actually an array with each array value being a reference to a form's/report's section. For forms, the Section property array is broken down as:

        Section(0) - Detail Section 
Section(1) - Form Header
Section(2) - Form Footer
Section(3) - Page Header
Section(4) - Page Footer

For reports, the section property array is broken down as:

        Section(0) - Detail Section 
Section(1) - Report Header
Section(2) - Report Footer
Section(3) - Page Header
Section(4) - Page Footer
Section(5) - Group Level 1 Header
Section(6) - Group Level 1 Footer
Section(7) - Group Level 2 Header
...etc.

With this information, you can customize the design of a form/report section programmatically. The following example creates a new report, hides the page footer by setting its Visible property to false, sets the Height property of the detail section, and enables its KeepTogether property:

        Dim MyReport As Report 
Set MyReport = CreateReport()
MyReport.Section(4).Visible = False
MyReport.Section(0).Height = 1760
MyReport.Section(0).KeepTogether = True

For more information on Microsoft Access libraries, query on the following words in the Microsoft Knowledge Base:

         "libraries AND debugging AND creating"

For more information about other ReportWizard and FormWizard functions, query on the following words in the Microsoft Knowledge Base:

"CreateControl AND CreateReportControl AND CreateForm AND
CreateReport AND 'Section Property' AND DeleteControl AND
DeleteReportControl AND CreateGroupLevel"

Wizards Part II - CreateControl(), CreateReportControl()
ID: Q93095 CREATED: 23-NOV-1992 MODIFIED: 23-NOV-1992

Summary

This article discusses the Microsoft Access undocumented functions CreateControl() and CreateReportControl(). If you intend to write your own Forms and/or Reports Wizard, you can use these functions to create controls on a form or report that is available in Design mode.

For more understanding of Microsoft Access Libraries, search
on the Knowledge Base for the following keywords:

        libraries AND debugging AND creating

For more information about other Wizard functions, query the Knowledge Base for:

     CreateControl AND CreateReportControl AND CreateForm AND CreateReport 
AND 'Section Property' AND DeleteControl AND DeleteReportControl
AND CreateGroupLevel

This article also assumes you are familiar with Access Basic and with designing forms and reports.


More Information

CreateControl() and CreateReportControl() can be used to create new controls for a form/report opened in Design mode. These functions require the name of the form/report represented as a string value, and a numeric code that represents the type of control. The list of control types and their associated numeric codes are shown below:

        Label .......... 100 
Box ............ 101
Line ........... 102
Picture ........ 103
Button ......... 104
Radio Button ... 105
Check Box ...... 106
Ole Object ..... 108
Text Box ....... 109

The CreateControl() and CreateReportControl() functions return a control object value, so you must first define a control variable, then Set the variable to the function name. Note the code example below which creates a form, then adds a button to the form:

        Dim MyForm As Form, MyControl As Control 
Set MyForm = CreateForm()
Set MyControl = CreateControl(MyForm.FormName, 104)

After executing the code example above, you can modify the properties of the new control via the control variable you defined.

For example:

        MyControl.Width = 2000 
MyControl.Caption = "&Sum All Records"

For controls that are frequently associated with fields in a table or query, you can modify the ControlSource property to bind the control. Some controls are created with Height and Width properties set to 0, so that they are - in effect - not visible. In addition, controls appear at the uppermost left-hand corner of the form by default. Because of this, you should make it a habit to adjust the size and position of the control immediately after creating it. The example below shows how to create, size, move, and bind a text box.

        Set MyControl = CreateControl(MyForm.FormName, 109) 
MyControl.Width = 1500
MyControl.Height = 200
MyControl.Top = 440
MyControl.Left = 200
MyControl.ControlSource = "[Category ID]"

In addition to specifying the form name and type of control, you can optionally specify the Section in which the control should be created. Note the syntactical structure of CreateControl(), (which is identical to the syntactical structure of CreateReportControl()):

        Function CreateControl (FormName As String, 
ControlType As Integer
[,SectionNumber As Integer])

Use the SectionNumber parameter to indicate what section the control is to be placed into. The section that is associated with the SectionNumber is the same as the index representing a section in a Section property array.


Wizards Part III - DeleteControl, DeleteReportControl
ID: Q93094 CREATED: 23-NOV-1992 MODIFIED: 23-NOV-1992


Summary

This article discusses the Microsoft Access undocumented commands DeleteControl, DeleteReportControl, and the undocumented function CreateGroupLevel(). If you intend to write your own Forms and/or Reports Wizard, you can use these functions to delete controls on a form or report that is available in Design mode, and create groups on a Report that is available in Design mode.

For more understanding of Microsoft Access Libraries, search on the Knowledge Base for the following keywords:

        libraries AND debugging AND creating

For more information about other Wizard functions, query the Knowledge Base for:

     CreateControl AND CreateReportControl AND CreateForm AND CreateReport 
AND 'Section Property' AND DeleteControl AND DeleteReportControl
AND CreateGroupLevel

More Information

DeleteControl and DeleteReportControl can be used to delete a control that exists on a form/report in design mode. Both of these functions require a string value that represents the name of the form and a string value that represents the name of the control.

DeleteControl and DeleteReportControl are commands - not functions. They do not return a value.

The example below creates a form, then creates a button on the form, displays a message, then deletes the button on the form:

        Dim MyForm As Form, MyControl As Control 
Set MyForm = CreateForm()
Set MyControl = CreateControl(MyForm.FormName, 104)
MsgBox "About to Delete " & MyControl.ControlName
DeleteControl MyForm.FormName, MyControl.ControlName

When you delete a control using DeleteControl or DeleteReportControl, there is no visual feedback that the control is gone if the form/report is not iconized. The control still appears as if it were not deleted even though you could not click it into focus. To make the deleted control disappear in such a case, you would have to repaint the form design window by minimizing and restoring it.

If you have a report available in design mode, you can create groups for it programmatically by using the CreateGroupLevel() function. The syntactical structure of CreateGroupLevel() is shown below:

        Function CreateGroupLevel(ReportName$,Expression$, 
HasHeader$, HasFooter$)

ReportName is a string expression that indicates the name of the Report.

Expression is a string expression that represents the field name or calculated field on which the group will be based.

HasHeader and HasFooter indicate whether the group includes a group header or group footer, respectively.

When CreateGroupLevel() is executed, it adds a group at the innermost level. For example, if one group already exists, CreateGroupLevel() will create a second group within the first group. CreateGroupLevel() returns a number indicating which level it created, beginning with zero. In the example just mentioned, CreateGroupLevel() would return 1 since it is the second group, and the first group was Group 0.

The preceeding articles are Copyright 1992 by Microsoft Corp.

The Bug List

Buglist for Microsoft Visual Basic

Believe it or not, all software has bugs. Some are called features. Whatever they are called, I'd like to inform you of them. In every issue of The BASIC Code Cache, The Bug List will detail some of the bugs and quirks in our commercial development tools. This issue details articles on Visual Basic for Windows and Visual Basic for MSDos bugs that are available in the Microsoft Knowledge Base. These can be found on Compuserve by typing GO MKB at any ! prompt.


Visual Basic for Windows

  • Q94166: GP/UAE When Closing a DDE Application trom the Task List
  • Q94167: GP/UAE with Stop Statement in Event Procedure and Deleted Sub
  • Q94216: GP/UAE After Undoing Edit of an Option Explicit Statement
  • Q94217: GP/UAE When Assign NULL to VBM_GETPROPERTY of Data Type HLSTD
  • Q94242: Using Graphics Method on Database Objects May Cause GP/UAE
  • Q94244: GP/UAE When Large Tag with MultiSelect of 30 or More Controls
  • Q94290: Setting Add Watch May Cause Your Program to Reset
  • Q94292: Setting Add Watch May Cause GP Fault or UAE
  • Q94293: Painting Problems When FontItalic Set to True for Text Box
  • Q94296: Grid Control Painted Incorrectly When PGUP or PGDN Pressed
  • Q94351: GP/UAE When New Project Loaded After Large Previous Project
  • Q94698: No Out of Memory Error Generated with Text Box > 32K
  • Q94773: Attempting to Refresh Null TableDef Field Causes GP Fault
  • Q94774: GP Fault When Using 8514 Driver with Long String in Text Box
  • Q94892: Making .EXE File May Cause GP Fault If Forms Saved as Binary
  • Q94939: Bad .MAK File Prevents Display of Make EXE File Dialog
  • Q95197: Stack Fault When 2-Item Combo Box Has Small Width Set in Move
  • Q95285: Large Sub, Function, or Module Can Cause GP Fault or UAE
  • Q95290: GP/UAE When Create or Use a Huge Array with Large Elements
  • Q95428: Error Message: Timeout While Waiting for DDE Response
  • Q95429: FixedCols Can Cause Paint Problem With Grid Control
  • Q95430: GP/UAE When Multi-Select Controls w/ No Properties in Common
  • Q95431: Type Mismatch Error When Use VAL Function on Large Hex Value
  • Q95498: Problems Calling DoEvents from a Scroll Bar Change Event
  • Q95499: Stack Fault May Occur If Trapping Divide By Zero
  • Q95500: GP Fault When Close Form That Contains a Single MCI Control
  • Q95501: MAPI: GP Fault When Attempt to Download 923 or More Messages
  • Q95508: Extra Characters in Masked Edit Cause Empty InvalidText Box
  • Q95509: Text Box/Masked Edit in Select Mode if MsgBox in LostFocus
  • Q95513: Negative ScaleHeight Resizes Control When Form Saved as ASCII
  • Q95514: Focus Rectangle Remains When Grid Loses Focus
  • Q95525: GP Fault When Erase User-Defined Array of Variable Strings
  • Q95590: Loading Project Gives Error: Custom control 'Graph' not found
  • Q95829: GP Fault When Making EXE If Declare Is Missing Lib & DLL Name
  • Q95830: Stack Fault When Move Method Makes Combo Box Width Too Small
  • Q96097: Resizing MDIForm with UI Does Not Update Height and Width

Visual Basic for DOS

  • Q96942: ""No currently active form"" with ISAM Statement In Quick
  • Q80412: ""Internal Error"" for SWAP of TYPE Elements in SUB Using VAL
  • Q90396: ERDEV$ Returns Incorrect Value Under MS-DOS 5.0
  • Q90905: Click Still Occurs when Using SetFocus to Prevent Focus Change
  • Q90961: SETUP.EXE on Bernoulli Hard Disk Is Not Supported
  • Q92953: Stand-Alone Program Using Overlays and ISAM Hangs on Open
  • Q93670: Using Run on Program That Has Overlays Causes Incorrect Error
  • Q93674: Run in Procedure That Dimensions Array Hangs VB Environment
  • Q94007: Basic Serial Communications Programs May Hang With No Error
  • Q94160: Text Box Does Not Highlight Text When Word Double-Clicked
  • Q94260: Pmt# Causes Illegal Function Call Error If No Math Coprocessor
  • Q94261: Code Remains in VBDOS.EXE After Change in FD.EXE
  • Q94262: Computer Hangs When Click Form Without Focus Then CTRL+BREAK
  • Q94289: Mouse Cursor Disappears When Using the CodeView Debugger
  • Q94663: Blank Screen In Monochrome Mode
  • Q94664: Chaining with Modal Form or Msg Box in Menu May Hang Computer
  • Q94692: Assignment in Immediate Window Causes Syntax Check In Editor
  • Q94693: ALTSETUP.BAT Does Not Create NEW-VARS.BAT
  • Q94694: C7 Module, Overlay, and Run-time Module Makes Computer Hang
  • Q94695: Error: Executable code not allowed in module level of a form
  • Q94730: Corrections for Errors in the Visual Basic for MS-DOS Manuals
  • Q94777: Arrow Keys Don't Activate Control Box in Form Containing Menus
  • Q94779: Disk not ready Error Saving File After Change to Invalid Drive
  • Q94780: ISAMCVT Problems Converting BTRIEVE Files
  • Q94781: Static Common Array Greater than 65510K May Hang the Computer
  • Q94782: Clipboard Not Cleared After Restart in Interpreter Environment
  • Q94786: File Not Found When Directory Name Contains Period
  • Q94787: Unable to Move or Size Form After Executing Width Statement
  • Q94788: Changing Visible or Enabled Property Can Cause Extra Change
  • Q94789: Height/Width Properties of Attached Scroll Bars May Be Wrong
  • Q94790: Errors When Use CHAIN: Illegal function call or Bad file mode
  • Q94791: Selecting a Menu Suspends All User Events
  • Q94792: Making the ENTER Key Act Like a TAB Key in Visual Basic
  • Q94793: Minimum Width of Text Box is 4 Characters Even Without Border
  • Q94823: PACKING.TXT for VB for MS-DOS Version 1.0 Professional Edition
  • Q94824: COMPAT.TXT for Visual Basic for MS-DOS 1.0
  • Q94831: Undocumented Error: Too many local strings in Sub/Function
  • Q94832: Value Property May Change When You Click the Scroll Bar Thumb
  • Q94833: Array Errors When Call Function in Other Module w/ No Declare
  • Q94834: Scrolling List Box Causes Click Event and Change in Selection
  • Q94835: No Resize Event When Maximize MDI Child
  • Q94836: Cannot Distinguish CTRL+DEL and CTRL+BACKSPACE In Key Events
  • Q94868: Linking with CMNDLG.LIB or SPIN.LIB Can Cause Library Error
  • Q94897: PACKING.TXT for VB for MS-DOS Version 1.0 Standard Edition
  • Q94937: Computer Hangs When Load Then Unload Form in Form_Load Event
  • Q94938: Overflow Error When Use ISAMREPR.EXE to Repair ISAM Database
  • Q95180: Getting Started with CodeView in Visual Basic for MS-DOS
  • Q95181: Create Link Overlays Using Parentheses or a .DEF File
  • Q95291: Obtaining the Module Name and Address of an Error
  • Q95363: Viewing Basic Variable-Length String Variables in CodeView
  • Q95432: Cannot Profile Program Compiled in Programming Environment
  • Q95433: /ES Option Is Not Valid in the Standard Edition
  • Q95438: OS/2 Version 2.0 System Error SYS3175 from LINK.EXE
  • Q95461: Memory Loss with Repeated Display of MsgBox or Modal Form
  • Q95481: On Gosub or On Goto Causes Error: Variable not declared
  • Q95863: Wrong Number of Dimensions in Common or Dim Statement
  • Q95942: HelpSetOptions Sets Visible Property to False on Wrong Button
  • Q96068: Use && to Display Ampersand Character in MsgBox Text
  • Q96099: How to Drop Down a Menu on the Startup Form of an Application
  • Q36576: CTRL+Z Embedded in Source Truncates BC.EXE Compilation
  • Q40547: BC.EXE Will Not Compile Files Named USER.*

loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT