Category : C++ Source Code
Archive   : TI1299.ZIP
Filename : TI1299.ASC
PRODUCT : Borland C++ NUMBER : 1299
VERSION : 3.x
OS : DOS
DATE : March 29, 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 : March 29, 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 : March 29, 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 : March 29, 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 : March 29, 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 : March 29, 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 : March 29, 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.
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/