home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / tsr / mgabra / mgabra.doc < prev    next >
Encoding:
Text File  |  1989-07-27  |  59.1 KB  |  1,557 lines

  1.  
  2.  
  3.  
  4.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  5.  
  6.  
  7.     SECTION 1 INTRODUCTION
  8.  
  9.     Welcome to Magic Software's Instant Resident Utility Maker
  10.     ABRACADABRA. Hopefully in no time at all we will be having you
  11.     create some amazing TSR programs with a simplicity BEFORE NOW
  12.     unheard of. We have also here at Magic coined a new term TCR
  13.     meaning Terminate but Continue Running which describes programs
  14.     which continue to run concurrently even while you are using the
  15.     pc to run a main program. These are just as easy to create with
  16.     ABRACADABRA.
  17.  
  18.     For me, writing TSRs used to be like first learning to program.
  19.     Without a library to facilitate me or even the know how to build
  20.     one I was somewhat in the dark. There wasn't even a book on the
  21.     subject. I was later to learn why. The secrets of this activity
  22.     were being guarded heavily by the few who knew them. I thought
  23.     this was completely at odds with the hacker ethic but what could
  24.     I do? Well after a few years of hobnobbing with these nuts,
  25.     geniuses and boneheads, each of whom had a piece of the puzzle I
  26.     was able to gather them all together and modularize them into
  27.     ABRACADABRA.
  28.  
  29.     For most of you, the fact that you were even interested in this
  30.     library guarantees you will have a fascinating time of it as
  31.     these secrets are revealed.
  32.  
  33.     If you are already familiar with these internals you can skip
  34.     right to the section describing the library primitives otherwise
  35.     read on.
  36.  
  37.     SECRETS OF TSR PROGRAMMING
  38.  
  39.     What makes a TSR a TSR? Certainly NOT just the fact that it
  40.     remains resident. Device drivers loaded in your CONFIG.SYS file
  41.     remain resident but they are not generally considered a TSR. A
  42.     TSR has several distinct qualities that define it.
  43.  
  44.     1. It remains in memory after initial loading from disk and can
  45.     be instantly invoked from memory.
  46.  
  47.     2. The invocation of a TSR must be able to occur WITHIN another
  48.     program. That's what gives them their utility value.
  49.  
  50.     3. The interrupted program can resume running after the TSR is
  51.     switched out.
  52.  
  53.     4. An additional quality we will add for a TCR (Terminate
  54.     Continue Running) is that it can continue to execute even after
  55.     it has been switched out.
  56.  
  57.  
  58.  
  59.  
  60.  
  61.                                     1
  62.  
  63.  
  64.  
  65.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  66.  
  67.  
  68.     When you are writing TSRs you are engaging in a limited degree of
  69.     multitasking. ABRACADABRA lets you take it to a full program swap
  70.     which means the ENTIRE program is switched, stack, data and all
  71.     INCLUDING screen and any disk access related memory items.
  72.  
  73.     It is no small feat to program but all this work has been
  74.     modularized for you in ABRACADABRA. If you have purchased the
  75.     source code then you can follow along in the next section,
  76.     otherwise you can skip right to the description of the
  77.     ABRACADABRA library functions and how to use them.
  78.  
  79.     What makes it so difficult? Why isn't it easy to write TSRs?
  80.  
  81.     Actually the program which swaps programs while complex, is not
  82.     the hardest part of this whole scenario. While complex, it is
  83.     quite abstract and orderly because it is a transaction that
  84.     occurs entirely between the CPU and memory. The 8086 has always
  85.     been somewhat friendly in those terms.
  86.  
  87.     The difficulties occur as you get further into the real world
  88.     away from the protected confines of the CPU and into the program
  89.     jungle called MS-DOS. DOS is essentially hostile toward attempts
  90.     at making it a multitasking program manager. So we have to do all
  91.     kinds of greasy kid stuff to make it comply with our wishes.
  92.     While the problem is complex, it is finite.
  93.  
  94.     The core of the problem, switching programs, is handled by simply
  95.     saving the swapped out programs complete register set and
  96.     replacing it with the swapped in programs registers. You can
  97.     examine this in more detail in the source listing of the macros
  98.     SAVPRC (save process) and RESPRC (restore process). When a
  99.     process is put to sleep it's registers are stored in a special
  100.     area loosely called the TASK CONTROL BLOCK (TCB). Other relevant
  101.     data is also stored here and we'll cover that next.
  102.  
  103.     Besides the registers, there is other baggage that each program
  104.     has attached that must also be switched. This consists of special
  105.     data areas DOS sets up for disk access, screen contents, video
  106.     modes, cursor position, and special interrupt addresses each
  107.     program uses for critical error handling and control-c break
  108.     checking.
  109.  
  110.     The unfriendly attitude DOS has regarding multitasking is very
  111.     deeply rooted in it's structure. A quick summary of what DOS is,
  112.     is simply a set of functions that a program can call to do
  113.     things. In this manner it is no different than a function library
  114.     you get with compiler type languages. It is designed however to
  115.     be called from anywhere. You don't have to know the actual
  116.     address of each function, you just load up your parameters and
  117.     execute a software interrupt 21h. This gives control of the
  118.     machine to DOS with the parameters you pass. It executes your
  119.     desire and returns control to your program when it is done.
  120.     However, DOS routines, like some languages, cannot handle
  121.  
  122.                                     2
  123.  
  124.  
  125.  
  126.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  127.  
  128.  
  129.     overlapping calls. You must finish one before another is
  130.     undertaken. This is because when you make a call, DOS switches
  131.     from your program's stack to it's own internal set. Whatever is
  132.     pushed here must be fully popped. If you try to call DOS before
  133.     it has finished a previous cycle everything goes fine but when
  134.     the previous cycle tries to complete it finds it's stack data has
  135.     been trashed. This is unfortunate because in a multitasking
  136.     environment you have programs which are all requesting DOS
  137.     assistance at roughly the same time.
  138.  
  139.     The way around this is to check if DOS is currently executing an
  140.     internal routine and have our programs wait until it is done
  141.     before requesting a subsequent service. A good solution would be
  142.     to latch onto the interrupt 21h and set a semaphore (flag)
  143.     whenever someone went through there and turn it off when they
  144.     came back out. That way we'd know when DOS was occupied.
  145.     Surprisingly DOS itself does just this and that flag is available
  146.     to our programs. There is an undocumented DOS feature which most
  147.     programmers call "The Dos Busy Flag" or "The Dos Critical Flag".
  148.     This flag exists at an address we can get by calling DOS function
  149.     34h. You won't find this in any Microsoft documentation. It is
  150.     simply listed as "Used Internally By Dos". So we get that address
  151.     and check that flag whenever we want to access DOS and if it's
  152.     busy we wait until it isn't.
  153.  
  154.     Because DOS is so finicky about when it can be called we cannot
  155.     simply invoke our TSR whenever someone asks. We must be polite
  156.     and wait until any DOS services are complete before we take over.
  157.     To do this we have to know whether DOS is busy or not.
  158.  
  159.     Now there is another set of routines called the BIOS (BASIC INPUT
  160.     OUTPUT SYSTEM) which is like DOS's DOS. DOS calls the BIOS when
  161.     it needs a nice prepackaged routine to access peripheral devices.
  162.     The BIOS has routines which are solely designed to organize
  163.     access to various devices on the PC such as disk drives, monitors
  164.     and clocks. The BIOS is actually stored in a chip on your pc and
  165.     each machine manufacturer supplies a BIOS (or should) when you
  166.     buy the machine. DOS is aptly named because it is a DISK
  167.     OPERATING SYSTEM. It's routines are very strong in handling disk
  168.     access but very weak in other areas. These weaknesses have made
  169.     programming the BIOS as common as using DOS. Something that
  170.     wasn't intended but has come about. Sort of like TSRs.
  171.  
  172.     The BIOS is particularly strong in video routines. It can also be
  173.     accessed directly by our programs if need be. Of course the
  174.     reason for all these layers of routines is to have each layer
  175.     present an identical appearance to our programs no matter what
  176.     machine we are running on from Hewlett Packard to real IBM. By
  177.     bypassing DOS it would seem we sacrifice a small degree of
  178.     compatibility from manufacturer to manufacturer but in fact an
  179.     IBM compatible must have a compatible BIOS these days since just
  180.     about every program written bypasses DOS in some way or another
  181.  
  182.  
  183.                                     3
  184.  
  185.  
  186.  
  187.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  188.  
  189.  
  190.     especially for video display which DOS has hideously poor
  191.     provision for. There doesn't even exist DOS functions to change
  192.     colors on the monitor it's so deficient.
  193.  
  194.     Thankfully the BIOS which is pretty compatible from machine to
  195.     machine is really only routines and no substitute stack areas.
  196.     When you call the BIOS it simply assumes your program's stack has
  197.     enough room to accommodate whatever it needs and doesn't bother
  198.     to swap at all. Thus it can be called and interrupted any number
  199.     of times. ABRACADABRA uses the BIOS a lot to "get around" DOS.
  200.     When a routine can be called again before it is finished it is
  201.     said to be re-entrant. You can RE ENTER it before it is finished.
  202.     Smartly written this BIOS.
  203.  
  204.     Now what do we want to accomplish with a TSR? Mainly we want that
  205.     facility instantly available. Ok, so that means we need to keep
  206.     the TSR in memory right? Ok so we need have a module which
  207.     handles the terminate aspect and the necessary memory allocation
  208.     associated with that. What else? Yes you ... That's right, we
  209.     want to be able to access it with a keystroke so we will have to
  210.     be tinkering with the way the PC accepts keystrokes. We need to
  211.     be able to program HOTKEYS. Oh yes, and because our programs can
  212.     optionally continue to run "in background" we will be looking at
  213.     something called TIMER TICK which we will use to control how long
  214.     each program gets control before is is forced to swap out in
  215.     order to share CPU time. And of course because we are possibly
  216.     using ABRACADABRA in conjunction with a compiled language we will
  217.     need to know a little bit about run time memory architecture of
  218.     compiled languages. Also, because we need to be able to control
  219.     the screen behavior when programs swap we will be delving into
  220.     that.
  221.  
  222.     COMPILED LANGUAGE ARCHITECTURE
  223.  
  224.     Modern compiled languages like BASIC, C and PASCAL share common
  225.     in memory organization. This is called RUN TIME ARCHITECTURE.
  226.     When your program is running it's memory is divided into these
  227.     areas. Some or all of these divisions exist in all languages but
  228.     the order they appear in memory may differ. The manual that came
  229.     with your language most likely has the details (in highly
  230.     technical terms) but below is a general synopsis of the area so
  231.     that you can understand some of the issues which follow.
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.                                     4
  245.  
  246.  
  247.  
  248.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  249.  
  250.  
  251.     Figure 1
  252.  
  253.     GENERIC RUNTIME ARCHITURE - (Memory addresses increase down the page)
  254.  
  255.     ║                     ║ Whatever was in memory when you loaded, your
  256.     ║ OTHER PROGRAMS      ║ program loads on top of it
  257.     ╚═════════════════════╝
  258.     ╔═════════════════════╗ CS Register
  259.     ║ PSP                 ║
  260.     ╠═════════════════════╣ Your Program Starts Here
  261.     ║                     ║
  262.     ║ CODE                ║ What Goes Here Examples: Goto, Gosub, Print etc.
  263.     ║                     ║
  264.     ╠═════════════════════╣ DS Register - Data Starts Here
  265.     ║ CONSTANT DATA       ║ What Goes Here Example: "Copyright 1987" etc.
  266.     ╟─────────────────────╢
  267.     ║ UNITIALIZED DATA    ║ What Goes Here Examples: NAME$, INT%, VARIABLE$
  268.     ╠═════════════════════╣
  269.     ║ STACK               ║
  270.     ╠═════════════════════╣ SS Register - Stack Starts Here Growing Downward
  271.     ║                     ║
  272.     ║ HEAP                ║ DYNAMIC MEMORY ALLOCATION Comes From Here
  273.     ║                     ║
  274.     ╚═════════════════════╝
  275.     ╔═════════════════════╗
  276.     ║ REST OF MEMORY      ║ Rest of Memory, sometimes this is also used
  277.     ║                     ║ As a HEAP
  278.  
  279.  
  280.     At the lowest point in memory is the PROGRAM SEGMENT PREFIX
  281.     (PSP). This is an area that DOS constructs when your program
  282.     loads that contains various information about your program. The
  283.     PSP sometimes exists at offset 0 from the CS register but this
  284.     cannot be counted upon. It is always 100 hex bytes long. Next
  285.     above the PSP at offset 100h into the program space comes the
  286.     program CODE. The actual instructions to the microprocessor.
  287.     Above the CODE comes various segments of data storage and the
  288.     programs DS register is usually set to the base of this area, the
  289.     first of which is usually INITIALIZED DATA, sometimes called
  290.     CONSTANT data or CONST internally. This is information such as
  291.     string literals that will not change as the program executes.
  292.     Next storage space for variables whose values may change but
  293.     whose memory allocation size remains constant. Internally this is
  294.     usually called DATA. Next usually comes STACK. Here is the space
  295.     where the stack is kept and most languages default to a stack
  296.     size of 256 bytes although this does differ radically depending
  297.  
  298.                                     5
  299.  
  300.  
  301.  
  302.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  303.  
  304.  
  305.     on the type of language. Above the stack comes an area called the
  306.     HEAP (Sometimes STACK is above HEAP). The heap is a resevoir of
  307.     memory that the program can call on if it needs more memory
  308.     during execution. This is called DYNAMIC MEMORY ALLOCATION.
  309.     Remember rarely does a language fit this description exactly so
  310.     check your manuals for the specifics.
  311.  
  312.     TSRSET - THE GATEWAY TO TSR PROGRAMMING
  313.  
  314.     ABRACADABRA's features can all be accessed by it's one main
  315.     function, TSRSET. In fact TSRSET is the only function most
  316.     programs will ever need to turn them into TSR's. TSRSET is coded
  317.     into your program by you and the parameters you give it determine
  318.     the operating characteristics of your TSR. Let's take each
  319.     parameter, what it does and why and how. That is, HOTKEYS, TIME
  320.     SWAPPING, TERMINATE AND STAY RESIDENT, SCREEN HANDLING and
  321.     INTERRUPT 28H COMPATIBILITY.
  322.  
  323.     Let's start with parameter 4 just to be difficult. Parameter 4
  324.     defines how your program deals with memory when it terminates and
  325.     stays resident. You basically have 3 choices. Either let
  326.     ABRACADABRA figure out how much memory you need, tell it
  327.     absolutely how many paragraphs of memory to reserve for your
  328.     program, or have it set the top of memory at a convenient
  329.     location for most languages, the stack floor. That address from
  330.     which the program's stack grows downward.
  331.  
  332.     If you put a zero you are telling ABRA to figure it out itself. A
  333.     well behaved, modern language does some house-cleaning
  334.     immediately upon loading. One of the things it does it turn over
  335.     any memory it isn't going to be using back to DOS. So what we
  336.     have TSRSET do is request more memory. DOS tells us the address
  337.     of the next block of unused memory and we assume that our program
  338.     lies safely below this so we truncate at this location.
  339.  
  340.     If you decide to put a -1 TSRSET will use the stack, which
  341.     usually but not always delineates top of program, to determine
  342.     where to truncate. If you are using what is called a SMALL MEMORY
  343.     MODEL, TSRSET knows that the stack and stack pointer always point
  344.     to the top of the programs initial memory allocation so it
  345.     determines where the stack is, adds a couple paragraphs for
  346.     insurance and Terminates leaving your program resident.
  347.  
  348.     If you give TSRSET any value besides 0 or -1 it uses this an an
  349.     absolute value of the number of paragraphs you want to remain in
  350.     memory OF THE PROGRAM DATA SEGMENT. Most languages have their
  351.     main data segment defined largely by the location of the DS
  352.     register, and almost always ABOVE the code area, it counts the
  353.     number of paragraphs you passed it and truncates your program
  354.     there plus a few insurance paragraphs. It then moves the stack
  355.     down into this area so its current and future values are
  356.     preserved.
  357.  
  358.  
  359.                                     6
  360.  
  361.  
  362.  
  363.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  364.  
  365.  
  366.     To do all these terminations TSRSET uses DOS function 31h which
  367.     is the DOS Terminate and Stay Resident function.
  368.  
  369.     Figure 2
  370.  
  371.     TERMINATE AND STAY RESIDENT OPTIONS
  372.  
  373.     ║                     ║
  374.     ║ OTHER PROGRAMS      ║
  375.     ╚═════════════════════╝
  376.     ╔═════════════════════╗
  377.     ║ PSP                 ║
  378.     ╠═════════════════════╣
  379.     ║                     ║
  380.     ║ CODE                ║
  381.     ║                     ║
  382.     ╠═════════════════════╣
  383.     ║ CONSTANT DATA       ║ ^
  384.     ╟─────────────────────╢ │
  385.     ║ UNITIALIZED DATA    ║ │
  386.     ╠═════════════════════╣ │
  387.     ║ STACK               ║ │ Other Options Truncate Anywhere and Move Stack
  388.     ╠═════════════════════╣ Option -1 Truncates Here
  389.     ║                     ║
  390.     ║ HEAP                ║
  391.     ║                     ║
  392.     ╚═════════════════════╝
  393.     ╔═════════════════════╗ Option 0 Truncates Here
  394.     ║ REST OF MEMORY      ║ Sometimes language still thinks this area is
  395.     ║ OTHER PROGRAMS      ║ Available for HEAP Allocation
  396.  
  397.  
  398.     Now, most languages, whether or not they make if accessible to
  399.     you the programmer or not, keep a large chunk of memory reserved
  400.     for what is called DYNAMIC MEMORY ALLOCATION. This workspace is
  401.     commonly referred to as THE HEAP. It is workspace memory that the
  402.     main program can use if it needs. For example in a language like
  403.     BASIC if you were to concatenate two strings the resulting string
  404.     has to go somewhere. The memory for it has to be requisitioned on
  405.     the fly. Languages have functions that allocate memory
  406.     DYNAMICALLY, while the program is running so everything does not
  407.     have to be preset allowing much more flexibility. Languages like
  408.     PASCAL and C have functions that the programmer can call in order
  409.     to request a piece of workspace. In C this duty is handled by the
  410.     ALLOC function family.
  411.  
  412.     In programming TSRs the HEAP is somewhat a nuisance. It is this
  413.     large piece of unused memory that you sometimes wish wasn't there
  414.     since in most cases you are trying to keep the program as small
  415.     as possible. On top of this sometimes, in what is called the
  416.     LARGE MEMORY MODELS, the compiler assumes that all the memory
  417.  
  418.                                     7
  419.  
  420.  
  421.  
  422.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  423.  
  424.  
  425.     past the program up to the end of physical memory is THE HEAP.
  426.     This means if your TSR has another program on top of it and the
  427.     TSR requests more memory it will simply go ahead and carve out a
  428.     chunk of the other program's space and use it (A problem we have
  429.     to live with until a PROTECTED MODE DOS becomes available) OR
  430.     think they have no HEAP space left because DOS says there is no
  431.     more memory left (Because another program is loaded therein).
  432.     Needless to say this does an effective job of killing the
  433.     computer right there. The LARGE memory models actually create
  434.     smaller programs because they keep the HEAP above the stack.
  435.     Since the HEAP is something that can or cannot be used according
  436.     to the programmer's discretion it is better that essential
  437.     program items like code and stack are kept as low in possible in
  438.     memory so that when you terminate you can amputate the HEAP
  439.     without losing that stack.
  440.  
  441.     Using other than option 0 is really butchering up the compiled
  442.     language. It's not pretty but it works.
  443.  
  444.     There are several solutions to this problem. Sometimes your
  445.     language has a function to adjust the size of the HEAP in which
  446.     case you should definitely go ahead and use it to size down this
  447.     monster. You can also avoid doing dynamic memory allocation
  448.     altogether which is not that difficult and in some cases, your
  449.     TSR is a full blown program in it's own right, not just a
  450.     utility, so HEAP allocation is necessary and not a nuisance.
  451.  
  452.     Ok, so now we have your program in memory and if it successfully
  453.     loads, that is, you didn't set your allocation too low, it is now
  454.     installed. The qualities it has now are dependent on the 2nd and
  455.     3rd parameters you gave the TSRSET function. If either are zero
  456.     then the following does not apply. If non-zero, each number
  457.     determines the number of timer clock ticks each program will
  458.     receive in turn. The first parameter is the number of ticks the
  459.     normal DOS program running in the foreground gets. The second
  460.     number is the number of ticks the TCR gets. Remember, if your
  461.     program is using this feature it is a TCR (Terminate Continue
  462.     Running).
  463.  
  464.     In order to perform the switching between tasks the ABRACADABRA
  465.     library has grafted itself into a hardware interrupt commonly
  466.     known as timer tick, or interrupt 1ch. When DOS comes up
  467.     interrupt 1CH is constantly firing about every 18th of a second.
  468.     In a virgin state that interrupt simply points to an interrupt
  469.     return (IRET) instruction,  however if you are running other TSRs
  470.     they usually use this one also as it is very convenient. Now
  471.     every 18th of a second or so we receive control and can do as we
  472.     please. Each of the swapping programs (DOS normal and TSR) has
  473.     stored in it's TASK CONTROL BLOCK the number of ticks it is
  474.     allowed to execute. When a program gets swapped in we load up a
  475.     variable called PERIOD (see source code) with the tick value.
  476.     Then each time timer tick gets control it decrements this value
  477.     by 1 and checks to see if 0 has been reached (See stime procedure
  478.  
  479.                                     8
  480.  
  481.  
  482.  
  483.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  484.  
  485.  
  486.     in source code). When 0 is reached we begin steps to switch out
  487.     the current program and switch in the other because this program
  488.     has used up it's time slice. Now there is more to our INT 1CH
  489.     handler than that but we will take that up in a minute.
  490.  
  491.     So let's assume our timer tick has counted down to zero and it is
  492.     time to swap. We don't directly swap, we simply set a variable
  493.     called doswap to 1 and wait until the necessary conditions for a
  494.     polite interruption are in existence. Timer tick is also the main
  495.     function responsible for checking these conditions. You'll notice
  496.     as you enter it that it checks several conditions before actually
  497.     invoking the SWPPRC (Swap Process) function (see source code).
  498.  
  499.     So every 18th of a second or so timer tick is checking to see if
  500.     we are ready to invoke our TSR. Sometimes DOS can be busy for
  501.     quite a while so our program may not have the rhythm we would
  502.     hope. It may take several seconds from the moment it's timer
  503.     ticks have run out to the time it is swapped if something like a
  504.     disk service is in progress.
  505.  
  506.     In addition to not interrupting DOS we must also beware of not
  507.     interrupting an external block device in the process of doing
  508.     something. Mainly a disk drive. We must let a disk drive complete
  509.     its request because if we in our TSR move the read/write head in
  510.     the middle of a read the interrupted program will finish off the
  511.     read or write with the head in the wrong place. Potentially very
  512.     disastrous. So we have the disk check interrupt which sits on top
  513.     of the bios disk service interrupt 13h and tells us when someone
  514.     is in there and prevents timer tick from actually invoking the
  515.     TSR.
  516.  
  517.     We also do the same thing with the video interrupt 10h to avoid
  518.     interrupting a program with a half loaded set of video card
  519.     registers.
  520.  
  521.     Now lets assume our TSR is not invoked by timer ticks but by the
  522.     keyboard. This is what the first parameter of TSRSET defines.
  523.     What the HOTKEY is. The detail section on TSRSET has all the
  524.     details on how to choose which key. Keyboard actions whenever
  525.     they occur cause an interrupt 9 and the CPU hands over temporary
  526.     control to whatever routine is there to handle interrupt 9.
  527.     Normally it is the BIOS but with todays TSRs which all use
  528.     HOTKEYS there can be 5 or 6 programs all waiting in line
  529.     salivating over the latest keystroke. Our interrupt 9 handler
  530.     just does a little bit of checking for the identity of the key.
  531.     If it is the key we defined as our HOTKEY is sets the doswap flag
  532.     to 1 and exits. It is now once again up to timer tick to actually
  533.     invoke our TSR when conditions are right.
  534.  
  535.     Now you may have been wondering what the int28 function does. It
  536.     looks very similar to timer tick and indeed it is a timer tick
  537.     function also. There are actually 3 timer interrupts going in the
  538.     pc when it is running. interrupt 28 is an auxiliary interrupt
  539.  
  540.                                     9
  541.  
  542.  
  543.  
  544.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  545.  
  546.  
  547.     that was apparently installed so that PRINT.COM could run
  548.     multitasking. You see, DOS has a function INPUT LINE which
  549.     accepts a whole line of input from the keyboard. All the while
  550.     this is going on the DOS busy flag is set so timer tick cannot
  551.     interrupt the program if a doswap is triggered. It is unfortunate
  552.     that COMMAND.COM uses this function to accept command lines. IF
  553.     we had to rely solely on timer tick we could never invoke a TSR
  554.     from the DOS command line. The way to circumvent this is to use
  555.     INT28h. DOS can actually be divided into 3 separate subprograms
  556.     somewhat reflecting release versions. When one section is busy it
  557.     is possible to access another section without causing the
  558.     non-reentrancy problems outlined at the beginning of this
  559.     chapter.
  560.  
  561.     When an interrupt 28 is active it means DOS is active on INPUT
  562.     LINE (function 0AH ) and so only functions 0CH and below are non
  563.     usable. You can use any of the functions above this without
  564.     crashing the system. Since functions 0CH and below deal only with
  565.     display output and keyboard input and are in general crummy
  566.     anyway, can design our TSRs not to use DOS for console I/O. In
  567.     fact, the BIOS itself is quite friendly when it comes to these
  568.     services. ABRACADABRA includes several functions that allow you
  569.     to do screen I/O and keyboard input without using DOS. You should
  570.     use these as opposed to language statements like PRINTF, PRINT,
  571.     INPUT, INKEY etc.
  572.  
  573.     Of course if you must use these you can. However you won't be
  574.     able to invoke the TSR during INPUT LINE. The sixth parameter in
  575.     TSRSET determines this. If it is a 1 it means your TSR does not
  576.     use any DOS functions below 0CH. If it is a zero it means it does
  577.     use them and not to allow a pop up in the middle of one of these
  578.     functions.
  579.  
  580.     There are some other non-minor but easily handled details to
  581.     cover.
  582.  
  583.     Whenever DOS is doing disk I/O there is a 128 byte area of memory
  584.     that all the data passes through on its way to your program. It
  585.     is called the DISK TRANSFER AREA, or DTA for short. If we
  586.     interrupt a program and are going to be doing any disk I/O we
  587.     must switch that area to our own program's DTA since DOS normally
  588.     only keeps one DTA for the entire system. Otherwise we will
  589.     scramble the interrupted programs last data transfer. When we
  590.     switch our TSR out we must restore the interrupted programs
  591.     former DTA.
  592.  
  593.     Whenever a critical error occurs like trying to access an open
  594.     floppy drive, DOS invokes an interrupt 24h. This is the notorious
  595.     Abort, Retry or Ignore prompt that comes up. Now we can't let a
  596.     user choose the Abort option or else we will exit the TSR and
  597.     crash the system so ABRACADABRA sets up it's own interrupt 24h
  598.     handler and tells DOS to ignore the error.
  599.  
  600.  
  601.                                    10
  602.  
  603.  
  604.  
  605.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  606.  
  607.  
  608.     When console I/O is going on the user is allowed to press
  609.     CONTROL-C or CONTROL-BREAK to abort the program. We don't want
  610.     this to happen either. Whenever CONTROL-C is pressed DOS invokes
  611.     interrupt 23h. ABRACADABRA sets up interrupt 23h to ignore
  612.     CONTROL-C and CONTROL-BREAK. Thus the only way for the user to
  613.     exit the TSR is with your, the programmer's, permission and that
  614.     would only be by an actual TSR removal, a complex procedure to
  615.     politely release all the strings the TSR pulled to be where it
  616.     got to be.
  617.  
  618.  
  619.  
  620.  
  621.  
  622.  
  623.  
  624.  
  625.  
  626.  
  627.  
  628.  
  629.  
  630.  
  631.  
  632.  
  633.  
  634.  
  635.  
  636.  
  637.  
  638.  
  639.  
  640.  
  641.  
  642.  
  643.  
  644.  
  645.  
  646.  
  647.  
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654.  
  655.  
  656.  
  657.  
  658.  
  659.  
  660.  
  661.  
  662.                                    11
  663.  
  664.  
  665.  
  666.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  667.  
  668.  
  669.  
  670.     SUMMARY
  671.  
  672.     TSRSET causes your program to ride important interrupt jumps and
  673.     monitor them in order to do TSR.
  674.  
  675.     Figure 3
  676.  
  677.         DOS                              TSR                    OTHER PROGRAMS
  678.   ╔══════════╗     ╔════════════════════════════════════════╗     ╔══════════╗
  679.   ║        <─╫─────╫────────────────────────────────────────╫─────╫─────┐    ║
  680.   ║Int 9h    ║     ║ Monitors Keyboard Waiting For Hotkey   ║     ║     │    ║
  681.   ║         ─╫─────╫────────────────────────────────────────╫─────╫─────┘    ║
  682.   ║        <─╫─────╫────────────────────────────────────────╫─────╫─────┐    ║    
  683.   ║Int 10h   ║     ║ Monitors Video Usage                   ║     ║     │    ║    
  684.   ║         ─╫─────╫────────────────────────────────────────╫─────╫─────┘    ║
  685.   ║        <─╫─────╫────────────────────────────────────────╫─────╫─────┐    ║
  686.   ║Int 13h   ║     ║ Monitors Disk Usage                    ║     ║     │    ║
  687.   ║         ─╫─────╫────────────────────────────────────────╫─────╫─────┘    ║
  688.   ║        <─╫─────╫───────────────────────────────┐        ║     ║          ║
  689.   ║Int 23h   ║     ║ Blocks Control-C Aborting     │        ║     ║          ║
  690.   ║         ─╫─────╫───────────────────────────────┘        ║     ║          ║
  691.   ║        <─╫─────╫───────────────────────────────┐        ║     ║          ║
  692.   ║Int 24h   ║     ║ Blocks Critical Error         │        ║     ║          ║
  693.   ║         ─╫─────╫───────────────────────────────┘        ║     ║          ║
  694.   ║        <─╫─────╫────────────────────────────────────────╫─────╫─────┐    ║
  695.   ║Int 1Ch   ║     ║ Monitors Auxilliary Timer Tick         ║     ║     │    ║
  696.   ║         ─╫─────╫────────────────────────────────────────╫─────╫─────┘    ║   
  697.   ║        <─╫─────╫────────────────────────────────────────╫─────╫─────┐    ║
  698.   ║Int 28h   ║     ║ Monitors Timer Tick                    ║     ║     │    ║
  699.   ║         ─╫─────╫────────────────────────────────────────╫─────╫─────┘    ║
  700.   ╚══════════╝     ╚════════════════════════════════════════╝     ╚══════════╝
  701.  
  702.                        12    
  703.                                    
  704.  
  705.  
  706.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  707.  
  708.  
  709.     SECTION 2 MGABRA.OBJ LIBRARY FUNCTIONS
  710.  
  711.     There are two files which contain the library functions.
  712.     MGABRA.OBJ contains the actual TSR functions and is all that you
  713.     really need MGUN.OBJ contains functions that deal will
  714.     uninstalling TSRs and polling them for information about their
  715.     status.
  716.  
  717.     All the functions below are far functions meaning they are called
  718.     from your program with a far call. Simply including the external
  719.     declaration file (MGABRA.H) in your source code will take care of
  720.     telling your compiler this. The primary and only absolutely
  721.     essential function to use is TSRSET. The others are there to help
  722.     you polish your TSR. Because they are in assembly language their
  723.     parameter passing is set thus the cdecl in case you are compiling
  724.     your other functions with PASCAL conventions.
  725.  
  726.     TSRSET(hotkey, tsrticks, dosticks, memory, screen, int28)
  727.  
  728.     PROTOTYPE:
  729.     int far cdecl tsrset(int key, int dosticks, int tsrticks, int
  730.     mem, int scswap, int int28);
  731.  
  732.     All the above parameters are 16 bit integer values.
  733.  
  734.     The HOTKEY is passed as a word value, high byte is shift key bit
  735.     number and the low byte is the normal scan key status. So the
  736.     value 0x0201 hex would mean the HOTKEY was left shift escape
  737.     because 02 is the bit the left shift key activates when pressed
  738.     and 01 is the scan code of the escape key. APPENDIX 1 is a table
  739.     of the values associated with each key. As another NOTE your TSRs
  740.     in native state use the same HOTKEY for pop up as well as pop
  741.     out. Although once your TSR is active you can use any key combo
  742.     combined with the SWAP function (covered later) to swap out the
  743.     TSR.
  744.  
  745.     Remember, these are NOT THE ASCII codes. They are a hardware
  746.     value sent by the keyboard whenever it is pressed. So you see the
  747.     Z key has only one value. This is because upper or lower case is
  748.     determined by the state of the shift keys, not solely by which
  749.     key is pressed.
  750.  
  751.     The next parameter, memory is the size of memory to reserve for
  752.     the program when it terminates. This is the most complex and
  753.     maddening part of TSR programming and is covered more thoroughly
  754.     above. Bascially If you put a zero ABRACADABRA will determine
  755.     memory by asking DOS where the first area of free memory is and
  756.     truncating your program beneath that. If you put a -1 ABRACADABRA
  757.     will truncate your program at the base of it's stack and if you
  758.     put any other value ABRACADABRA will leave that many paragraphs
  759.     above the program's DS register (DATA SPACE) in memory and
  760.     relocate the stack safely within that area.
  761.  
  762.  
  763.                                    14
  764.  
  765.  
  766.  
  767.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  768.  
  769.  
  770.     The tsrticks and dosticks parameters determine how many timer
  771.     ticks each process will get. The first parameter is how many
  772.     ticks the DOS program will get and the second is how many ticks
  773.     the TSR gets. This can be used to have a program continue to run
  774.     when it is swapped out. Remember that the timer tick occurs 18.2
  775.     times a second so if you want this value to be in seconds you
  776.     must multiply by 18.2.
  777.  
  778.     The next parameter controls the manner in which the TSR will
  779.     manage screen when it is swapped. Each bit in this word has a
  780.     special function. If one, the corresponding function is enabled.
  781.     See APPENDIX 2 for a table of the specific values you can use
  782.     with this function.
  783.  
  784.     The reason for the "swap by key" parameters is so you can have
  785.     your TCR running in background and if the user wants it full
  786.     blown into foreground only then will the screens swap. You
  787.     wouldn't want the screen swapping every 1/2 second if you were
  788.     running the TCR on the timer ticks. Your TCR can poll the
  789.     function SWPING and if it's true (1) then don't have it write to
  790.     the screen. If it's false (0) then that means your TCR has the
  791.     full screen so it's ok to write to it. Even better is to have
  792.     your TCR (Terminate Continue Running) write all it's output to a
  793.     video page other than 1. Then when you swap it in all the video
  794.     output it has created is live on that page. The function PUTCHR
  795.     has been provided for this purpose.
  796.  
  797.     The INT28 is an option. If your TSR program uses DOS services
  798.     under 0CH you will not be able to invoke it under certain
  799.     circumstances. That is, whenever DOS is using those services.
  800.     They are all services that deal with screen I/O and keyboard
  801.     input. For greater versatility you should write your own screen
  802.     and keyboard I/O and never use language statements like PRINT and
  803.     INPUT (basic) but if you must, set this parameter to 0. You will
  804.     not be able to invoke the TSR from the COMMAND.COM prompt. If
  805.     your program does not use DOS services less than 0CH you can set
  806.     this flag to 1 which will allow you to invoke it in a greater
  807.     number of circumstances. The functions PUTCHR, CONOUT and INKEY
  808.     have been provided for you to go around DOS to do console I/O.
  809.     You can use them as primitives to construct your own console I/O
  810.     that does not use DOS.
  811.  
  812.     Examples:
  813.  
  814.     tsrset(0x083B, 5, 1, 0, 56, 1);
  815.  
  816.     Set the HOTKEY to ALT-F1 (0x083B), have the program multitask
  817.     with 5 timer ticks of the DOS program for every 1 tick of the TCR
  818.     program. Have it figure out itself how much memory to retain (0).
  819.     Have it swap the entire screen content only when the hot key is
  820.     used (56) and it does not use any DOS functions below 0CH (1).
  821.  
  822.     tsrset(0x78, 0, 0, 1000, 0, 0);
  823.  
  824.                                    15
  825.  
  826.  
  827.  
  828.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  829.  
  830.  
  831.  
  832.     Have the hotkey set to the gray plus (+) key, no timer tick
  833.     multitasking enables, have it save 1000 paragraphs of memory when
  834.     it initially loads and terminates. No inherent screen control
  835.     active and it uses DOS functions less than 0CH so don't let it
  836.     come up
  837.     when DOS is inputting a line of text.
  838.  
  839.     SWPSCR(mode)
  840.  
  841.     PROTOTYPE:
  842.     int far cdecl swpscr(int mode);
  843.  
  844.     SWPSCR allows you to change the swapscreen parameter that you
  845.     originally set with TSRSET. Your TSR can dynamically change the
  846.     way it treats the screen by resetting the screen swap mode with
  847.     this function. The values of mode are the same as those used by
  848.     the TSRSET function. Sometimes your TSR will pop up a window and
  849.     you don't want to switch the whole screen, just the cursor, so
  850.     you can put a 1 here. If you want to whole screen swapped those
  851.     options are also available. In it's default state ABRACADABRA
  852.     ensures that no ugly snow appears on the screen when using the
  853.     Color Graphics Adapter. This slows down screen swapping so if
  854.     snow isn't a problem you can set the 256 bit on and it will skip
  855.     checking for snow.
  856.  
  857.     HOTKEY(key)
  858.  
  859.     PROTOTYPE:
  860.     int far cdecl hotkey(int keyval);
  861.  
  862.     The HOTKEY function lets your TSR dynamically change the key
  863.     which activates it. The value of key is the same as that used in
  864.     TSRSET to initially set the hotkey. You can disable the hotkey by
  865.     assigning key the value 0.
  866.  
  867.     Example:
  868.  
  869.     hotkey(0);
  870.  
  871.     disables HOTKEY action altogether.
  872.  
  873.     hotkey(0x0839);
  874.  
  875.     Sets the HOTKEY to ALT SPACE because 08 is the bit pattern for
  876.     Alt key press and 39h is the scan code of the space bar. Remember
  877.     this parameter takes a 16 bit integer so passing it in hex makes
  878.     it easier to see because the high byte is the first two hex
  879.     digits and the low byte is the second two.
  880.  
  881.     TIMER(tsrticks, dosticks)
  882.  
  883.     PROTOTYPE:
  884.  
  885.                                    16
  886.  
  887.  
  888.  
  889.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  890.  
  891.  
  892.     int far cdecl timer(int dosticks, int tsrticks);
  893.  
  894.     The TIMER function allows your TSR to change the value of the
  895.     ticks parameters initially set with TSRSET. You can disable the
  896.     timer altogether by the statement timer(0, 0);.
  897.  
  898.     Example:
  899.  
  900.     timer(10, 1);
  901.  
  902.     This gives the TSR 1 timer tick for every 10 of the foreground
  903.     DOS program.
  904.  
  905.     SWAP
  906.  
  907.     PROTOTYPE:
  908.     int far cdecl swap(void);
  909.  
  910.     The swap function takes no parameters. It is used by your TSR to
  911.     exit and swap back in the program that was interrupted. So a TSR
  912.     can tell itself to swap out and this doesn't have to be
  913.     determined by a hot key only.
  914.  
  915.     Example:
  916.     if (time == 012099) swap();
  917.  
  918.     SWPING
  919.  
  920.     PROTOTYPE:
  921.     int far cdecl swping(void);
  922.  
  923.     SWPING is a function that sets nothing but returns a non-zero
  924.     value if the timer tick activation is currently on (meaning
  925.     multi-tasking is occurring) and 0 if the timer is disabled. If
  926.     you want your TSR to base some of it's activity on whether it is
  927.     multitasking or not you can use this function to determine that.
  928.  
  929.     Example:
  930.  
  931.     if (!swping()) conout("Hello There!");
  932.  
  933.     Will ensure that your TCR won't print to the screen while another
  934.     program is running. It will only print this if the TCR is
  935.     switched in fully.
  936.  
  937.     SWAPNO, SWAPYES
  938.  
  939.     PROTOTYPES:
  940.     int far cdecl swapno(void);
  941.     int far cdecl swapyes(void);
  942.  
  943.  
  944.  
  945.  
  946.                                    17
  947.  
  948.  
  949.  
  950.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  951.  
  952.  
  953.     SWAPNO enables or disables swapping entirely. Sometimes there may
  954.     be a critical function happening and you don't want swapping to
  955.     occur so you call SWAPNO. To re-enable swapping call SWAPYES.
  956.  
  957.     Example:
  958.  
  959.     swapno();
  960.  
  961.     Would disable swapping entirely. The only way to re-enable it is
  962.     for the TSR to execute
  963.  
  964.     swapyes();
  965.  
  966.     STATUS(value)
  967.  
  968.     PROTOTYPE:
  969.     int far cdecl status(int val);
  970.  
  971.     STATUS is a way for you to set a value which tells other MAGIC
  972.     tsrs when they ask, what the status is of this TSR. For example
  973.     if you want to remove a TSR you ask it first if it is OK (It may
  974.     have files open or other non-interruptable procedures). You
  975.     determine what the values mean, status just sets a value from 0
  976.     to 65535.
  977.  
  978.     Example:
  979.  
  980.     status(12)
  981.  
  982.     Now when any program asks PROCST(<tsr address>); it would receive
  983.     a 12 in return. You can have the numbers mean whatever you want
  984.     and supposedly your collection of TSRs would share a common set
  985.     of status codes.
  986.  
  987.     ID(number)
  988.  
  989.     PROTOTYPE:
  990.     int far cdecl id(int id);
  991.  
  992.     ID is like status except it allows you to have the TSR set a
  993.     number for an identification. If you write multiple TSRs and have
  994.     a collection each should call ID with it's own unique number.
  995.     That way programs which poll the TSRs know which one they are
  996.     talking to.
  997.  
  998.     INKEY
  999.  
  1000.     PROTOTYPE:
  1001.     int far cdecl inkey(void);
  1002.  
  1003.     Inkey waits for the next keystroke and returns an int value
  1004.     representing it. It is talking directly to the BIOS so bypasses
  1005.     DOS. This way you don't have to worry about the interrupt 28h
  1006.  
  1007.                                    18
  1008.  
  1009.  
  1010.  
  1011.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  1012.  
  1013.  
  1014.     problem. The returned integer value has to be broken down. The
  1015.     high byte is the ASCII code of the character typed. If it is a
  1016.     zero it means a special key was typed, like F1 or PGUP. The low
  1017.     byte is the scan code of the key that was typed. You can do
  1018.     whatever you want with this information. Remember that INKEY does
  1019.     not echo to the screen. YOU have to write that in.
  1020.  
  1021.     Example:
  1022.  
  1023.     int k;
  1024.     char h;
  1025.     char *s;
  1026.     conout("Enter Your Name");
  1027.     k = inkey();
  1028.     h = k/256;
  1029.     while(h <> "\015"){
  1030.        *s++ = h;
  1031.        k = inkey();
  1032.        h = k/256;
  1033.     }
  1034.  
  1035.     CONOUT(string)
  1036.  
  1037.     PROTOTYPE:
  1038.     int far cdecl conout(char far *s);
  1039.  
  1040.     You pass conout the address of the null terminated string and it
  1041.     outputs the string on the console. It bypasses DOS and thus gets
  1042.     around the interrupt 28 problem. It is possible to use printf
  1043.     like functions. You have to use SPRINTF which sends the formatted
  1044.     string to memory and then use conout to send that memory block to
  1045.     the console. Cursor position is automatically updated to the end
  1046.     of the string. CONOUT uses BIOS video function 14.
  1047.  
  1048.     Example:
  1049.     conout("Hey dude! Your TSR is working! Let's Party!");
  1050.  
  1051.     PUTCHR(cursor row, column, video page, attribute, character)
  1052.  
  1053.     PROTOTYPE:
  1054.     int far cdecl putchr(int row, int col, int page, int att, char
  1055.     c);
  1056.  
  1057.     Putchr allows a pin point placement of a character anywhere in
  1058.     the pc's video pages with whatever attribute you want. You pass
  1059.     it all this information. With this service however the cursor
  1060.     position is not automatically updated. You have to handle that
  1061.     yourself.
  1062.  
  1063.     Example:
  1064.  
  1065.     putchr(12, 40, 2, 16, 'X');
  1066.  
  1067.  
  1068.                                    19
  1069.  
  1070.  
  1071.  
  1072.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  1073.  
  1074.  
  1075.     Would put an X in the middle of video page 2 with color attribute
  1076.     16.
  1077.  
  1078.     MGUN FUNCTIONS
  1079.  
  1080.     The functions in MGUN deal with de-installing TSRS.
  1081.  
  1082.     TSRS
  1083.  
  1084.     PROTOTYPE:
  1085.     int far cdecl tsrs(void);
  1086.  
  1087.     TSRS returns non-zero if any MAGIC TSR's are in memory and 0 if
  1088.     not.
  1089.  
  1090.     FIRSTSR
  1091.  
  1092.     PROTOTYPE:
  1093.     int far * cdecl far firstsr(void);
  1094.  
  1095.     FIRSTSR returns a 32 bit pointer to the first TSR in the chain of
  1096.     TSR's in memory. Note: it does not point to the TSRs PSP or base,
  1097.     only to it's external access function CLEAR. This is so other
  1098.     routines, now knowing this address, can call it and get
  1099.     information about the TSR. If FIRSTSR returns a 0 there are no
  1100.     MAGIC TSRs in memory.
  1101.  
  1102.     You don't have to treat this pointer as other than a 4 byte value
  1103.     as you will only use it as a parameter to the other functions in
  1104.     this section. i.e. don't get muddled about what how you are going
  1105.     to manipulate a 4 byte pointer, just declare the pointer variable
  1106.     as such and use it. The internals are taken care of.
  1107.  
  1108.     PROCID(tsr address)
  1109.  
  1110.     PROTOTYPE:
  1111.     int far cdecl procid(int far *f);
  1112.  
  1113.     PROCID when passed the address of a TSR (Determined with FIRSTSR
  1114.     or NEXTSR) will return the integer value set with ID by the TSR.
  1115.     You can tell which TSR is which by using this function.
  1116.  
  1117.     PROCST(tsr address)
  1118.  
  1119.     PROTOTYPE:
  1120.     int far cdecl procst(int far *f);
  1121.  
  1122.     PROCST when given the address of a TSR will return the status
  1123.     code set with the STATUS function. You can tell what a TSR is up
  1124.     to
  1125.     if it sets this appropriately with STATUS. Remember, the status
  1126.     is just a number. You determine what it means and your collection
  1127.     of TSRs should all share a common set of status meanings.
  1128.  
  1129.                                    20
  1130.  
  1131.  
  1132.  
  1133.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  1134.  
  1135.  
  1136.  
  1137.     NEXTSR(tsr address)
  1138.  
  1139.     PROTOTYPE:
  1140.     int far * cdecl far nextsr();
  1141.  
  1142.     Given the address of one TSR NEXTSR will return the address of
  1143.     the next one. If it returns a 0 there is no next one.
  1144.  
  1145.     UN(tsr address)
  1146.  
  1147.     PROTOTYPE:
  1148.     int far cdecl un(int far *f);
  1149.  
  1150.     UN when passed a TSR address will uninstall it and return to DOS
  1151.     any memory it was using. A TSR cannot UN itself when it is in
  1152.     residency. TSR's MUST be uninstalled in reverse order they were
  1153.     installed. This may seem inconvenient but in reality MS-DOS does
  1154.     not deallocate memory until memory above is deallocated so it
  1155.     doesn't do any good to de-install a TSR below another one.
  1156.  
  1157.     CHECK(id)
  1158.  
  1159.     PROTOTYPE:
  1160.     int far * cdecl far check(int id);
  1161.  
  1162.     If you give check an id it will return a far (32 bit) pointer the
  1163.     tsr with that id is in memory or a zero if it isn't. You can use
  1164.     it in the beginning of a program load and give a message like
  1165.     "Program Already Loaded" so they don't load a duplicate of the
  1166.     thing.
  1167.  
  1168.     SUMMING IT ALL UP
  1169.  
  1170.     Now that we have looked at all the theory behind what goes on
  1171.     lets run down step by step what you have to do to create your
  1172.     TSR.
  1173.  
  1174.     1. Write your program as a normal DOS program BUT use the special
  1175.     MGABRA console I/O functions, CONOUT, PUTCHR and INKEY. Debug it
  1176.     thoroughly. Remember a TSR crashing will crash the whole system.
  1177.     Also put in STATUS functions with appropriate values wherever the
  1178.     program is doing something that makes it dangerous to remove from
  1179.     memory.
  1180.  
  1181.     2. Decide where your program is going to put it's video output.
  1182.     If it will run concurrently with the foreground DOS program you
  1183.     can't have it printing to video page 0 ALL the time.
  1184.  
  1185.     3. Remove any code that lets the program terminate. A TSR can
  1186.     NEVER terminate like a normal program. It must be uninstalled.
  1187.     You can leave CONTROL-BREAK active for now though because the
  1188.     next step will seal that one up.
  1189.  
  1190.                                    21
  1191.  
  1192.  
  1193.  
  1194.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  1195.  
  1196.  
  1197.  
  1198.     4. Add the TSRSET function near the beginning of the program,
  1199.     preferably immediately after you have set up the screen mode for
  1200.     your program. Also call the ID function with a number for program
  1201.     identification just before you call TSRSET.
  1202.  
  1203.     5. Use 0 for parameter 4 of TSRSET. Compile, link and execute. If
  1204.     the system crashes you should experiment with non-zero values for
  1205.     this until the program loads without crashing. Sometimes it is
  1206.     better to make all the TSRSET parameters command line changeable
  1207.     so you can rapidly get the best combination before you hard code
  1208.     them in.
  1209.  
  1210.     6. Run your TSR and fine tune it with the other MGABRA and MGUN
  1211.     functions.
  1212.  
  1213.     PROBLEMS
  1214.  
  1215.     Here are some common problems and their solutions:
  1216.  
  1217.     WHEN TSR/TCR IS INVOKED THE SYSTEM CRASHES
  1218.  
  1219.     Ok. Before you make your program a TSR, run it as a normal
  1220.     program. If it runs ok only then have it call TSRSET. If it then
  1221.     crashes the problem is most likely that the stack has been moved
  1222.     into the code and scrambled the interrupt handlers. Just give
  1223.     your TSR more resident space. Always start with parameter 4 at
  1224.     zero as this is the safest route.
  1225.  
  1226.     TSR LOADS FINE BUT SYSTEM CRASHES AS SOON AS NEXT PROGRAM IS
  1227.     LOADED
  1228.  
  1229.     The problem is the same as the above except in this case the next
  1230.     program load is loading into the TSR's interrupt vector code and
  1231.     scrambling it. The TSR has simply been truncated too short.
  1232.     Increase the value of the fourth parameter in TSRSET.
  1233.  
  1234.     TSR LOADS UP BUT DATA IS SCRAMBLED WHEN I RUN IT OR IT GOES OFF
  1235.     INTO NEVER NEVER LAND AND THE SCREEN IS FULL OF GARBAGE.
  1236.  
  1237.     Some run time architecture puts the stack beneath the data at
  1238.     runtime. You have to manually experiment with the proper value
  1239.     for the 4th parameter in TSRSET. Set it quite large, say 10,000
  1240.     and work down getting the lowest possible value you can without
  1241.     crashing it. That 4th parameter basically relocates the stack.
  1242.     You want to make sure it goes above all your CONSTANT DATA and
  1243.     HEAP.
  1244.  
  1245.     TSR LOADS AND EXECUTES BUT SYSTEM CRASHES AFTER I RETURN TO
  1246.     INTERRUPTED PROGRAM.
  1247.  
  1248.  
  1249.  
  1250.  
  1251.                                    22
  1252.  
  1253.  
  1254.  
  1255.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  1256.  
  1257.  
  1258.     There is a good possibility that the TSR courrupted the other
  1259.     program's memory. Remember if you are using a large memory model
  1260.     runtime architecture with your compiled language that using
  1261.     dynamic memory allocation will cause the TSR to allocate memory
  1262.     from possibly already in use areas. Very nasty as it could be
  1263.     eating the interrupted program. Try a small memory model and see
  1264.     if it's ok then.
  1265.  
  1266.     TSR LOADS UP BUT SYSTEM GIVES FATAL: INTERNAL STACK ERROR AFTER I
  1267.     INVOKE THE TSR AND RETURN TO THE INTERRUPTED PROGRAM.
  1268.  
  1269.     Some of your code is using DOS functions 0CH or less to do
  1270.     console I/O. You are probably using WRITELN, WRITE, PRINTF,
  1271.     PRINT, INKEY, INPUT, SCANF or something like that. Instead use
  1272.     our provided functions for this or else put a 0 in the sixth
  1273.     parameter of TSRSET.
  1274.  
  1275.     TSR LOADS UP BUT SYSTEM CRASHES WHEN I TRY TO INVOKE IT
  1276.  
  1277.     Almost always a stack problem as outlined above. Experiment with
  1278.     different values for the 4th TSRSET parameter.
  1279.  
  1280.     IMPORTANT TIPS ON WRITING TSRS
  1281.  
  1282.     Remember your TSR is running somewhat in violation of the laws of
  1283.     DOS so there are some things you can't do.
  1284.  
  1285.     Don't have your program terminate normally. If you do DOS returns
  1286.     to COMMAND.COM and you'll have two COMMAND.COMs operating side by
  1287.     side and not for long either. Any second the system will go
  1288.     splat. Of course this could be interesting but unless that is the
  1289.     intent of your program the user will get very confused. The only
  1290.     way to remove your TSR gracefully from memory is with the UN
  1291.     function. If you terminate that way your interrupt handlers are
  1292.     still live and DOS will de-allocate them at which point your
  1293.     machine will go bye bye.
  1294.  
  1295.     If you have a TCR like a modem program that runs in background
  1296.     remember not to have it write to the console because it will
  1297.     overwrite the foreground program. While not fatal it is messy.
  1298.     You can have your TCR (with CGA or EGA) write to a separate video
  1299.     page. That way when you invoke it with the HOTKEY all the data
  1300.     that has been scrolling by will be there. Or you could use the
  1301.     SWPING function and only allow it to write when it isn't
  1302.     multitasking. Of course this way you lose any screen output
  1303.     occurring during that time. There are ways around this and
  1304.     ABRACADABRA gives you the primitives to implement it. You have to
  1305.     use your imagination. But then, that's why you are a programmer
  1306.     isn't it?
  1307.  
  1308.     In general since TSR's are meant to be utilities you want them to
  1309.     be as small as possible. If you are using a compiled language you
  1310.     will run into the problem that most of them allocate minimally
  1311.  
  1312.                                    23
  1313.  
  1314.  
  1315.  
  1316.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  1317.  
  1318.  
  1319.     64k to data ON TOP OF CODE. Some of the languages provide
  1320.     functions to size down that area so use those before you call
  1321.     TSRSET. Using the default of 0 for parameter 4 is not always the
  1322.     best thing to do. You may have to manually experiment with the
  1323.     best value here. For C we have found the COMPACT model to create
  1324.     the smallest TSRs, not the SMALL or TINY models.
  1325.  
  1326.     In all our endeavors here at MAGIC we have found that the context
  1327.     switching is the most robust section of ABRACADABRA. Swapping
  1328.     processes is NEVER the problem. 95% of the problems are caused by
  1329.     the initial Terminate and Stay Resident phase and how much data
  1330.     and stack space remains. Once you get by that hassle you are home
  1331.     free.  The other 5% are non-fatal and are caused by screen,
  1332.     cursor and keyboard conflicts. For example, some programs do not
  1333.     use the BIOS to position the cursor so when we get their cursor
  1334.     position to save it prior to swapping it is inaccurate and thus
  1335.     restores to a funny position when they swap back in. Non-Fatal of
  1336.     course but messy. It usually re-positions on the first keystroke.
  1337.     Some machines like the Compaqs give an electronic POP and blank
  1338.     out noticeably when you swap screens. You can also hear little
  1339.     electronic chatter from the box when they are writing to other
  1340.     than video page 0. There's nothing to be done about that for now,
  1341.     it's a hardware problem!
  1342.  
  1343.     You can't have two or more multitasking TCRs running at once.
  1344.     When they swap they start choking each other by restoring a half
  1345.     swapped foreground process. You end up with just one in control
  1346.     of the entire machine unable to swap out.
  1347.  
  1348.     Remember to have your TSR's set status codes appropriate to their
  1349.     conditions. If you open files make sure the user doesn't
  1350.     un-install it without closing them first or else he'll lose that
  1351.     data. You use the STATUS function for that.
  1352.  
  1353.     Call TSRSET early on because once it is used you cannot return to
  1354.     any code prior to it's calling. Because it has possibly truncated
  1355.     any stack returns prior to it's calling.
  1356.  
  1357.     Run your programs as NON-TSR's first to make sure they are fully
  1358.     debugged. A TSR crashing usually crashes the whole system, not
  1359.     just itself.
  1360.  
  1361.     You may have custom needs for which the default ABRACADABRA
  1362.     library is not suited. For that you will need to also purchase
  1363.     the source code. It is easy to modify and well documented.
  1364.  
  1365.     If you are working in the TURBO C integrated environment don't
  1366.     RUN your TSR from within it. Otherwise you are loading as a child
  1367.     process of TURBO C and when you exit TURBO C your TSR will be
  1368.     removed from memory which means all the interrupts you were
  1369.     orchestrating will be going nowhere and the system will
  1370.     immediately crash.
  1371.  
  1372.  
  1373.                                    24
  1374.  
  1375.  
  1376.  
  1377.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  1378.  
  1379.  
  1380.     If you have the source code remember when you assemble it to use
  1381.     the /mx option to preserve case sensitivity. Otherwise when you
  1382.     link, all the ABRACADABRA externals will not resolve.
  1383.  
  1384.     All the ABRACADABRA functions are FAR FUNCTIONS so you can use
  1385.     them with any of the memory models. We have found that the
  1386.     smallest TSRs result when using the compact model but on occasion
  1387.     they don't work at all with that memory model.
  1388.  
  1389.     We here at MAGIC like to consider ourselves hackers in the
  1390.     lowliest sense of the word and we are here to support what we
  1391.     hope is an upcoming generation of youngsters who consider the
  1392.     ability to program as a prerequisite to life.
  1393.  
  1394.     Happy Hacking!
  1395.  
  1396.  
  1397.  
  1398.  
  1399.  
  1400.  
  1401.  
  1402.  
  1403.  
  1404.  
  1405.  
  1406.  
  1407.  
  1408.  
  1409.  
  1410.  
  1411.  
  1412.  
  1413.  
  1414.  
  1415.  
  1416.  
  1417.  
  1418.  
  1419.  
  1420.  
  1421.  
  1422.  
  1423.  
  1424.  
  1425.  
  1426.  
  1427.  
  1428.  
  1429.  
  1430.  
  1431.  
  1432.  
  1433.  
  1434.                                    25
  1435.  
  1436.  
  1437.  
  1438.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  1439.  
  1440.  
  1441.     ~B~APPENDIX 1 Key Scan Code Values
  1442.     ~LH8~
  1443.     ~G~SHIFT KEY VALUES (high byte)
  1444.  
  1445.         0 = normal
  1446.         1 = right shift
  1447.         2 = left shift
  1448.         4 = control
  1449.         8 = alt
  1450.        16 = scroll lock
  1451.        32 = num lock
  1452.       128 = insert
  1453.  
  1454.     ~G~NORMAL KEY SCAN CODES (low byte)
  1455.  
  1456.     KEY  SCAN CODE    KEY  SCAN CODE    KEY  SCAN CODE  KEY  SCAN
  1457.     CODE
  1458.     ===  =========    ===  =========    ===  =========  ===
  1459.     =========
  1460.     1         2       K         37      ;         39    BACKARROW 14
  1461.     2         3       L         38      '         40    RETURN    28
  1462.     3         4       M         50      `         41    GREY -    74
  1463.     4         5       N         49      \         43    GREY +    78
  1464.     5         6       O         24      ,         51    HOME      71
  1465.     6         7       P         25      /         53    PGUP      73
  1466.     7         8       Q         16      *         55    PGDN      81
  1467.     8         9       R         19      SPACE     57    END       79
  1468.     9         10      S         31      ESCAPE    1     UP        72
  1469.     0         11      T         20      F1        59    DOWN      80
  1470.     A         30      U         22      F2        60    RIGHT     77
  1471.     B         48      V         47      F3        61    LEFT      75
  1472.     C         46      W         17      F4        62
  1473.     D         32      X         45      F5        63
  1474.     E         18      Y         21      F6        64
  1475.     F         33      Z         44      F7        65
  1476.     G         34      -         12      F8        66
  1477.     H         35      =         13      F9        67
  1478.     I         23      [         26      F10       68
  1479.     J         36      ]         27      .         52
  1480.  
  1481.  
  1482.  
  1483.  
  1484.  
  1485.  
  1486.  
  1487.  
  1488.  
  1489.  
  1490.  
  1491.  
  1492.  
  1493.  
  1494.  
  1495.                                    26
  1496.  
  1497.  
  1498.  
  1499.     ABRACADABRA! For Turbo C by Walt Howard Jr. 213-477-4151
  1500.  
  1501.  
  1502.     ~B~APPENDIX 2 Screen Swap Parameter Values
  1503.     ~G~
  1504.  
  1505.         1 = swap cursor whenever programs swap
  1506.         2 = save screen whenever programs swap
  1507.         4 = restore screen whenever programs swap
  1508.         8 = swap cursor only if TSR swap by key
  1509.        16 = save screen only if TSR swap by key
  1510.        32 = restore screen only if TSR swap by key
  1511.       256 = don't take any precautions to avoid "snow" on screen
  1512.  
  1513.  
  1514.  
  1515.  
  1516.  
  1517.  
  1518.  
  1519.  
  1520.  
  1521.  
  1522.  
  1523.  
  1524.  
  1525.  
  1526.  
  1527.  
  1528.  
  1529.  
  1530.  
  1531.  
  1532.  
  1533.  
  1534.  
  1535.  
  1536.  
  1537.  
  1538.  
  1539.  
  1540.  
  1541.  
  1542.  
  1543.  
  1544.  
  1545.  
  1546.  
  1547.  
  1548.  
  1549.  
  1550.  
  1551.  
  1552.  
  1553.  
  1554.  
  1555.  
  1556.                                    27
  1557.