home *** CD-ROM | disk | FTP | other *** search
- #include "..\MEMORY\MEMORY.HPP"
- #include <dos.h>
-
- // ------------------------------------------------------------------
- // File: XMS.CPP
- // Path: ...\REHACK\MEMORY\XMS.CPP
- // Version: 0.01
- // Author: Pat Reilly
- // CIS Id: 71333,2764
- // Created On: 6/28/93
- // Modified On:
- // Description: XmsMemory class for REHACK. See MEMORY.TXT for
- // more details.
- // Tabs: 4
- // ------------------------------------------------------------------
-
- struct XmsMove
- {
- long size;
- word srcHandle;
- dword srcAddr;
- word destHandle;
- dword destAddr;
- };
-
- // class UMBMemory is used internally by XmsMemory.
- // It represents a Upper Memory Block (UMB) MemoryObject
- // class, but is only used to 'lock' a XmsMemory block from
- // XMS. Since 286 machines won't have UMBs available, its
- // safest to only use these internally. If you want, I suppose
- // you can move the class definition to a header file (ie
- // MEMORY.H) and use this as another MemoryObject derived class.
- // Note that lock() and unlock() do nothing - the UMB is
- // allocated in one place for its life (from allocate() to free()).
-
- class UmbMemory : public MemoryObject
- {
- public:
-
- UmbMemory();
- UmbMemory(word);
-
- virtual MemType type();
- virtual bool allocate(word);
- virtual void free();
- virtual void FAR* lock();
- virtual void unlock();
- virtual long memAvail();
- virtual long maxAvail();
-
- protected:
- word theSeg;
- };
-
- UmbMemory::UmbMemory()
- {
- theSeg = 0U;
- }
-
- UmbMemory::UmbMemory(word sz)
- {
- theSeg = 0U;
- allocate(sz);
- }
-
- MemType UmbMemory::type()
- {
- return MemUnknown;
- }
-
- long UmbMemory::memAvail()
- {
- return 0L;
- }
-
- long UmbMemory::maxAvail()
- {
- return 0L;
- }
-
- bool UmbMemory::allocate(word sz)
- {
- if(theSeg != 0 || sz == 0)
- return false;
-
- theSeg = XmsMemory::allocUmb(sz);
- if( theSeg != 0 )
- memsize = sz;
- return bool(theSeg != 0);
- }
-
- void UmbMemory::free()
- {
- if(theSeg != 0 && lockflag == 0)
- {
- XmsMemory::freeUmb(theSeg);
- theSeg = 0;
- memsize = 0;
- }
- }
-
- void FAR* UmbMemory::lock()
- {
- if( theSeg == 0 )
- return 0;
- lockflag++;
- void FAR* ptr = MK_FP(theSeg, 0);
- return ptr;
- }
-
- void UmbMemory::unlock()
- {
- if( lockflag )
- lockflag--;
- }
-
-
- bool XmsMemory::isInitialized = false;
- XmsMemory* XmsMemory::head = 0;
- long XmsMemory::lastAddr = 0L;
- word XmsMemory::handle = 0U;
- dword XmsMemory::fnAddr = 0UL;
- static XmsMove xmsMove;
-
- // Function called at program exit to remove all XMS allocated.
- void ClearXms()
- {
- word handle = XmsMemory::handle;
- dword fn = XmsMemory::fnAddr;
- if( handle != 0 )
- asm {
- mov dx, handle
- mov ah, 0x0A
- call dword ptr [fn]
- }
- }
-
- #pragma exit ClearXms
-
- XmsMemory::XmsMemory()
- {
- init();
- }
-
- XmsMemory::XmsMemory(word sz)
- {
- init();
- allocate(sz);
- }
-
- bool XmsMemory::allocate(word sz)
- {
- if( handle == 0 || memsize != 0 || sz == 0 || sz > XmsMaxBlkSize )
- return false;
-
- long aAddr = 0;
- XmsMemory* parent = head;
- if( head == 0 )
- {
- if( sz > lastAddr )
- return false;
- }
-
- else
- {
- while( parent->next != 0 )
- {
- aAddr = parent->addr + parent->memsize;
- if( fitsInto( aAddr, parent->next->addr, sz) )
- break;
- parent = parent->next;
- }
- if( parent->next == 0 )
- {
- aAddr = parent->addr+parent->memsize;
- if( !fitsInto( aAddr, lastAddr, sz) )
- return false;
- }
- }
-
- if( parent == 0 )
- {
- next = 0;
- head = this;
- }
- else
- {
- next = parent->next;
- parent->next = this;
- }
- addr = aAddr;
- memsize = sz;
- return true;
- }
-
- void XmsMemory::free()
- {
- XmsMemory *ptr;
-
- if( memsize == 0 || lockflag != 0 )
- return;
-
- if( head == this )
- head = head->next;
- else
- for( ptr = head; ptr->next; ptr = ptr->next )
- if( ptr->next == this )
- {
- ptr->next = ptr->next->next;
- break;
- }
- addr = 0;
- next = 0;
- memsize = 0;
- }
-
- void FAR* XmsMemory::lock()
- {
- if( memsize == 0 )
- return 0;
-
- if( !lockflag )
- {
- // Try and use a UMB block first.
- frame = new UmbMemory(memsize);
- if( !frame || frame->memSize() != memsize )
- {
- delete frame;
- // Next, try using conventional memory.
- frame = new ConvMemory(memsize);
- if( !frame || frame->memSize() != memsize )
- {
- delete frame;
- // Finally, try using EMS memory.
- frame = new EmsMemory(memsize);
- if( !frame || frame->memSize() != memsize )
- {
- delete frame;
- frame = 0;
- return 0;
- }
- }
- }
- // Now lock the frame (can only fail with an EMS block).
- frameBuf = frame->lock();
- if( frameBuf == 0 )
- {
- frame->unlock();
- frame->free();
- delete frame;
- frame = 0;
- return 0;
- }
-
- xmsMove.size = memsize;
- xmsMove.srcHandle = handle;
- xmsMove.srcAddr = addr;
- xmsMove.destHandle = 0;
- xmsMove.destAddr = ((dword)(FP_SEG(frameBuf)) << 16) |
- ((dword)(FP_OFF(frameBuf)));
- word o = FP_OFF( &xmsMove );
- word s = FP_SEG( &xmsMove );
- dword fn = fnAddr;
- asm {
- push ds
- mov si, o
- mov ax, s
- mov ds, ax
- mov ah, 0x0B
- call dword ptr [fn]
- pop ds
- }
- }
- lockflag++;
- return frameBuf;
- }
-
- void XmsMemory::unlock()
- {
- if( !lockflag )
- return;
-
- lockflag--;
- if( lockflag == 0 )
- {
- xmsMove.size = memsize;
- xmsMove.srcHandle = 0;
- xmsMove.srcAddr = ((dword)(FP_SEG(frameBuf)) << 16) |
- ((dword)(FP_OFF(frameBuf)));
- xmsMove.destHandle = handle;
- xmsMove.destAddr = addr;
- word o = FP_OFF( &xmsMove );
- word s = FP_SEG( &xmsMove );
- dword fn = fnAddr;
- asm {
- push ds
- mov si, o
- mov ax, s
- mov ds, ax
- mov ah, 0x0B
- call dword ptr [fn]
- pop ds
- }
- frame->unlock();
- frame->free();
- delete frame;
- frame = 0;
- }
- }
-
- long XmsMemory::memAvail()
- {
- if( handle == 0 )
- return 0L;
-
- long l = lastAddr;
- XmsMemory* ptr;
-
- for( ptr = head; ptr != 0; ptr = ptr->next )
- l -= ptr->memsize;
- return l;
- }
-
- long XmsMemory::maxAvail()
- {
- if( handle == 0 )
- return 0L;
-
- long tmp, l = 0L;
- XmsMemory* ptr;
-
- if( head == 0 )
- l = lastAddr;
- else
- {
- for( ptr = head; ptr->next != 0; ptr = ptr->next )
- {
- tmp = ptr->next->addr - ptr->addr - ptr->memsize;
- if( tmp > l )
- l = tmp;
- }
- tmp = lastAddr - ptr->addr - ptr->memsize;
- if( tmp > l )
- l = tmp;
- }
- return l;
- }
-
- void XmsMemory::init()
- {
- word o, s;
-
- if( !isInitialized )
- {
- isInitialized = true;
-
- if(getvect(0x2F) != 0)
- {
- _AX = 0x4300; // Ensure XMS installed.
- asm int 0x2F;
- if( !(_AL & 0x80) )
- return;
-
- _AX = 0x4310; // Get the function address
- asm int 0x2F;
- o = _BX;
- s = _ES;
- fnAddr = ((dword)(s) << 16) | (dword)o;
- dword fn = fnAddr;
-
- asm {
- mov ah, 0
- call dword ptr [fn]
- }
- if( _AH < 2 )
- return;
-
- asm {
- mov ah, 8
- call dword ptr [fn]
- }
- o = _AX;
- if( o < 64 ) // Must be 64K to be worthwhile
- {
- asm {
- mov ah, 2
- call dword ptr [fn]
- }
- return;
- }
-
- asm {
- mov dx, o
- mov ah, 9
- call dword ptr [fn]
- }
- s = _DX;
- if( !_AX )
- {
- asm {
- mov ah, 2
- call dword ptr [fn]
- }
- return;
- }
- handle = s;
- lastAddr = (long)o * 1024L;
- }
- }
- }
-
- bool XmsMemory::fitsInto(long addr, long next, word sz)
- {
- if( next <= addr || next-addr < sz )
- return false;
- else
- return true;
- }
-
- word XmsMemory::allocUmb(word sz)
- {
- if(handle == 0)
- return 0U;
-
- word s = (sz >> 4) + ((sz & 0x0F) != 0);
- dword fn = fnAddr;
- asm {
- mov dx, s
- mov ah, 0x10
- call dword ptr [fn]
- }
- if( !_AX )
- return 0;
- s = _BX;
- return s;
- }
-
- void XmsMemory::freeUmb(word s )
- {
- if( handle == 0 || s == 0 )
- return;
-
- dword fn = fnAddr;
- asm {
- mov dx, s
- mov ah, 0x11
- call dword ptr [fn]
- }
- }
-