home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 14 / CDACTUAL.iso / cdactual / demobin / share / program / c / XMS11.ZIP / XMSCPP.TXT < prev    next >
Encoding:
Text File  |  1990-08-31  |  40.1 KB  |  893 lines

  1. Turbo C++ XMS Interface Library
  2. -------------------------------
  3. Version 1.1
  4. by Richard Vuduc
  5. Copyright 1990, Richard Vuduc
  6.  
  7. Contents
  8. --------
  9. Disclaimer................................................. 1
  10.  
  11. The Beginning.............................................. 1
  12.  
  13. Where To Contact Me........................................ 1
  14.  
  15. Introduction............................................... 2
  16.  
  17. Implementation............................................. 2
  18.  
  19. HIMEM.SYS.................................................. 3
  20.  
  21. Overview of the Product.................................... 3
  22.  
  23. XMSDriver Example.......................................... 4
  24.  
  25. XMSHandle Example.......................................... 5
  26.  
  27. Intro to the Routines...................................... 6
  28.  
  29. XMSDriver Class............................................ 6
  30.                       XMSDriver, Inst, GetAvail,
  31.                       GetTotal, InstHMA, ReqHMA............ 7
  32.  
  33.                       RelHMA, GetHMAPtr, A20Enable,
  34.                       A20Disable, A20LEnable, 
  35.                       A20Disable, A20Query, HMAWrite....... 8
  36.  
  37.                       HMARead, EMBAlloc, EMBFree,
  38.                       EMBLock.............................. 9
  39.  
  40.                       EMBUnlock, EMBMoveToExt, 
  41.                       EMBMoveToCon, EMBExtToExt,
  42.                       HndReqPtr, HndRelPtr.................10
  43. XMSHandle Class............................................11
  44.                       XMSHandle............................11
  45.  
  46.                       ~XMSHandle, Realloc,
  47.                       Bounds, GetPtr, SetPtr, IncPtr,
  48.                       SetSwap, GetHandle, GetSize..........12
  49.  
  50.                       Get, Store, CRealloc, GetCache,
  51.                       SetCache, CBounds....................13
  52.  
  53.                       CacheRead, CacheWrite,
  54.                       CacheUpdate..........................14
  55.  
  56. Writing Your Own Get and Store Routines....................14
  57.  
  58. The End....................................................14
  59.  
  60. ----------
  61. DISCLAIMER
  62. ----------
  63. There's no real need for this section; it just makes it look more
  64. official.  The only thing I can think of to put here is that if
  65. there's something wrong in here, too bad.  No false statements were
  66. put in here on purpose.  And, if the earth implodes because something
  67. I wrote in here, so be it.  I will not be responsible.
  68.  
  69. -------------
  70. THE BEGINNING
  71. -------------
  72. Yes, friends, my name is Richard Vuduc and I am 15 years old (not
  73. that that's important or anything, I just thought it was worth
  74. mentioning).  And, for your viewing pleasure, I have assembled a
  75. library of neet little tools to help you make use of extended memory.
  76.  
  77. Early this summer, I bought a copy of Turbo C++.  Here, I would like
  78. to present something I threw together for other owners of Turbo C++
  79. (and soon, if I get a reasonable response, owners of a lot of other
  80. compilers, C or otherwise, including Pascal and Assembly).
  81.  
  82. -------------------
  83. WHERE TO CONTACT ME
  84. -------------------
  85. Forward your messages to me at my CIS account (actually, it's the
  86. account of the place where I work, but I use it for them):
  87.  
  88.         Richard Vuduc, CIS 70022,1332
  89.  
  90. I LOVE getting mail, so please send something.
  91.  
  92. Also, there's no charge for this library of routines.  If you like
  93. them and want to send money to a starving high school student, who
  94. has nothing but the clothes on his back and some loose leaf notebook
  95. paper (keep in mind school starts soon), please feel free to send
  96. donations of money ($1.00 and up, please) to me at:
  97.  
  98.     Richard Vuduc
  99.     3711 S. George Mason Drive, Suite C-1-W
  100.     Falls Church, Va 22041
  101.  
  102. You can, if you want, send me a check made out to your favorite
  103. charity and I'll forward it to them.
  104.  
  105. To register yourself, please leave a note for me at my CIS account
  106. and I'll do so.  Senders of money should also leave a note to let me
  107. know it's coming and for immediate registration.  You don't have to
  108. pay to register (but if you want to see another kid go to college,
  109. you better send something).  Also feel free to distribute this
  110. elsewhere PROVIDED you DO NOT charge anyone for this.  That's my
  111. job, so DON'T DO IT.
  112.                                - 1 -
  113. -----
  114. INTRO
  115. -----
  116. You here all about extended memory in all the IBM computer magazine
  117. headlines these days - but what is it, really?  How can I use it? 
  118. What good is it?  I wondered these same things as well, and I
  119. decided to go out and find out instead of partying all summer. 
  120. Here's what I found...
  121.  
  122.     - There are a couple of ways to access extended memory.  Most
  123. AT's have BIOS routines (int 15h) that provide a means by which to
  124. access extended memory.
  125.  
  126.     - Microsoft's eXtended Memory Manager (XMM) is another way to
  127. access extended memory.  Windows 286 and Windows 3 have HIMEM.SYS
  128. bundled with them.  Not only do they allow access to extended memory,
  129. but also to the High Memory Area (HMA), and the Upper Memory Area
  130. (UMA, 640K to 1024K).  This is (I'm sure you know this already) the
  131. area just above the 1MB region.  More on this later.
  132.  
  133.     - Using the VDISK interface protocol.  This is basically access
  134. to extended memory just like VDISK would.
  135.  
  136.     - Some VCPI thing is another way.  I think you need a 386 for
  137. this one (something I do not currently possess in my home), and is
  138. really a DOS Extender (you can look it up yourself).
  139.  
  140. Anyway, I wanted to be able to access extended memory, too.  Why
  141. extended memory?  Well, it seems like such an untapped resource
  142. (unlike EMS, which you can get three zillion articles on), I decided
  143. to do the public a favor and assemble a FREE library you can use it
  144. with (see the about the author section for more details).  Since I
  145. also have a new compiler (Turbo C++, and the other Tools like the
  146. Turbo Debugger and Assembler), I decided to take this opportunity to
  147. do something great and spectacular and, well, just something "me."
  148.  
  149. --------------
  150. IMPLEMENTATION
  151. --------------
  152. One day I sat down and thought about which of the four methods for
  153. accessing extended memory I should use.  It occurred to me that the
  154. easiest one to implement were the BIOS routines.  Unfortunately, I
  155. decided against that for now.  The BIOS routines were clunky to use;
  156. I eventually opted for the Microsoft HIMEM.SYS method.
  157.  
  158. Two things brought me to HIMEM.  The first was the fact that I did
  159. have the HIMEM driver (with Windows 286 and the upgrade to 3).  I
  160. also saw an article on writing a RAM disk thing using HIMEM as the
  161. interface.  Great - I had example code so this should be easy. 
  162. Unfortunately, the article didn't document much, so I continued
  163. onward looking for more documentation...and eventually found
  164. HIMEM.ARC, available in the Microsoft Systems Forum on CompuServe.
  165.  
  166. Using the document in there, I continued to code (in assembly for
  167. low-level routines, and used C++ for the upper level routines) and
  168. created a single class for managing extended memory - XMSDriver.
  169.  
  170. Although I'm not releasing the source code yet (a teenager is very
  171. self conscious about zits, hair, clothes, and code), I don't want to
  172.                              - 2 -
  173. get harrased about how this C++ class isn't a good object oriented
  174. class design, blah, blah blah...  I realize I didn't design the
  175. heirarchy well (there's only one method), but I didn't need to.  The
  176. real purpose of putting into a class was to encapsulate all the code
  177. and internal data without using globals, etc.  Classes were the
  178. perfectly neet way to put everything together in one package.  So
  179. there.
  180.  
  181. -----
  182. HIMEM
  183. -----
  184. Here's some background info on the theories behind HIMEM.  If you
  185. think you already know enough, so be it.  If you need more info, you
  186. can also get HIMEM.ARC from the MSSYS forum on CompuServe (I'm sure
  187. it's on BIX, too).
  188.  
  189. Okay, here's the run down on what HIMEM is supposed to do for the
  190. average "joe programmer":
  191.  
  192.     - HIMEM will provide a standard method to gain access to the
  193. loads and loads of extended memory that exist in 286, 386, and 486
  194. machines (and I'm sure for the 586, 686, 786, 886, 986, and the
  195. 81086, 81186, 81286, 81386,...88086, 88186, 88286,...90086,...).  It
  196. should also take care of fragmentation and provide support routines
  197. for accessing, allocating, releasing, and moving extended memory.
  198.  
  199.     - HIMEM will provide a standard method by which to access Upper
  200. Memory Blocks.  UMB's are the area betwee 640K and 1024K (normally
  201. used as video memory, LAN and EMS space, BIOS, etc.  Basically, it
  202. returns a segment pointer to that block.
  203.  
  204.     - HIMEM let's you use and execute code from the High Memory Area. 
  205. The HMA is the area between 1024K and 1088K without leaving real
  206. mode.  It does it like this:  Let's say you have the segment:offset
  207. pointer 0xFFFF:0000.  On 286 and 386 systems, you have enough address
  208. lines to access more memory than a regular old 8086.  On 286+
  209. machines, you can enable the 21st address line (8086's have only 20
  210. address lines) and access a little more extended memory, making this
  211. a valid pointer -> 0xFFFF:0BA3.  On 8086's, this would just wrap
  212. around to the beginning of RAM.
  213.  
  214. --------
  215. OVERVIEW
  216. --------
  217. In this section, I want to present a brief overview of all the neet
  218. things you get with this library, and what you're supposed to do to
  219. them.
  220.  
  221. In the library, I have defined two main classes: XMSDriver and
  222. XMSHandle.  XMSDriver is the class which you create an instance of to
  223. handle the nitty gritty details of extended memory interface, and
  224. which you also use to perform low-level extended memory management. 
  225. XMSHandle is one step above XMSDriver.  Basically, you use XMSDriver
  226. to allocate a block and get a pointer to XMSHandle.  Then, you use
  227. XMSHandle to get and store data, etc. in extended memory.  If you
  228. want to use the High Memory Area, however, you will have to currently
  229. use XMSDriver.  Generally, you'll probably use the XMSHandle class
  230. for all your extended memory managment routines.  For the low-level
  231. stuff, you'll have to use XMSDriver (after I present the general
  232.                              - 3 -
  233. outline steps for using each one, you can decide for yourself which
  234. one to use).
  235.  
  236. The XMSDriver class implements most of the HIMEM functions directly,
  237. i.e., most of the XMSDriver functions have a corresponding HIMEM
  238. function (if you look at the XMS spec in HIMEM.ARC, you'll see the
  239. amazing likeness in function).  This is the main reason I call it
  240. the 'low-level managment routines' class.  You should usually only
  241. create ONE instance of the XMSDriver class globally - it's not really
  242. intended to be created multiple times (just as is the case with
  243. HIMEM.SYS itself - I don't think you can load two or twenty-five
  244. copies of HIMEM.SYS at any one time on one machine).  Then, once you
  245. have created an instance of XMSDriver, you simply reference it as you
  246. would any other class and call functions.  Here is a sample of
  247. creating an instance, and it's usage:
  248.  
  249. XMSDriver
  250. ---------
  251. // SOMEPRG.CPP - Does something
  252. #include <iostream.h>
  253. #include "xms.h"            // You MUST include this header file
  254.                         // to use the XMSDriver class.  There
  255.                         // are two header files in the library,
  256.   ...                    // but the other one is included inside
  257.                         // this one (and is for use with
  258.                         // XMSHandle).
  259. XMSDriver XMM;            // Create an instance of the XMSDriver
  260. int something;            // class.  You should do this globally
  261.                            // for access in ALL routines (although
  262.     ...                    // the demo1 program has it in 'main()'
  263.  
  264. void main( void )
  265. {
  266.   int handle;                // You can declare variables to hold
  267.                         // the handle number when you request
  268.     ...                    // extended memory blocks
  269.  
  270.   if( ! XMM.Inst() )        // Determine the presence of HIMEM.SYS
  271.       err_disp( NO_XMS );         // this would be called when there's no
  272.                         // HIMEM.SYS
  273.  
  274.   if( XMM.GetAvail() < 64 )  // Determine whether or not there's
  275.     err_disp( NOT_ENOUGH );  // enough ext mem available for your app
  276.  
  277. //*********High Memory Area Management
  278.   if( ! XMM.ReqHMA() )        // Use this function to get the HMA
  279.     err_disp( NO_HMA );        // this is called when there is no HMA
  280.  
  281.   XMM.A20Enable();            // To use the HMA, turn the A20 line on
  282.   
  283.   hma_ptr = XMM.GetHMAPtr();    // Get the HMA pointer to access HMA
  284.  
  285.   *hma_ptr = 'A';            // Manipulate the pointer
  286.                         // Alternatively, you could use the 
  287.     ...                    // HMARead and HMAWrite functions for a
  288.                         // more independent method
  289.  
  290.   XMM.A20Disable();        // When you're finished, turn A20 off
  291.   XMM.RelHMA();            // and release the HMA for someone else
  292.                                 - 4 -
  293. //*******Extended Memory Block Managment Routines
  294.   handle=XMM.EMBAlloc(10);    // Here, a 10K block has been allocated
  295.                         // in extended memory.  'handle' would
  296.   if( !handle )            // be zero if the request failed
  297.     err_disp( EMB_ERR );
  298.  
  299.   XMM.EMBRealloc( handle, 12 );            // Reallocate blocks, move blocks
  300.   XMM.EMBMoveToExt( handle, 0, ptr, 35 );    // to and from extended memory
  301.   XMM.EMBMoveToCon( ptr, handle, 0, 35 );
  302.     ...
  303.   XMM.EMBFree( handle );    // Free the extended memory block 
  304.   cout << "Done...So what did you think?\n";
  305. }
  306.  
  307. ---------
  308. XMSHandle
  309. ---------
  310. As I have said more than I need to, the XMSDriver is fairly low-level
  311. as far as extended memory management is concerned.  It is for this
  312. reason that I created the XMSHandle class.  You still use EMBAlloc to
  313. allocate a block, but then you call XMSDriver::HndReqPtr and you get
  314. a pointer to the XMSHandle class.  This pointer is simply a handle to
  315. the extended memory block you allocated with EMBAlloc.  Once you have the pointer to
  316. XMSHandle class, you can start using higher-level routines.  These
  317. higher level routines allow you to get individual items from extended
  318. memory.  It basically treats the EMB as a huge array that can contain
  319. any number of different data items that you can retrieve in any
  320. order.  You use routines like Get( item ) and Store( item ).  The Get
  321. and Store routines have been overridden so you can store multiple
  322. different items.  For example, there are Get and Store routines for
  323. characters, longs, integers, and also large blocks of data (void
  324. pointers).  I've included the source for the overridden Get and Store
  325. routines so you can write your own Get and Store routines for other
  326. data types including structures and other classes.  Here's the
  327. breakdown on the procedure...
  328.  
  329. // SOMEPRG1.CPP - Does something else
  330. #include <iostream.h>
  331. #include "xms.h"            // You include this header file as
  332.     ...                    // usual.  It's essentially the same
  333.                         // procedure as with the 'XMSDriver'
  334.                         // class
  335. XMSDriver XMM;            // Create an instance of the XMSDriver
  336. XMSDriver *xmsptr = &XMM;    // AND a GLOBAL pointer to that instance
  337.                         // that MUST be called 'xmsptr.'
  338.     ...                    // The routines in XMSHandle need to
  339.                         // access the XMSDriver, so they do it
  340.                         // via a pointer to any instance of it.
  341. void main( void )
  342. {
  343.   long temp;
  344.   int handle;                // You can declare variables to hold
  345.   XMSHandle *hptr;            // the handle number when you request
  346.     ...                    // extended memory blocks (just as
  347.                         // before).  You also need to create
  348.                         // a pointer to an XMSHandle.
  349.  
  350.   if( ! XMM.Inst() )        // Determine the presence of HIMEM.SYS
  351.       err_disp( NO_XMS );         // this would be called when there's no
  352.                         // HIMEM.SYS
  353.  
  354.                             - 5 -
  355.   if( XMM.GetAvail() < 64 )  // Determine whether or not there's
  356.     err_disp( NOT_ENOUGH );  // enough ext mem available for your app
  357.  
  358. //*******Extended Memory Block Managment Routines
  359.   handle=XMM.EMBAlloc(10);    // Here, a 10K block has been allocated
  360.                         // in extended memory.  'handle' would
  361.   if( !handle )            // be zero if the request failed
  362.     err_disp( EMB_ERR );
  363.  
  364.   hptr = XMM.HndReqPtr(handle);    // Get the handle pointer.  You can
  365.                             // now use hptr to access the EMB
  366.  
  367.   hptr->Realloc( 20 );            // Reallocate to 20K
  368.   hptr->SetPtr( 5 );            // Set the index in the array
  369.   hptr->Get( temp );            // This gets the 6th element in the
  370.                             // EMB (EMB[5], 5 set at SetPtr(5))
  371.     ...
  372.   hptr->Store( 100L );            // Store a number up there.
  373.  
  374.   XMM.HndRelPtr( hptr->GetHandle() );    // Release the pointer when
  375.                                 // you've finished with it
  376.   cout << "No more...Go bye bye!\n";
  377. }
  378.  
  379. The XMSHandle class is more flexible with extended memory transfers. 
  380. You can define your own Get and Store routines (examples later) and
  381. it's probably preferrable that you use XMSHandle (of course, I
  382. couldn't care less which one you use).
  383.  
  384. ------------
  385. THE ROUTINES
  386. ------------
  387. I have not implemented the Upper Memory Block functions yet; I need
  388. to get something started and distributed so I can get a feel for the
  389. response.  For more info on High Mem, just get a copy of HIMEM.ARC on
  390. the Microsoft Systems Forum (go MSSYS, I think).
  391.  
  392. Note that there are some "private:" functions in the XMSDriver class.
  393. These are for internal function use ONLY.
  394.  
  395. When you want to access some extended memory, you need to declare a
  396. class variable (called an "instance," I guess) called whatever you
  397. want to call it (check out the demo, XMSDEMO.CPP, for an example), of
  398. type XMSDriver.  Then you can start calling methods...
  399. * Example:
  400.  
  401. void main( void )
  402. {
  403.     XMSDriver XMM;                  // Declare an XMM
  404.     ...
  405.     Available = XMM.GetAvail( );    // Get available memory
  406.     if( !XMM.ReqHMA( ) )            // Requesting HMA...
  407.     ...
  408. }
  409.  
  410. I have, in the header file, declared an enumerated type called
  411. 'boolean'.  The values in this are True and False.  I hope they don't
  412.                                 - 6 -
  413. collide with any booleans you declare.  They are used internally and
  414. as return values for various functions in the two classes.
  415.  
  416. Also note that I have not implemented any serious error checking.  If
  417. a function returns False (meaning an error occurred), you'll be hard
  418. pressed to find out why.  This is easy to implement - I'm sorry I
  419. didn't do it.  Yeah, yeah, yeah...I know there isn't any way to find
  420. out currently, aside from dumping the registers (the error code is
  421. in the BL register).
  422.  
  423. Below, I have the detailed list of all the functions in the XMSDriver
  424. and XMSHandle functions.  All the XMSDriver functions come first.
  425.  
  426. XMSDriver::XMSDriver( void ) and XMSDriver::~XMSDriver( void );
  427. ---------------------------------------------------------------
  428. These are the constructor and destructor for the driver (wa la!). 
  429. This constructor performs all the necessary initialization functions,
  430. including determining the presence of the HIMEM driver.  The
  431. destructor, when run, does not automatically go through and release 
  432. any unreleased XMS handles that are still open.  You must do this
  433. explicitly.
  434.  
  435. boolean XMSDriver::Inst( void );
  436. --------------------------------
  437. This routine returns True if HIMEM is installed, and XMSDriver has
  438. set everything up for using it; otherwise it returns False if HIMEM
  439. is not installed.
  440.  
  441. long XMSDriver::GetAvail( void );
  442. ---------------------------------
  443. This routine returns the largest available memory block.  Note that
  444. this is not always the same as the Total amount of memory installed
  445. or the total amount of memory free (confused?).  Because extended
  446. memory can be fragmented, this only returns the largest availble
  447. unfragmented block.
  448.  
  449. long XMSDriver::GetTotal( void );
  450. ---------------------------------
  451. Upon return, this function returns the amount of extended memory
  452. free.  This is greater than or equal to the largest available block
  453. of extended memory.
  454.  
  455. ******************* High Memory Functions ***************************
  456. boolean XMSDriver::InstHMA( void )
  457. ----------------------------------
  458. This function determines whether or not the High Memory Area has been
  459. allocated.  It returns True if the high memory area is available,
  460. False if not.
  461.  
  462. boolean XMSDriver::ReqHMA( void )
  463. ---------------------------------
  464. This function requests use of the High Memory Area from HIMEM.SYS. 
  465. It returns True if HMA access is granted to the application, False
  466. otherwise.  Only allocate the HMA if you plan to use a good portion
  467. of it, as other applications may need the HMA.  The HMA is only given
  468. out as one large block to an application, so use it wisely.  Also,
  469. don't forget to cleanup after yourself and release the HMA when you
  470. are through.
  471.  
  472.                                 - 7 -
  473. void XMSDriver::RelHMA( void )
  474. ------------------------------
  475. This function attempts to free the High Memory Area.  There is no
  476. return, because the only way the High Memory Area could be not
  477. released is if you didn't own it in the first place, or if it didn't
  478. exist.
  479.  
  480. void *XMSDriver::GetHMAPtr( void )
  481. ----------------------------------
  482. This function returns a pointer to the High Memory Area, or NULL if
  483. the Area is not available.  Use the pointer returned by this function
  484. WITH CAUTION.  Many of the MS-DOS routines will normalize these
  485. pointers and wrap the addresses around.  For safety's sake, try and
  486. use the HMARead and HMAWrite functions, clumsy as they are.
  487.  
  488. // ********A20 line functions
  489. Recall that the HMA is possible because the 286+ machines have
  490. additional address lines (the 21st line in particular).  The A20 line
  491. is off on the 286 by default, because some applications depend on the
  492. wrap around at the top (I have no idea what applications depend on
  493. this, but that's what Microsoft says).  In order to use the HMA, you
  494. must enable the A20 address line.  Don't forget to disable it after
  495. you are through.
  496.  
  497. boolean XMSDriver::A20Enable( void )
  498. ------------------------------------
  499. This function attempts to enable the A20 line so folks like you can
  500. access the HMA.  It returns True when the A20 line has been
  501. successfully enabled.
  502.  
  503. void XMSDriver::A20Disable( void )
  504. ----------------------------------
  505. This function disables the A20 line.  There is no return value.
  506.  
  507. boolean XMSDriver::A20LEnable( void )
  508. -------------------------------------
  509. This function enables the A20 line locally.  I'm not quite sure what
  510. this means, but I suspect it's so you can enable the line and not
  511. worry about the state of line currently.  In other words, you can
  512. enable the line for your own purposes, regardless of the current
  513. state of the A20 line.  You need to perform a local disable when
  514. you're through.
  515.  
  516. void XMSDriver::A20LDisable( void )
  517. ------------------------------------
  518. "Locally Disable the A20 line" this function has been dubbed (I had
  519. to use a different intro so you wouldn't get too bored).  There is no
  520. return.
  521.  
  522. boolean XMSDriver::A20Query( void )
  523. -----------------------------------
  524. This function queries the state of the A20 line.  It returns True if
  525. the A20 line is enabled, False otherwise.
  526.  
  527. void far *HMAWrite( unsigned ItemSize, unsigned Index, unsigned Length,
  528.                 void far *Data );
  529. ----------------------------------------------------------------------
  530. This function is kind of involved, but I'll explain it as best I can. 
  531. Basically, it's a high level write to high memory area function.  It
  532.                               - 8 -
  533. might be simpler to just maintain a pointer to the High Memory Area
  534. (the HMA begins at 0xFFFF:000A; 64k - 16 bytes long) than to use this
  535. function, but it's up to you.  This function treats the "Data" (last
  536. parameter) as an array.  Each array element is ItemSize long.  The
  537. function will begin copying at Data[ Index ], and will copy Length
  538. elements of the array (including that point).  It returns a pointer
  539. to the High Memory Area pointing to the first element if Data that
  540. was copied, or NULL if the function failed.
  541.  
  542. void far *HMARead( unsigned ItemSize, unsigned Index, unsigned Length, 
  543.                 void far *Data );
  544. ----------------------------------------------------------------------
  545.  
  546. This function is similar to HMAWrite except that it reads from the
  547. High Memory Area, and returns a pointer to Data. It treats the High
  548. Memory Area as an array, each element is ItemSize bytes long.  It
  549. copies Length elements starting at the beginning of the High Memory
  550. Area + Index (in other words, it starts reading at Index offset into
  551. the HMA).  It copies all this junk into Data, and returns the pointer
  552. to Data (NULL on failure).
  553.  
  554. **End of High Memory Area Management Functions (what a mouth full)
  555.  
  556. **************** Extended Memory Block functions
  557. The following functions allow the management of extended memory. 
  558. Basically, you call a function requesting some extended memory.  The
  559. function returns a handle to that memory, and you use that handle to
  560. access the memory block later.  Every time you allocate a block of
  561. extended memory, you are getting what's called an Extended Memory
  562. Block (EMB).  You must use the handle to use the EMB.  For your
  563. convenience, I have provided some routines to copy blocks of data to
  564. and from extended memory.  Actually, I think that you are forced to
  565. use them, whether or not you want to.
  566.  
  567. By the way, one of the Extended Memory Block Management Functions in
  568. Microsoft's HiMEM.SYS is not implemented.  That is function 0x0E -
  569. Query Extended Memory block.  It's used to get info on the Extended
  570. Memory Block.  I will implement it later, so don't cry.
  571.  
  572. NOTE: For from-to extended memory transfers, 'size' must be even. The
  573. function will not succeed unless size is even.  It's also advisable to
  574. word align data you store in the EMB because they generally run much
  575. faster on 2/3/486 machines.
  576.  
  577. unsigned XMSDriver::EMBAlloc( unsigned size )
  578. ---------------------------------------------
  579. This routine will try as hard as it can to allocate a block of
  580. extended memory 'size' bytes in length.  It returns a handle to the
  581. EMB on success, otherwise it will return 0.  The location of this
  582. block in extended memory is not known as it may be moved around by
  583. the driver to relieve fragmentation.
  584.  
  585. void XMSDriver::EMBFree( unsigned handle )
  586. ------------------------------------------
  587. This function frees the handle specified by 'handle.'  There is no
  588. return.
  589.  
  590. long XMSDriver::EMBLock( unsigned handle )
  591. ------------------------------------------
  592.                                - 9 -
  593. I'm not totally sure I understand what this is for, but I'll take a
  594. stab.  This function locks a previously allocated EMB.  Locking the
  595. block guarantees that the HIMEM driver will NOT move it around.  This
  596. way, you can get direct access to the block using the BIOS routines,
  597. or whatever.  This function returns a 32-bit linear address pointer
  598. to the extended memory block, or 0 if an error occurred.
  599.  
  600. boolean XMSDriver::EMBUnlock( unsigned handle )
  601. --------------------------------------------
  602. This function releases the lock that was put on the handle
  603. previously.  Lock counts are maintained, meaning if you lock a block
  604. 3 times, you have to unlock it 3 times as well before it is actually
  605. unlocked (I guess).  It returns True on success, False on failure (so
  606. don't make me feel like a failure and send money or 10 pages of
  607. praise) (just kidding) (not) (way) (no way)...
  608.  
  609. boolean XMSDriver::EMBMoveToExt( unsigned dhandle, unsigned doff,
  610.                             void far *p, long size );
  611. -----------------------------------------------------------------
  612. This function moves a block of conventional memory to extended
  613. memory.  Actually, it really copies the block as opposed to freeing
  614. it.  dhandle is the handle of the destination EMB, and doff is the
  615. offset into the EMB to begin the transfer.  It returns True if the
  616. move was a success, False if it failed.  By the way, 'size' is the
  617. size of the block to move in bytes.
  618.  
  619. boolean XMSDriver::EMBMoveToCon( void far *p,
  620.                             unsigned shandle, unsigned soff,
  621.                             long size );
  622. ------------------------------------------------------------------
  623. This function moves a block of extended memory to conventional memory
  624. (the pointer *p).  shandle is the handle number of the source EMB,
  625. and soff is the offset into the shandle to begin copying.  'size' is
  626. the size in bytes to transfer.  Returns True on success and False on
  627. failure (say, you wouldn't happen to see a pattern in the return
  628. values, would you?).
  629.  
  630. boolean XMSDriver::EMBExtToExt( unsigned dhandle, unsigned doff,
  631.                            unsigned shandle, unsigned soff 
  632.                            long size);
  633. --------------------------------------------------------------------
  634. This function copies data from one EMB to another EMB.  dhandle and
  635. shandle are the destination and source handles respectively (gee, i
  636. bet you would've never guessed that) and doff and soff the offsets
  637. into the block.  'size' is the size in bytes of the transfer.  It
  638. returns True on success, and False on failure.
  639.  
  640. XMSHandle *XMSDriver::HndReqPtr( unsigned handle );
  641. ----------------------------------------
  642. This function returns a pointer to one of the EMB in the form of the
  643. XMSHandle class.  After receiving this pointer, you can use the
  644. XMSHandle functions (described below).  For most, the XMSHandle
  645. routines will provide barely reasonable and tolerable functions for
  646. extended memory block manipulation.
  647.  
  648. void XMSDriver::HndRelPtr( unsigned handle );
  649. ----------------------------------
  650. Call this routine with the handle number (you can use one of the
  651. XMSHandle routines to get the handle number) to release the block
  652.                             - 10 -
  653. back to HIMEM.  It is recommended that you always implicitly do this
  654. (although the XMSDriver destructor will destroy them all for you) in
  655. order to keep memory free for other things.
  656.  
  657.    ***************** The XMSHandle Functions *****************
  658. The XMSHandle classes has various functions for manipulating extended
  659. memory, and an item you might find interesting - a conventional
  660. memory data cache.
  661.  
  662. "A cache? What for?"  Well, as you will discover, the Get and Store
  663. routines are overloaded so that you can retrieve single data items at
  664. any time.  HIMEM.SYS is optimized for large, block moves.  As a
  665. matter of fact, it moves large blocks fairly quickly (even on my
  666. lowly 8mHz 286).  In XMSDEMO2.CPP, you will see the function declared
  667. called 'fill_emb.'  This function is designed to demonstrate the
  668. single data item transfer of the Get/Store routine.  However, the
  669. overhead involved to move a single data item slows performance
  670. incredibly, because the HIMEM driver requires that a parameter block
  671. be setup with pointers here and there...a heck of a lot for just one
  672. byte.  For my small applications, anyway, I just need to operate on
  673. an individual data item basis, so I designed this class around that. 
  674. To speed up transfers, I use a small conventional memory cache to
  675. allow quick updates of extended memory, and quick accesses to the
  676. data there.  I also designed the Get and Store routines so that they
  677. can be overloaded to handle other data types besides the one's that I
  678. have setup - char, int, and long.
  679.  
  680. Before I get into the detail regarding the individual members, I will
  681. attempt to explain how XMSHandle is setup.  After all the functions,
  682. I will explain how to overload the Get and Stores for your own
  683. datatypes.
  684.  
  685. The XMSHandle class has control over a single EMB.  Inside the
  686. XMSHandle class is a variable called 'Handle' that allows it to
  687. access that data through the XMSDriver.  To access that data, it uses
  688. the internal Handle, and calls the XMSDriver through the pointer
  689. called 'XMSDriver *xmsptr.'  This is why you have to declare this in
  690. your programs.
  691.  
  692. The XMSHandle treats it's EMB as a huge array.  Internally, it keeps
  693. a counter called 'Index.'  'Index' points to a byte offset within
  694. the extended memory block.  Using this index as a pointer, I am
  695. assuming that the data kept in extended memory is going to be
  696. accessed pretty heavily as a linear block (as in the example program,
  697. XMSDEMO2.CPP), or array.  When you use the single item Get and Store
  698. routines, they use 'Index' as the place to get data from.
  699.  
  700. Here are all the functions, as you ordered.
  701.  
  702. ****Standard management functions
  703.  
  704. XMSHandle::XMSHandle( unsigned csize );
  705. ---------------------------------------
  706. The constructor for the class excepts one parameter - the size of the
  707. conventional memory data cache, in bytes.  The constructor is called
  708. by the XMSDriver EMB allocation routine when an allocation request
  709. has been made.  csize is set to 50 by default.  If there is not
  710. enough memory to set up a 50 byte cache, it will reduce the size
  711. attempt to 10 bytes.  If a 10 byte request fails, the cache will not
  712.                                 - 11 -
  713. be set up at all.  The cache may be any size up to the size of the
  714. EMB itself.  The cache size MUST be even for the XMSMove functions.
  715.  
  716. XMSHandle::~XMSHandle( void )
  717. -----------------------------
  718. This destructor releases the cache set up before (if it was setup).
  719.  
  720. boolean XMSHandle::Realloc( unsigned ksize )
  721. --------------------------------------------
  722. This function will attempt to reallocate the EMB.  'ksize' is the new
  723. size of the cache in bytes.  If the Realloc function fails, it
  724. returns False, and you must call CRealloc to reallocate the cache
  725. (which gets destroyed before the call to the HIMEM reallocation
  726. function).  Otherwise, the block's size is readjusted.  If the size
  727. of the block reduces so that it's size is less than that of the
  728. cache, the cache size will be reduced to the size of the extended
  729. memory block.  It returns True if it succeeds.
  730.  
  731. boolean XMSHandle::Bounds( long i )
  732. -----------------------------------
  733. This function tests 'i' and determines whether or not it is within
  734. the boundaries of the extended memory block.  Typically, this
  735. function is called internally in SetPtr to determine whether the
  736. requested pointer is within the range of the block.
  737.  
  738. long XMSHandle::GetPtr( void );
  739. -------------------------------
  740. This function returns the position of the pointer 'Index' currently.
  741.  
  742. boolean XMSHandle::SetPtr( long i )
  743. -----------------------------------
  744. Use this function to change the current index pointer to another
  745. place within the EMB.  If 'i' is outside the boundaries of the
  746. Extended Memory Block, it returns False and does not reposition the
  747. pointer.  Otherwise (if successful), it returns True.
  748.  
  749. void XMSHandle::IncPtr( long size = 0 )
  750. -----------------------------------
  751. This function increments the current pointer by 'size' bytes.  If
  752. size is set to zero (the default), the pointer will increment by only
  753. one byte using the ++ operator (for faster increments).  Otherwise,
  754. size is added to 'Index.'  If that sum is outside the range of the
  755. extended memory block, the 'Index' pointer will wrap around (e.g., if
  756. Index is 10, the size of the EMB is 12, and 'size' is 5, the index
  757. pointer will be placed at 3).
  758.  
  759. void XMSHandle::SetSwap( boolean s )
  760. ------------------------------------
  761. This function is not currently implemented.
  762.  
  763. unsigned XMSHandle::GetHandle( void )
  764. -------------------------------------
  765. This function returns the handle number of the EMB that this function
  766. controls.
  767.  
  768. long XMSHandle::GetSize( void )
  769. -------------------------------
  770. This returns the size, in bytes, of the extended memory block.
  771.  
  772.                               - 12 -
  773. *****Get and Store functions
  774. boolean XMSHandle::Get( void far *a, unsigned& len, long off = -1 )
  775. -------------------------------------------------------------------
  776. This will retrieve a large block of memory from extended memory and
  777. copy it to conventional memory, into the pointer 'a'.  len is a
  778. reference parameter that may be modified to show the true length of
  779. the copied block.  'off' indicates where in the extended memory block
  780. the data should be read from.  If 'off' is not specified (the default
  781. value of -1 is used), or if 'off' is explicitly set to -1, then the
  782. data read will occur from the current index pointer.  The function
  783. returns False if the data could not be read, or True if the function
  784. was successful.
  785.  
  786. void XMSHandle::Get( char& a )
  787. void XMSHandle::Get( long& a )
  788. void XMSHandle::Get( int&  a )
  789. ------------------------------
  790. These three functions are used to manipulate the data on a single
  791. data item by single data item basis.  A variable 'a' is read from the
  792. extended memory block beginning at the current 'Index.'  That value
  793. is stored in 'a', with the appropriate type cast.  You may overwrite
  794. these with your own functions.
  795.  
  796. boolean XMSHandle::Store( void far *a, unsigned& len, long off = -1 )
  797. ---------------------------------------------------------------------
  798. This function stores the data in 'a' into the EMB.  The store begins
  799. at 'off' (the -1 default value writes from the current 'Index'), and
  800. 'len' bytes are written into the EMB.  'len' may be changed to
  801. reflect the actual number of bytes written.  The function returns
  802. True on success, or False if there was an error.
  803.  
  804. void XMSHandle::Store( char& a )
  805. void XMSHandle::Store( long& a )
  806. void XMSHandle::Store( int&  a )
  807. --------------------------------
  808. These three functions operate similarly to their Get counterparts. 
  809. They store the value found at 'a' into the EMB, starting at the
  810. current Index pointer.  There is no return value.
  811.  
  812. *****Cache functions
  813. boolean XMSHandle::CRealloc( unsigned size )
  814. --------------------------------------------
  815. CRealloc reallocates the size of the cache.  It returns True if the
  816. cache was successfully set to 'size' bytes, False otherwise.
  817.  
  818. boolean XMSHandle::GetCache( void )
  819. -----------------------------------
  820. Use this function to determine whether or not the cache is currently
  821. on.  It returns True if it's on, False otherwise.
  822.  
  823. void XMSHandle::SetCache( boolean s )
  824. -------------------------------------
  825. Use this function to set the state of the cache.  Set s = True to
  826. enable cache operations, or s = False to disable the cache.
  827.  
  828. boolean XMSHandle::CBounds( long i )
  829. ------------------------------------
  830. This function verifies that 'i' is within the cache boundaries. 
  831. Typically, it is used internally to decide whether or not to update
  832.                                 - 13 -
  833. the cache.  It returns True if the byte at 'i' is in the cache, or
  834. False otherwise.
  835.  
  836. void XMSHandle::CacheRead( void )
  837. ---------------------------------
  838. This function reloads the cache.  Beginning with the data at 'Index',
  839. it will read in the next few sequential bytes until it is able to
  840. fill the cache entirely.
  841.  
  842. void XMSHandle::CacheWrite( void )
  843. ----------------------------------
  844. This function dumps the contents of the current cache and reloads
  845. extended memory.  Data is never directly written to the extended
  846. memory block until an explicit CacheWrite has been performed
  847. (although all the internal functions like Store, Get, SetPtr, IncPtr,
  848. etc. will properly update the cache, thus you should never actually
  849. need to flush the cache buffer manually).
  850.  
  851. void XMSHandle::CacheUpdate( unsigned chksize=1 )
  852. -------------------------------------------------
  853. This function checks for 'chksize' bytes to see if they are in the
  854. cache.  If the requested number of bytes ('chksize') beginning at 
  855. the index pointer 'Index' cannot be found within the cache, it will
  856. load that data into the cache.  Otherwise, it does nothing.
  857.  
  858. ********* Writing your own Get/Store routines
  859. I've tried to make it as simple as possible for the average
  860. "joe-programmer" to use write his/her own Get/Store routines. 
  861. Writing your own Get/Store procedures is very simple - I have
  862. included the source (XMSHRW.CPP) for the XMSHandle Get/Store
  863. routines.
  864.  
  865. Most of the details are in the source, and you can follow the
  866. examples given.  Basically, you must make sure that the cache is
  867. updated, and that you retrieve data from the cache if it's on.  Other
  868. wise, you need to do a direct read from extended memory, calling the
  869. xmsptr->EMBMoveTo... whatever routine.  You also need to check to see
  870. whether the WHOLE data item can be found within the cache, especially
  871. on the write routines.  I have dropped the checking for the Get
  872. routines - you may decide that they should be in.
  873.  
  874. The CacheUpdate command will take care of doing most of the checking. 
  875. You can specify a '1' in the parameter - this tells the cache you are
  876. ABSOLUTELY POSITIVE the cache needs to be updated.  This way, you
  877. avoid the double checking and save a little time.
  878.  
  879. ********************* The End (almost) *****************************
  880. I worked pretty hard on this, and it's still far from perfect (what a
  881. bummer, dude).  I released it in it's "far from perfect" state
  882. because I wanted to see if it was worth all the time I spent.  This
  883. is why it's very important that I get some feedback from you guys. 
  884. It's also a way for me to assess whether or not it's worth it for me
  885. to program all kinds of apps and libraries for other people.  It's
  886. hard to find friends who do this kind of system level programming, so
  887. I'm on my own on most of this stuff.
  888.  
  889.                         - Management
  890.  
  891.  
  892.                         - Last (14) -
  893.