Dec 222017
 
Access extended/expanded memory from QuickBasic without first having to check which type is available.
File QBXM10.ZIP from The Programmer’s Corner in
Category BASIC Language
Access extended/expanded memory from QuickBasic without first having to check which type is available.
File Name File Size Zip Size Zip Type
QBXM.BI 1335 332 deflated
QBXM.DOC 98432 23078 deflated
QBXM.LIB 15975 6562 deflated
QBXMAPND.DOC 24704 7545 deflated
TPCREAD.ME 199 165 deflated
XMDEMO1.BAS 11577 3525 deflated
XMDEMO2.BAS 4559 1446 deflated
XMDEMO3.BAS 1207 446 deflated

Download File QBXM10.ZIP Here

Contents of the QBXM.DOC file



QBXM ver 1.0
Copyright 1991, Thomas J. Vought



Overview

QBXM is a library of routines that allow you to transparently
access either expanded (LIM 4.0 EMS) or extended memory (XMS 2.0)
directly from your BASIC program.

The type of memory installed in the computer your application is
running on makes no difference, the same calls are used to manip-
ulate either expanded or extended memory. QBXM adjusts for the
type of memory installed.

QBXM will preserve the extra memory across programs so you can
load frequently used data once and access it later through QBXM
from other programs that you "RUN" or "CHAIN". The only require-
ment is that either a LIM 4.0 EMS expanded memory driver, or an
XMS 2.0 extended memory driver (ie: HIMEM.SYS) be installed
before the QBXM routines are called.

Throughout this manual, I will try to avoid using the terms
expanded and extended, since the type is unimportant, and simply
refer to the EMS/XMS memory as eXtra Memory. (hence the name,
QBXM.)


Files Supplied:

The QBXM10.ZIP file should contain:

QBXM.LIB The object file library.
QBXM.DOC This file, the manual.
QBXMAPND.DOC An appendix to the manual which highlights
some differences between LIM and XMS,
and how they're resolved with QBXM.
QBXM.BI Basic include file with declare statements.
XMDEMO1.BAS Demo programs showing most of the features
XMDEMO2.BAS of QBXM with emphasis on preserving extra
XMDEMO3.BAS memory across programs.


















1


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

Getting Started:

The QBXM routines are distributed with just the OBJ file library,
QBXM. Due to the number of different QuickLibrary support li-
braries that are in circulation, it makes a smaller archive file
to leave the QuickLibraries up to you to build. So charging
right ahead, determine which QuickLib support file you have.
Some examples are:

BQLB40.LIB for QuickBasic 4.0
BQLB41.LIB for QuickBasic 4.0b / BASIC 6.0
BQLB45.LIB for QuickBasic 4.5

Note that this shareware release of QBXM does not support BASIC
PDS 7.0+'s far strings. That precludes using them in a QBX
QuickLib, though the .LIB file can be linked in with EXE's gener-
ated with the default near strings of the BC compiler. Regis-
tered users will receive a 7.0 far string compatible library.

From the command line, issue the following command, substituting
the proper support library from above for "supportLIB":


>LINK /Q QBXM.LIB,QBXM.QLB,null,supportLIB;


To add the QBXM.LIB file to other LIB files you have, use the
LIB.EXE program:


>LIB yourLib.LIB +QBXM.LIB;


Which adds the QBXM routines to the LIB file named "yourLib.lib".
After which you can create a new QuickLibrary just like above:


>LINK /Q yourLib.LIB,yourLib.QLB,nul,supportLIB;


















2


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

Design Logic


Expanded memory accessed through an Expanded Memory Manager (LIM
EMS 4.0) and extended memory accessed through an Extended Memory
Manager (XMS spec 2.0) are obviously two completely different
animals. What I've tried to do with QBXM is to tame the two
beasts and use features of each in a consistent way. This causes
features of one specification to be added to the other, and
limits of one to be imposed on the other. If you are familiar
with both the expanded memory specification and the extended
memory specification, you may recognize where adjustments were
made to each. If you're interested, I've included an appendix
that outlines the differences in the specifications and how I
adjusted QBXM to end up with a unified interface.

What was most important to me in writing these routines was to be
able to ignore the coding hassles of two different specifica-
tions. All you should have to do is write one line of code to
access the extra memory, whether it is expanded or extended. One
alternative is to write the program for one type of extra memory,
and not allow your program to run on machines without that spe-
cific type of memory.

Another alternative is to write your program in such a way that
decisions are made in the code depending on what type of memory
is installed at run time. For example:

IF ems THEN
CALL allocateEMS...
ELSEIF xms THEN
CALL allocateXMS...
ELSE
...whatever..
END IF

This would require using two separate sets of library routines
whose code would be linked in to access both types of extra
memory. Only one set of routines would be called, depending on
the run time conditions. Why link in twice as much code as
needed with the resulting waste of space? QBXM eliminates this
overhead by having one set of routines for either type of memory.

The QBXM routines are written entirely in assembly language to
ensure the highest possible execution speed. In addition, the
library consists of 12 separate object modules. Each module is
geared toward a different area of extra memory use. Only the
code actually needed will be linked into your program, resulting
in the smallest possible .EXE file.








3


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

Terms & One Rule

Some terms I use throughout this documentation should be ex-
plained. One I already mentioned is that I refer to either EMS
or XMS memory as "Extra Memory." Since the routines in QBXM
handle both transparently, there is no need to differentiate
between the two. Another term is "Pages", borrowed from the EMS
paged memory technique. In QBXM, a page is 16,384 (16K) bytes of
memory, and is the smallest amount that can be allocated by the
routines. Records are the same as you're used to in dealing with
random access files or user defined TYPE'd structures, with one
major difference:

All records must be an EVEN length.

This is a limitation imposed by the XMS which does not allow byte
memory moves, only word (2 byte) moves. For more on accessing
odd length records, see the appendix file.


Calling Sequence

The GetXM routine must be called before any of the other extra
memory routines. It checks for expanded memory first, and if not
found, checks for XMS. Since EMS access is quicker in most cases
than XMS, if both are installed, only EMS will be used. An EMS
driver or an XMS driver (such as HIMEM.SYS) must be loaded.
There are other ways to access extended memory, but they are not
standardized, thus I felt it was the better course not to use any
extended memory except through the XMS driver.

GetXM sets internal flags within the QBXM routines, and clears
other QBXM variables, so it should only be called once in an
application. If you are CHAIN'ing or RUN'ing to another program
and you want to preserve the data that is in extra memory, GetXM
should NOT be called by the CHAIN'd to program, just the initial
program. Most of the routines will fail with a -1 error code (No
extra memory) if GetXM wasn't called previously.

The GetXM routine will return the type of extra memory installed,
and the major and minor version of the driver in use. One trio
of routines, PutNameXM, GetNameXM and ClearNamesXM require ver-
sion 4.0 of the EMS driver, if EMS is in use. If your program
will use the PutNameXM, GetNameXM or ClearNamesXM routines, and
EMS is in use, then you have to check that the major version of
the EMS driver is 4 or greater. If you use the PutNameXM rou-
tine, and do not use one of the 'automatic' extra memory clean up
routines, then ClearNamesXM must be called at the end of your
program.







4


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

After the extra memory routines are initialized by GetXM, any of
the other routines can be called in any order. Any extra memory
that your programs allocate, though, must be released when your
program is finished running. Both the EMS and XMS specifications
rely on well behaved programs. If you don't release the extra
memory you allocate, it will not be available for later programs
to use, until the machine is rebooted.

QBXM supplies three methods for making sure that memory allocated
by your program(s) is released. The first requires you to take
on the burden, by closing each memory handle you open individual-
ly. For each open/allocate call, there is a close/release call:

Open/Allocate: Close/Release:
-------------- --------------
OpenXM CloseXM
OpenScreenXM CloseScreenXM
OpenRecXM CloseXM
PutNameXM ClearNamesXM
LoadFileXM CloseXM
LoadScrFileXM CloseScreenXM

A second method is to make one call at the point where your
program terminates, whether in an error routine or normally:

CloseAllXM

Both of the previous methods allow you to select the point at
which extra memory is released. Both will also allow you to
CHAIN or RUN another program and leave the extra memory intact by
not releasing the extra memory.

The last method is to call AutoCloseXM anywhere in your program.
When called, AutoCloseXM forces BASIC and QuickBASIC to call
CloseAllXM when your program ends, whether via an error or normal
termination. This is the simplest method for programs that do
not RUN or CHAIN another program that will need the data in extra
memory. When BASIC encounters a CHAIN or RUN statement, and
AutoCloseXM has been called, CloseAllXM will be invoked. This
means that the extra memory data that you may want to pass to a
subsequent program will be lost.

When you are working in the QuickBASIC environment, AutoCloseXM
should be used while you are debugging your program. This will
ensure that if you select "Continue" at a "You must restart your
program after this change" prompt, extra memory will be released.
Same case if you restart your program from someplace after extra
memory has been allocated, having invoked AutoCloseXM earlier
will make sure that the extra memory is released.







5


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

Sharing Extra Memory Between Programs

The key to sharing extra memory among a series of programs is to
make sure that the current state of extra memory and QBXM are
passed to and from each program. Remember that extra memory will
not change, but when a program starts up, there is no information
about what extra memory holds. When QBXM is initialized by a
call to GetXM, flags and variables within QBXM are set to default
values. Each time you manipulate extra memory, these variables
are adjusted.

The QBXM status variables require a total of 530 bytes. They can
be passed to your program via a call to SaveParamXM. Once you
have these parameters in a BASIC variable, you can pass it to
another program that you CHAIN to. The BASIC variable must be
declared as a "COMMON SHARED" variable in both programs.
XMDEMO1.BAS and XMDEMO2.BAS show how this is done. CHAIN re-
quires the BASIC run time module to work correctly. If you
prefer to "RUN" a second program, and compile with the /O switch,
then pass the status variable via a disk file. The receiving
program must call RestParamXM and pass the routine the status
variable. Once the internal QBXM variables are restored, the
extra memory blocks and data are available as they were in the
previous program.

An example of how to share extra memory between a series of
programs may be in order at this point.

Assume you have an order entry, inventory and invoicing system,
and that each of the major areas are processed by individual
programs invoked from MENU.BAS, the start-up program:

MENU.BAS:
Needs no data in particular, but does load a file of
help screens for the system, if they haven't been
loaded already. So print your sign on copyright
message and a "just a moment" line.

Test the COMMON SHARED variable that holds the extra
memory status. If it is all zeros, then MENU.EXE is
being run for the first time. In that case call GetXM
to initialize extra memory and load the help screens.
If the variable is not all zeros, then MENU is being
CHAINed to by one of the other programs:

DEFINT A-Z
COMMON SHARED xmBuf AS STRING * 530

IF xmBuf = STRING$(530, 0) THEN
CALL GetXM(major, minor, memType)
CALL LoadScrFileXM("HELPSCRN.DAT", hScreens, errCode)
ELSE
CALL RestParamXM(VARSEG(xmBuf), VARPTR(xmBuf), errCode)
END IF


6


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

After the menu program checks extra memory, loads help
screens if needed etc. it then present a menu for the
user to select an operation from:

User selects order entry:

MENU.BAS calls SaveParamXM and passes the buffer to
the order entry program via the COMMON SHARED variable
and by CHAIN'ing to the order entry program:

CALL SaveParamXM(VARSEG(xmBuf), VARPTR(xmBuf), errCode)
CHAIN "ORDERS"

Order entry needs to access both "customers" and
"inventory" data.

Calls GetNameXM to see if "customers" is in memory.
If not, checks available extra memory and loads
the customer data base into extra memory and uses
PutNameXM to name the memory handle "customers".

DEFINT A-Z
COMMON SHARED xmBuf AS STRING * 530

CALL GetNameXM ("CUSTOMERS", cMemHandle, errCode)

IF cMemHandle = 0 THEN
f$ = drive$ + ":\" + path$ + "CUSTOMER.DAT"
cLen = LEN (customerRec)
CALL LoadFileXM (f$, cLen, cMemHandle, cRecs&, errCode)
IF errCode THEN GOSUB xmErrorTrap
END IF

Calls GetNameXM to see if "inventory" is in memory.
If not, it calls LoadFileXM to load the data
and uses PutNameXM to name the memory handle
"inventory".

CALL GetNameXM ("INVENTORY", iMemHandle, errCode)

IF iMemHandle = 0 THEN
f$ = drive$ + ":\" + path$ + "INVENTORY.DAT"
iLen = LEN (inventoryRec)
CALL LoadFileXM (f$, iLen, iMemHandle, iRecs&, errCode)
IF errCode THEN GOSUB xmErrorTrap
END IF

.... program does it's thing ....

If an error, like not enough memory to load a file:
Use GetNameXM to see if "invoices" is hogging memory.
If it is, call CloseXM with the handle that GetNameXM
returns to free some up. Then load the file that order
entry needs, either Customers or Inventory.


7


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


When finished with order entry, before CHAIN'ing back
to the main menu program, call SaveParamXM to pass the
current extra memory status back to the main menu
program.

CALL SaveParamXM(VARSEG(xmBuf), VARPTR(xmBuf), errCode)
CHAIN "MENU"

The MENU program will test xmBuf and find that it's not
a string of zeros, meaning there is extra memory in use.
This time, MENU will just restore the extra memory status:


User selects inventory:

MENU.BAS calls SaveParamXM and passes the buffer to
the inventory program via a COMMON SHARED variable
and by CHAIN'ing to the inventory program.

Inventory needs to access only "inventory" data.
Calls GetNameXM to see if "inventory" is in memory.

If it's not, it calls LoadFileXM to load the data
and uses PutNameXM to name the memory handle.

If an error, like not enough memory to load a file:
Use GetNameXM to see if another program is using
memory, and if it is, call CloseXM with the handle
that GetNameXM returned to free some up. Load the
the data that the inventory program needs, and
name it with PutNameXM as "inventory".

When the inventory program is finished, it calls
SaveParamXM to save the current conditions of extra
memory, and passes the buffer back to the Menu program
with a common shared variable and a CHAIN.

User selects invoices:

MENU.BAS calls SaveParamXM and passes the buffer to
the invoicing program via a COMMON SHARED variable
and by CHAIN'ing to the order entry program.

The invoice program needs to access both "customers"
"inventory" and "invoice" data.

Calls GetNameXM to see if "customers" is in memory.
Calls GetNameXM to see if "invoices" is in memory.
Calls GetNameXM to see if "inventory" is in memory.

If one or more isn't in extra memory, it calls
LoadFileXM to load the data it needs, and uses
PutNameXM to name each memory handle.


8


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

If there's an error, like not enough memory to load a
complete file:

Decide the best course of action.... In this
situation, leaving the invoice file data on disk
is probably best. Customer data and inventory
data needs to be accessed more often then the
invoice file.


Once the invoice program is done, it calls SaveParamXM
to save the current state of extra memory to a common
shared buffer variable and CHAIN's back to the main
menu program.

User selects EXIT from MENU.BAS:

Call CloseAllXm and exit MENU.BAS to system.

Now the above is pretty simplistic, but nowhere in the system is
there a close/release call, except when the user exits from the
main menu. This allows all the individual programs to access
data loaded by other programs, only loading what's needed one
time, or if there's a memory squeeze, dumping data that the
current program doesn't need. Of course each program needs an
error trap. If an error is trapped, and it is an unrecoverable
error, files should be written from extra memory and CloseAllXM
invoked to clean up memory.




























9


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

The programs described previously all use the CHAIN command so
that a buffer with the extra memory information can be passed
from one application to the next. CHAIN requires the use of the
BASIC run time module. If you prefer to compile stand-alone
applications (with the /O option), another means of passing the
extra memory status information has to be used. The only method
I can think of is to write a file to disk when exiting the pro-
gram, and read it upon start up of the next program in sequence.
For example, PROG_A.BAS takes the following action upon comple-
tion:

CALL SaveParamXM (VARSEG(xmBuf), VARPTR(xmBuf), errCode)

handle = FREEFILE
OPEN "XM_STATUS.DAT" FOR BINARY AS handle
PUT handle, 1, xmBuf
CLOSE handle
RUN "PROG_B"

Where xmBuf is DIM'ed as STRING * 530.

Then PROG_B.BAS would take the following actions upon start-up:

DIM xmBuf AS STRING * 530

handle = FREEFILE
OPEN "XM_STATUS.DAT" FOR BINARY AS handle
GET handle, 1, xmBuf
CLOSE handle
KILL "XM_STATUS.DAT"

CALL RestParamXM (VARSEG(xmBuf), VARPTR(xmBuf), errCode)


Routine Types

The routines in QBXM can be broken down into four categories,
Status/Informational, Bulk Memory Moves, Full Screen Handling and
Record Orientated.

Each procedure is described in detail on the following pages.















10


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: AutoCloseXM

SYNTAX: CALL AutoCloseXM

PASS: Nothing

RETURNS: Nothing


AutoCloseXM registers the CloseAllXM routine with BASIC. When
the current application ends, all extra memory that has been
allocated is released. The memory released will be the memory
allocated by the current program and any that was allocated in
previous programs, if the extra memory status has been passed
from previous programs to the current one properly.

CloseAllXM will be invoked by a CHAIN, RUN, END or STOP (not in
QB) statement if AutoCloseXM has been previously invoked.

I have found it best to use AutoCloseXM at the start of a program
when working in the QuickBASIC environment. While developing an
application, you're more likely to stop and restart, or to make
changes to the code requiring a restart. I have found it very
easy to use up 3 megs of EMS by not remembering to close extra
memory handles that were opened by my program that didn't run to
normal termination. If you don't have TurboPower Software's
MAPMEM program, look for it. A real help during development.
MAPMEM version 2.9 shows XMS memory also.


















EXAMPLE:
CALL AutoCloseXM


SEE ALSO: CloseAllXM, CloseScreenXM, CloseXM




11


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: ClearNamesXM

SYNTAX: CALL ClearNamesXM

PASS: Nothing

RETURNS: Nothing


When called, ClearNamesXM wipes out any names assigned to extra
memory handles that were allocated by the current (or previous)
program(s). It is included to help maintain the integrity of
extra memory when your program terminates.

When memory handles are assigned a name under an XMS environment,
the first call to PutNameXM allocates a 2k block of extended
memory for use by QBXM to handle the housekeeping involved. As
handles are named, searched for and subsequently closed, this 2k
block of memory is accessed and updated. There is no way to
directly access this memory block from BASIC, but it does have
to be released when your program terminates, otherwise the 2k
would not be available to later applications.

When the CloseAllXM routine is called, it in turn evokes this
routine to make sure that the 2k XMS buffer is released. Auto-
CloseXM ensures that CloseAllXM is called when the program termi-
nates, so most bases are covered. Care has to be taken to ensure
that the 2k block is released when memory handles are closed
individually, and your program has used the PutNameXM routine.

If you do not use CloseAllXM or AutoCloseXM, and you use the
PutNameXM routine, then ClearNamesXM should be called at the end
of your program. There is no way for QBXM to 'know' to close out
the named handle buffer unless you instruct it to do so.
















SEE ALSO: AutoCloseXM, CloseAllXM, PutNameXM




12


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: CloseAllXM

SYNTAX: CALL CloseAllXM

PASS: Nothing

RETURNS: Nothing


CloseAllXM releases all extra memory, including any screen memory
or named handle memory that was allocated by your program(s)
through QBXM. This routine is invoked when your application
terminates, if AutoCloseXM was called previously.

If you do not use AutoCloseXM, for instance when CHAINing or
RUNning other programs that will access the same handles in extra
memory, then this procedure must be called when the program ends
either because of an error or a normal termination.

Remember that both the expanded and extended memory specifica-
tions rely on applications deallocating memory when they are
finished with the resources. If you don't deallocate the memory,
it will not be available again until you reboot.




















EXAMPLE:

CALL CloseAllXM
END



SEE ALSO: AutoCloseXM, CloseScreenXM, CloseXM




13


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: CloseScreenXM

SYNTAX: CALL CloseScreenXM

PASS: Nothing

RETURNS: Nothing


CloseScreenXM closes a previously opened extra memory buffer used
for screen display and swapping. No parameters need to be passed
because QBXM tracks the memory handle assigned to a screen inter-
nally.

Extra memory allocated for screen storage is released by the
CloseAllXM or AutoCloseXM routines also.




























EXAMPLE:
CALL CloseScreenXM




SEE ALSO: OpenScreenXM




14


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: CloseXM

SYNTAX: CALL CloseXM (handle%, errCode%)

PASS: handle% the extra memory handle that was returned by
one of the extra memory open routines.

RETURNS: errCode% equal to zero if no problems are encountered.


CloseXM releases any memory that was allocated to the specified
handle, without affecting the status of any other extra memory
handles.

The method used to open the extra memory handle is not important.
Handles are returned for record orientated and bulk memory allo-
cations only.





















EXAMPLE:
pgs = 3
invLen = LEN (invoiceRecord)
CALL OpenRecXM (pgs, invLen, invHandle, errCode)
...
...
...
CALL CloseXM (invHandle, errCode)




SEE ALSO: AutoCloseXM, CloseAllXM, CloseScreenXM




15


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: Conv2XM

SYNTAX:

CALL Conv2XM (fSeg%, fOfs%, hndle%, bytes%, xmOfs&, errCode%)

PASS:
fSeg% The segment address of the memory block you want
to move to extra memory. VARSEG(variable)

fOfs% The offset address of the memory block you want
to move to extra memory. VARPTR(variable)

hndle% The extra memory handle that was returned by a
previous OpenXM call.

bytes% The EVEN number of bytes to transfer, must be
less than or equal to 64k.

xmOfs& A long integer specifying where in extra memory
the data is to be placed. First byte = 0.

RETURNS:
errCode% If there is a problem.


Right off I'm going to tell you to avoid passing variable length
strings. The address calculations, SADD, SSEG and all will make
you crazy, plus there is the LEN calculation on each, keeping
track of where in extra memory different strings are etc. Think
in structures, arrays, records, user defined types etc. It will
keep your programming challenges to a minimum.

That said, Conv2XM is a bulk memory move type operation, where
you specify the location of the data in the conventional memory
BASIC data area. The routine needs both the segment and offset
addresses of the source memory. Target memory consists of both
an extra memory handle and an offset within that handle at which
to start storing x number of bytes.

This routine is intended for passing arrays into and out of extra
memory, whether they are arrays of integers, longs, single preci-
sion, double precision or a user defined type. The key is to
remember that the bytes to move should be an even number. The
only place where an odd number of bytes may become a factor is
with a user defined type with an odd number of subscripts.









16


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

NAME: Conv2XM (continued)

Calculating the number of bytes depends on the type of array
times the number of elements. Each integer element requires 2
bytes, a long or single precision requires 4 and a currency or
double precision requires 8 bytes. A user defined type of
course, can be variable.

EXAMPLE:

TYPE CustomerRecord
name AS STRING * 26
addr1 AS STRING * 26
addr2 AS STRING * 26
city AS STRING * 16
state AS STRING * 2
zip AS STRING * 5
acctID AS STRING * 9
END TYPE

DIM SHARED customer AS CustomerRecord
...
...
cLen = LEN (customer)
f$ = "CUSTOMER.DAT"
CALL LoadFileXM (f$, cLen, cHandle, cAvail&, errCode)
...
...
INPUT "Customer ID: ",id$
id$ = UCASE$(id$)
id$ = LEFT$(id$ + STRING$(9,0), 9) 'Think 0 is right.
CALL GetCustomer (id$, found)

SUB GetCustomer (id$, found)
SHARED cHandle, cAvail&

'Routine searches the customer database previously loaded into
'extra memory, for the customer ID passed in. Returns found
'equal to the record number and the customer record filled in.
'If not found, will return found = 0. CASE sensitive.

memFree& = FRE(-1) 'How much memory free?

IF memFree& > 64000& THEN
memFree& = 64000& 'Stay within 64k limit.
END IF

elements& = memFree& / LEN(customer)

IF elements& > 32000& THEN elements& = 32000&
IF elements& > cAvail& THEN elements& = cAvail&
....(continued)....




17


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

NAME: Conv2XM (continued)

DIM temp(1 to elements&) AS CustomerRecord

a& = elements& * LEN(customer) 'Bytes to move might be
byteHex$ = HEX$(a&) 'greater than 32767. If
bytes = VAL (byteHex$) 'so, this will pass a
'negative number.
xmOfs& = 0 'Read from offset in XM
count = 0 'Elements checked
found = 0 'Assume not found

DO
vSeg = VARSEG(temp(1)) 'May move, so check
vPtr = VARPTR(temp(1)) ' before each call.
CALL XM2Conv (vSeg, vPtr, cHandle, bytes, xmOfs&, errCode)

FOR i = 1 TO elements
IF temp(i).acctID = id$ THEN
found = count + i
customer = temp(i)
EXIT SUB
END IF
NEXT

count = count + elements
xmOfs& = xmOfs& + bytes
LOOP UNTIL count > cAvail

END SUB





















SEE ALSO: XM2Conv




18


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: GetNameXM

SYNTAX: CALL GetNameXM (handleName$, handle%, errCode%)

PASS: handleName$ A string specifying the text to search
for.

RETURNS: handle% The integer extra memory handle that
handleName is assigned to, if not found
will be zero.

errCode% If the handle name is not found, or
another error occurs.


REQUIRES: EMS version 4.0 only if EMS is in use.


GetNameXM allows you to search the extra memory handles in use
for a specified name. Case is not sensitive, handle names are
converted to all uppercase by PutNameXM when it is assigned and
the name you pass to GetNameXM is converted before the search.

Now a little technical note. The XMS (extended memory) specifi-
cation does not provide for named handles. QBXM implements them
internally and uses it's own routines to manipulate them. Named
handles are a feature of EMS (expanded memory) specification 4.0,
and QBXM uses the expanded memory manager to manage the handle
names. This brings up two points. One is that attempting to
call GetNameXM or PutNameXM when running under EMS versions lower
than 4 will cause an errCode return. My feeling is that this
should not be a problem, EMS 4.0 having been available for as
long as it has. However, when GetXM is called, it may be advan-
tageous to check the major% variable returned if flag% is re-
turned equal to 1 (EMS), and your code uses the named handle
routines. The second thing is the rare possibility that two
different programs running under a multitasking system may employ
the same handle. Slim chance, I agree, but I felt it should be
mentioned, as your code may be running in tandem. Again, these
are only situations that may arise when your code is running
under EMS. Under XMS, with QBXM handling the names, there will
be no conflict because the multiple sessions will each have their
own, individual environments.







SEE ALSO: PutNameXM




19


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: GetPagesXM

SYNTAX: CALL GetPagesXM (total%, pages%)

PASS: Nothing

RETURNS: For expanded memory:

total% equals the pages of memory installed.

pages% equals the number of free (unallocated)
pages.

For extended memory:

total% equals the number of pages available.

pages% equals the largest number of pages that
can be allocated to a handle.


GetPagesXM can be called to determine what the status of extra
memory is at a particular point. If a memory allocation request
fails with a "not enough memory available" error, GetPagesXM can
be called to determine what amount may be available. Your pro-
gram should then take appropriate action based on the amount
available.

There is a slight difference in the total% variable passed back
from GetPagesXM depending on whether EMS or XMS is in use. With
EMS the total variable is the total of physically installed
pages. With XMS, the total variable represents the total amount
of free extended memory, not the physically installed amount. If
another program is concurrently using extended memory, you won't
know about it. There may be occasions in a multi-tasking situa-
tion where extended memory is broken up, and the pages variable
will be lower then the total variable. With extended memory,
pages indicates the largest block of memory that can be allocated
to one handle.

EXAMPLE:
'Calculate amount of extra memory needed to store an array:
needed& = (UBOUND(array) - LBOUND(array) + 1) * bytesPerElem
pgsNeeded = CINT(needed& \ 16384)
IF needed& MOD 16384 then pgsNeeded = pgsNeeded + 1
CALL GetPagesXM (total, free)
IF free >= pgsNeeded THEN
CALL OpenXM (pgsNeeded, arrayHandle, errCode)
ELSE .....


SEE ALSO: GetXM



20


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: GetRecXM

SYNTAX: CALL GetRecXM (hndle%, recNum&, vSeg%, vPtr%, errCode%)

PASS: hndle% the extra memory handle returned by QBXM when
the file was loaded, or the memory allocated.

recNum& the record number to retrieve, (first record
is one) as a long integer.

vSeg% is the segment where the record data is to be
put in BASIC's data area.

vPtr% is the offset address where the record data
is to be put in BASIC's data area.

RETURNS: errCode% if there is a problem.

GetRecXM retrieves a record from extra memory and stores it at
the address specified by the vSeg and vPtr variables. The varia-
ble pointed to by the segment address and offset address must of
course, be large enough to hold the record. The record size is
determined by the record length variable passed to QBXM in the
LoadFileXM or OpenRecXM sub programs.

EXAMPLE:
TYPE InventoryRecord
part AS STRING * 8
onHand AS INTEGER
cost AS SINGLE
retail AS SINGLE
END TYPE

DIM SHARED inventory AS inventoryRecord
'LoadFileXM etc....
INPUT "Part? "; partWanted$
getRec& = 1
found% =0
DO
CALL GetRecXM (iHndle%, getRec&, VARSEG(inventory) _
VARPTR(inventory), errCode%)
IF errCode% THEN ....
IF inventory.part = partWanted$ THEN
found% = -1
EXIT DO
ELSE
getRec& = getRec& + 1
END IF
LOOP WHILE getRec& <= maxRecs&

SEE ALSO: LoadFileXM, OpenXM, PutRecXM




21


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: GetXM

SYNTAX: CALL GetXM (major%, minor%, flag%)

PASS: Nothing

RETURNS: major% the integer portion of the EMS/XMS driver
version installed.

minor% the fractional portion of the EMS/XMS driver
version installed.

flag% indicates what type of extra memory is
installed:
0 = None
1 = Expanded (EMS)
2 = Extended (XMS)

GetXM, besides returning the information above, initializes
internal variables used by other routines in QBXM. The important
thing to remember is that this routine should only be called once
by a single program, or once by the first program in a series of
programs that are CHAIN'd to, or RUN by the initial program. If
the version of the driver, or the type of driver is of concern,
it should be passed in common to other programs in the chain.

The major version of the driver is returned as an integer, as is
the minor version. Dividing the minor version integer returned
by 10 should be sufficient for most needs. For example:

CALL GetXM (major%, minor%, flag%)
version! = major% + (minor% / 10)
IF flag% = 1 THEN PRINT USING "EMS version: #.##"; version%
IF flag% = 2 THEN PRINT USING "XMS version: #.##"; version%

GetXM must be called before any other routine in QBXM so that the
type of extra memory being used can be determined for following
routines. Most other routines will fail with an error code of -1
(no extra memory) if GetXM hasn't been called. The Screen-
CountXM% FUNCTION is an exception, it can be called before GetXm
and will return 0.









SEE ALSO: GetPagesXM




22


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: LoadFileXM

SYNTAX: CALL LoadFileXM (fileNme$,recLen%,hndle%,recs&,eCode%)

PASS: fileNme$ A fully qualified file name that can include
a drive and path.

recLen% Specify the size of the records in the file
for use by the GetRecXM, PutRecXM, SaveFileXM
routines etc.

RETURNS: hndle% An extra memory handle that can used by other
QBXM routines to access the data from the
file.

recs& A LONG integer indicating the number of
records loaded from the file.

eCode% If there is a problem.


LoadFileXM attempts to copy a file from disk into extra memory.
The extra memory allocated is always rounded up to the next page.
For example, a 20,000 byte file of 20 byte long records would use
two pages of extra memory, or 32,768 bytes. The records& varia-
ble returned divides the total bytes in the file by the record
size. In the above example, 20,000 divided by 20 bytes per
record would return a record count of 1000. The actual number of
records that can be stored in extra memory can be determined by
using the RecCountXM& FUNCTION. The difference between the
memory space allocated and the number of records in the file is
the amount you can add to the memory 'file' before a write is re-
quired. In the above example, 1638 records& in extra memory,
(32,768 \ 20 = 16384) less 1000 records in the file means 638
records can be added without an extra memory error. If the file
size happens to be an exact multiple of 16,384, an extra page is
still allocated. For example a file of 2048 records, each 32
bytes long would create a file size of 65,536 bytes. When load-
ed, an extra page would be added: 65,536 + 16,384 = 81,920 bytes
of extra memory (5 pages) would be allocated. The 81,920 bytes
divided by a record size of 32 means that RecCountXM would return
2560, allowing an extra 512 records to be appended to the file.

You can use SaveFileXM when the memory 'file' reaches it's maxi-
mum extra memory allocation, close the extra memory handle, then
call LoadFileXM again to gain more room for appending records.

LoadFileXM will run slower when XMS is in use then when EMS is in
use. For details, see the documentation appendix file.

SEE ALSO: GetRecXM, PutRecXM, SaveFileXM




23


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: LoadScrFileXM

SYNTAX: CALL LoadScrFileXM (fileName$, screenCount%, errCode%)

PASS: fileName$ The fully qualified file name to load.

RETURNS: screenCount% The number of screens in the file.

errCode% If there is a problem.


LoadScrFileXM loads a file into extra memory that can be manipu-
lated by the SaveScreenXM, RestScreenXM and SaveScrFileXm rou-
tines. The screens used by all the QBXM routines are full sized,
25 row by 80 column text screens, and use video page 0 only.

The screenCount% variable returned by this routine is a count of
the screens in the file. Each screen requires 4,000 bytes, so
the file size being loaded is divided by 4,000 to determine the
proper value for screenCount%. Note that a full page multiple is
always allocated, so there may be room to store an extra screen
or two. The number of screens allocated can always be determined
with the ScreenCountXM% FUNCTION.

My examples use help screens, but "Fill in the form" screens are
another good use for these routines.

EXAMPLE:

f$ = drive$ + ":\" + path$ + "HELPSCRN.DAT"
CALL LoadScrFileXM (f$, helpScreens, errCode)
lastScreen = ScreenCountXM%
...
'user hits help Function key, set helpNumber based on
'operation currently being implemented, then CALL a
'a BASIC routine that looks like...
....
CALL SaveScreenXM(lastScreen, errCode)
CALL RestScreenXM(helpNumber, errCode)
DO:LOOP WHILE INKEY$ = ""
CALL RestScreenXM(lastScreen, errCode)









SEE ALSO: OpenScreenXM, CloseScreenXM
SaveScrFileXM, ScreenCountXM%



24


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: OpenRecXM

SYNTAX: CALL OpenRecXM (pages%, recLen%, handle%, errCode%)

PASS: pages% Number of 16k blocks of memory requested.

recLen% The record length to assign to this handle.
The record length must be an even number.

RETURNS: handle% The extra memory handle assigned to the block
allocated, if successful.

errCode% If there is a problem.


OpenRecXM allows you to allocate a block of extra memory that you
can access with the record orientated QBXM routines. The record
length you pass must be even (a multiple of 2) and is stored
internally by QBXM so it does not have to be passed with every
put or get call. If successful, OpenRecXM will return a handle
that you must use to access the allocated block of memory with
other routines. If an error code is returned, the handle number
should be considered invalid.



























SEE ALSO: CloseXM, GetRecXM, PutRecXM




25


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: OpenScreenXM

SYNTAX: CALL OpenScreenXM (screenCount%, errCode%)

PASS: screenCount% The number of full 25x80 screens you
want to store in extra memory.

RETURNS: errCode% If there is a problem.


OpenScreenXM allocates 4000 bytes for each screen you specify in
the screenCount integer. As with all the extra memory routines,
only multiples of an extra memory page are allocated. Since an
extra memory page is 16384 bytes, a rule of thumb is that there
will be a multiple of 4 screens actually available. If you want
to store a screen on the fly, you can usually do so by using one
of the extra screens that may be available. The ScreenCount%
FUNCTION is available to give the true number of screens avail-
able.

No extra memory handle is returned by the OpenScreenXM routine.
The handle is stored internally by QBXM, thus eliminating the
need to store and pass an extra memory handle.


EXAMPLE:

' Suppose that you always want space for an extra screen
' to be available for on the fly saves.

screensNeeded = whatever

IF screensNeeded MOD 4 = 0 THEN
screensNeeded = screensNeeded + 1
END IF

CALL OpenScreenXM (screensNeeded, errCode)













SEE ALSO: CloseScreenXM, LoadScrFileXM
SaveScrFileXM, ScreenCountXM%



26


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: OpenXM

SYNTAX: CALL OpenXM (pages%, handle%, errCode%)

PASS: pages% The number of 16K extra memory pages needed.

RETURNS: handle% An integer handle that must be used when
accessing the extra memory block.

errCode% If there is a problem.


OpenXM allocates a block of extra memory, which can be accessed
with the 'bulk' memory transfer routines, Conv2XM and XM2Conv.
You need to pass it the number of 16k pages that you want, and
OpenXM will return an integer extra memory handle that you can
use to access the block. The bulk memory routines are handy for
freeing up conventional memory to make room for more data as it's
needed. If you use a number of arrays for instance, that are
SHARED throughout the program, it's possible to initialize each
one, store it in extra memory, ERASE the array, then continue the
initialize, store, erase sequence for all the arrays. When a
procedure needs to access the data, REDIM the array, copy the
data back from extra memory to conventional and use it. If the
procedure doesn't change the values in the array, it can be
erased again upon exit from the procedure, or if changed, trans-
ferred back to extra memory.

Another bulk memory move might use the BASIC screen pages 0
through 3 (on a color machine), where QBXM's screen routines only
save and restore video page 0. If you wanted to save all four
video pages, you would allocate one extra memory page, then use
Conv2XM to save the display pages like this:

CALL OpenXM (1, handle, errCode)
IF errCode THEN.....
CALL Conv2XM(&hB800, 0, handle, 16384, 0&, errCode)

Video pages are 4096 bytes long in the real world, so four would
require the full 16384 bytes. The B800hex is the segment address
of the color screen text buffer, B000hex is the monochrome buff-
er, which is only 4096 (1 video page) bytes long anyway.








SEE ALSO: Conv2XM, XM2Conv




27


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: PageCountXM% FUNCTION

SYNTAX: x% = PageCountXM% (handle%)

PASS: handle% The extra memory handle your inquiring about.

RETURNS: An integer count of the pages allocated to
the specified handle.



PageCountXM is an INTEGER FUNCTION (and as such must be declared
to be of use!) that returns the number of pages that have been
allocated to a specific extra memory handle. This is useful for
when a previous program allocated the extra memory and you'd like
to know what is available in a later program.

When loading a file into extra memory, QBXM rounds up to the next
full page, so there is always room to append extra records. If a
subsequent program is running after the file has been allocated,
the previous program should pass the number of valid records.
Then this routine can be called to determine the number of re-
cords that can be appended to the extra memory 'file'.

Formula would be (assuming handle% and validRecs& are known):

x% = PageCountXM (handle%)
totalRecs& = (CLNG(x%) * 16384&) \ recSize%
freeRecs& = totalRecs& - validRecs&


























28


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: PutNameXM

SYNTAX: CALL PutNameXM (hName$, handle%, errCode%)

PASS: hName$ A string specifying the text name to assign
to the extra memory handle. 8 bytes max.

handle% The integer extra memory handle that hName$
is to be assigned to.

RETURNS: errCode% If there is a problem.


REQUIRES: EMS version 4.0 only if EMS is in use.


PutNameXM allows you to assign an extra memory handle a unique
name. Case is not sensitive, handle names are converted to all
uppercase by PutNameXM when called. Only the first eight bytes
of handleName are used.

Now a little technical note. The XMS (extended memory) specifi-
cation does not provide for named handles. QBXM implements them
internally and uses it's own routines to manipulate them. Named
handles are a feature of EMS (expanded memory) specification 4.0,
and QBXM uses the expanded memory manager to manage the handle
names. This brings up two points. One is that attempting to
call GetNameXM or PutNameXM when running under EMS versions lower
than 4 will cause an errCode return. My feeling is that this
should not be a problem, EMS 4.0 having been available for as
long as it has. However, when GetXM is called, it may be advan-
tageous to check the major% variable returned if flag% is re-
turned equal to 1 (EMS), and your code uses the named handle
routines. The second thing is the rare possibility that two
different programs running under a multitasking system may employ
the same handle. Slim chance, I agree, but I felt it should be
mentioned, as your code may be running in tandem. Again, these
are only situations that may arise when your code is running
under EMS. Under XMS, with QBXM handling the names, there will
be no conflict because the multiple sessions will each have their
own, individual environments.









SEE ALSO: GetNameXM




29


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: PutRecXM

SYNTAX: CALL PutRecXM (hndle%, recNum&, vSeg%, vPtr%, errCode%)

PASS: hndle% The integer extra memory handle returned
by OpenRecXM or LoadFileXM.

recNum& A long integer indicating the record number,
the first record being 1.

vSeg% The segment address of the variable that has
the data to move to extra memory.

vPtr% The offset address of the variable that has
the data to move to extra memory.

RETURNS: errCode% If there is a problem.


PutRecXM takes a record variable in BASIC's data space and trans-
fers it to extra memory, placing it in the position specified by
the record number you pass. The length of the record in BASIC's
data space must be the same as the length you passed to OpenRecXM
or LoadFileXM when the extra memory was allocated. The record
length for each extra memory handle opened for record type access
is stored internally by QBXM, eliminating the need to pass it
with every call to GetRecXM or PutRecXM.























SEE ALSO: GetRecXM, OpenRecXM




30


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: RecCountXM& FUNCTION

SYNTAX: x& = RecCountXM& (handle%)

PASS: Memory handle of a 'record' orientated allocation.

RETURNS: A long integer indicating the number of records the
memory handle can hold.


Remember to DECLARE RecCountXM& as a LONG INTEGER function,
otherwise BASIC will give you the old 'Array Not Defined' mes-
sage. If you fail to DECLARE it as a FUNCTION returning a long
integer, you'll get some pretty interesting results. Forewarned
is forearmed.

RecCountXM& is used to determine just how many records will fit
in a specified extra memory handle. The size of the allocated
block of memory is divided by the record size that was specified
in the LoadFileXM or OpenRecXM call.






























SEE ALSO: LoadFileXM, OpenRecXM




31


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: RestParamXM

SYNTAX: CALL RestParamXM (vSeg%, vOfs%, errCode%)

PASS: vSeg% The segment address of a 530 byte buffer that
was filled in by a call to SaveParamXM

vOfs% The offset address of the above buffer.

RETURNS: errCode% If a problem is encountered.


RestParamXM sets up the internal variables used by QBXM that were
saved with SaveParamXM. These two routines are intended for use
when you want to CHAIN or RUN another program that will share
data in the extra memory. The buffer used must be at least 530
bytes long, the type can be anything but a variable length
string. So, all the following declarations will fit the bill:

DIM buffer AS STRING * 530
DIM buffer%(1 TO 265)
DIM buffer&(1 TO 133)
DIM buffer!(1 TO 133)
DIM buffer#(1 TO 67)

The fixed length string or integer array are best, as they don't
require any wasted bytes.

If you wish to CHAIN to another program that will use the extra
memory allocated and initialized by a first program, the buffer
variable should be declared as COMMON SHARED in both programs.

If you RUN a second program, then the only(?) method to pass the
buffer is via a disk file. The receiving program should read in
the buffer, delete the file and call RestParamXM.

Note that GetXM and CloseAllXM clear out all the internal varia-
bles that QBXM uses, so care should be taken in cases where a
chain of programs are going to be sharing extra memory. Remember
that AutoCloseXM will cause a call to CloseAllXM when a CHAIN
statement is encountered or a program terminates with an END or
RUN statement.








SEE ALSO: SaveParamXM




32


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: RestScreenXM

SYNTAX: CALL RestScreenXM (screenNum%, errCode%)

PASS: screenNum% The desired screen number from extra
memory.

RETURNS: errCode% If there is a problem.


RestScreenXM copies a specified screen (not video page) from
extra memory into the video adapter's memory for video page zero.
The screen to be displayed can be placed into extra memory with a
call to SaveScreenXM or LoadScrFileXM.

Both RestScreenXM and SaveScreenXM use the fastest possible
method to move screens back and forth in memory. This will cause
snow on some CGA adapters. My feeling is that smaller code size
and faster execution are more important than making sure snow
won't appear on some lower quality CGA adapters. If this
presents a problem, let me know, and if there is enough of a
demand I may add CGA checking in future releases.




























SEE ALSO: OpenScreenXM, SaveScreenXM, LoadScrFileXM




33


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: SaveFileXM

SYNTAX: CALL SaveFileXM (fileN$, handle%, records&, errCode%)

PASS: fileN$ The fully qualified file name to write.

handle% The extra memory handle that has the data to
copy to the file.

records& A long integer with the number of records to
write.

RETURNS: errCode% An error code if a problem is encountered.


SaveFileXM writes the data in extra memory to the file you speci-
fy. The file name came include an optional drive and path if
needed. SaveFileXM starts at the first record in extra memory to
save the specified number of records. If the file named is not
on disk, it is created, if it does exist on disk it is truncated
to zero bytes, then the extra memory data is written to the file.
The operation is similar to BASIC's OPEN FOR OUTPUT file routine.

My thinking in using an over-write file method is in keeping with
my idea that an entire file is being loaded in and manipulated.
If an APPEND method is desired, let me know, and if there is
demand, I will add it to any future updates.

SaveFileXM will run slower when XMS is in use then when EMS is in
use. For details, see the documentation appendix file.




















SEE ALSO: LoadFileXM, OpenRecXM, GetRecXM, PutRecXM




34


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: SaveParamXM

SYNTAX: CALL SaveParamXM (vSeg%, vOfs%, errCode%)

PASS: vSeg% The segment address of a 530 byte buffer that
will be filled in by the routine.

vOfs% The offset address of the above buffer.

RETURNS: errCode% If a problem is encountered.


SaveParamXM fills the specified buffer with the current values of
the internal variables used by QBXM. RestParamXM uses this data
to restore the extra memory state as it was when SaveParamXM was
called. These two routines are intended for use when you want to
CHAIN or RUN another program that will share data in the extra
memory. The buffer used must be at least 530 bytes long, the
type can be anything but a variable length string. So, all the
following declarations will fit the bill:

DIM buffer AS STRING * 530
DIM buffer%(1 TO 265)
DIM buffer&(1 TO 133)
DIM buffer!(1 TO 133)
DIM buffer#(1 TO 67)

The fixed length string or integer array are best, as they don't
require any wasted bytes.

If you wish to CHAIN to another program that will use the extra
memory allocated and initialized by a first program, the buffer
variable should be declared as COMMON SHARED in both programs.

If you RUN a second program, then the only(?) method to pass the
buffer is via a disk file. The sending program should call
SaveParamXM, open a disk file, write the buffer, close the file
and then run the subsequent program.

Note that GetXM and CloseAllXM clear out all the internal varia-
bles that QBXM uses, so care should be taken in cases where a
chain of programs are going to be sharing extra memory. Remember
that AutoCloseXM will cause a call to CloseAllXM when a CHAIN
statement is encountered or a program terminates with an END or
RUN statement.





SEE ALSO: RestParamXM




35


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: SaveScreenXM

SYNTAX: CALL SaveScreenXM (screenNum%, errCode%)

PASS: screenNum% Screen number to copy the current video
page zero to.

RETURNS: errCode% If there is a problem.


SaveScreenXM copies the contents of the current display (video
page zero) to a specified screen in extra memory. The screen to
be saved can be placed into extra memory at any location (screen
number) within the number of screens allocated via LoadScrFileXM
or OpenScreenXM. The screen can be displayed again with a call
to RestScreenXM.

Both RestScreenXM and SaveScreenXM use the fastest possible
method to move screens back and forth in memory. This will cause
snow on some CGA adapters. My feeling is that smaller code size
and faster execution are more important than making sure snow
won't appear on some lower quality CGA adapters. If this
presents a problem, let me know, and if there is enough of a
demand I may add CGA checking in future releases.


























SEE ALSO: OpenScreenXM, RestScreenXM, SaveScrFileXM




36


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: SaveScrFileXM

SYNTAX: CALL SaveScrFileXM (fileN$, scrCount%, errCode%)

PASS: fileN$ The fully qualified file name to write.

scrCount% The number of screens to write to the file.

RETURNS: errCode% If there is a problem.


SaveScrFileXM saves a file onto disk from extra memory that can
be used later by the LoadScrFileXM routine. The screens used by
all the QBXM routines are full sized, 25 row by 80 column text
screens, and use video page 0 only.

The scrCount% variable passed to this routine is a count of the
screens to be written to the file. The first screen up through
scrCount% will saved. Each screen requires 4,000 bytes, so the
file size will be a multiple of 4,000.

If the specified file exists, it will be overwritten. This
routine behaves similar to BASIC's OPEN FOR OUTPUT file method.



























SEE ALSO: OpenScreenXM, CloseScreenXM
LoadScrFileXM, ScreenCountXM%



37


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: ScreenCountXM%

SYNTAX: DECLARE FUNCTION ScreenCountXM% ()
screens% = ScreenCountXM%

PASS: Nothing.

RETURNS: Nothing.


First, always remember to declare this routine as an INTEGER
function, if you don't, you'll get an "Array Not Defined" error
message. If you don't define it as an INTEGER function, when you
call it, you may end up with a system hang.

ScreenCountXM% returns the maximum number of screens that can be
stored in the extra memory screen buffer. This should not be
considered as a count of valid screens, because there may be
extra screen space beyond those actually in use. See the
LoadScrFileXM and OpenScrXM routines for information on how extra
memory is allocated for screen saving and restoring.





























SEE ALSO: LoadScrFileXM, OpenScreenXM




38


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


NAME: XM2Conv

SYNTAX:

CALL XM2Conv (tSeg%, tOfs%, hndle%, bytes%, xmOfs&, errCode%)

PASS:
tSeg% The segment address of the memory block you want
to fill from extra memory. VARSEG(variable)

tOfs% The offset address of the memory block you want
to fill from extra memory. VARPTR(variable)

hndle% The extra memory handle that was returned by a
previous OpenXM call.

bytes% The EVEN number of bytes to transfer, must be
less than or equal to 64k.

xmOfs& A long integer specifying where in extra memory
the data read is to start from. First byte = 0.

RETURNS:
errCode% If there is a problem.

Right off I'm going to tell you to avoid passing variable length
strings. That said, XM2Conv is a bulk memory move type opera-
tion, where you specify where the data space is in the conven-
tional BASIC data area. The routine needs both the segment and
offset addresses of the target memory, and you must be sure that
the target memory is large enough to hold the byte count. Source
memory consists of both an extra memory handle and an offset
within that handle at which to start storing x number of bytes.

This routine is intended for passing arrays into and out of extra
memory, whether they are arrays of integers, longs, single preci-
sion, double precision or a user defined type. The key is to
remember that the bytes to move should be an even number, and the
only place where an odd number of bytes may become a factor is
with a user defined type with an odd number of subscripts.

Calculating the number of bytes depends on the type of array
times the number of elements. Each integer element requires 2
bytes, a long or single precision requires 4 and a currency or
double precision requires 8 bytes. A user defined type of
course, can be variable.




SEE ALSO: Conv2XM




39


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

REGISTRATION

QBXM is not public domain material, it is shareware. As such you
are granted the right to use it for a 30 day evaluation period,
after which you must register QBXM or discontinue it's use. If
you received QBXM from a disk distribution service, any cost to
you was for materials, shipping and handling. Said costs were
not for the purposes of licensing the software on the disk, the
author receives nothing from the fees you pay to a distribution
service.

Under no circumstances is the right to distribute a program using
the QBXM routines granted, unless the QBXM library has been
registered. Use QBXM for your personal uses during the evalua-
tion period, and if you find it useful, please register it. If
you wish to sell or distribute a program that uses QBXM, regis-
tration is mandatory.

Registration cost is $25.00. Registration allows you to use QBXM
on one machine at a time. Copy it to all the machines you devel-
op on if you'd like, but please realize that a licensed copy of
QBXM is intended for the licensee's use only. Site licenses are
available at the following rates:

1 to 10 users: $25.00 each
11 to 50 users: 20.00 each
51 and above: 15.00 each.

Benefits for registering:

1. Your conscience will allow you to sleep at night.

2. Registered users receive a licensed copy of QBXM suit-
able for use in programs they distribute.

3. Your significant other won't think poorly of you.

4. Registered users will receive a licensed copy of the
next upgrade to the program, if any, delivered right to their
door.

5. The possibility of your being sucked up into a UFO may
be lessened.

6. If I get a 720/1.44 disk change problem figured out,
I'll throw in a copy of my personal disk copy program that uses
the QBXM routines to copy disks larger then 360k without swapping
them into and out of the drive. Don't know about you, but it
drives me crazy when I have 4 megs of memory and have to swap
disks into and out of the drive to copy them.

7. A BASIC 7.0 Far String Compatible library will be sent
to registered users.
A registration form for your use is on the last page.


40


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

WARRANTY

There isn't any. QBXM is distributed as is, without any warranty
of any kind, express or implied, as to its fitness for any par-
ticular purpose. Every attempt has been made to verify that QBXM
works as described in this manual, and if there is a bug reported
to me, it will be corrected and distributed to registered users
as quickly as possible, with a description of any changes made to
the library.


CONTACTING ME

I can be reached via US mail at:

5 John Street
Morganville, NJ 07751-9762

On Compuserve via e-mail to Tom Vought, 70054,1367

Or if you like to live dangerously, at:

The Off-Hour Rockers BBS
908-727-6785 or
908-727-6917

Both nodes being 8N1 and 1200/2400/9600 (USR). Join the BASIC
conference at the main menu prompt (j;7), which I host and leave
a message to Tom Vought. First time callers are granted full
access, there is no upload-download ratio policy, and all in all,
the BBS is there to just have fun on. I will always have the
latest copy of QBXM on line for downloading from conference 7,
the BASIC conference.

In addition to QBXM, the latest version of 123-Write is also
always available as 123Wnn.ZIP where nn is the version number.
At this time, 2.0 is the latest release, so a Z command with a
filespec of 123W will find 123W20.ZIP. 123-Write is a shareware
library for QuickBASIC 4.0 and 4.5 and BASIC 6.0, 7.0 and 7.1
that allows you to write Lotus 123 compatible spreadsheet files
from within your BASIC program. Saves a lot of Lotus Macro
coding and related BASIC work to export/import spreadsheets.
Will work with any spreadsheet program that will read a .WK?
file.












41


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

Error Codes

The EMS specifies error codes of one byte from 80 hex through A4
hex, and the XMS specifies one byte error codes from 80 hex
through B2 hex. DOS will return error codes as one byte from 1
through 5A. Then of course, I want to be able to pass QBXM spe-
cific errors back to the calling procedure. So, the scheme I
came up with for the errCode integer returned by QBXM follows:

Internal errors are negative, EMS and DOS errors are returned
positive with the error code byte unchanged, and XMS errors
(except 'Name not found' which is the same as the EMS code) are
positive, but the one byte error code is expanded to two, the
prefix byte being a 1, making them greater than 255. The codes
returned are:









































42


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

QBXM generated errors:

Hex Dec Meaning:

FFFF -1 No extra memory installed, or not initialized
by GetXM.

FFFE -2 Out of range handle. Must be between 1 and
127 inclusive.

FFFD -3 Page request out of range. Must be between
1 and 512 inclusive.

FFFC -4 Record size not even. All record lengths
must be a multiple of 2 bytes.

FFFB -5 A screen memory buffer is already open. Only
one screen buffer can be open at a time.

FFFA -6 Screen number out of range. Screens must be
between 1 and the maximum screen allocated,
inclusive. The maximum screen number can be
determined with the ScreenCountXM% FUNCTION.

FFF9 -7 No screen memory allocated. OpenScreenXM or
LoadScrFileXM must be called before Put/Get
ScreenXM.

FFF8 -8 Invalid record number. The record number
passed to Get/Put RecXM is not within the
range of records allocated. The maximum
value for the record number can be deter-
mined with the RecCountXM& FUNCTION.

FFF7 -9 Invalid string passed. Probably a null
string was passed to one of the QBXM
routines.

FFEC -20 These are codes I assigned for internal code
errors within QBXM. In all my testing, I
FFEB -21 haven't encountered them. If you should,
please contact me with as much detail as
possible about how the error was generated.













43


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

DOS Generated errors:

(Some DOS critical errors will be intercepted by BASIC, for
example, a drive door being open. Others should only be
file related, and I limited this list to the likely ones.)

Hex Dec Meaning (DOS generated):

2 2 File not found.

3 3 Path not found.

4 4 Too many open files. (FILES= in CONFIG.SYS)

5 5 Access denied.

6 6 Handle invalid. (Please report.)

F 15 Invalid drive.

13 19 Write protected disk.

15 21 Drive not ready.

17 23 Data error on Read.

19 25 Seek error.

1B 27 Sector not found.

Then there are a ton of network related errors. A good DOS
reference should be handy for that kind of work!
























44


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


EMS Generated errors:

Hex Dec Meaning:

80 128 Internal error in expanded memory manager
software. (Might be the driver's memory was
corrupted.)

81 129 Hardware malfunction.

82 130 Memory manager busy. (Multi-Task? Retry I
suppose.)

83 131 Invalid handle. (QBXM should catch this one)

84 132 Function not defined. (Put/Get name with EMS
3.0 or 3.2? Otherwise let me know.)

85 133 Handles exhausted.

86 134 Contact author.

87 135 Request is for more pages than physically
installed in machine.

88 136 Request is for more pages than are currently
free.

89 137 Tried to allocate zero pages.

8A 138 Please contact me with the specifics.
through QBXM does not use any EMS functions that
9F 159 should cause these errors.

A0 160 No handle found for the specified name. QBXM
should return handle=0 with GetNameXM.

A1 161 There is already a handle with the same name.
QBXM converts all handle names to uppercase.
May occur if multiple copies of your code are
running.

A3 163 Contact author.

A4 164 Access denied by operating system. Shouldn't
happen with QBXM. Contact me with specifics.










45


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

XMS Generated errors:

Hex Dec Meaning:

A0 160 No handle found for the specified name. QBXM
should return handle=0 with GetNameXM.

180 384 Function not implemented. Shouldn't happen.

181 385 VDISK type device driver was detected. XMS
will not load if there is VDISK type device
driver using extended memory, and will abort
functions if one is loaded after the XMS
driver. See the appendix file for more info
on XMS and allocation strategies.

182 386 An A20 line error occurred. (Hardware Error)

18E 398 General driver error. (Memory corrupted?)

18F 399 Unrecoverable driver error.

190 400 Errors returned by functions that are not
through used by QBXM. Probable memory corruption.
194 404

1A0 416 All extended memory is allocated.

1A1 417 All extended memory handles exhausted. XMS
allows up to 128 handles. HIMEM.SYS defaults
to 32. The /NUMHANDLES=nn switch can be used
on the command line in CONFIG.SYS to increase
the number available.

1A2 418 Invalid handle. QBXM should catch this,
please contact me if encountered.

1A3 419 Errors returned by variables used within
through QBXM. Please contact me with details.
1A6 422

1A7 423 Invalid length. QBXM should catch this and
return -4, if not please supply me with the
conditions that caused this error.

1A8 424 Invalid overlap in a move request.

1A9 425 Parity error detected.

1AA 426 Again, errors that shouldn't be generated by
& above any QBXM routines. If they occur, please let
me know the details.




46


QBXM ver 1.0
Copyright 1991, Thomas J. Vought

Routine Index

Routine name and parameters: Page

AutoCloseXM () 11
ClearNamesXM () 12
CloseAllXM () 13
CloseScreenXM () 14
CloseXM (handle%, errCode%) 15
Conv2XM (fSeg%, fOfs%, hndle%, bytes%, xmOfs&, eCode%) 16
GetNameXM (hName$, handle%, errCode%) 19
GetPagesXM (total%, pages%) 20
GetRecXM (handle%, recNum&, vSeg%, vPtr%, errCode%) 21
GetXM (major%, minor%, flag%) 22
LoadFileXM (filename$, reclen%, handle%, records&, errCode%) 23
LoadScrFileXM (filename$, screenCount%, errCode%) 24
OpenRecXM (pages%, reclen%, handle%, errCode%) 25
OpenScreenXM (screenCount%, errCode%) 26
OpenXM (pages%, handle%, errCode%) 27
PageCountXM% (handle%) FUNCTION 28
PutNameXM (hName$, handle%, errCode%) 29
PutRecXM (handle%, recNum&, vSeg%, vPtr%, errCode%) 30
RecCountXM& () FUNCTION 31
RestParamXM (vSeg%, vOfs%, errCode%) 32
RestScreenXM (screenNum%, errCode%) 33
SaveFileXM (filename$, handle%, records&, errCode%) 34
SaveParamXM (vSeg%, vOfs%, errCode%) 35
SaveScreenXM (screenNum%, errCode%) 36
SaveScrFileXM (filename$, screenCount%, errCode%) 37
ScreenCountXM% () FUNCTION 38
XM2Conv (toSeg%, toOfs%, handle%, bytes%, xmOfs&, errCode%) 39

























47


QBXM ver 1.0
Copyright 1991, Thomas J. Vought


Please complete and mail to:

Thomas J. Vought
5 John Street
Morganville, NJ 07751-9762


NAME: ________________________________________________

STREET: ________________________________________________

CITY: ________________________________________________

STATE & ZIP: ___________ _____________________


For registration of QBXM version 1.0:

COPIES: ________ at: $__________ each = $____________

Disk format for registered copy and first upgrade:

3.5" ______ 5.25" ______


Just curious, where did you get QBXM from?

__________________________________________________________

__________________________________________________________


Comments? I'd love to hear them, here, on the back or on a
separate page. (Is the documentation clear etc?)
















Please make checks payable to Thomas J. Vought, and mark them
"REG: QBXM 1.0". Thank you.



48




 December 22, 2017  Add comments

Leave a Reply