home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c017 / 34.ddi / CSWAPXXX.ZIP / SWAP.DOC < prev    next >
Encoding:
Text File  |  1990-09-06  |  38.8 KB  |  1,125 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.                                   swap()
  15.  
  16.  
  17.                                 Version 2.0
  18.                              September 6, 1990
  19.  
  20.  
  21.                             Copyright (C) 1990
  22.                            by Marty Del Vecchio
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40.  
  41.  
  42.  
  43.  
  44.      This package (swap) includes an MS-DOS assembly-language routine that
  45.      can be called from a C program.  It will swap most of the current
  46.      program to extended memory (supplied by an XMS driver, such as
  47.      HIMEM.SYS), expanded memory (EMS version 3.2 or 4.0), or disk, thus
  48.      freeing up more memory for DOS.  It will then execute another program
  49.      in its place, and re-load the original program to its original state. 
  50.      This allows large DOS programs to execute other programs without the
  51.      original program taking up DOS memory.
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59.                              Table of Contents
  60.  
  61.  
  62.      I.   Introduction . . . . . . . . . . . . . . . . . . .  1
  63.  
  64.      II.  File List  . . . . . . . . . . . . . . . . . . . .
  65.  
  66.      III. Functional Description . . . . . . . . . . . . . .
  67.           A.   DOS Memory Management . . . . . . . . . . . .
  68.           B.   How swap() Works  . . . . . . . . . . . . . .
  69.           C.   Swapping to Different Media . . . . . . . . .
  70.                1.   Extended Memory  . . . . . . . . . . . .
  71.                2.   Expanded Memory  . . . . . . . . . . . .
  72.                3.   DOS Disk File  . . . . . . . . . . . . .
  73.  
  74.      IV.  Calling the swap() Routine . . . . . . . . . . . .
  75.           A.   The swap() Return Code  . . . . . . . . . . .
  76.           B.   Program File to Execute . . . . . . . . . . .
  77.           C.   Program Command Line  . . . . . . . . . . . .
  78.           D.   EXEC Return Code Pointer  . . . . . . . . . .
  79.           E.   Swap File Name  . . . . . . . . . . . . . . .
  80.  
  81.      V.   Customizing swap() . . . . . . . . . . . . . . . .
  82.           A.   Memory Model  . . . . . . . . . . . . . . . .
  83.           B.   Swap Locations  . . . . . . . . . . . . . . .
  84.           C.   Swap Order  . . . . . . . . . . . . . . . . .
  85.  
  86.      VI.  Information  . . . . . . . . . . . . . . . . . . .
  87.  
  88.  
  89.  
  90.  
  91.  
  92. I.   Introduction
  93.  
  94.      Most DOS programmers have figured out how to load and execute another
  95. DOS program from inside their own program (using the DOS EXEC system call). 
  96. Almost invariably, they discover a rather large problem:  with their
  97. original program loaded in memory, there is little memory left over in which
  98. to run the child program.  Often, there is not enough memory to run even a
  99. DOS shell.
  100.  
  101.      This package provides a solution to that problem.  The swap() routine
  102. will swap the original program to extended memory, expanded memory, or disk,
  103. then free up that memory.  It will then execute the DOS program specified by
  104. the caller.  When that program terminates, the original program is loaded
  105. back into memory, and it continues execution.
  106.  
  107.      By default, the swap() routine will attempt to swap the current program
  108. to extended memory;if that fails, it will try expanded memory; if that
  109. fails, it will try a DOS disk file.  By re-assembling the routine in
  110. (SWAP.ASM), the programmer can specify which combination of the above media
  111. to attempt to swap to, and in which order the swapping shall be attempted. 
  112. Details are provided in Chapter V.
  113.  
  114.      These routines have been tested with DOS versions 3.30 and 4.01.  They
  115. have been tested with Turbo C version 2.0, Microsoft C version 5.10, and
  116. Turbo C++ version 1.0.  All of these compilers comply with the Microsoft DOS
  117. standard segment naming and ordering convention (called DOSSEG in MASM).  If
  118. your C compiler does not support this convention, please contact me:  these
  119. routines should be adaptable to any compiler.
  120.  
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145.  
  146. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          1
  147.  
  148.  
  149.  
  150.  
  151.  
  152.  
  153. II.  File List
  154.  
  155.      The following files should be found in this release:
  156.  
  157.      SWAP.DOC       This file.  Documentation for use of the swap() routine.
  158.      SWAP.ASM       The assembly-language source file for the swap()
  159.                     routines.  Requires the Microsoft Macro Assembler
  160.                     version 5.10 to assemble.
  161.      SWAP.H         Header file for SWAP.ASM.  Contains function prototypes
  162.                     and constant definitions needed to use swap().
  163.  
  164.      SWAPS.OBJ      swap() assembled for Small memory model.
  165.      SWAPM.OBJ      swap() assembled for Medium memory model.
  166.      SWAPC.OBJ      swap() assembled for Compact memory model.
  167.      SWAPL.OBJ      swap() assembled for Large memory model.
  168.  
  169.      SWAPXMS.OBJ    swap() assembled for Small memory model, will only
  170.                     attempt to swap to XMS extended memory.
  171.      SWAPEMS.OBJ    swap() assembled for Small memory model, will only
  172.                     attempt to swap to EMS expanded memory.
  173.      SWAPMEM.OBJ    swap() assembled for Small memory model, will attempt to
  174.                     swap to extended memory, then expanded.
  175.      SWAPDISK.OBJ   swap() assembled for Small memory model, will only
  176.                     attempt to swap to DOS disk file.
  177.  
  178.      SWAP.MAK       MAKE file to create all possible combinations of swap()
  179.                     routine (memory model vs. swap location).
  180.  
  181.      SWAPTEST.C     Sample program that uses swap().  Demonstrates how to
  182.                     call swap().
  183.      SWAPTEST.MSC   MAKE file to create SWAPTEST.EXE with Microsoft C
  184.                     version 5.10.
  185.      SWAPTEST.LNK   Linker response file for SWAPTEST.EXE and Microsoft C.
  186.      SWAPTEST.PRJ   Project file to create SWAPTEST.EXE with Turbo C version
  187.                     2.0.
  188.      SWAPTEST.OBJ   Object module file for SWAPTEST.C, compiled with
  189.                     Microsoft C version 5.10.
  190.      SWAPTEST.EXE   Sample executable demonstrating swap(), compiled with
  191.                     Microsoft C version 5.10
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          2
  208.  
  209.  
  210.  
  211.  
  212.  
  213.  
  214. III. Functional Description
  215.  
  216.  
  217. A.  DOS Memory Management
  218.  
  219.      The functionality of swap() depends on the simplicity and
  220. predictability of the DOS memory management system.  The same system that
  221. was introduced in DOS version 1.0 in 1981 is still in use in DOS 4.01,
  222. released in 1989.
  223.  
  224.      Basically, DOS has 640K of memory to manage:  the hex addresses from
  225. 0000 to 9FFF (understanding DOS segments is not a requirement of this
  226. package!).  Once DOS is loaded, there is one large block of free memory.  In
  227. front of this block is a 16-byte header called a Memory Control Block (MCB),
  228. which contains information about the block such as how large it is.
  229.  
  230.      Whenever a DOS program is loaded and executed, DOS allocates part of
  231. this block of memory and assigns it to the program.  The program's block of
  232. memory gets its own MCB, and the remaining memory gets another MCB.  DOS
  233. functions 48 hex (allocate memory block), 49 hex (free memory block), and 4A
  234. hex (change size of memory block) all affect the chain of memory blocks
  235. maintained by DOS.
  236.  
  237.      Here is a map of what happens when FATHER.EXE, a mythical example
  238. program, is loaded into DOS and then executes a child program (CHILD.EXE):
  239.  
  240.  Before executing CHILD         Address        While executing CHILD
  241. +------------------------+       0000        +------------------------+
  242. +                        +                    +                       +
  243. +    Used by DOS, TSRs   +                   +    Used by DOS, TSRs   +
  244. +------------------------+       2000        +------------------------+
  245. +                        +                   +                        +
  246. +    FATHER.EXE, the     +                   +      FATHER.EXE        +
  247. +    current program     +                   +                        +
  248. +------------------------+       4000        +------------------------+
  249. +                        +                   +                        +
  250. +    DOS Free Memory     +                   +    CHILD.EXE, the      +
  251. +                        +                   +    current program     +
  252. +                        +                   +                        +
  253. +                        +       6000        +                        +
  254. +                        +                   +                        +
  255. +                        +                   +                        +
  256. +                        +                   +                        +
  257. +                        +                   +                        +
  258. +                        +                   +------------------------+
  259. +                        +                   +                        +
  260. +                        +                   +    DOS Free Memory     +
  261. +                        +                   +                        +
  262. +                        +                   +                        +
  263. +------------------------+       9FFF        +------------------------+
  264.  
  265.  
  266.  
  267.  
  268. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          3
  269.  
  270.  
  271.  
  272.  
  273.  
  274.  
  275.  
  276.      As you can see, when CHILD.EXE is executed, DOS splits up the large
  277. "DOS Free Memory" block into two smaller blocks--one used by CHILD, and the
  278. other still marked as free.  And notice that while CHILD is running, FATHER
  279. is still occupying a large block of DOS memory.  This puts a limit on the
  280. size program that CHILD can be.  
  281.  
  282.      In this picture, since there is free memory immediately after CHILD,
  283. CHILD can call DOS system function 4A hex to increase the size of its memory
  284. block.  A program can always decrease the size of its memory block, as long
  285. as it no longer accesses information outside of its block.  And finally, a
  286. program can call DOS system function 48 hex to allocate a new block of
  287. memory, if any DOS free memory exists.
  288.  
  289.  
  290. B.   How swap() Works
  291.  
  292.      As stated above, DOS memory management is very predictable.  The swap()
  293. routine takes advantage of this predictability in the following manner. 
  294. Assume that the FATHER.EXE program above uses swap() to execute CHILD.EXE.
  295.  
  296.      1)   swap() takes the contents of the memory block that FATHER occupies
  297.           and saves it outside of DOS memory (to extended memory, expanded
  298.           memory, or disk).
  299.  
  300.      2)   swap() calls DOS system function 4A hex to shrink the size of
  301.           FATHER's memory block.  It makes this block as small as possible
  302.           while still keeping the swap() routine in memory.
  303.  
  304.      3)   swap() calls DOS system function 4B hex to execute the CHILD.EXE
  305.           program (as specified by the caller).
  306.  
  307.      4)   When CHILD.EXE terminates, swap() again calls DOS system function
  308.           4A hex, this time to restore FATHER's block to the same size it
  309.           was before swap() was called.
  310.  
  311.      5)   Finally, swap() retrieves the original contents of FATHER's memory
  312.           block (saved in step 1) and restores the FATHER.EXE program to its
  313.           original state.
  314.  
  315.      The key here is step 4.  We assume that the CHILD program is not a
  316. Terminate and Stay Resident (TSR) program, and that when it terminates, the
  317. memory it occupied is again free.  If this is the case, the DOS system call
  318. 4A will predictably let us grow our memory block back to its original size.
  319.  
  320.  
  321.  
  322.  
  323.  
  324.  
  325.  
  326.  
  327.  
  328.  
  329. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          4
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.      Following are maps of what happens in the above process:
  337.  
  338.   Before FATHER       While CHILD is      After CHILD ends
  339.   executes CHILD      executing           and FATHER is restored
  340. +-------------------+-------------------+-------------------+    0000
  341. +  DOS, TSRs, etc.  +  DOS, TSRs, etc.  +  DOS, TSRs, etc.  +
  342. +-------------------+-------------------+-------------------+    2000
  343. +    FATHER.EXE     + FATHER (swap code)+    FATHER.EXE     +
  344. +    (original      +-------------------+    (restored      +    3000
  345. +      size)        +                   +    to original    +
  346. +                   +     CHILD.EXE     +       size)       +
  347. +                   +                   +                   +
  348. +                   +                   +                   +
  349. +-------------------+                   +-------------------+    6000
  350. +                   +                   +                   +
  351. + DOS Free Memory   +                   + DOS Free Memory   +
  352. +                   +                   +                   +
  353. +                   +-------------------+                   +
  354. +                   +                   +                   +
  355. +                   + DOS Free Memory   +                   +
  356. +                   +                   +                   +
  357. +                   +                   +                   +
  358. +                   +                   +                   +
  359. +                   +                   +                   +
  360. +                   +                   +                   +
  361. +                   +                   +                   +
  362. +-------------------+-------------------+-------------------+
  363.  
  364.      There are several restrictions on use of the swap() routine, but the
  365. bottom line is that swap() lets you free all but about 2 kilobytes
  366. (depending on memory model) of your program's memory for use by another
  367. program.  Guidelines for using swap() are described in Chapter IV.
  368.  
  369.  
  370. C.   Swapping to Different Media
  371.  
  372.      The swap() routine can be configured to swap your program to extended
  373. memory, expanded memory, or disk.  This behavior can be customized, as
  374. discussed in Chapter V.  This section details how swap() deals with each
  375. media.
  376.  
  377.  
  378. 1.   Extended Memory
  379.  
  380.      Extended memory is a term used to describe memory available on 80286-
  381. and 80386-based personal computers that is not DOS memory.  On such a PC,
  382. the first megabyte of memory (0K to 1024K) is used for DOS memory, system
  383. BIOS, adapter BIOS and memory, etc.  Memory above 1024K is called extended
  384. memory.  It is generally not used by DOS, which is designed to run on the
  385. 8086 processor, which can only address the first 1024K of memory.
  386.  
  387.      Until recently, there had been no standard way of allocating,
  388.  
  389.  
  390. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          5
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397. addressing, and using this memory.  Access to extended memory depended to
  398. some extent on a vendor's hardware design.  The main problem was ownership
  399. of this memory--there was no standard way that one program (such as a disk
  400. cache) could tell another program that it owned a block of extended memory.
  401.  
  402.      Recently, however, the eXtended Memory Specification (XMS) was released
  403. by Microsoft and other companies.  The XMS spec described a driver that
  404. controlled all of extended memory, and defined a programming interface to
  405. that driver that applications could use to allocate, use, and free extended
  406. memory.  Microsoft ships such a driver (called HIMEM.SYS) with its Windows
  407. programs, and it is generally available on bulletin boards.
  408.  
  409.      In order for swap() to use extended memory, HIMEM.SYS (or an
  410. equivalent) must be loaded.  If a system has extended memory, but is not
  411. running HIMEM.SYS, swap() will not be able to see the memory, and cannot use
  412. it.
  413.  
  414.      When swap() tries to use XMS extended memory, it first checks to see if
  415. HIMEM.SYS (or an equivalent) is loaded.  It does this by calling the
  416. multiplex interrupt (2F hex) with 4300 hex in AX.  If HIMEM.SYS is loaded,
  417. it returns 80 hex in AL.
  418.  
  419.      Once swap() confirms that HIMEM.SYS is loaded, it calculates how much
  420. extended memory it needs, and calls XMS function 09, allocate extended
  421. memory block.  If this call fails (there is not enough extended memory
  422. free), the swap to extended memory fails.  If the allocate call succeeds,
  423. swap() will call XMS function 0B hex, move extended memory block.  It sets
  424. up a request packet to copy the contents of the current program's memory
  425. block into the extended memory block it has just allocated.
  426.  
  427.      The swap() routine will then shrink its DOS memory block, call the DOS
  428. EXEC function to execute the requested program, and restore the DOS memory
  429. block to its original size.  Details on this are found in Chapter III.
  430.  
  431.      Once the executed program terminates, swap() again calls XMS function
  432. 0B hex to copy the contents of the program from extended memory back into
  433. the DOS memory block.  Finally, XMS function 0A hex is called to free the
  434. allocated extended memory, and swap() returns to the caller.
  435.  
  436.      At this point, the original program resides in DOS memory just as it
  437. did before the call to swap(), and swap() has completely cleaned up its
  438. usage of XMS extended memory.
  439.  
  440.  
  441. 2.   Expanded Memory
  442.  
  443.      Expanded memory is a special kind of memory that can be added to any
  444. PC, but that does not exist in the processor's address space.  Lotus, Intel,
  445. and Microsoft (LIM) defined a specification of how to provide expanded
  446. memory in a PC and how to access it from an application program.  The
  447. original specification was called LIM EMS 3.2, and it was updated to version
  448. 4.0 later.  The swap() routine can use either version.
  449.  
  450.  
  451. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          6
  452.  
  453.  
  454.  
  455.  
  456.  
  457.  
  458.  
  459.      Expanded memory is provided in a system in 16-kilobyte (16K) blocks
  460. called pages.  An application can allocate and free any number of pages in
  461. units referred to by handles.  When the application wants to copy data to or
  462. from a page, it asks the EMS driver to map that page into the PC's address
  463. space.  The EMS driver has at a minimum four locations where it can map a
  464. page of expanded memory.  These locations are found in the first megabyte of
  465. the PC address space, between 640K and 1 megabyte.
  466.  
  467.      When swap() tries to use EMS memory, it first checks to see if an EMS
  468. driver is loaded.  It does this by looking at interrupt vector 67 hex.  The
  469. string "EMM0XXXX" should be found 13 bytes after that vector address.  If it
  470. is, an EMS driver is loaded.
  471.  
  472.      Once swap() confirms that an EMS driver is loaded, it calculates how
  473. many 16K expanded memory pages it needs, and calls EMS function 43 hex,
  474. allocate expanded memory pages.  If this call fails (there is not enough
  475. expanded memory free), the swap to expanded memory fails.
  476.  
  477.      If this call succeeds, swap() will copy the contents of the current
  478. program to the expanded memory block in 16K blocks.  To do this, swap() must
  479. repeatedly call EMS function 44 hex, map EMS pages to physical memory. 
  480. After mapping each page (page 0, 1, etc.), swap() simply does a memory copy
  481. of 16K bytes.  This process is repeated until the entire program has been
  482. saved to expanded memory.
  483.  
  484.      The swap() routine will then shrink its DOS memory block, call the DOS
  485. EXEC function to execute the requested program, and restore the DOS memory
  486. block to its original size.  Details on this are found in Chapter III.
  487.  
  488.      Once the executed program terminates, swap() again calls EMS function
  489. 44 hex to map the expanded memory into physical memory.  It will copy the
  490. contents of the program from expanded memory back into the DOS memory area
  491. in 16K blocks.  Finally, EMS function 45 hex is called to free the allocated
  492. expanded memory, and swap() returns to the caller.
  493.  
  494.      At this point, the original program resides in DOS memory just as it
  495. did before the call to swap(), and swap() has completely cleaned up its
  496. usage of EMS expanded memory.
  497.  
  498.  
  499. 3.   DOS Disk File
  500.  
  501.      The swap() routine can also use the DOS file system to temporarily save
  502. the contents of a program.  Although swapping to a disk file is much slower
  503. than swapping to extended or expanded memory, it is just as effective.
  504.  
  505.      The name of the disk file to swap to is provided by the caller as a
  506. parameter (see Chapter IV).  The swap() routine will call DOS function 3C
  507. hex to create the file (or truncate it if it already exists).  The file will
  508. be hidden to provide a small amount of protection for the file.  If this
  509. create fails, the swap to disk fails.
  510.  
  511.  
  512. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          7
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.      Once the file is created, the swap() routine follows a procedure
  521. similar to the one outlined above in the description for swapping to EMS. 
  522. The original program will be swapped in 32K blocks to the disk file, and the
  523. data will be written with DOS function 40 hex.  If any call to this function
  524. fails, it most likely means that the disk is full.  If this happens, swap()
  525. will delete the file and the swap to disk fails.  Otherwise, swap() will
  526. continue to write 32K blocks until the entire program is saved.
  527.  
  528.      The swap() routine will then shrink its DOS memory block, call the DOS
  529. EXEC function to execute the requested program, and restore the DOS memory
  530. block to its original size.  Details on this are found in Chapter III.
  531.  
  532.      When the executed program terminates, swap() will call DOS function 3D
  533. hex to open the swap file.  If the file is not there, swap() cannot restore
  534. the original program.  If this is the case, swap() will print an error
  535. message to the screen and terminate the program.
  536.  
  537.      If the file is there, swap() will simply read 32K chunks from the disk
  538. file into the DOS memory block using DOS function 3F hex.  It will do this
  539. until the entire contents of the original program are restored.  It will
  540. then call DOS function 41 hex to delete the swap file.
  541.  
  542.      At this point, the original program resides in DOS memory just as it
  543. did before the call to swap(), and swap() has completely cleaned up its
  544. usage of DOS file system.
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552.  
  553.  
  554.  
  555.  
  556.  
  557.  
  558.  
  559.  
  560.  
  561.  
  562.  
  563.  
  564.  
  565.  
  566.  
  567.  
  568.  
  569.  
  570.  
  571.  
  572.  
  573. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          8
  574.  
  575.  
  576.  
  577.  
  578.  
  579.  
  580. IV.  Calling the swap() Routine
  581.  
  582.      The swap() routine is designed to be called in a C program.  This is
  583. the function prototype for swap():
  584.  
  585.      int swap (char *program_name, 
  586.                char *command_line, 
  587.                char *exec_return, 
  588.                char *swap_fname);
  589.  
  590.      For example, to execute a DOS command shell and display a directory of
  591. the C: drive, you would call swap() this way:
  592.  
  593. swap_ret = swap ("C:\\COMMAND.COM", "/C dir c:", 
  594.                  &exec_ret, "swap.fil");
  595.  
  596.      When building a program with swap(), you should put the swap() object
  597. module as early in the linker list as possible.  In Turbo C, it should be
  598. the first line in the project file (see SWAPTEST.PRJ).  For Microsoft C, it
  599. should be the first object module in the link line (or linker response file,
  600. see SWAPTEST.LNK).
  601.  
  602.      The swap() routine also returns an int return code to the caller. 
  603. Following are descriptions for this return code and each of these
  604. parameters.
  605.  
  606.  
  607. A.   The swap() Return Code
  608.  
  609.      The swap() function returns an integer signifying the success or
  610. failure of the swap and execute.  There are four possible return codes,
  611. defined in SWAP.H and here:
  612.  
  613. 0:   SWAP_OK             Success--current program swapped, new program
  614.                          executed, and original program restored.
  615. 1:   SWAP_NO_SHRINK      Unable to shrink DOS memory block size.  This
  616.                          indicates an error in the DOS Memory Control Block
  617.                          chain.  This is unlikely.
  618. 2:   SWAP_NO_SAVE        Unable to save the program to any one of extended
  619.                          memory, expanded memory, or disk (depending on
  620.                          which functions were assembled).  The new program
  621.                          was not executed.
  622. 3:   SWAP_NO_EXEC        Unable to execute the new program.  If swap()
  623.                          returns this code, the parameter exec_return (see
  624.                          below) contains the DOS error code.
  625.  
  626.      In addition to these return codes, there is another type of error that
  627. can occur in swap() that cannot be returned to the caller.  If swap() is
  628. unable to restore the original program after calling the DOS EXEC function,
  629. it cannot return to the caller, because the caller no longer exists in DOS
  630. memory!
  631.  
  632.  
  633.  
  634. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          9
  635.  
  636.  
  637.  
  638.  
  639.  
  640.  
  641.      This error can occur for various reasons.  If the program was swapped
  642. to disk, and the disk file was erased by the executed program, swap() has
  643. nothing to restore.  In addition, errors encountered in the XMS or EMS
  644. driver can cause this.
  645.  
  646.      If this happens, swap() takes the only recourse it can.  It prints the
  647. following message to the screen (the standard error location):
  648.  
  649.      SWAP:  Unable to restore program.
  650.  
  651. It then calls the DOS terminate function (4C hex) and returns 255 (FF hex)
  652. as the return code.  This code can be queried using the DOS ERRORLEVEL
  653. function.  For example, take this batch file:
  654.  
  655. Echo About to execute program that demonstrates swap():
  656. swaptest
  657. if errorlevel 255 echo ERROR--swap() was unable to restore program!
  658.  
  659.  
  660. B.   Program File to Execute
  661.  
  662.      The first parameter, program_name, is a pointer to a null-terminated
  663. string that contains the full path and file name of the program to be
  664. executed.  For example, if you wanted to execute a program called TEST.EXE
  665. which is located in C:\UTIL, you must call swap() this way:
  666.  
  667. swap_ret = swap ("C:\\UTIL\\TEST.EXE", "", &exec_ret, "swap.fil");
  668.  
  669.      The swap() routine will NOT perform any of the following functions:
  670.  
  671.      --   Search the DOS PATH environment variable for a program to execute
  672.      --   Redirect input or output with "<" or ">"
  673.      --   Execute a batch file
  674.  
  675. These functions cannot be performed by swap() because they are functions of
  676. the DOS command processor (COMMAND.COM), and not of the DOS EXEC function
  677. that swap() uses.  In order to do any of these things, you must explicitly
  678. invoke the command processor with the "/C" parameter, which tells
  679. COMMAND.COM to execute the following command.  For example, to execute a DIR
  680. command and redirect the output to "DIR.OUT", you would call swap() this
  681. way:
  682.  
  683. char *comspec;
  684. comspec = getenv ("COMSPEC");
  685. swap_ret = swap (comspec, "/C dir >dir.out", &exec_ret, "swap.fil");
  686.  
  687.      The getenv() function is available in Turbo C and Microsoft C to search
  688. the current environment for a string.  We use it here to determine where the
  689. DOS command processor is.
  690.  
  691.      When passing the program name parameter to swap(), remember that the
  692. "\" character, used by DOS as a directory and file name separator, is used
  693.  
  694.  
  695. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         10
  696.  
  697.  
  698.  
  699.  
  700.  
  701.  
  702. by C to indicate an escape character.  Thus, to specify the file
  703. C:\UTIL\TEST.EXE, you must pass it as "C:\\UTIL\\TEST.EXE".
  704.  
  705.      The program to be executed MUST NOT be a Terminate and Stay Resident
  706. (TSR) program.  If it is, swap() will not be able to grow the original
  707. program's DOS memory block back to its original size, and thus the original
  708. program cannot be re-loaded.
  709.  
  710.      Finally, remember that the name of the program file to be executed can
  711. be up to 127 characters (not including the null byte) long.  It is the
  712. responsibility of the caller to ensure that the file name is not longer than
  713. 127 characters.
  714.  
  715.  
  716. C.   Program Command Line
  717.  
  718.      The second parameter passed to swap() is the command line for the
  719. program to be run.  It is a pointer to a null-terminated string that can be
  720. between 0 and 127 characters (not including the null byte).  This string
  721. should NOT include the name of the program to be executed--that should be
  722. passed as a separate parameter as described above.
  723.  
  724.      For example, to call PKZIP.EXE and have it store files in TEST.ZIP, you
  725. would call swap() this way:
  726.  
  727. swap_ret = swap ("C:\\UTIL\\PKZIP.EXE", "-r -P test.zip *.*",
  728.                  &exec_ret, "swap.fil");
  729.  
  730.      It is the responsibility of the caller to ensure that the command line
  731. parameter string is not longer than 127 characters.
  732.  
  733.  
  734. D.   EXEC Return Code Pointer
  735.  
  736.      The exec_return is a pointer to a char (8-bit value) where swap() will
  737. return information from the DOS EXEC function.  What is stored in this
  738. location depends on whether the swap() routine was successful or not.
  739.  
  740.      If swap() is successful (and returns 0, SWAP_OK described above),
  741. exec_return contains the return code of the executed program.  This is the
  742. same value used in the DOS ERRORLEVEL comparison.  For example, if you
  743. execute PKUNZIP.EXE, and it gives the return code 0, meaning success, the
  744. byte pointed to by exec_return will be set to 0 by swap().
  745.  
  746.      If swap() is unsuccessful when trying to execute the new program (and
  747. returns 3, SWAP_NO_EXEC), swap() will place the DOS error code returned by
  748. EXEC in this value.  According to the DOS technical reference manual, this
  749. code will be one of the following (as defined in SWAP.H):
  750.  
  751. 0x01: BAD_FUNC           Bad DOS function number--unlikely
  752. 0x02: FILE_NOT_FOUND     File not found--couldn't find program_name
  753. 0x05: ACCESS_DENIED      Access denied--couldn't open program_name 
  754.  
  755.  
  756. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         11
  757.  
  758.  
  759.  
  760.  
  761.  
  762.  
  763. 0x08: NO_MEMORY          Insufficient memory to run program_name
  764. 0x0A: BAD_ENVIRON        Invalid environment segment--unlikely  
  765. 0x0B: BAD_FORMAT         Format invalid--unlikely
  766.  
  767.      Here is an example of how to handle error codes:
  768.  
  769. char swap_ret, exec_ret;
  770.  
  771. swap_ret = swap ("C:\\UTIL\\PKUNZIP.EXE", "D:TEST.ZIP",
  772.                  &exec_ret, "swap.fil");
  773. switch (swap_ret)
  774.    {
  775.    case SWAP_OK:         printf ("Successful, program returned %d.",
  776.                                  (int)exec_ret);
  777.                          break;
  778.    case SWAP_NO_SHRINK:  printf ("Unable to shrink DOS memory block.");
  779.                          break;
  780.    case SWAP_NO_SAVE:    printf ("Unable to save program.");
  781.                          break;
  782.    case SWAP_NO_EXEC:    printf ("EXEC call failed.  DOS error is: ");
  783.                          switch (exec_ret)
  784.                             {
  785.                             case BAD_FUNC:
  786.                               printf ("Bad function.\n");   break;
  787.                             case FILE_NOT_FOUND:
  788.                               printf ("File not found.\n"); break;
  789.                             case ACCESS_DENIED:
  790.                               printf ("Access denied.\n");  break;
  791.                             case NO_MEMORY:
  792.                               printf ("Insufficient memory.\n"); break;
  793.                             case BAD_ENVIRON:
  794.                               printf ("Bad environment.\n"); break;
  795.                             case BAD_FORMAT:
  796.                               printf ("Bad format.\n");      break;
  797.                             }
  798.                          break;
  799.    }
  800.  
  801.  
  802. E.   Swap File Name
  803.  
  804.      The final parameter, swap_fname, is a pointer to a null-terminated
  805. string that contains the name of a DOS file to swap the program to.  This is
  806. only needed if the version of swap() you are using will try to swap to disk
  807. (see Chapter V).  If your version of swap() does not swap to disk at all,
  808. you can pass the null string ("").  This parameter will only be used if
  809. swap() actually does try to swap to disk.
  810.  
  811.      This file name need not be a complete drive, directory, and path name. 
  812. If the drive is not specified, it will be placed on the current drive; if
  813. the directory is not specified, it will be placed in the current directory.
  814.  
  815.  
  816.  
  817. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         12
  818.  
  819.  
  820.  
  821.  
  822.  
  823.  
  824.      It is up to the caller to choose a safe file name for swapping.  You
  825. should not choose the name of a file that already exists, as that file's
  826. contents will be lost when swap() truncates it.  Because of this, you should
  827. be very careful not to specify the same file name for two different programs
  828. that use swap().
  829.  
  830.      For example, if you have a program called A.EXE which uses swap to call
  831. program B.EXE, which uses swap() to call program C.EXE, you must choose
  832. different swap file names.  If you use the same name (such as
  833. "C:\\SWAP.FIL") for both, you will have a problem.  When A.EXE executes
  834. B.EXE, c:\swap.fil will be created, and will contain the contents of A.EXE. 
  835. When B.EXE executes C.EXE and swaps to c:\swap.fil, the original contents of
  836. the file will be erased and replaced with the contents of B.EXE.  When C.EXE
  837. terminates, c:\swap.fil will be read and deleted.  Then when B.EXE
  838. terminates, the swap() routine in A.EXE will not find c:\swap.fil, and
  839. cannot reload A.EXE.
  840.  
  841.  
  842.  
  843.  
  844.  
  845.  
  846.  
  847.  
  848.  
  849.  
  850.  
  851.  
  852.  
  853.  
  854.  
  855.  
  856.  
  857.  
  858.  
  859.  
  860.  
  861.  
  862.  
  863.  
  864.  
  865.  
  866.  
  867.  
  868.  
  869.  
  870.  
  871.  
  872.  
  873.  
  874.  
  875.  
  876.  
  877.  
  878. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         13
  879.  
  880.  
  881.  
  882.  
  883.  
  884.  
  885. V.   Customizing swap()
  886.  
  887.  
  888.      As stated above, the default configuration for swap() is a Small memory
  889. model function that attempts to swap in the following order:
  890.  
  891.      1)   XMS extended memory
  892.      2)   EMS expanded memory
  893.      3)   DOS disk file
  894.  
  895. You can use the included source file (SWAP.ASM) and the Microsoft Macro
  896. Assembler (MASM) version 5.10 to create a customized version of the swap()
  897. routine.  To assemble the default version of swap(), you would execute MASM
  898. this way:
  899.  
  900.      masm swap /mx;
  901.  
  902. This will create SWAP.OBJ.  You must include "/mx" on the MASM command line
  903. to tell the assembler to maintain the case of all variables and functions
  904. declared there.  This allows the C program to access these items.
  905.  
  906.      This chapter describes how to create a customized version of swap().
  907.  
  908.  
  909. A.   Memory Model
  910.  
  911.      The swap() routine supports four different C memory models, as defined
  912. by Microsoft C and Turbo C.  The memory model specifies the number of
  913. segments for code and data, and therefore the size of a code or data
  914. pointer.  These memory models are:
  915.  
  916.      Small     One code segment, one data segment
  917.      Medium    Multiple code segments, one data segment
  918.      Compact   One code segment, multiple data segments
  919.      Large     Multiple code segments, multiple data segments
  920.  
  921.      The swap() source file (SWAP.ASM) can be configured to support any of
  922. these memory models with a command-line parameter to MASM.  The parameter is
  923. "/D" followed by the memory model name.  For example, to create a Large-
  924. model version of swap, you would assemble SWAP.ASM this way:
  925.  
  926.      masm swap /DLarge;
  927.  
  928. This will create SWAP.OBJ that supports the Large memory model.  Case does
  929. not matter when specifying the memory model.  If no model is specified, the
  930. Small model is assumed.
  931.  
  932.      In addition to the above memory models, the Huge model should also be
  933. supported by assembling swap() for the Large model.
  934.  
  935.  
  936. B.   Swap Locations
  937.  
  938.  
  939. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         14
  940.  
  941.  
  942.  
  943.  
  944.  
  945.  
  946.  
  947.      The swap() routine will swap a program to extended memory, expanded
  948. memory, or disk file.  If you do not want swap() to swap to all of these
  949. locations, you can re-assemble a custom version.  However, it is more
  950. flexible to allow swap() to try all three locations, and the extra code
  951. needed is minimal.
  952.  
  953.      This is also done with the "/D" switch to MASM, followed by one of the
  954. following:  "xms" for extended memory, "ems" for expanded memory, and "disk"
  955. for disk file.  For example, to assemble a version of swap() that only
  956. attempts to swap to extended memory, you would say:
  957.  
  958.      masm swap /Dxms;
  959.  
  960. To assemble a version of swap() that attempts to swap to extended or
  961. expanded memory, you would say:
  962.  
  963.      masm swap /Dxms /Dems;
  964.  
  965.  
  966. C.   Swap Order
  967.  
  968.      By default, swap() attempts to swap the original program to extended
  969. memory;  if that fails, to expanded memory;  and if that fails, to disk. 
  970. Naturally, it will only try each location if that location was specified
  971. (see B. above).
  972.  
  973.      If you want to change the order in which swap() attempts to save the
  974. program, you must change the source file SWAP.ASM manually.  Towards the end
  975. of the file, there is a routine called save_program.  It contains three
  976. blocks of code:
  977.  
  978. ; ********************************************************************
  979. IFDEF USE_XMS
  980. IF1
  981.    %out -- XMS extended memory
  982. ENDIF
  983.                 call    save_xms  ; Try saving to XMS extended memory
  984.                 jnc     save_ok   ; Carry clear == success, all done
  985. ENDIF
  986. ; ********************************************************************
  987.  
  988.  
  989. ; ********************************************************************
  990. IFDEF USE_EMS
  991. IF1
  992.    %out -- EMS expanded memory
  993. ENDIF
  994.                 call    save_ems  ; Try saving to EMS expanded memory
  995.                 jnc     save_ok   ; Carry clear == success, all done
  996. ENDIF
  997. ; ********************************************************************
  998.  
  999.  
  1000. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         15
  1001.  
  1002.  
  1003.  
  1004.  
  1005.  
  1006.  
  1007.  
  1008.  
  1009. ; ********************************************************************
  1010. IFDEF USE_DISK
  1011. IF1
  1012.    %out -- DOS disk file
  1013. ENDIF
  1014.                 call    save_disk ; Try saving to DOS disk file
  1015.                 jnc     save_ok   ; Carry clear == success, all done
  1016. ENDIF
  1017. ; ********************************************************************
  1018.  
  1019.      These blocks are separated by lines of asterisks.  If you wanted swap()
  1020. to try expanded memory, then extended memory, then disk, you would move the
  1021. middle block (IFDEF USE_EMS to ENDIF) before the middle block.  This is
  1022. easily accomplished with most text editors.  
  1023.  
  1024.  
  1025.  
  1026.  
  1027.  
  1028.  
  1029.  
  1030.  
  1031.  
  1032.  
  1033.  
  1034.  
  1035.  
  1036.  
  1037.  
  1038.  
  1039.  
  1040.  
  1041.  
  1042.  
  1043.  
  1044.  
  1045.  
  1046.  
  1047.  
  1048.  
  1049.  
  1050.  
  1051.  
  1052.  
  1053.  
  1054.  
  1055.  
  1056.  
  1057.  
  1058.  
  1059.  
  1060.  
  1061. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         16
  1062.  
  1063.  
  1064.  
  1065.  
  1066.  
  1067.  
  1068. VI.  Information
  1069.  
  1070.      The original version of swap() was released as SWAP100.ZIP on April 1,
  1071. 1990.  That version supported swapping to expanded memory and to disk, and
  1072. only the Small memory model was supported.
  1073.  
  1074.      Since then, I have had several requests to support more memory models. 
  1075. After prodding from people such as Norman Hamer (Seattle) and William Wood
  1076. (Burke, VA), I finally found the time to do this.  In addition, I added
  1077. support for XMS extended memory, and also made the swap() routine
  1078. configurable as described in Chapter V.
  1079.  
  1080.      This version of swap(), like the previous version, is hereby released
  1081. into the public domain for free use by anybody and everybody.  However, all
  1082. the contents of this package still remain:
  1083.  
  1084.      Copyright (C) 1990 by Marty Del Vecchio.  All Rights Reserved.
  1085.  
  1086.  
  1087.      I am not requesting a donation from anybody who uses the contents of
  1088. this package.  I just ask that everybody who does use swap() realize the
  1089. amount of work that went into coding it, and appreciate the fact that I
  1090. fully commented and released the source code for free.
  1091.  
  1092.      Everything in this package is provided with no warranties whatsoever,
  1093. express nor implied, for any functionality or fitness for a specific
  1094. purpose.  The author will not be held responsible for any damages whatsoever
  1095. resulting from the use of this package, and will not be held responsible if
  1096. the package does not perform.  User beware!
  1097.  
  1098. My home address is:
  1099.  
  1100.      Marty Del Vecchio
  1101.      99 Marlboro Road
  1102.      Southborough, MA  01772
  1103.  
  1104. My home phone number is:
  1105.  
  1106.      (508) 485-9718
  1107.  
  1108. My internet mail address is:
  1109.  
  1110.      marty@bsn.mceo.dg.com
  1111.  
  1112. My main bulletin board is:
  1113.  
  1114.      Channel 1 BBS
  1115.      Boston, MA
  1116.      (617) 354-8873
  1117.  
  1118.  
  1119.  
  1120.  
  1121.  
  1122. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         17
  1123.  
  1124.  
  1125.