Etc.

We Pause For This Special Report

Do you ever wish you could pause a report every time it fills up a
screen?  How do you do this without modifying the .frg file or putting
the REPORT FORM command in a loop?

Try this:

m_pwait              = _pwait
pwait           = .T.
m_plength               = _plength
_plength                = 22
          
SET PRINTER TO NUL    &&<- The NUL device is new in 1.1
          
REPORT FORM myreport TO PRINT
          
SET PRINTER TO
_pwait          = m_pwait
_plength                = m_plength

The _pwait setting pauses printing for cut-sheet feeders. The _plength
setting is set to whatever the desired screen length should be.  The
report is then printed to the NUL device with all print settings
respected (including the pause for a new sheet of paper; which is
never needed).        

Note that the _pwait setting is not respected when printing to the
screen or to a file.

Your Number Is Up

For those who have dBASE IV version 1.1 by way of a product update
from 1.0, you may have a question on what serial number to use at the
Installation sign-on screen.  The number you would use is the same as
the serial number used in your version 1.0.  The entire serial number,
including the hyphen and the two numbers following the hyphen must be
entered.  Your dBASE IV 1.0 serial number can be located on the System
Disk #1 or Installation disk or on the bottom of the 1.0 product box. 
Updates are sent out with the words "ON FILE" printed on the Install
or System disk.  Check the Getting Started manual for complete
instructions on installing your 1.1 update.

Regenerating Design Files

If you are experiencing problems with your dBASE IV 1.0-generated
reports, forms, labels, queries and Application Generator programs,
try regenerating these design files in version 1.1.  In addition to
avoiding some compatibility issues, the newly generated programs will
run more efficiently since they will take advantage of the new
features in version 1.1.

Overcoming PROMPT FIELDS Restriction

Wouldn't your life be complete if you could figure out an easy way to
have a multiple field POPUP...one where you could specify several
fields by incorporating a PROMPT FIELDS a,b,c instead of being limited
to one?  Well, listed on the following page is a procedure that not
only allows multiple fields in the POPUP, but also allows multiple
fields from several related databases.  The way this works is by
defining bars which consist of the data where each bar is defined in
the SCAN/ENDSCAN loop.  

PROCEDURE PopBar
                PARAMETER FieldVal
                DEFINE POPUP Popfields FROM 1, 1
                ON SELECTION POPUP Popfields DEACT POPUP
                BarX = 1
                SCAN FOR Client = FieldVal              && i.e. Client
"000001"
                        DEFINE BAR BarX OF Popfields PROMPT TRIM(Fname)+"
"+TRIM(Lname)
                        *This is where you put in your list of FIELDS
                        BarX = BarX + 1                         && Increment
the BAR Number
                ENDSCAN
                ACTIVATE POPUP Popfields
RETURN
* EoP: PopBar

To get fancy, you could define header information in the bar before
the SCAN/ENDSCAN loop, detail information in the loop, and footer
information after, all within one POPUP.   For example:  

DEFINE BAR 1 of Popfields PROMPT Fieldval + " " + B->Fname + " " + ;
B->Lname + C->AcctBal
DEFINE BAR 2 of Popfields PROMPT REPLICATE("=",50)
BarX = 3                                        && Set the starting BAR at the
proper position.
SCAN ...                                        && The elipsis implies
elaborated code.
                DEFINE BAR BarX OF Popfields PROMPT ;
                        DTOC(E->PastDueDt) + STR(D->PastDueAmt)
                ...
ENDSCAN
DEFINE BAR BarX of ... PROMPT REPLICATE("=",50)
DEFINE BAR BarX + 1 of ... PROMPT "First Line of 'Footer' in POPUP"
DEFINE BAR BarX + 2 of ... PROMPT "Second ...
...
Hard Drive Utilities

Hard disks come in a great variety of configurations.  How they are
configured internally is directly reflected in the amount of capacity
the drive has. 

A hard disk is divided into heads, cylinders (also referred to as
tracks), and sectors. Think of each head referring to a side of an
album and imagine you had a record player that could play either side
of the record and it could do this for more than one album at a time. 
Cylinders are subdivisions of each platter. Think of them as the
dividers between songs on an album, but imagine all the songs on both
sides of all the records are exactly the same size, so there is the
same number of songs on every album.  Sectors divide the "albums"
like  pie slices.  The first hard disks only had one platter and one
head with a relatively low density.  As they improved, more platters
were added and they put heads on both sides of the platter and
increased the density.  

Then there is the BIOS.  In a PC's BIOS there is a list of hard disk
configurations that can be chosen from to install a hard drive.  In
some cases, the BIOS has a very limited set of configurations to
choose from and as new hard disk technology is developed even a BIOS
with a large selection to choose from will become outdated.  What
about a hard disk whose configuration does not appear in the BIOS
drive type table?  How do you add those drives to their systems? 
That's where the programs SpeedStor and OnTrack come into play which
are often bundled with the hardware. 

Finally there's DOS. When DOS originally came out, you could only have
one partition. It made sense since there weren't any hard disks that
exceeded 32 MB in total capacity.  Then they added multiple
partitioning capabilities.  With multiple partitions you end up with
one physical hard disk being broken up into multiple logical drives,
in other words, one hard drive could have more than one drive letter,
like C: D: E:  and so on. 

DOS 3.30 still limited you to a maximum size of 32 MB partition. 
That's fine if you have a 40 or 60 meg drive because you only end up
with 2 or 3 drive letters.  But if you have a 350 MB hard disk, you'd
end up needing an alphabet with more than 26 letters.  This is before
considering a network or a file that is larger than 32 MB? 

Compaq came out with a DOS 3.31 that addressed this problem by
allowing you to create a partition that used as much physical drive
capacity as was available. It did this by altering the sector size.
This resulted in a lot of compatability problems.   Below are the
descriptions of three common hard drive utilities, none of which
should have to be disabled to run dBASE IV version 1.1.  At least one
of these drivers has posed a conflict with Dbcache.  Disabling these
drivers is not recommended.  If you are having trouble installing on a
logical drive, try installing on drive C which usually will be found
to have the most conventional setup.  You could then copy the
information from drive C to the desired drive and erase the
installation on drive C. 

Hardrive.sys or SStor.sysStorage Dimension's Speedstor program comes
bundled with Maxtor/Storage Dimension's hard drives, but is used a lot
with other drives.  Although it tends to be very reliable, we've heard
unconfirmed reports about conflicts with one of our products, Control
Room.  This program/driver combination is used to allow a PC to use
drive types not supported in the BIOS.  Also, it allows you to have
partitions that exceed the DOS 3.x 32 MB partition limitations by
increasing the sector size to more than the standard 512 bytes.  

DMDrivr.binSeagate's OnTrack/DiskManager program does the same thing
as the above program, but it is not as generic as Speedstor.  It is
primarily for configuring Seagate drives, whereas SpeedStor has a
massive list of drives it can help you configure. 

FixT_drv.sysGolden Bow's VFeature Deluxe program; a combination of a
driver and a customized COMMAND.COM.  Don't disable this driver if you
have trouble installing dBASE IV.  We've seen hard disk data be
inexplicably corrupted and the exact cause has not yet been
determined. 

One additional note regarding this particular utility: after
installing, you will have only 478,736 bytes free if you load only the
driver and have FILES equal to 40, and BUFFERS equal to 15.  Although
that's enough to load dBASE IV 1.1, it is less than ideal for any
memory intensive application run in dBASE IV.  We also have reports
that DBCACHE hangs with this driver loaded on a PS/2 model 80
containing 2 MB RAM. 

Using the KEYBOARD Command

If your program uses an interrupt routine such as ON KEY LABEL or UDF
which performs a REPLACE on the currently selected database, special
consideration must be given if this interrupt routine branches from
EDIT or or an @GET.VALID.REQUIRED UDF().  If no change is actually
typed into the record, the REPLACE command desired during the
interrupt routine will not get saved to the disk buffer. 

How do you make sure that the REPLACE command is saved?  The solution
is in making sure the record is changed, easily accomplished with the
new KEYBOARD command.  The workaround is to do a Ctrl-U twice (in
other words, Delete, Un-Delete) 

KEYBOARD CHR(21)+CHR(21) 

so that the internal flag that indicates a record change is set for
the record.  This will not work with BROWSE.  Another combination that
will work is

KEYBOARD CHR(24)+CHR(5) 

because pressing the down arrow key then up arrow key will flip the
change flag.  

For example, a common question is how to date stamp a record while
browsing the database. Simply having a statement such as

ON KEY LABEL F5 REPLACE B_DATE with DATE() 

will not work.  Instead, call a procedure  with your ON KEY LABEL
command like the one listed here that uses the KEYBOARD command to
stuff the information into the screen buffer.

.USE <database>
.ON KEY LABEL F5 DO Rep_Proc
.BROWSE 
PROCEDURE Rep_Proc
                IF VARREAD() = "B_DATE"                 && Cursor is on b-day
field
                        KEYBOARD CHR(1) + LEFT(DTOC(DATE()),2) + ;
                        SUBSTR(DTOC(DATE()),4,2) +
RIGHT(DTOC(DATE()),2)         
                ELSE                                                    
&& cursor is elsewhere in record
                        REPLACE B_DATE WITH DATE()
                        KEYBOARD CHR(24)+CHR(5)
                ENDIF
RETURN

There are, of course, other applications for this technique but 
remember, you need to know whether the REPLACE is called by an  EDIT
or a BROWSE since they need two different key sequences. 
