PRODUCT : Borland C++ NUMBER : 1299 VERSION : 3.x OS : DOS DATE : October 25, 1993 PAGE : 1/7 TITLE : Example of how to access extended (XMS) memory. /************************************************************* This program shows how to use XMS. In this example, we simulate a large array in XMS and show that it works by writing values into it and reading them out again. Compile in any model but HUGE and make sure you have HIMEM.SYS or another XMS manager loaded. Many thanks to Ray Duncan, whose book "Extending DOS" (written with many others) was very helpful. ************************************************************/ #ifdef __HUGE__ #error This example cannot be compiled in the huge memory model. #endif #include #include #include #include #define TRUE 1 #define FALSE 0 // BLOCKSIZE will be the size of our real-memory buffer that // we'll swap XMS through (must be a multiple of 1024, since // XMS is allocated in 1K chunks.) Can be > 64K as implemented #define BLOCKSIZE (1024L*16) // XMSParms is a structure for copying information to and from // real-mode memory to XMS memory struct parmstruct { // blocklength is the size in bytes of block to copy unsigned long blockLength; // sourceHandle is the XMS handle of source; 0 means that // sourcePtr will be a 16:16 real-mode pointer, otherwise // sourcePtr is a 32-bit offset from the beginning of the // XMS area that sourceHandle points to unsigned int sourceHandle; PRODUCT : Borland C++ NUMBER : 1299 VERSION : 3.x OS : DOS DATE : October 25, 1993 PAGE : 2/7 TITLE : Example of how to access extended (XMS) memory. far void *sourcePtr; // destHandle is the XMS handle of destination; 0 means that // destPtr will be a 16:16 real-mode pointer, otherwise // destPtr is a 32-bit offset from the beginning of the XMS // area that destHandle points to unsigned int destHandle; far void *destPtr; } XMSParms; // XMSFunc is a function pointer we'll use to call into the XMS // manager void far (*XMSFunc) (void); // XMSBuf is the real-mode memory buffer for transfers to and // from XMS. Make it a huge * instead of a far * if BLOCKSIZE // is >= 64K unsigned long huge *XMSBuf; // XMSHandle is the handle we'll use to refer to our // XMS allocation // when talking to the XMS manager unsigned int XMSHandle; // a flag which says whether the current buffer has been // written into or not char curBlockDirty=FALSE; // the part of our XMS allocation that is currently copied // into real memory int curBlock=-1; // returns TRUE if XMS present, FALSE otherwise char XMSCheck() { _AX=0x4300; geninterrupt(0x2F); return (_AL==0x80); } // GetXMSEntry sets XMSFunc to the XMS Manager entry point // so we can call it later void GetXMSEntry(void) { PRODUCT : Borland C++ NUMBER : 1299 VERSION : 3.x OS : DOS DATE : October 25, 1993 PAGE : 3/7 TITLE : Example of how to access extended (XMS) memory. _AX=0x4310; geninterrupt(0x2F); XMSFunc= (void (far *)(void)) MK_FP(_ES,_BX); } // XMSSize returns the total kilobytes available, and the size // in kilobytes of the largest available block void XMSSize(int *kbAvail, int *largestAvail) { _AH=8; (*XMSFunc)(); *largestAvail=_DX; *kbAvail=_AX; } char GetBuf(void) { XMSBuf=(unsigned long far *) farmalloc(BLOCKSIZE); if (XMSBuf==NULL) { printf("Couldn't allocate %u bytes for real-memory buffer\n", BLOCKSIZE); return FALSE; } return TRUE; } char AllocXMS(unsigned long numberBytes) { int numBlocks; // divide by BLOCKSIZE to get number of blocks numBlocks=(int) (numberBytes/BLOCKSIZE); if ((numberBytes%BLOCKSIZE) != 0) ++numBlocks; _DX=(int) (numBlocks*(BLOCKSIZE/1024)); _AH=9; (*XMSFunc)(); if (_AX==0) { printf("Could not allocate %u %u-byte blocks of XMS\n", numBlocks,BLOCKSIZE); return FALSE; PRODUCT : Borland C++ NUMBER : 1299 VERSION : 3.x OS : DOS DATE : October 25, 1993 PAGE : 4/7 TITLE : Example of how to access extended (XMS) memory. } XMSHandle=_DX; return TRUE; } // CleanUpAndLeave() frees up the XMS handle that we allocated void CleanUpAndLeave(void) { printf("Cleaning up and leaving.\n"); _DX=XMSHandle; _AH=0x0A; (*XMSFunc)(); exit(1); } // GetCorrectBlock() makes sure that the current block stored // in the buffer XMSBuf is the correct block by swapping the // current block out and bringing in a new block void GetCorrectBlock(unsigned int block) { // curBlockDirty is checked for an optimization: we write // out the current buffer back out to XMS only if it's // "dirty" (been written into). if (curBlockDirty) { // write dirty block from XMSBuf out to XMS printf("Writing out used block %d\n", curBlock); XMSParms.sourceHandle=0; XMSParms.sourcePtr=XMSBuf; XMSParms.destHandle=XMSHandle; XMSParms.destPtr=(void far *) (((long)curBlock) * BLOCKSIZE); XMSParms.blockLength=BLOCKSIZE; // pass a pointer to the parameters structure to // the XMS Manager _SI=FP_OFF(&XMSParms); _AH=0x0B; (*XMSFunc)(); if (_AX==0) { printf("Error writing block %d!\n",curBlock); PRODUCT : Borland C++ NUMBER : 1299 VERSION : 3.x OS : DOS DATE : October 25, 1993 PAGE : 5/7 TITLE : Example of how to access extended (XMS) memory. CleanUpAndLeave(); } } // fetch block from XMS into XMSBuf buffer printf("Getting XMS block %d\n",block); XMSParms.sourceHandle=XMSHandle; XMSParms.sourcePtr=(void far *) (((long)block) * BLOCKSIZE); XMSParms.destHandle=0; XMSParms.destPtr=XMSBuf; XMSParms.blockLength=BLOCKSIZE; _SI=FP_OFF(&XMSParms); _AH=0x0B; (*XMSFunc)(); if (_AX==0) { printf("Error reading block %d!\n",block); CleanUpAndLeave(); } curBlockDirty=FALSE; curBlock=block; } // PutVal() puts a value into the "big array" using // GetCorrectBlock() to swap the buffer to/from XMS // if necessary // You could improve performance in PutVal() and GetVal() by // using bit-shifts instead of divides, and by using the '&' // operator instead of '%' to find the position in XMSBuf. void PutVal(unsigned long loc, unsigned long val) { unsigned int block; block=(int) (loc/(BLOCKSIZE/sizeof(long))); if (block != curBlock) GetCorrectBlock(block); // note that the current block in XMSBuf has been used so // we won't forget to write it out later curBlockDirty=TRUE; // the buffer holds BLOCKSIZE bytes, // or BLOCKSIZE/sizeof(long) long's) XMSBuf[loc % (BLOCKSIZE/sizeof(long)) ] = val; } PRODUCT : Borland C++ NUMBER : 1299 VERSION : 3.x OS : DOS DATE : October 25, 1993 PAGE : 6/7 TITLE : Example of how to access extended (XMS) memory. // GetVal() returns the value from a point in the "big array" // using GetCorrectBlock() to swap buffer to/from XMS if // necessary long GetVal(unsigned long loc) { unsigned int block; block=(int) (loc/(BLOCKSIZE/sizeof(long))); if (block != curBlock) GetCorrectBlock(block); return( XMSBuf[loc % (BLOCKSIZE/sizeof(long)) ] ); } int main() { int kbAvail,largestAvail; unsigned long i; if (XMSCheck) printf("XMS Available ...\n"); else { printf("XMS Not Available\n"); return(1); } GetXMSEntry(); XMSSize(&kbAvail,&largestAvail); printf("Kilobytes Available: %d; Largest block: %dK\n", kbAvail,largestAvail); if (!GetBuf()) { printf("Error allocating buffer!\n"); return(1); } // We'll allocate space for 50,000 Long's (200,000 bytes) // in our simulated array. if (!AllocXMS(sizeof(long)*50000L)) return(1); // put a lot of values in our simulated array, and read // them back to make sure that they're out there for (i=0; i<50000L; i++) PRODUCT : Borland C++ NUMBER : 1299 VERSION : 3.x OS : DOS DATE : October 25, 1993 PAGE : 7/7 TITLE : Example of how to access extended (XMS) memory. PutVal(i,i); for (i=0; i<50000L; ++i) if (GetVal(i)!=i) { printf("Error: %lu != %lu\n",i,GetVal(i)); break; } CleanUpAndLeave(); return(0); } DISCLAIMER: You have the right to use this technical information subject to the terms of the No-Nonsense License Statement that you received with the Borland product to which this information pertains.