home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-06-18 | 96.1 KB | 2,929 lines |
-
- 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
-
-