home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 8
/
CDASC08.ISO
/
NEWS
/
676
/
XMSIF
/
XMSIF.DOC
< prev
next >
Wrap
Text File
|
1993-10-07
|
44KB
|
975 lines
XMSIF
C Interface to XMS Functions
XMSIF version 1.5
by James W. Birdsall
05/16/93
0. CONTENTS
-----------
0. CONTENTS
I. INTRODUCTION
I.1 WHAT IS SUPPORTED
I.2 COPYRIGHT, LICENSE, AND WARRANTY DISCLAIMER
II. COMPILING AND LINKING WITH THE LIBRARIES
II.1 WITH C
II.2 WITH C++
II.3 XMSTEST, THE EXAMPLE PROGRAM
III. PROGRAMMING WITH XMSIF
III.1 INITIALIZING THE LIBRARY
III.2 ORDINARY USE
III.3 TIPS ON USING EMBS
III.4 TIPS ON USING UMBS
III.5 OTHER TIPS
III.6 FUNCTION GROUPINGS
IV. LIBRARY REFERENCE
IV.1 GLOBAL VARIABLES
IV.2 EMB FUNCTIONS
IV.3 UMB FUNCTIONS
V. ERROR CODES
V.1 INTERNAL ERRORS
V.2 XMS DRIVER ERRORS
VI. THE END
VI.1 ACKNOWLEDGEMENTS
I. INTRODUCTION
---------------
XMSIF provides a high-level interface to XMS control functions for
common operations such as allocating and freeing XMS extended memory
blocks (EMBs) and upper memory blocks (UMBs), and copying data to and
from EMBs. A raw interface to the driver has been included to allow more
convenient access to driver functions not otherwise supported.
XMSIF is written in assembly language for speed and assembled with
Borland's Turbo Assembler (TASM) 2.5. The source code is not compatible
with the Microsoft Assembler (MASM).
I.1 WHAT IS SUPPORTED
---------------------
XMSIF expressly supports the Microsoft eXtended Memory Specification
(XMS) versions 2.0 and 3.0. Versions below 2.0 are not supported.
Versions above 3.0 are supported as 3.0.
XMSIF supports tiny, small, medium, compact, large, and huge memory
models. The small model library supports both tiny and small models, so
no library is provided specifically for tiny model.
XMSIF supports any version of Turbo C, Turbo C++, or Borland C++, in
both C and C++ modes, and Microsoft C 6.00/A and C/C++ 7.0. XMSIF has
been tested with Borland C++ 2.0, Turbo C 2.0, Microsoft C 6.00A, and
Microsoft C/C++ 7.0 in all of the supported memory models. XMSIF should
work with earlier versions of Microsoft C and any other MS-DOS C
compiler that 1) uses compatible parameter passing and return methods
and 2) can use standard-format libraries.
I.2 COPYRIGHT, LICENSE, AND WARRANTY DISCLAIMER
-----------------------------------------------
XMSIF is not in the public domain. All the files are copyright 1991,
1992, 1993 by James W. Birdsall, all rights reserved. Permission is
granted to do the following:
You may freely redistribute this archive, so long as it contains
all the files listed in the file MANIFEST, intact and
unmodified.
You may use the libraries in programs for your own use. You may
not distribute programs linked with these libraries.
Payment of the $5 shareware registration fee ($50 for commercial use)
grants the following license, in addition to the permissions listed
above:
You may request the source to XMSIF. You may modify the source
as necessary for use in your programs. However, you may not
redistribute either the original or modified source. There is no
additional charge for source.
You may distribute programs linked with either the original
libraries or libraries generated from source you have modified,
without royalty, provided you (a) do not alter or remove
copyright notices contained therein and (b) you indemnify, hold
harmless, and defend the author from and against any claims or
lawsuits, including attorney's fees, that arise or result from
the use or distribution of your software product.
For the purposes of this license, commercial use is defined as use by an
incorporated entity in a software product that is regarded as the
product of the corporation, no matter how the software product is
distributed, but only if 100 or more copies of the product are expected
to be made.
Registered users will also receive update notices and bug reports,
and are entitled to use future versions without further payment.
The contents of the distribution archive, and all other related
files, information, and services are provided "as is" and without
warranty. To the extent permitted by applicable law, the author
disclaims all warranties, express or implied, including but not limited
to, any implied warranty of merchantability or fitness for a particular
purpose. While effort has been made to ensure that the files, information,
and services are accurate and correct, the author shall not be liable
for damages arising out of the use of or inability to use this product,
including but not limited to, loss of profit, data, or use of this
software, or special, incidental, or consequential damages or other
similar claims, even if the author has been specifically advised of the
possibility of such damages. Some states do not allow the exclusion of
incidental or consequential damages, so the foregoing limitation may not
apply to you.
Information on contacting the author is provided at the end of this
file.
II. COMPILING AND LINKING WITH THE LIBRARIES
--------------------------------------------
This section describes how to use the XMSIF libraries with your
programs.
XMSIF is provided as Borland/Microsoft standard library files.
Libraries are provided for small, medium, compact, large, and huge
memory models (tiny model uses the small model library). The model for
which a library is intended is indicated by the last letter of the
filename proper, which is the same as the first letter for the model.
For example, XMSIFL.LIB is the large model library.
II.1 WITH C
-----------
To use XMSIF in C programs, you must #include the file XMSIF.H in
every source file that calls XMSIF functions, accesses XMSIF global
variables, or uses #defined constants provided by XMSIF.
The procedures for linking XMSIF with the rest of your program vary
according to the compiler and method you are using. In general, you must
include the appropriate library (the library corresponding to the memory
model in which you have compiled the rest of your program) in the link.
If you are compiling in the Integrated Development Environment of
Turbo/Borland C[++], you should include the name of the appropriate
library in the project file for your program. For example, if you are
working in the compact memory model, you should include XMSIFC.LIB in
your project file.
If you are using a command-line compiler (bcc, tcc, or cl) to compile
and link, simply place the full name of the appropriate XMSIF library on
the command line. For example, "bcc -mc foo.c xmsifc.lib" will compile
the file "foo.c" in the compact model and link it with xmsifc.lib.
If you are linking manually (using TLINK or LINK), place the name of
the appropriate library in with the other libraries. For example,
tlink c0c.obj foo.obj, foo.exe, foo.map, cc.lib xmsifc.lib
or
link foo.obj, foo.exe, foo.map, xmsifc.lib ;
will link the object "foo.obj" with the appropriate startup object and
standard library (LINK automatically includes the startup object and
standard library, so it is not necessary to explicitly include them) and
the compact model XMSIF library.
II.2 C++
--------
To use XMSIF in C++ programs, you must #include the file XMSIF.HPP in
every file that calls XMSIF functions, accesses XMSIF global variables,
or uses #defined constants provided by XMSIF. Be careful to include
XMSIF.HPP instead of XMSIF.H. If you include the wrong one, you will
probably see "undefined symbol" errors when linking.
Otherwise, the procedures for using XMSIF with C++ programs are the
same as for using it with C programs.
II.3 XMSTEST, THE EXAMPLE PROGRAM
---------------------------------
A large and complete example program and tester, XMSTEST, has been
included in this distribution. It can be compiled in any of the
supported memory models, with either Borland or Microsoft compilers.
The test program has four source files: XMSTEST.C, XMSTEST2.C,
XMSTEST3.C, and TESTUTIL.C, and two header files: XMSTEST.H and
TESTUTIL.H. When compiling in tiny model with Borland compilers, an
additional file, STACK.OBJ, is needed. STACK.ASM, which is the source
for STACK.OBJ, has been included for completeness.
Example makefiles have been included for Borland and Microsoft
compilers. EXMAKEBC is the example makefile for Borland C++ 2.0,
EXMAKETC is the example makefile for Turbo C[++], and EXMAKEMS is the
example makefile for Microsoft C. Complete instructions for making the
example program and using the example makefiles are included at the
beginning of each makefile. More information about the program is also
included at the beginning of XMSTEST.C.
XMSTEST requires a single free EMB of at least 81,920 bytes in order
to perform the copy-function tests. It requires at least one free UMB in
order to perform all the UMB-function tests. If your system does not
support UMBs, XMSTEST will note this fact and skip inappropriate
UMB-function tests. If your system does support UMBs but none are free,
XMSTEST will assume that your system does not support UMBs and will also
skip inappropriate UMB-function tests. XMSTEST also requires at least
165,000 bytes of available conventional memory to run.
XMSTEST may require the command-line parameters "-q" or "-w" to run
on your system. You may also wish to use the "-3" parameter to perform
more complete testing if your system is a 386 or better. A full
explanation of these parameters and what they do may be found at the
beginning of XMSTEST.C.
III. PROGRAMMING WITH XMSIF
---------------------------
This section describes how to make XMSIF calls in your program, and
details various tricks and tips which you may find useful.
III.1 INITIALIZATION
--------------------
The library initialization function XMMlibinit() _must_ be called
before any other XMSIF calls are made. All other XMSIF functions are
guaranteed to fail if called before XMMlibinit(). XMMlibinit()
determines whether an XMS driver is present and sets up various internal
and global variables necessary to the functioning of XMSIF.
III.2 ORDINARY USE
------------------
XMSIF provides several sets of functions. First, there is a set of
functions which are intended to be orthogonal with the standard C
functions malloc(), realloc(), and free(), and the Borland/Turbo C[++]
function coreleft(), for EMBs. These functions are XMMalloc(),
XMMrealloc(), XMMfree(), XMMcoreleft(), and XMMallcoreleft().
Second, there is a group of functions for copying data to and from
EMBs. These functions are XMMcopyto(), XMMcopyfrom(), _XMMcopy(),
XMMicopyto(), XMMicopyfrom(), and _XMMicopy().
Third, there is a group of miscellaneous functions: XMMlibinit(),
XMMgetversion(), XMMrawcall(), and XMMraw3().
Finally, there is a set of functions which are intended to be
orthogonal with the standard C functions malloc() and free(), and the
Borland/Turbo C[++] function coreleft(), for UMBs. These functions are
UMBalloc(), UMBfree(), UMBcoreleft(), and UMBallcoreleft(). For details
on these functions and all the others listed above, see section IV.2.
To use EMBs (Extended Memory Blocks), first it is necessary to
allocate some. This is done with XMMalloc(), which takes a size in bytes
and returns a handle which will be used to reference the allocated
memory. EMBs are subject to fragmentation problems; it is not possible
to allocate with XMMalloc() more extended memory than is in the largest
free block. The size of the largest free block, in bytes, is returned by
XMMcoreleft(). The total of all free EMBs is returned by
XMMallcoreleft(). Other considerations about using EMBs are discussed in
section III.3 below. To adjust the size of an existing EMB, use
XMMrealloc().
The only way to get data to or from an EMB is via the XMS driver's
copying functions. The XMSIF copying functions provide handy interfaces
to the underlying driver functions and provide extra processing to
remove some of the limitations on the driver functions (such as the
inability to copy an odd number of bytes).
The miscellaneous functions listed above initialize XMSIF
(XMMlibinit(), see section III.1), return the XMS version implemented by
the driver (XMMgetversion()), and allow programs to call the driver more
directly, specifying values for all the relevant registers
(XMMrawcall() and XMMraw3()).
Finally, to use UMBs (Upper Memory Blocks, which may exist in unused
spaces between 640K and 1M), first it is necessary to allocate one (or
more). This is done with UMBalloc(), which takes a size in bytes and
returns a far pointer to the UMB. UMBs are subject to fragmentation
problems; it is not possible to allocate with UMBalloc() more memory
than is in the largest free block. The size of the largest free block,
in bytes, is returned by UMBcoreleft(). The total of all free UMBs is
returned by UMBallcoreleft(). Other problems with using UMBs are
discussed in section III.4 below. Since UMBs can be accessed directly,
no copying functions are provided for them.
Many functions return a status directly. For those functions, a
return value of 0 indicates success and a return value of XMMOOPS
indicates failure. The global variable _XMMerror contains an error code
which gives further information on why the function failed, or has value
0 if the function succeeded. Many functions return some other value
instead of a status code (0 or XMMOOPS). In these cases, the value of
_XMMerror should be checked upon return. The recommended method of
error-checking is indicated for each function in section IV.2 below.
III.3 TIPS ON USING EMBS
------------------------
As mentioned above, EMBs are subject to fragmentation problems, and
the limit on allocation is the size of the largest free block. This has
some interesting side effects. For one, there is no single measure of
free extended memory. In some cases, the size of the largest free block
will be most useful, in other cases, the total of all free blocks. Thus,
both XMMcoreleft() and XMMallcoreleft() are provided. But a consequence
of having multiple measures is that allocations may change the values in
unanticipated ways. For example, while any allocation will change the
total of all free blocks, it may or may not change the size of the
largest free block depending on the size of the allocation request and
the allocation strategy followed by the XMS driver. For example, if the
allocation request is small enough to fit into a smaller free block, the
XMS driver may perform the allocation from the smaller block, leaving
the size of the largest free block unchanged. Or it may always perform
allocations from the largest free block, in which case the size of the
largest free block will change. In summary, do not depend on the size of
the largest free block changing when you allocate extended memory.
Furthermore, not all XMS drivers behave in exactly the same way.
While writing XMSTEST, I observed distinct differences between QEMM 5.12
and HIMEM.SYS 2.77. The most obvious difference is that when allocating
under QEMM, the total of all free blocks drops by the size of the
allocation rounded up to the nearest 16K, instead of the size rounded up
to the nearest 1K (the minimum allocation unit for EMBs). This is
probably related to QEMM's support of EMS, which has a minimum
allocation unit of 16K. XMSTEST's -q parameter is a direct response to
this difference in behavior. When allocating from a DOS session under
MS-Windows 3.1, the total of all free blocks drops by the size of the
allocation rounded up to the nearest 4K. This is probably because the
386 supports memory mapping in units of 4K. XMSTEST's -w parameter is a
direct response to this difference in behavior. In summary, do not
depend on the total of all free blocks changing by the amount you think
it will.
Finally, there are some speed considerations when using EMBs. For
maximum speed, copy the largest blocks you can. Each copy of an even
number of bytes makes one call to the XMS driver. Each copy of an odd
number of bytes makes two calls to the XMS driver. And each copy of a
single byte requires three calls to the XMS driver in order to reliably
copy the desired byte without corrupting surrounding data (remember that
the XMS driver itself can only copy even numbers of bytes). To get a
good idea of relative speeds of various sizes of copies, run XMSTEST --
it performs some speed tests, returning times in ticks (at 18.2 ticks
per second). Large copies may be hundreds of times faster than multiple
small copies to move the same number of bytes. If you have to make lots
of small copies, try using the interval copy functions (_XMMicopy() et
al.). They make the same number of calls to the XMS driver, but the
loops are tightly coded in assembly and are marginally faster than
performing the same loop yourself. And, as a last consideration, note
that different XMS drivers may be faster or slower. Results from XMSTEST
showed that QEMM was roughly 40% faster than HIMEM.SYS.
III.4 TIPS ON USING UMBS
------------------------
It is probably better not to use UMBs if there isn't a powerful
reason to do so. UMBs are not present on many systems, may be all used
on other systems, and some XMS drivers have buggy UMB support functions.
UMBs are blocks of memory between 640K (the top of conventional
memory) and 1M (in general, the top of memory addressable in real mode).
Systems based on the 80286 do not have UMBs unless there is special
hardware support on the motherboard or elsewhere. Even if the hardware
support is present, an XMS driver is also required to provide the UMB
management functions. Systems based on the 80386 and up do not require
the hardware support, but do require a driver (such as QEMM, EMM386.SYS,
386-to-the-Max, etc.) which uses the processor's on-board memory mapping
capability to make extended memory appear between 640K and 1M, in unused
holes between video memory, ROMs, and anything else inhabiting that
space. Then they may require a separate XMS driver to actually provide
the UMB management functions. QEMM and 386-to-the-Max include XMS
drivers within themselves; EMM386.SYS requires HIMEM.SYS.
Even if the system has the requisite support and drivers, UMBs may
not be available to your application. DOS 5.0, for example, depending on
the configuration, may allocate all UMBs to itself.
Lastly, some XMS drivers have buggy UMB support functions. While
testing XMSIF, I discovered that QEMM 5.12 may return a random error
code when there are no more free UMBs. In fact, it may not return an
error code at all -- it may leave the contents of that register
untouched. Various measures to combat this problem have been taken
within XMSIF with sufficient success that XMSTEST can perform the
UMB-function tests under QEMM 5.12 correctly, but other XMS drivers may
have other bugs. In summary, I would advise that you avoid the use of
UMBs unless there is a powerful reason to do so, and even then your
program should be ready to deal with error returns or unusual results.
III.5 OTHER TIPS
----------------
Neither EMBs nor UMBs are deallocated automatically when a program
exits. If the program does not deallocate EMBs or UMBs that it has
allocated, those EMBs and/or UMBs are stuck, not available to any other
program until the machine is rebooted. Under normal circumstances, it is
easy enough to free EMBs and UMBs when they are no longer needed.
However, an emergency exit due to the user hitting control-break or due
to a hardware error (e.g. the famous "Abort, Retry, Fail?") can cause
EMBs or UMBs to become stuck unless your program takes special measures
to intercept these errors and perform cleanup before exiting. There are
a number of ways to do this and they vary from compiler to compiler.
Look for functions named things like ctrlbrk(), harderr(), and signal().
If you are copying array elements, XMMicopyto(), XMMicopyfrom(), or
_XMMicopy() may be more efficient. These functions allow copying of
elements of fixed size which are separated by gaps also of fixed size.
For example, if you have an array of integers and wish to copy all the
even-indexed elements (a[0], a[2], a[4], etc.), these functions are
faster than calling a standard copying function (XMMcopyto(),
XMMcopyfrom(), or _XMMcopy()) from within a loop.
III.6 FUNCTION GROUPING
-----------------------
The XMSIF functions have been arranged in the library in such a way
as to reduce the number of unnecessary functions linked into your
program. There are currently two groups:
FUNCTIONS VARIABLES
--------- ---------
GROUP 1: XMMlibinit(), XMMgetversion(), _XMMerror, _XMMversion,
XMMcoreleft(), XMMallcoreleft(), _xmsif_vers_vers,
XMMalloc(), XMMrealloc(), XMMfree(), _xmsif_vers_date,
_XMMcopy(), _XMMicopy() _xmsif_vers_time
GROUP 2: UMBcoreleft(), UMBallcoreleft(), none
UMBalloc(), UMBfree()
GROUP 3: XMMrawcall(), XMMraw3() none
If your program references any of the functions or variables in a group,
all the functions and variables in that group will be linked in. Note
that group one will always be linked, since it contains XMMlibinit(),
which all XMSIF-using programs must call.
IV. LIBRARY REFERENCE
---------------------
IV.1 GLOBAL VARIABLES
---------------------
_XMMerror
---------
unsigned char const _XMMerror;
_XMMerror contains the error code from the last XMSIF call. If the
call succeeded, _XMMerror will be 0. If the call failed because the XMS
driver returned an error, _XMMerror contains the error code returned by
the XMS driver. If the call failed because XMSIF detected an error
internally, _XMMerror contains an internal error code. A list of error
code values, their meanings, and #defined constants for them is in
section V.
_XMMversion
-----------
unsigned int const _XMMversion;
_XMMversion contains the XMS version implemented by the XMS driver in
packed BCD format. For example, if the XMS version is 2.0, the value of
_XMMversion will be 0x0200. The high byte of _XMMversion represents two
digits to the left of the decimal point (one digit per nibble) and the
low byte represents two digits to the right of the decimal point (again,
one digit per nibble). This value is the same as that returned by
XMMgetversion().
xmsif_vers_vers, xmsif_vers_date, xmsif_vers_time
-------------------------------------------------
char const xmsif_vers_vers[];
char const xmsif_vers_date[];
char const xmsif_vers_time[];
These are null-terminated strings containing information about the
name and version of the library, the date of assembly, and the time of
assembly, respectively.
IV.2 EMB FUNCTIONS
------------------
_XMMcopy() - copy data
----------
int _XMMcopy(unsigned long clen,
int shan, unsigned long soff,
int dhan, unsigned long doff);
int XMMcopyfrom(unsigned long clen,
int handle, unsigned long soff,
unsigned char far *dest);
int XMMcopyto(unsigned long clen,
unsigned char far *src,
int handle, unsigned long doff);
_XMMcopy() allows painless copying from conventional memory to an
EMB, from an EMB to conventional memory, from one EMB to another, or
even from one point in conventional memory to another. Areas larger than
64K can be copied without special treatment. Clen bytes of data are
copied. If shan is nonzero, it is assumed to be the handle of an EMB,
and soff is treated as a byte offset into the EMB owned by shan. If shan
is zero, soff is treated as a segment:offset far pointer to conventional
memory. The pair of shan and soff indicate where the data is to be
copied from (the source). Dhan and doff work similarly, but indicate
where the data is to be copied to (the destination).
This function returns 0 on success or XMMOOPS on error. The specific
error may be determined from _XMMerror. If clen is 0, the function
returns immediately without error.
XMMcopyfrom() is a macro which provides a convenient interface to
_XMMcopy() for copying data from an EMB to conventional memory. Clen
bytes of data are copied. Handle is the handle of an EMB, and soff is a
byte offset into the EMB owned by handle. The pair of handle and soff
indicate where the data is to be copied from. Dest is a far pointer to
conventional memory and indicates where the data is to be copied to. The
returns are the same as for _XMMcopy().
XMMcopyto() is a macro which provides a convenient interface to
_XMMcopy() for copying data to an EMB from conventional memory. Clen
bytes of data are copied. Src is a far pointer to conventional memory
and indicates where the data is to be copied from. Handle is the handle
of an EMB, and doff is a byte offset into the EMB owned by handle. The
pair of handle and doff indicate where the data is to be copied to. The
returns are the same as for _XMMcopy().
_XMMicopy() - copy data by intervals
-----------
int _XMMicopy(unsigned long nelem, int elsize,
unsigned int sskip, int shan, unsigned long soff,
int dhan, unsigned long doff, unsigned int dskip);
int XMMicopyfrom(unsigned long nelem, int elsize, unsigned int byteskip,
int handle, unsigned long soff,
unsigned char far *dest);
int XMMicopyto(unsigned long nelem, int elsize, unsigned int byteskip,
unsigned char far *src,
int handle, unsigned long doff);
_XMMicopy() allows painless copying of array elements from
conventional memory to an EMB, from an EMB to conventional memory, from
one EMB to another, or even from one point in conventional memory to
another. Calculation of addresses, skipping of unwanted elements, etc.,
are all handled by the function. Elements spread across more than 64K
or totalling more than 64K in length can be copied without special
treatment.
Nelem elements are copied, each of which is elsize bytes long. If
shan is nonzero, it is assumed to be the handle of an EMB, and soff is
treated as a byte offset into the EMB owned by shan. If shan is zero,
soff is treated as a segment:offset far pointer to conventional memory.
The pair of shan and soff indicate where the data is to be copied from
(the source). Dhan and doff work similarly, but indicate where the data
is to be copied to (the destination). Sskip and dskip indicate the
number of bytes between elements in the source and destination,
respectively.
If nelem or elsize is zero, the function returns immediately without
error. If nelem is one, _XMMcopy() is called internally. Elsize must be
in the range 0 through 16384, or the function will return with error
XMM_ELTOOBIG (in _XMMerror). Sskip and dskip must both be in the range 0
through 32768, or the function will return with error XMM_SKTOOBIG (in
_XMMerror).
This function returns 0 on success or XMMOOPS on error. The specific
error may be determined from _XMMerror.
XMMicopyfrom() is a macro which provides a more convenient interface
to _XMMicopy() for copying data from an EMB to conventional memory with
sskip equal to dskip. Nelem elements are copied, each of which is elsize
bytes long. Handle is the handle of an EMB, and soff is a byte offset
into the EMB owned by handle. The pair of handle and soff indicate where
the data is to be copied from. Dest is a far pointer to conventional
memory and indicates where the data is to be copied to. Byteskip is the
number of bytes between elements, the same for both source and
destination. The returns are the same as for _XMMicopy().
XMMicopyto() is a macro which provides a more convenient interface
to _XMMicopy() for copying data to an EMB from conventional memory with
sskip equal to dskip. Nelem elements are copied, each of which is elsize
bytes long. Src is a far pointer to conventional memory and indicates
where the data is to be copied from. Handle is the handle of an EMB, and
doff is a byte offset into the EMB owned by handle. The pair of handle
and doff indicate where the data is to be copied to. Byteskip is the
number of bytes between elements, the same for both source and
destination. The returns are the same as for _XMMicopy().
XMMallcoreleft() - get total of all free EMBs
----------------
unsigned long XMMallcoreleft(void);
unsigned long XMMcoreleft(void);
XMMallcoreleft() returns the total size of all free EMBs, in bytes.
Note that when all EMBs have been allocated, the driver itself returns
an error (0xA0, XMM_NOFREEX). This behavior is masked by
XMMallcoreleft() -- if there are no free EMBs, XMMallcoreleft() returns
0L, not an error. _XMMerror should be checked after calling this
function (it is reset to 0 if there are no free EMBs).
XMMcoreleft() returns the size of the largest free EMB, in bytes.
Note that when all EMBs have been allocated, the driver itself returns
an error (0xA0, XMM_NOFREEX). This behavior is masked by XMMcoreleft() --
if there are no free EMBs, XMMcoreleft() returns 0L, not an error.
_XMMerror should be checked after calling this function (it is reset to
0 if there are no free EMBs).
XMMalloc() - allocate EMB
----------
int XMMalloc(unsigned long bytes);
int XMMrealloc(int handle, unsigned long bytes)
XMMalloc() allocates an EMB. It takes the given number of bytes
and rounds it up to the nearest kilobyte, then allocates an EMB that
many kilobytes in size. It returns the EMB handle assigned by the XMS
driver. _XMMerror should be checked after calling this function.
Note that EMBs cannot be allocated in units smaller than a kilobyte
(1024 bytes). Requesting one byte will allocate 1K; 1025 bytes will
allocate 2K. Requesting zero bytes allocates a handle but no memory.
Note that it is not possible to allocate in one XMMalloc() call more
extended memory than is in the largest free EMB. This is a limitation of
the XMS driver. See section III.3 above for more information on EMB
allocation limitations.
XMMrealloc() adjusts the size of an EMB previous allocated with
XMMalloc(). Handle is the handle of the EMB to be adjusted. The given
number of bytes is rounded up to the nearest kilobyte, then the EMB is
adjusted to that size, if possible. XMMrealloc() returns the handle of
the new block, which is always the same as the handle of the old block.
_XMMerror should be checked after calling this function.
XMMcopyfrom() - copy data from EMB
-------------
int XMMcopyfrom(unsigned long clen,
int handle, unsigned long soff,
unsigned char far *dest);
See _XMMcopy().
XMMcopyto() - copy data to EMB
-----------
int XMMcopyto(unsigned long clen,
unsigned char far *src,
int handle, unsigned long doff);
See _XMMcopy();
XMMcoreleft() - get size of largest free EMB
-------------
unsigned long XMMcoreleft(void);
See XMMallcoreleft().
XMMfree() - deallocate an EMB
---------
int XMMfree(int handle);
This function accepts an EMB handle (as returned by XMMalloc() or
otherwise obtained from the XMS driver) and releases it and the EMB
associated with it (if any). This function returns 0 on success or
XMMOOPS on error. The specific error may be determined from _XMMerror.
XMMgetversion() - obtain XMS version implemented by XMS driver
---------------
int XMMgetversion(void);
This function returns the XMS version implemented by the XMS driver.
The version number is in packed BCD format as in the global variable
_XMMversion, and is in fact the same value. _XMMerror should be checked
after calling this function.
XMMicopyfrom() - copy data by intervals from EMB
--------------
int XMMicopyfrom(unsigned long nelem, int elsize, unsigned int byteskip,
int handle, unsigned long soff,
unsigned char far *dest);
See _XMMicopy().
XMMicopyto() - copy data by intervals to EMB
------------
int XMMicopyto(unsigned long nelem, int elsize, unsigned int byteskip,
unsigned char far *src,
int handle, unsigned long doff);
See _XMMicopy().
XMMlibinit() - initialize XMSIF
------------
int XMMlibinit(void);
XMMlibinit() initializes XMSIF. Any other XMSIF function will return
with error XMM_NOINIT (in _XMMerror) if called before XMMlibinit() has
been called. This function returns 0 on success, XMMOOPS on error, or
NOXMM if no XMS driver is detected. The specific error may be determined
from _XMMerror.
XMMrawcall() - call XMS driver directly
------------
int XMMrawcall(struct XMMregs *regs);
void XMMraw3(struct XMMbigregs *regs);
XMMrawcall() is a raw interface directly to the XMS driver,
supporting calls which use only 16-bit registers. The XMMregs structure
has fields for the AX, BX, DX, SI, and DS registers, which include all
the 16-bit registers used as parameters for calls to the XMS driver. The
values in the structure are placed in the appropriate registers before
the XMS driver is called, and the registers are copied back into the
structure after the XMS driver call returns. Check XMSIF.H or XMSIF.HPP
for the exact format of the XMMregs structure.
Since the XMS specification provides a uniform error indication for
all XMS calls, XMMrawcall() is able to determine if the call performed
caused an error. It returns 0 on success or XMMOOPS on error. The
specific error may be determined from _XMMerror; the error code can also
be found in the low byte of the regBX field of the XMMregs structure.
XMMraw3() is a raw interface directly to the XMS driver, supporting
the calls added in version 3.0 which use 32-bit registers. The
XMMbigregs structure has fields for the EAX, EBX, ECX, and EDX
regusters, which include all the 32-bit registers used as parameters for
calls to the XMS driver. The values in the structure are placed in the
appropriate registers before the XMS driver is called, and the registers
are copied back into the structure after the XMS driver call returns.
Check XMSIF.H or XMSIF.HPP for the exact format of the XMMbigregs
sturcture.
These calls do not provide a uniform error indication, so XMMraw3()
does not return anything. The low 8 bits of EBX (register BL) are copied
to _XMMerror, but they may not be meaningful. In general, it is
necessary to look at the register contents to determine success or
failure. Not all calls use all of each register, so be careful when
examining values. If the XMS driver is version 2.0, _XMMerror is set to
XMM_BADVERS.
Note that this function must not be used on 286 (or earlier)
machines. It uses 386 instructions to access the registers, which will
probably crash older processors. Furthermore, HIMEM versions 3.03
through 3.07 are known to crash when these calls are made on 286 or
earlier machines. It is up to the application to ensure that this call
is only used on 386 or better machines.
XMMraw3() - call XMS driver directly with extended registers
---------
See XMMrawcall().
XMMrealloc() - adjust the size of an EMB
------------
See XMMalloc().
IV.3 UMB FUNCTIONS
------------------
UMBallcoreleft() - get total of all free UMBs
----------------
unsigned long UMBallcoreleft(void);
unsigned long UMBcoreleft(void);
UMBallcoreleft() returns the total size of all free UMBs, in bytes.
Note that when all UMBs have been allocated, the driver itself returns
an error (0xB1, UMB_NOFREEUMB). This behavior is masked by
UMBallcoreleft() -- if there are no free UMBs, UMBallcoreleft() returns
0L, not an error. If the XMS driver does not support UMBs at all, it
returns an error (0x80, XMM_UNIMP). This is also masked by
UMBallcoreleft(). Again, 0L will be returned, not an error. _XMMerror
should be checked after calling this function (it is reset to 0 when a
masked error occurs).
UMBcoreleft() returns the size of the largest free UMB, in bytes.
Note that when all UMBs have been allocated, the driver itself returns
an error (0xB1, UMB_NOFREEUMB). This behavior is masked by UMBcoreleft() --
if there are no free UMBs, UMBcoreleft() returns 0L, not an error. If
the XMS driver does not support UMBs at all, it returns an error (0x80,
XMM_UNIMP). This is also masked by UMBallcoreleft(). Again, 0L will be
returned, not an error. _XMMerror should be checked after calling this
function (it is reset to 0 when a masked error occurs).
UMBalloc() - allocate UMB
----------
void far *UMBalloc(unsigned long bytes, unsigned long *finalsize);
This function allocates an UMB. It takes the given number of bytes
and rounds it up to the nearest multiple of 16, then allocates a UMB
that many bytes in size. The actual size in bytes of the UMB allocated
is returned in the unsigned long pointed to by finalsize. UMBalloc()
returns a far pointer to the UMB; this pointer should be cast to a type
other than void before being used to access the UMB. _XMMerror should be
checked after calling this function.
Note that UMBs cannot be allocated in units smaller than a paragraph
(16 bytes). Requesting one byte will allocate 16; 17 bytes will allocate
32.
Note that it is not possible to allocate in one UMBalloc() call more
extended memory than is in the largest free UMB. This is a limitation of
the XMS driver. See section III.4 above for more information on UMB
allocation limitations.
UMBcoreleft() - get size of largest free UMB
-------------
unsigned long UMBcoreleft(void);
See UMBallcoreleft().
UMBfree() - deallocate an UMB
---------
int UMBfree(void far *handle);
This function accepts a pointer to a UMB (as returned by UMBalloc())
and releases that UMB. If the pointer has been modified, UMBfree()
attempts to return it to canonical form before calling the XMS driver.
However, for maximum reliability, UMBfree() should be called with an
unmodified copy of the pointer returned by UMBalloc(). This function
returns 0 on success or UMBOOPS on error. The specific error may be
determined from _XMMerror.
V. ERROR CODES
--------------
This section is a list of the error codes to which the global
variable _XMMerror may be set, and the values and meanings thereof.
V.1 INTERNAL ERRORS
-------------------
Internal codes indicate an error detected by XMSIF itself.
NAME VALUE MEANING
---- ----- -------
XMM_NOINIT 0x40 XMMlibinit() must be called before any
other XMSIF function can be called.
XMM_UMBHUGE 0x41 Size of UMB requested is larger than
XMS driver can handle (maximum UMB
request size is 1M).
XMM_BADPTR 0x42 The UMB pointer passed to UMBfree()
is corrupt.
XMM_ELTOOBIG 0x43 The element size passed to XMMicopyto(),
XMMicopyfrom(), or _XMMicopy() is too big.
XMM_SKTOOBIG 0x44 The skip size passed to XMMicopyto(),
XMMicopyfrom(), or _XMMicopy() is too big.
XMM_BADVERS 0x45 Certain functions are not supported
under XMS version 2.0.
V.2 XMS DRIVER ERRORS
---------------------
These codes are defined in the XMS specification and are returned by
the XMS driver. They are saved in _XMMerror by XMSIF without alteration.
NAME VALUE MEANING
---- ----- -------
XMM_UNIMP 0x80 Function is not implemented
XMM_VDISK 0x81 VDISK device driver was detected
XMM_A20ERROR 0x82 A20 error occurred
XMM_GENERROR 0x83 General driver error occurred
XMM_UNRECERROR 0x84 Unrecoverable driver error occurred
XMM_NOHMA 0x90 HMA (High Memory Area) does not exist
XMM_HMAUSED 0x91 HMA already allocated
XMM_HMATOOBIG 0x92 Request to allocate HMA denied because
amount of HMA requested is less than
minimum parameter given to XMS driver
on its command line
XMM_HMANOALLOC 0x93 HMA is not allocated
XMM_A20STILLEN 0x94 A20 line is still enabled
XMM_NOFREEX 0xA0 All EMBs (Extended Memory Blocks) are
allocated
XMM_NOFREEXHAN 0xA1 No free EMB handles
XMM_BADXHAN 0xA2 EMB handle is invalid
XMM_BADSRCHAN 0xA3 Source EMB handle is invalid
XMM_BADSRCOFF 0xA4 Source offset in EMB is beyond end of EMB
XMM_BADDESTHAN 0xA5 Destination EMB handle is invalid
XMM_BADDESTOFF 0xA6 Destination offset in EMB is beyond end
of EMB
XMM_BADLENGTH 0xA7 Length is invalid
XMM_COPYOVERLAP 0xA8 Overlap in copy request is invalid
XMM_PARITY 0xA9 Parity error was detected
XMM_NOLOCK 0xAA EMB is not locked
XMM_LOCKED 0xAB EMB is locked
XMM_TOOMANYLOCKS 0xAC EMB lock count overflowed
XMM_LOCKFAIL 0xAD EMB lock failed
XMM_UMBSMALLER 0xB0 UMB (Upper Memory Block) of size requested
is not available; however, a smaller UMB
is available
XMM_NOFREEUMB 0xB1 All UMBs are allocated
XMM_BADUMBHAN 0xB2 UMB handle (same as segment address of
start of UMB) is invalid
VI. THE END
-----------
Technical support via email is available from the following addresses:
INTERNET:
The following are alternate addresses for the same place:
support@picarefy.com
picarefy!support@amc.com
picarefy!support@netcom.com
uunet!uw-coco!amc-gw!picarefy!support
COMPUSERVE:
71261,1731
GENIE:
J.BIRDSALL2
Registrations should be sent to:
James W. Birdsall
11112 NE 124 LN #D204
Kirkland, WA 98034
If you have an email address on any of the networks listed above,
please include it when registering, especially if you are requesting
source code. It is much easier to send the source code by email. Also,
please specify what sort of archive (ZIP, ZOO, ARC, LZH, ARJ, UNIX shar)
you can handle most easily.
NOTE: IF YOU DO NOT PROVIDE AN EMAIL ADDRESS, YOU WILL ONLY RECEIVE
MAJOR VERSION UPDATES. YOU WILL NOT RECEIVE MINOR VERSIONS. PLEASE
PROVIDE AN EMAIL ADDRESS IF YOU HAVE ANY WAY OF DOING SO.
VI.1 ACKNOWLEDGEMENTS
---------------------
Thanks to Bob Parsons of Parsons Technology Inc. for some good suggestions
on the documentation and for providing the original C++ header file.