home *** CD-ROM | disk | FTP | other *** search
- Turbo C++ XMS Interface Library
- -------------------------------
- Version 1.1
- by Richard Vuduc
- Copyright 1990, Richard Vuduc
-
- Contents
- --------
- Disclaimer................................................. 1
-
- The Beginning.............................................. 1
-
- Where To Contact Me........................................ 1
-
- Introduction............................................... 2
-
- Implementation............................................. 2
-
- HIMEM.SYS.................................................. 3
-
- Overview of the Product.................................... 3
-
- XMSDriver Example.......................................... 4
-
- XMSHandle Example.......................................... 5
-
- Intro to the Routines...................................... 6
-
- XMSDriver Class............................................ 6
- XMSDriver, Inst, GetAvail,
- GetTotal, InstHMA, ReqHMA............ 7
-
- RelHMA, GetHMAPtr, A20Enable,
- A20Disable, A20LEnable,
- A20Disable, A20Query, HMAWrite....... 8
-
- HMARead, EMBAlloc, EMBFree,
- EMBLock.............................. 9
-
- EMBUnlock, EMBMoveToExt,
- EMBMoveToCon, EMBExtToExt,
- HndReqPtr, HndRelPtr.................10
- XMSHandle Class............................................11
- XMSHandle............................11
-
- ~XMSHandle, Realloc,
- Bounds, GetPtr, SetPtr, IncPtr,
- SetSwap, GetHandle, GetSize..........12
-
- Get, Store, CRealloc, GetCache,
- SetCache, CBounds....................13
-
- CacheRead, CacheWrite,
- CacheUpdate..........................14
-
- Writing Your Own Get and Store Routines....................14
-
- The End....................................................14
-
- ----------
- DISCLAIMER
- ----------
- There's no real need for this section; it just makes it look more
- official. The only thing I can think of to put here is that if
- there's something wrong in here, too bad. No false statements were
- put in here on purpose. And, if the earth implodes because something
- I wrote in here, so be it. I will not be responsible.
-
- -------------
- THE BEGINNING
- -------------
- Yes, friends, my name is Richard Vuduc and I am 15 years old (not
- that that's important or anything, I just thought it was worth
- mentioning). And, for your viewing pleasure, I have assembled a
- library of neet little tools to help you make use of extended memory.
-
- Early this summer, I bought a copy of Turbo C++. Here, I would like
- to present something I threw together for other owners of Turbo C++
- (and soon, if I get a reasonable response, owners of a lot of other
- compilers, C or otherwise, including Pascal and Assembly).
-
- -------------------
- WHERE TO CONTACT ME
- -------------------
- Forward your messages to me at my CIS account (actually, it's the
- account of the place where I work, but I use it for them):
-
- Richard Vuduc, CIS 70022,1332
-
- I LOVE getting mail, so please send something.
-
- Also, there's no charge for this library of routines. If you like
- them and want to send money to a starving high school student, who
- has nothing but the clothes on his back and some loose leaf notebook
- paper (keep in mind school starts soon), please feel free to send
- donations of money ($1.00 and up, please) to me at:
-
- Richard Vuduc
- 3711 S. George Mason Drive, Suite C-1-W
- Falls Church, Va 22041
-
- You can, if you want, send me a check made out to your favorite
- charity and I'll forward it to them.
-
- To register yourself, please leave a note for me at my CIS account
- and I'll do so. Senders of money should also leave a note to let me
- know it's coming and for immediate registration. You don't have to
- pay to register (but if you want to see another kid go to college,
- you better send something). Also feel free to distribute this
- elsewhere PROVIDED you DO NOT charge anyone for this. That's my
- job, so DON'T DO IT.
- - 1 -
- -----
- INTRO
- -----
- You here all about extended memory in all the IBM computer magazine
- headlines these days - but what is it, really? How can I use it?
- What good is it? I wondered these same things as well, and I
- decided to go out and find out instead of partying all summer.
- Here's what I found...
-
- - There are a couple of ways to access extended memory. Most
- AT's have BIOS routines (int 15h) that provide a means by which to
- access extended memory.
-
- - Microsoft's eXtended Memory Manager (XMM) is another way to
- access extended memory. Windows 286 and Windows 3 have HIMEM.SYS
- bundled with them. Not only do they allow access to extended memory,
- but also to the High Memory Area (HMA), and the Upper Memory Area
- (UMA, 640K to 1024K). This is (I'm sure you know this already) the
- area just above the 1MB region. More on this later.
-
- - Using the VDISK interface protocol. This is basically access
- to extended memory just like VDISK would.
-
- - Some VCPI thing is another way. I think you need a 386 for
- this one (something I do not currently possess in my home), and is
- really a DOS Extender (you can look it up yourself).
-
- Anyway, I wanted to be able to access extended memory, too. Why
- extended memory? Well, it seems like such an untapped resource
- (unlike EMS, which you can get three zillion articles on), I decided
- to do the public a favor and assemble a FREE library you can use it
- with (see the about the author section for more details). Since I
- also have a new compiler (Turbo C++, and the other Tools like the
- Turbo Debugger and Assembler), I decided to take this opportunity to
- do something great and spectacular and, well, just something "me."
-
- --------------
- IMPLEMENTATION
- --------------
- One day I sat down and thought about which of the four methods for
- accessing extended memory I should use. It occurred to me that the
- easiest one to implement were the BIOS routines. Unfortunately, I
- decided against that for now. The BIOS routines were clunky to use;
- I eventually opted for the Microsoft HIMEM.SYS method.
-
- Two things brought me to HIMEM. The first was the fact that I did
- have the HIMEM driver (with Windows 286 and the upgrade to 3). I
- also saw an article on writing a RAM disk thing using HIMEM as the
- interface. Great - I had example code so this should be easy.
- Unfortunately, the article didn't document much, so I continued
- onward looking for more documentation...and eventually found
- HIMEM.ARC, available in the Microsoft Systems Forum on CompuServe.
-
- Using the document in there, I continued to code (in assembly for
- low-level routines, and used C++ for the upper level routines) and
- created a single class for managing extended memory - XMSDriver.
-
- Although I'm not releasing the source code yet (a teenager is very
- self conscious about zits, hair, clothes, and code), I don't want to
- - 2 -
- get harrased about how this C++ class isn't a good object oriented
- class design, blah, blah blah... I realize I didn't design the
- heirarchy well (there's only one method), but I didn't need to. The
- real purpose of putting into a class was to encapsulate all the code
- and internal data without using globals, etc. Classes were the
- perfectly neet way to put everything together in one package. So
- there.
-
- -----
- HIMEM
- -----
- Here's some background info on the theories behind HIMEM. If you
- think you already know enough, so be it. If you need more info, you
- can also get HIMEM.ARC from the MSSYS forum on CompuServe (I'm sure
- it's on BIX, too).
-
- Okay, here's the run down on what HIMEM is supposed to do for the
- average "joe programmer":
-
- - HIMEM will provide a standard method to gain access to the
- loads and loads of extended memory that exist in 286, 386, and 486
- machines (and I'm sure for the 586, 686, 786, 886, 986, and the
- 81086, 81186, 81286, 81386,...88086, 88186, 88286,...90086,...). It
- should also take care of fragmentation and provide support routines
- for accessing, allocating, releasing, and moving extended memory.
-
- - HIMEM will provide a standard method by which to access Upper
- Memory Blocks. UMB's are the area betwee 640K and 1024K (normally
- used as video memory, LAN and EMS space, BIOS, etc. Basically, it
- returns a segment pointer to that block.
-
- - HIMEM let's you use and execute code from the High Memory Area.
- The HMA is the area between 1024K and 1088K without leaving real
- mode. It does it like this: Let's say you have the segment:offset
- pointer 0xFFFF:0000. On 286 and 386 systems, you have enough address
- lines to access more memory than a regular old 8086. On 286+
- machines, you can enable the 21st address line (8086's have only 20
- address lines) and access a little more extended memory, making this
- a valid pointer -> 0xFFFF:0BA3. On 8086's, this would just wrap
- around to the beginning of RAM.
-
- --------
- OVERVIEW
- --------
- In this section, I want to present a brief overview of all the neet
- things you get with this library, and what you're supposed to do to
- them.
-
- In the library, I have defined two main classes: XMSDriver and
- XMSHandle. XMSDriver is the class which you create an instance of to
- handle the nitty gritty details of extended memory interface, and
- which you also use to perform low-level extended memory management.
- XMSHandle is one step above XMSDriver. Basically, you use XMSDriver
- to allocate a block and get a pointer to XMSHandle. Then, you use
- XMSHandle to get and store data, etc. in extended memory. If you
- want to use the High Memory Area, however, you will have to currently
- use XMSDriver. Generally, you'll probably use the XMSHandle class
- for all your extended memory managment routines. For the low-level
- stuff, you'll have to use XMSDriver (after I present the general
- - 3 -
- outline steps for using each one, you can decide for yourself which
- one to use).
-
- The XMSDriver class implements most of the HIMEM functions directly,
- i.e., most of the XMSDriver functions have a corresponding HIMEM
- function (if you look at the XMS spec in HIMEM.ARC, you'll see the
- amazing likeness in function). This is the main reason I call it
- the 'low-level managment routines' class. You should usually only
- create ONE instance of the XMSDriver class globally - it's not really
- intended to be created multiple times (just as is the case with
- HIMEM.SYS itself - I don't think you can load two or twenty-five
- copies of HIMEM.SYS at any one time on one machine). Then, once you
- have created an instance of XMSDriver, you simply reference it as you
- would any other class and call functions. Here is a sample of
- creating an instance, and it's usage:
-
- XMSDriver
- ---------
- // SOMEPRG.CPP - Does something
- #include <iostream.h>
- #include "xms.h" // You MUST include this header file
- // to use the XMSDriver class. There
- // are two header files in the library,
- ... // but the other one is included inside
- // this one (and is for use with
- // XMSHandle).
- XMSDriver XMM; // Create an instance of the XMSDriver
- int something; // class. You should do this globally
- // for access in ALL routines (although
- ... // the demo1 program has it in 'main()'
-
- void main( void )
- {
- int handle; // You can declare variables to hold
- // the handle number when you request
- ... // extended memory blocks
-
- if( ! XMM.Inst() ) // Determine the presence of HIMEM.SYS
- err_disp( NO_XMS ); // this would be called when there's no
- // HIMEM.SYS
-
- if( XMM.GetAvail() < 64 ) // Determine whether or not there's
- err_disp( NOT_ENOUGH ); // enough ext mem available for your app
-
- //*********High Memory Area Management
- if( ! XMM.ReqHMA() ) // Use this function to get the HMA
- err_disp( NO_HMA ); // this is called when there is no HMA
-
- XMM.A20Enable(); // To use the HMA, turn the A20 line on
-
- hma_ptr = XMM.GetHMAPtr(); // Get the HMA pointer to access HMA
-
- *hma_ptr = 'A'; // Manipulate the pointer
- // Alternatively, you could use the
- ... // HMARead and HMAWrite functions for a
- // more independent method
-
- XMM.A20Disable(); // When you're finished, turn A20 off
- XMM.RelHMA(); // and release the HMA for someone else
- - 4 -
- //*******Extended Memory Block Managment Routines
- handle=XMM.EMBAlloc(10); // Here, a 10K block has been allocated
- // in extended memory. 'handle' would
- if( !handle ) // be zero if the request failed
- err_disp( EMB_ERR );
-
- XMM.EMBRealloc( handle, 12 ); // Reallocate blocks, move blocks
- XMM.EMBMoveToExt( handle, 0, ptr, 35 ); // to and from extended memory
- XMM.EMBMoveToCon( ptr, handle, 0, 35 );
- ...
- XMM.EMBFree( handle ); // Free the extended memory block
- cout << "Done...So what did you think?\n";
- }
-
- ---------
- XMSHandle
- ---------
- As I have said more than I need to, the XMSDriver is fairly low-level
- as far as extended memory management is concerned. It is for this
- reason that I created the XMSHandle class. You still use EMBAlloc to
- allocate a block, but then you call XMSDriver::HndReqPtr and you get
- a pointer to the XMSHandle class. This pointer is simply a handle to
- the extended memory block you allocated with EMBAlloc. Once you have the pointer to
- XMSHandle class, you can start using higher-level routines. These
- higher level routines allow you to get individual items from extended
- memory. It basically treats the EMB as a huge array that can contain
- any number of different data items that you can retrieve in any
- order. You use routines like Get( item ) and Store( item ). The Get
- and Store routines have been overridden so you can store multiple
- different items. For example, there are Get and Store routines for
- characters, longs, integers, and also large blocks of data (void
- pointers). I've included the source for the overridden Get and Store
- routines so you can write your own Get and Store routines for other
- data types including structures and other classes. Here's the
- breakdown on the procedure...
-
- // SOMEPRG1.CPP - Does something else
- #include <iostream.h>
- #include "xms.h" // You include this header file as
- ... // usual. It's essentially the same
- // procedure as with the 'XMSDriver'
- // class
- XMSDriver XMM; // Create an instance of the XMSDriver
- XMSDriver *xmsptr = &XMM; // AND a GLOBAL pointer to that instance
- // that MUST be called 'xmsptr.'
- ... // The routines in XMSHandle need to
- // access the XMSDriver, so they do it
- // via a pointer to any instance of it.
- void main( void )
- {
- long temp;
- int handle; // You can declare variables to hold
- XMSHandle *hptr; // the handle number when you request
- ... // extended memory blocks (just as
- // before). You also need to create
- // a pointer to an XMSHandle.
-
- if( ! XMM.Inst() ) // Determine the presence of HIMEM.SYS
- err_disp( NO_XMS ); // this would be called when there's no
- // HIMEM.SYS
-
- - 5 -
- if( XMM.GetAvail() < 64 ) // Determine whether or not there's
- err_disp( NOT_ENOUGH ); // enough ext mem available for your app
-
- //*******Extended Memory Block Managment Routines
- handle=XMM.EMBAlloc(10); // Here, a 10K block has been allocated
- // in extended memory. 'handle' would
- if( !handle ) // be zero if the request failed
- err_disp( EMB_ERR );
-
- hptr = XMM.HndReqPtr(handle); // Get the handle pointer. You can
- // now use hptr to access the EMB
-
- hptr->Realloc( 20 ); // Reallocate to 20K
- hptr->SetPtr( 5 ); // Set the index in the array
- hptr->Get( temp ); // This gets the 6th element in the
- // EMB (EMB[5], 5 set at SetPtr(5))
- ...
- hptr->Store( 100L ); // Store a number up there.
-
- XMM.HndRelPtr( hptr->GetHandle() ); // Release the pointer when
- // you've finished with it
- cout << "No more...Go bye bye!\n";
- }
-
- The XMSHandle class is more flexible with extended memory transfers.
- You can define your own Get and Store routines (examples later) and
- it's probably preferrable that you use XMSHandle (of course, I
- couldn't care less which one you use).
-
- ------------
- THE ROUTINES
- ------------
- I have not implemented the Upper Memory Block functions yet; I need
- to get something started and distributed so I can get a feel for the
- response. For more info on High Mem, just get a copy of HIMEM.ARC on
- the Microsoft Systems Forum (go MSSYS, I think).
-
- Note that there are some "private:" functions in the XMSDriver class.
- These are for internal function use ONLY.
-
- When you want to access some extended memory, you need to declare a
- class variable (called an "instance," I guess) called whatever you
- want to call it (check out the demo, XMSDEMO.CPP, for an example), of
- type XMSDriver. Then you can start calling methods...
- * Example:
-
- void main( void )
- {
- XMSDriver XMM; // Declare an XMM
- ...
- Available = XMM.GetAvail( ); // Get available memory
- if( !XMM.ReqHMA( ) ) // Requesting HMA...
- ...
- }
-
- I have, in the header file, declared an enumerated type called
- 'boolean'. The values in this are True and False. I hope they don't
- - 6 -
- collide with any booleans you declare. They are used internally and
- as return values for various functions in the two classes.
-
- Also note that I have not implemented any serious error checking. If
- a function returns False (meaning an error occurred), you'll be hard
- pressed to find out why. This is easy to implement - I'm sorry I
- didn't do it. Yeah, yeah, yeah...I know there isn't any way to find
- out currently, aside from dumping the registers (the error code is
- in the BL register).
-
- Below, I have the detailed list of all the functions in the XMSDriver
- and XMSHandle functions. All the XMSDriver functions come first.
-
- XMSDriver::XMSDriver( void ) and XMSDriver::~XMSDriver( void );
- ---------------------------------------------------------------
- These are the constructor and destructor for the driver (wa la!).
- This constructor performs all the necessary initialization functions,
- including determining the presence of the HIMEM driver. The
- destructor, when run, does not automatically go through and release
- any unreleased XMS handles that are still open. You must do this
- explicitly.
-
- boolean XMSDriver::Inst( void );
- --------------------------------
- This routine returns True if HIMEM is installed, and XMSDriver has
- set everything up for using it; otherwise it returns False if HIMEM
- is not installed.
-
- long XMSDriver::GetAvail( void );
- ---------------------------------
- This routine returns the largest available memory block. Note that
- this is not always the same as the Total amount of memory installed
- or the total amount of memory free (confused?). Because extended
- memory can be fragmented, this only returns the largest availble
- unfragmented block.
-
- long XMSDriver::GetTotal( void );
- ---------------------------------
- Upon return, this function returns the amount of extended memory
- free. This is greater than or equal to the largest available block
- of extended memory.
-
- ******************* High Memory Functions ***************************
- boolean XMSDriver::InstHMA( void )
- ----------------------------------
- This function determines whether or not the High Memory Area has been
- allocated. It returns True if the high memory area is available,
- False if not.
-
- boolean XMSDriver::ReqHMA( void )
- ---------------------------------
- This function requests use of the High Memory Area from HIMEM.SYS.
- It returns True if HMA access is granted to the application, False
- otherwise. Only allocate the HMA if you plan to use a good portion
- of it, as other applications may need the HMA. The HMA is only given
- out as one large block to an application, so use it wisely. Also,
- don't forget to cleanup after yourself and release the HMA when you
- are through.
-
- - 7 -
- void XMSDriver::RelHMA( void )
- ------------------------------
- This function attempts to free the High Memory Area. There is no
- return, because the only way the High Memory Area could be not
- released is if you didn't own it in the first place, or if it didn't
- exist.
-
- void *XMSDriver::GetHMAPtr( void )
- ----------------------------------
- This function returns a pointer to the High Memory Area, or NULL if
- the Area is not available. Use the pointer returned by this function
- WITH CAUTION. Many of the MS-DOS routines will normalize these
- pointers and wrap the addresses around. For safety's sake, try and
- use the HMARead and HMAWrite functions, clumsy as they are.
-
- // ********A20 line functions
- Recall that the HMA is possible because the 286+ machines have
- additional address lines (the 21st line in particular). The A20 line
- is off on the 286 by default, because some applications depend on the
- wrap around at the top (I have no idea what applications depend on
- this, but that's what Microsoft says). In order to use the HMA, you
- must enable the A20 address line. Don't forget to disable it after
- you are through.
-
- boolean XMSDriver::A20Enable( void )
- ------------------------------------
- This function attempts to enable the A20 line so folks like you can
- access the HMA. It returns True when the A20 line has been
- successfully enabled.
-
- void XMSDriver::A20Disable( void )
- ----------------------------------
- This function disables the A20 line. There is no return value.
-
- boolean XMSDriver::A20LEnable( void )
- -------------------------------------
- This function enables the A20 line locally. I'm not quite sure what
- this means, but I suspect it's so you can enable the line and not
- worry about the state of line currently. In other words, you can
- enable the line for your own purposes, regardless of the current
- state of the A20 line. You need to perform a local disable when
- you're through.
-
- void XMSDriver::A20LDisable( void )
- ------------------------------------
- "Locally Disable the A20 line" this function has been dubbed (I had
- to use a different intro so you wouldn't get too bored). There is no
- return.
-
- boolean XMSDriver::A20Query( void )
- -----------------------------------
- This function queries the state of the A20 line. It returns True if
- the A20 line is enabled, False otherwise.
-
- void far *HMAWrite( unsigned ItemSize, unsigned Index, unsigned Length,
- void far *Data );
- ----------------------------------------------------------------------
- This function is kind of involved, but I'll explain it as best I can.
- Basically, it's a high level write to high memory area function. It
- - 8 -
- might be simpler to just maintain a pointer to the High Memory Area
- (the HMA begins at 0xFFFF:000A; 64k - 16 bytes long) than to use this
- function, but it's up to you. This function treats the "Data" (last
- parameter) as an array. Each array element is ItemSize long. The
- function will begin copying at Data[ Index ], and will copy Length
- elements of the array (including that point). It returns a pointer
- to the High Memory Area pointing to the first element if Data that
- was copied, or NULL if the function failed.
-
- void far *HMARead( unsigned ItemSize, unsigned Index, unsigned Length,
- void far *Data );
- ----------------------------------------------------------------------
-
- This function is similar to HMAWrite except that it reads from the
- High Memory Area, and returns a pointer to Data. It treats the High
- Memory Area as an array, each element is ItemSize bytes long. It
- copies Length elements starting at the beginning of the High Memory
- Area + Index (in other words, it starts reading at Index offset into
- the HMA). It copies all this junk into Data, and returns the pointer
- to Data (NULL on failure).
-
- **End of High Memory Area Management Functions (what a mouth full)
-
- **************** Extended Memory Block functions
- The following functions allow the management of extended memory.
- Basically, you call a function requesting some extended memory. The
- function returns a handle to that memory, and you use that handle to
- access the memory block later. Every time you allocate a block of
- extended memory, you are getting what's called an Extended Memory
- Block (EMB). You must use the handle to use the EMB. For your
- convenience, I have provided some routines to copy blocks of data to
- and from extended memory. Actually, I think that you are forced to
- use them, whether or not you want to.
-
- By the way, one of the Extended Memory Block Management Functions in
- Microsoft's HiMEM.SYS is not implemented. That is function 0x0E -
- Query Extended Memory block. It's used to get info on the Extended
- Memory Block. I will implement it later, so don't cry.
-
- NOTE: For from-to extended memory transfers, 'size' must be even. The
- function will not succeed unless size is even. It's also advisable to
- word align data you store in the EMB because they generally run much
- faster on 2/3/486 machines.
-
- unsigned XMSDriver::EMBAlloc( unsigned size )
- ---------------------------------------------
- This routine will try as hard as it can to allocate a block of
- extended memory 'size' bytes in length. It returns a handle to the
- EMB on success, otherwise it will return 0. The location of this
- block in extended memory is not known as it may be moved around by
- the driver to relieve fragmentation.
-
- void XMSDriver::EMBFree( unsigned handle )
- ------------------------------------------
- This function frees the handle specified by 'handle.' There is no
- return.
-
- long XMSDriver::EMBLock( unsigned handle )
- ------------------------------------------
- - 9 -
- I'm not totally sure I understand what this is for, but I'll take a
- stab. This function locks a previously allocated EMB. Locking the
- block guarantees that the HIMEM driver will NOT move it around. This
- way, you can get direct access to the block using the BIOS routines,
- or whatever. This function returns a 32-bit linear address pointer
- to the extended memory block, or 0 if an error occurred.
-
- boolean XMSDriver::EMBUnlock( unsigned handle )
- --------------------------------------------
- This function releases the lock that was put on the handle
- previously. Lock counts are maintained, meaning if you lock a block
- 3 times, you have to unlock it 3 times as well before it is actually
- unlocked (I guess). It returns True on success, False on failure (so
- don't make me feel like a failure and send money or 10 pages of
- praise) (just kidding) (not) (way) (no way)...
-
- boolean XMSDriver::EMBMoveToExt( unsigned dhandle, unsigned doff,
- void far *p, long size );
- -----------------------------------------------------------------
- This function moves a block of conventional memory to extended
- memory. Actually, it really copies the block as opposed to freeing
- it. dhandle is the handle of the destination EMB, and doff is the
- offset into the EMB to begin the transfer. It returns True if the
- move was a success, False if it failed. By the way, 'size' is the
- size of the block to move in bytes.
-
- boolean XMSDriver::EMBMoveToCon( void far *p,
- unsigned shandle, unsigned soff,
- long size );
- ------------------------------------------------------------------
- This function moves a block of extended memory to conventional memory
- (the pointer *p). shandle is the handle number of the source EMB,
- and soff is the offset into the shandle to begin copying. 'size' is
- the size in bytes to transfer. Returns True on success and False on
- failure (say, you wouldn't happen to see a pattern in the return
- values, would you?).
-
- boolean XMSDriver::EMBExtToExt( unsigned dhandle, unsigned doff,
- unsigned shandle, unsigned soff
- long size);
- --------------------------------------------------------------------
- This function copies data from one EMB to another EMB. dhandle and
- shandle are the destination and source handles respectively (gee, i
- bet you would've never guessed that) and doff and soff the offsets
- into the block. 'size' is the size in bytes of the transfer. It
- returns True on success, and False on failure.
-
- XMSHandle *XMSDriver::HndReqPtr( unsigned handle );
- ----------------------------------------
- This function returns a pointer to one of the EMB in the form of the
- XMSHandle class. After receiving this pointer, you can use the
- XMSHandle functions (described below). For most, the XMSHandle
- routines will provide barely reasonable and tolerable functions for
- extended memory block manipulation.
-
- void XMSDriver::HndRelPtr( unsigned handle );
- ----------------------------------
- Call this routine with the handle number (you can use one of the
- XMSHandle routines to get the handle number) to release the block
- - 10 -
- back to HIMEM. It is recommended that you always implicitly do this
- (although the XMSDriver destructor will destroy them all for you) in
- order to keep memory free for other things.
-
- ***************** The XMSHandle Functions *****************
- The XMSHandle classes has various functions for manipulating extended
- memory, and an item you might find interesting - a conventional
- memory data cache.
-
- "A cache? What for?" Well, as you will discover, the Get and Store
- routines are overloaded so that you can retrieve single data items at
- any time. HIMEM.SYS is optimized for large, block moves. As a
- matter of fact, it moves large blocks fairly quickly (even on my
- lowly 8mHz 286). In XMSDEMO2.CPP, you will see the function declared
- called 'fill_emb.' This function is designed to demonstrate the
- single data item transfer of the Get/Store routine. However, the
- overhead involved to move a single data item slows performance
- incredibly, because the HIMEM driver requires that a parameter block
- be setup with pointers here and there...a heck of a lot for just one
- byte. For my small applications, anyway, I just need to operate on
- an individual data item basis, so I designed this class around that.
- To speed up transfers, I use a small conventional memory cache to
- allow quick updates of extended memory, and quick accesses to the
- data there. I also designed the Get and Store routines so that they
- can be overloaded to handle other data types besides the one's that I
- have setup - char, int, and long.
-
- Before I get into the detail regarding the individual members, I will
- attempt to explain how XMSHandle is setup. After all the functions,
- I will explain how to overload the Get and Stores for your own
- datatypes.
-
- The XMSHandle class has control over a single EMB. Inside the
- XMSHandle class is a variable called 'Handle' that allows it to
- access that data through the XMSDriver. To access that data, it uses
- the internal Handle, and calls the XMSDriver through the pointer
- called 'XMSDriver *xmsptr.' This is why you have to declare this in
- your programs.
-
- The XMSHandle treats it's EMB as a huge array. Internally, it keeps
- a counter called 'Index.' 'Index' points to a byte offset within
- the extended memory block. Using this index as a pointer, I am
- assuming that the data kept in extended memory is going to be
- accessed pretty heavily as a linear block (as in the example program,
- XMSDEMO2.CPP), or array. When you use the single item Get and Store
- routines, they use 'Index' as the place to get data from.
-
- Here are all the functions, as you ordered.
-
- ****Standard management functions
-
- XMSHandle::XMSHandle( unsigned csize );
- ---------------------------------------
- The constructor for the class excepts one parameter - the size of the
- conventional memory data cache, in bytes. The constructor is called
- by the XMSDriver EMB allocation routine when an allocation request
- has been made. csize is set to 50 by default. If there is not
- enough memory to set up a 50 byte cache, it will reduce the size
- attempt to 10 bytes. If a 10 byte request fails, the cache will not
- - 11 -
- be set up at all. The cache may be any size up to the size of the
- EMB itself. The cache size MUST be even for the XMSMove functions.
-
- XMSHandle::~XMSHandle( void )
- -----------------------------
- This destructor releases the cache set up before (if it was setup).
-
- boolean XMSHandle::Realloc( unsigned ksize )
- --------------------------------------------
- This function will attempt to reallocate the EMB. 'ksize' is the new
- size of the cache in bytes. If the Realloc function fails, it
- returns False, and you must call CRealloc to reallocate the cache
- (which gets destroyed before the call to the HIMEM reallocation
- function). Otherwise, the block's size is readjusted. If the size
- of the block reduces so that it's size is less than that of the
- cache, the cache size will be reduced to the size of the extended
- memory block. It returns True if it succeeds.
-
- boolean XMSHandle::Bounds( long i )
- -----------------------------------
- This function tests 'i' and determines whether or not it is within
- the boundaries of the extended memory block. Typically, this
- function is called internally in SetPtr to determine whether the
- requested pointer is within the range of the block.
-
- long XMSHandle::GetPtr( void );
- -------------------------------
- This function returns the position of the pointer 'Index' currently.
-
- boolean XMSHandle::SetPtr( long i )
- -----------------------------------
- Use this function to change the current index pointer to another
- place within the EMB. If 'i' is outside the boundaries of the
- Extended Memory Block, it returns False and does not reposition the
- pointer. Otherwise (if successful), it returns True.
-
- void XMSHandle::IncPtr( long size = 0 )
- -----------------------------------
- This function increments the current pointer by 'size' bytes. If
- size is set to zero (the default), the pointer will increment by only
- one byte using the ++ operator (for faster increments). Otherwise,
- size is added to 'Index.' If that sum is outside the range of the
- extended memory block, the 'Index' pointer will wrap around (e.g., if
- Index is 10, the size of the EMB is 12, and 'size' is 5, the index
- pointer will be placed at 3).
-
- void XMSHandle::SetSwap( boolean s )
- ------------------------------------
- This function is not currently implemented.
-
- unsigned XMSHandle::GetHandle( void )
- -------------------------------------
- This function returns the handle number of the EMB that this function
- controls.
-
- long XMSHandle::GetSize( void )
- -------------------------------
- This returns the size, in bytes, of the extended memory block.
-
- - 12 -
- *****Get and Store functions
- boolean XMSHandle::Get( void far *a, unsigned& len, long off = -1 )
- -------------------------------------------------------------------
- This will retrieve a large block of memory from extended memory and
- copy it to conventional memory, into the pointer 'a'. len is a
- reference parameter that may be modified to show the true length of
- the copied block. 'off' indicates where in the extended memory block
- the data should be read from. If 'off' is not specified (the default
- value of -1 is used), or if 'off' is explicitly set to -1, then the
- data read will occur from the current index pointer. The function
- returns False if the data could not be read, or True if the function
- was successful.
-
- void XMSHandle::Get( char& a )
- void XMSHandle::Get( long& a )
- void XMSHandle::Get( int& a )
- ------------------------------
- These three functions are used to manipulate the data on a single
- data item by single data item basis. A variable 'a' is read from the
- extended memory block beginning at the current 'Index.' That value
- is stored in 'a', with the appropriate type cast. You may overwrite
- these with your own functions.
-
- boolean XMSHandle::Store( void far *a, unsigned& len, long off = -1 )
- ---------------------------------------------------------------------
- This function stores the data in 'a' into the EMB. The store begins
- at 'off' (the -1 default value writes from the current 'Index'), and
- 'len' bytes are written into the EMB. 'len' may be changed to
- reflect the actual number of bytes written. The function returns
- True on success, or False if there was an error.
-
- void XMSHandle::Store( char& a )
- void XMSHandle::Store( long& a )
- void XMSHandle::Store( int& a )
- --------------------------------
- These three functions operate similarly to their Get counterparts.
- They store the value found at 'a' into the EMB, starting at the
- current Index pointer. There is no return value.
-
- *****Cache functions
- boolean XMSHandle::CRealloc( unsigned size )
- --------------------------------------------
- CRealloc reallocates the size of the cache. It returns True if the
- cache was successfully set to 'size' bytes, False otherwise.
-
- boolean XMSHandle::GetCache( void )
- -----------------------------------
- Use this function to determine whether or not the cache is currently
- on. It returns True if it's on, False otherwise.
-
- void XMSHandle::SetCache( boolean s )
- -------------------------------------
- Use this function to set the state of the cache. Set s = True to
- enable cache operations, or s = False to disable the cache.
-
- boolean XMSHandle::CBounds( long i )
- ------------------------------------
- This function verifies that 'i' is within the cache boundaries.
- Typically, it is used internally to decide whether or not to update
- - 13 -
- the cache. It returns True if the byte at 'i' is in the cache, or
- False otherwise.
-
- void XMSHandle::CacheRead( void )
- ---------------------------------
- This function reloads the cache. Beginning with the data at 'Index',
- it will read in the next few sequential bytes until it is able to
- fill the cache entirely.
-
- void XMSHandle::CacheWrite( void )
- ----------------------------------
- This function dumps the contents of the current cache and reloads
- extended memory. Data is never directly written to the extended
- memory block until an explicit CacheWrite has been performed
- (although all the internal functions like Store, Get, SetPtr, IncPtr,
- etc. will properly update the cache, thus you should never actually
- need to flush the cache buffer manually).
-
- void XMSHandle::CacheUpdate( unsigned chksize=1 )
- -------------------------------------------------
- This function checks for 'chksize' bytes to see if they are in the
- cache. If the requested number of bytes ('chksize') beginning at
- the index pointer 'Index' cannot be found within the cache, it will
- load that data into the cache. Otherwise, it does nothing.
-
- ********* Writing your own Get/Store routines
- I've tried to make it as simple as possible for the average
- "joe-programmer" to use write his/her own Get/Store routines.
- Writing your own Get/Store procedures is very simple - I have
- included the source (XMSHRW.CPP) for the XMSHandle Get/Store
- routines.
-
- Most of the details are in the source, and you can follow the
- examples given. Basically, you must make sure that the cache is
- updated, and that you retrieve data from the cache if it's on. Other
- wise, you need to do a direct read from extended memory, calling the
- xmsptr->EMBMoveTo... whatever routine. You also need to check to see
- whether the WHOLE data item can be found within the cache, especially
- on the write routines. I have dropped the checking for the Get
- routines - you may decide that they should be in.
-
- The CacheUpdate command will take care of doing most of the checking.
- You can specify a '1' in the parameter - this tells the cache you are
- ABSOLUTELY POSITIVE the cache needs to be updated. This way, you
- avoid the double checking and save a little time.
-
- ********************* The End (almost) *****************************
- I worked pretty hard on this, and it's still far from perfect (what a
- bummer, dude). I released it in it's "far from perfect" state
- because I wanted to see if it was worth all the time I spent. This
- is why it's very important that I get some feedback from you guys.
- It's also a way for me to assess whether or not it's worth it for me
- to program all kinds of apps and libraries for other people. It's
- hard to find friends who do this kind of system level programming, so
- I'm on my own on most of this stuff.
-
- - Management
-
-
- - Last (14) -