[ PowerBASIC Programmer's Guide ]
[ to find questionable areas,
try Control_QA, "**************"
I added this first section, and edited it to speak more to them directly,
as "you", and to a lower capability level. " I changed the
order of the sections. ]
-
Chapter 14
POPUP
(TERMINATE AND STAY RESIDENT) PROGRAMMING
Popup programs will save you time by being ready to use at the touch of a button. They can run in the background. They can help you prevent "out of memory" error messages, by letting you break up big huge programs into smaller pieces. And they can respond to interrupts.
PowerBASIC's popup programming mechanisms make it easy to create advanced Terminate and Stay Resident" (TSR) programs, without needing to buy extra software, or spending days exploring advanced technical reference manuals, trying to write it yourself.
Most of the tedious details are taken care of by PowerBASIC.
Built-in popup programming mechanisms give an average PowerBASIC programmer the ability to do things formerly done only by assembly language or "C" language programmers.
PowerBASIC gives you several different methods of controlling how these popup programs can be "popped up" to the foreground to run, and how they can be "popped down", to become dormant in the background until needed again.
PowerBASIC takes care of swapping these popup programs in and out.
All of this is built into PowerBASIC v3.0 and later.
Many details that have not yet been built into PowerBASIC are documented in this chapter on popup programming, and in the PowerBASIC Reference Guide.
To make it easier for you, sample source code utilizing the popup commands are included in the manual.
**************************and in the example code on the floppy???
If you need more help, that is not covered in these manuals, or in the examples, call PowerBASIC's technical support.
COMPATIBILITY
PowerBASIC popup programs are compatible with DOS v2.0 and above, and with most other TSR programs. Rules for writing your popup program so that it will be compatible are on page *********
USES OF POPUP PROGRAMS
POPUP KEY Ready to use at the touch of a button
With the POPUP KEY command, your program can be ready to use at the touch of a button. You will not need to remember a whole long filename to get it started.
When it gets finished, it pops down again, and your screen will look just like it did before you touched the hot key. You will be at the exact same place in your first program.
A POPUP KEY program that is already memory resident can be re-activated faster with a "hot key" than by loading it in from the disk drive each time. This will save you time.
Remarks
Once the POPUP KEY command is executed, the hot key chosen cannot be used for other features elsewhere in your software. It becomes installed at a level closer to the keyboard input itself, and can only be removed by uninstalling the popup program, or by temporarily disabling the popup activation checking. See POPUP KEY OFF, POPUP KEY ON.
POPUP TIMER Background, timer-controlled
Using POPUP TIMER to activate your popup program gives you "set and forget" timer-controlled capability, in the background.
Once a POPUP TIMER program is installed, it will stay loaded, dormant in the background. Every so often, it will "pop up" to the foreground to run for a few microseconds, then go back to sleep in the background, without you having to worry about it.
You can put your attention on the program that you are running in the foreground.
This is similar to multitasking. You can use a background level to do work that does not need operator attention, like printing pages.
The microprocessor speed is so fast, compared to your typing speed, that a background program can run without you even noticing it.
POPUP QUIET Timer-controlled activation
Using POPUP QUIET to activate your popup program also gives you "set and forget", timer-controlled capability, but instead of regular intervals like POPUP TIMER, a POPUP QUIET program will only be activated when the human operator does NOT use the computer for a while, when no keyboard or mouse activity occurs for a certain number of minutes.
The software timer will be reset to zero every time that you press a button on the keyboard or move your mouse.
This command can be used for a screen-saving program with an older style monitor. In some companies, it could be used to be sure that a particular class of worker is on duty, for instance, a security guard or a nuclear power plant operator.
If no one is typing into the keyboard, or moving the mouse, the computer program would assume that no one is "watching", and activate an alarm or call a telephone number, to tell a human being to come and see what is happening.
In an educational setting, it could be used to identify periods when the student needs some extra help in certain subject areas. In the same way, it could be used to identify times when a novice computer user, or a new user of your software, might need an extra level of help file.
POPUP INTERRUPT
Computer-controlled activation
Hardware or software interrupts
Using POPUP INTERRUPT as the method to activate your popup program gives you interrupt-driven computer-controlled activation. Once installed, they can be re-activated on demand, without you having to be there, by either software or hardware interrupts. This is also "set and forget" capability.
When POPUP INTERRUPT is used to service hardware interrupts, swapping may not be possible.
POPUP INTERRUPT uses a unique interrupt number for each popup program. Each POPUP INTERRUPT program works like a "private" telephone line. It does not have to ignore program calls that are not addressed to it, like programs using POPUP MULTIPLEX must do. Examples are programs operating a fax computer board, or a modem program.
POPUP MULTIPLEX
Computer-controlled activation
Software interrupts
Using POPUP MULTIPLEX to activate your popup program also gives you software interrupt-driven computer-controlled activation. Once installed, these programs can be re-activated on demand, by software interrupts. This is also "set and forget" capability.
POPUP MULTIPLEX uses the same interrupt number for each popup program attached to it, but also uses two register masks to identify which popup program is being called.
This works like a mailbox or extension number, and a personal identification number. Each POPUP MULTIPLEX program must check these two register masks and ignore all "party-line calls" except its own calls. It is possible to handle more popup programs with the same interrupt number, but response to time- critical functions like a COM port is not as fast as with POPUP INTERRUPT.
RELIEVE MEMORY SHORTAGES
Breaking your program up into smaller independent modules that interact with a mainline module, can mean that your program can keep on growing and becoming more complex, and yet not be limited by 640kb.
This can become important as you develop your software more and more. Adding more features, and more error-checking and error-recovery code, will eventually make your program grow too large for available RAM.
If you have been frustrated by the "Out of Memory" error message, as the reward for all your hard work, the POPUP MULTIPLEX and POPUP INTERRUPT program mechanisms may be the answer to your problem.
You can relieve the memory shortages by taking seldom-called chunks of source code out of your big program, and making them into independent popup programs.
These memory-resident smaller modules are sometimes called "overlay" programs. In popped-down, swapped-out status, these overlay programs can each use as little as 5kb of conventional RAM memory.
The remainder of their memory images are stored temporarily in EMS memory, or on a disk file.
Likely candidates for this conversion would be subroutines or functions, or groups of these, that are largely self-contained, and do not require a lot of variable passing.
Even programs that need a lot of variables to be passed as parameters can use other means, like saving important variables to a disk file, or swapping the data to a disk file, using BSAVE and BLOAD.
Making smaller faster program modules will make your programs more versatile and powerful.
ESSENTIAL STEPS
In invoking PowerBASIC's popup features:
To install a popup program,
Select the popup activation method.
Pop down.
When activated, it will
Pop up.
Perform some work.
Loop to pop down again
or
Uninstall.
POPPING DOWN
Popup Inactivation Methods
The user can choose from these methods of "popping down",
POPUP SLEEP USING EMS Uses EMS memory to swap
POPUP SLEEP USING FileName$ Uses a disk file to swap
POPUP SLEEP USING EMS, FileName$ Uses EMS memory or
a disk file to swap
POPUP SLEEP Becomes dormant without swapping
REMARKS
If you have enough EMS memory, POPUP SLEEP USING EMS is the fastest choice.
Before "popping down", the program needs to release extra memory that has been allocated by PowerBASIC, but has not used for the heap, or else there will be a lot of wasted EMS memory or disk space.
Use the SETMEM function, with a negative number larger than 640kb. PowerBASIC will try to release it all, but it will not cause an error if it is not an exact number.
dummy=SETMEM(-700000)
To reserve space for allocating dynamic arrays after it is popped up, use the SETMEM function, with a positive number equal to the number of bytes that will be needed, for instance, 8000 bytes.
dummy=SETMEM(8000)
When popping down again, after being activated,PowerBASIC will re-inactivate the popup program, using the same POPUP SLEEP method, and ignoring any USING options.
POPPING UP
Popup activation methods
The user can choose from these methods of "popping up",
POPUP KEY CHR$( RequiredShiftKeys, scancode (, OptionalShiftKeys) )
POPUP INTERRUPT InterruptNo%, timeout, ChainBefore, ChainAfter
POPUP MULTIPLEX AXmask, DXmask
POPUP QUIET Ticks
POPUP TIMER Ticks
UNINSTALLING
The popup program will be uninstalled by either of the two following
methods:
* Use of the END command
* Finishing execution of the popup program without looping to
pop down again
Techniques for signaling when a popup program should terminate and become uninstalled include passing it a pre-defined value in a register, or a special hot key from the operator.
Before any method of uninstalling should be performed, POPUP(1) should be checked, to see if it is safe to uninstall.
Example
rem false (busy) is zero
rem true (ready) is non-zero
SafeToUninstallFlag%=POPUP(1)
IF ISFALSE SafeToUninstallFlag% THEN
print"Unable to uninstall"
ELSE
print"Uninstalling"
END
END IF
On the command line
Xcommand$=UCASE$(command$)
if Xcommand$="OFF" then goto UninstallMe
Input a special character
PRINT "Type Q to uninstall, ENTER to resume sleep."
a$ = INPUT$(1) 'wait for key to cancel
IF UCASE$(A$)="Q" THEN
UninstallMe:
IF POPUP(1) THEN
dummy2$=FNKeepScreen$
LOCATE 12,20
PRINT " +-------------------------------------+" ;
LOCATE 13,20
PRINT " ¦ Uninstalling KEEPTIME ¦" ;
LOCATE 14,20
PRINT " ¦ ¦" ;
LOCATE 15,20
PRINT " ¦ ¦" ;
LOCATE 16,20
PRINT " +-------------------------------------+" ;
LOCATE 15,26
INPUT "ENTER TO CONTINUE ";X$
dummy$=FNRestoreScreen$ (dummy2$)
END 'this uninstalls us
END IF
REG 1, &HC001 : REG 4, 252 ' Alter AX,DX to show we were here
POPUP SLEEP ' before going to sleep
WEND
Pass it a special number
( POPUP INTERRUPT or POPUP MULTIPLEX )
DUMMY&=SETMEM(-70000) '...............................Allocate 1K of RAM
DUMMY&=SETMEM(+1024)
POPUP INTERRUPT &H99, 10, OFF, OFF '..........Popup on CALL INTERRUPT &H99
DO
POPUP SLEEP USING EMS '...............Swap to EMS and go to sleep
IF REG(1)=255 THEN '...................255 in REG(1) means END!
dummy=FNDeathKnell
ELSE '........................Here, we're popping up for some ACTION!
SELECT CASE REG(1) '.........REG(1) contains info from caller
CASE 0 '..........................popup help screens
:
CASE 1 '.........................popup a text editor
:
CASE 2 '......................popup a modem terminal
:
CASE 3 '.................Popup a disk-tree directory
:
END SELECT
END IF
input"Do you want to exit? ";x$: if x$="Y" then END
LOOP '...............................We terminate elsewhere. Do this forever
def FNDeathKnell
POPUP TIMER 18 '.......................Popup now every second
DO WHILE Seconds < 5 '.................Try this for 5 seconds
POPUP SLEEP '.............Allow caller to exit to DOS
IF POPUP(1) THEN '.................We can remove TSR!
PRINT "Tsr removed."
END '.....................End and free memory
END IF '............Otherwise, can't free memory yet!
INCR Seconds '................increment and try again
LOOP '.............................No use trying for too long
PRINT "Unable to remove TSR." '.....................Tisk Tisk
PRINT "4K left in memory." '.............We can't free the 4K
POPUP STUFF CHR$(13),0,0 '........To force another DOS prompt
END '.............................So just end and leave it be
end def
dummy=FNBiologicalClockOFF (InterruptNumber%)
def FNBiologicalClockOFF (InterruptNumber%)
rem Call the TSR for the last time and order it to die
REG 1, 255 ' destruct command
CALL INTERRUPT InterruptNumber%
PRINT "Program Ending"
END
end def
Extra Popup Commands
----------------------------------------------------------------
In some popup programs, you may want to simulate user input, for instance, to create a continuously running demo, for display in a store. The command POPUP STUFF can "stuff" the keyboard buffer and fool the keyboard driver program to make it appear that a person has typed these characters into the keyboard.
Another use might be a computer-based tutorial, like a demo, or a software testing process, with simulated input.
POPUP STUFF TextString$, InitialDelayTicks%, TicksBetweenChar%
This could be used to read in lines from a text file on the disk, and funnel these lines to the keyboard, like running a batch file.
The second parameter allows you to build in a pause before stuffing starts.
The third parameter allows you to build in a shorter wait in between each character, to make it appear to run slow enough for a person passing by to notice.
If you used it to "playback" commands from a disk text file, like in batch mode, you could set the second and third parameters to high numbers while you tested the program, then change them to 1 for faster execution.
USING SAMPLE PROGRAMS AS A TEMPLATE
rem cloned from ASCIITSR.BAS
$COMPILE EXE ' this tells PB to make a standalone EXE
$LIB IPRINT OFF ' allow graphic characters to print
dummy=FNSaveConditionsBeforeChangingThem
%AX=1: %DX=4
x& = SETMEM(-700000) ' release unused memory before sleep
PopupPgmName$="............" '
POPUP KEY CHR$(8,30,247) ' ALT A is the hot key
AXmask%=&HC000: DXmask%=254 ' installs itself with these masks
POPUP MULTIPLEX AXmask%, DXmask% ' reg AX and DX get this pattern as an ID
REG %AX, AXmask%
REG %DX, DXmask% ' check to see if installed already
CALL INTERRUPT &H2F ' do the multiplex interrrupt
IF REG(1)=&HC001 AND REG(4)=252 THEN
LOCATE 12,20
PRINT "+-------------------------------------+";
LOCATE 13,20
PRINT "¦ ";PopupPgmName$;" is already installed ¦";
LOCATE 14,20
PRINT "+-------------------------------------+";
END 'we were already installed
END IF
if len(PopupPgmName$)>8 then
SwapFile$ = LEFT$(CURDIR$,2)+"\"+left$(PopupPgmName$,8)+".SWP"
else
SwapFile$ = LEFT$(CURDIR$,2)+"\"+PopupPgmName$+".SWP"
end if
REG %AX, &HC001 ' Alter AX,DX to show we were here
REG %DX, 252 ' this protects against repetitive installations
dummy=FNRestoreConditionsBeforePoppingDownOrUninstalling
POPUP SLEEP USING EMS, SwapFile$ ' before going to sleep
WHILE 1=1
dummy=FNSaveConditionsBeforeChangingThem
' checking to see if this call is for us
IF REG(1)=AXmask% AND REG(4)=DXmask% THEN
' yes, it is ours
GOSUB YourProcedure
rem ...
rem ...
END IF
a$ = INPUT$(1) 'wait for key to cancel
dummy=FNRestoreConditionsBeforePoppingDownOrUninstalling
IF UCASE$(A$)="Q" THEN IF POPUP(1) THEN END 'this uninstalls us
REG %AX, &HC001
REG %DX, 252 ' Alter AX,DX to show we were here
POPUP SLEEP ' before going to sleep
WEND
YourProcedure:
rem ...
rem ...
RETURN
COMPATIBLITY WITH OTHER SOFTWARE
To be "well-behaved", and coexist compatibly with other modules or other vendors' software, your popup program should save initial conditions of the following system functions, before changing them, and then restore them before uninstalling or popping back down.
* default drive and subdirectory
Use CURDIR$ to save. Use CHDIR and CHDRIVE to restore conditions.
* screen mode
Use internal variables "pbvScrnMode" and "pbvScrnCols" to save conditions.
Use SCREEN and WIDTH to restore conditions.
* screen contents
Use PEEK$ or BSAVE to save the screen contents.
Use POKE$ or BLOAD to restore the screen contents.
PEEK$ and POKE$ will use RAM memory for storage.
BSAVE and BLOAD will use disk space for storage.
* cursor position
Use POS and CSRLIN to save cursor position.
Use LOCATE to restore saved cursor position.
* closing any open files
Use CLOSE.
----------------------------------------------------------------
Example functions, which may need further testing:
def FNSaveDefaultDriveAndSubdirectory$
CurrentDirectory$=CURDIR$
FNSaveDefaultDriveAndSubdirectory$=CurrentDirectory$
end def
def FNRestoreDefaultDriveAndSubdirectory$
print"CurrentDirectory$=";CurrentDirectory$
CHDRIVE left$(CurrentDirectory$,2)
CHDIR CurrentDirectory$
end def
def FNTestSaveAndRestoreDefaultDriveAndDirectory
CurrentDirectory$=FNSaveDefaultDriveAndSubdirectory$
print"Now at ";CURDIR$
CHDRIVE "E:"
CHDIR "\CALRES2"
print"Now changed to ";CURDIR$
dummy$=FNRestoreDefaultDriveAndSubdirectory$
print"Now changed back to ";CURDIR$
end def
def FNSwapOutScreenToString$
x% = POS : y% = CSRLIN
DEF SEG = &hB800
SaveScreen$ = PEEK$(0,4000) ' save the entire screen
FNSwapOutScreenToString$=SaveScreen$
end def
def FNRestoreScreenFromString$
DEF SEG = &hB800
POKE$ 0, SaveScreen$ : LOCATE y%, x% 'restore screen
SaveScreen$="": 'releases memory
end def
def FNSaveScreenMode%
rem Use internal variables "pbvScrnMode" and "pbvScrnCols" to save conditions.
rem documentation on this is found in the help files
SavedScreenMode%=pbvScrnMode
SavedScreenColumns%=pbvScrnCols
end def
def FNRestoreScreenMode%
SCREEN SavedScreenMode%
WIDTH "SCRN:", SavedScreenColumns%
end def
def FNSaveCursorPosition
BeforeX%=CSRLIN
BeforeY%=POS(0)
end def
def FNRestoreCursorPosition
LOCATE BeforeX%,BeforeY%,1
end def
def FNSaveConditionsBeforeChangingThem
CurrentDirectory$=FNSaveDefaultDriveAndSubdirectory$
BeforeScreenMode%=FNSaveScreenMode%
dummy=FNSaveCursorPosition
SaveScreen$=FNSwapOutScreenToString$
end def
def FNRestoreConditionsBeforePoppingDownOrUninstalling
dummy$=FNRestoreDefaultDriveAndSubdirectory$
dummy$=FNRestoreScreenFromString$
dummy$=FNRestoreScreenMode%
dummy=FNRestoreCursorPosition
end def
ORDER OF INSTALLING AS TSR
Popup programs installed using the POPUP MULTIPLEX interrupt are tried according to which are the newest, somewhat like a pushdown stack.
The checking of these register masks against the list of installed register mask values proceeds in reverse order, checking the newest installed one first, and then down the list to the longest installed program last.
A multiplex TSR can call another multiplex TSR only if the second one was loaded before it.
To call one multiplex TSR from another multiplex TSR, set the registers AX and DX with the correct values, and issue a CALL INTERRUPT &H2F.
The correct values for these registers are like a mailbox or extension number, and the password PIN that goes with it, or like needing two keys to get into your safety deposit box, yours and the one the bank keeps.
METHODS OF PASSING PARAMETERS
BETWEEN POPUP PROGRAMS
When calling a popup program, with POPUP INTERRUPT or POPUP MULTIPLEX,
you can pass parameters to it thru the registers.
POPUP MULTIPLEX can return values in the registers, when it completes, or pops back down.
POPUP INTERRUPT restores the registers to the values it saved at the beginning of its execution, so it cannot return values using the registers.
CAUTIONS
Do not try to swap in and out a program with an open COM line.
Interrupt-driven popup programs may not use SHELL, or any other form of call to
MS-DOS, because MS-DOS is not re-entrant.
See MS-DOS Developer's Guide, page 130-131
CHOOSING THE INTERRUPT NUMBER
FOR POPUP INTERRUPT
Various sources of information will tell you which system interrupts are available for users. The program ASQ, that comes with 386MAX, by Qualitas, tells us that the following interrupts are available on an 80386.
Interrupt Title # Name
ROM BASIC &H18
User Interrupt &H60 thru &H66 None
Not used &H78 thru &H7F None
Reserved by BASIC &H80 thru &H85 None
Used by BASIC &H86 thru &HE7 None
Used by BASIC &HE8 thru &HE9 -Available-
Used by BASIC &HEF -Available-
Not used &HF9 None
Not used &HFA -Available-
Not used &HFB -Available-
Not used &HFE -Available-
PowerBASIC Reference Guide, page 252, tells us that PowerBASIC uses interrupts &H08, &H09, &H10, &H13, &H17, &H21, &H28, and &H2F.
Your popup programs can probably use any interrupt number that is normally marked as "Reserved for BASIC", or "Used by BASIC", except the ones explicitly reserved for use by PowerBASIC, mentioned above.
Qualitas has released a shareware version of ASQ.
Disclaimer
Since each person's PC has its own unique configuration, as well as its own unique set of drivers, TSR's, and programs, no absolutely certain list of interrupt numbers that are safe to use, can be reliably defined for everyone, and printed in a book.