monty@blackhole.lerc.nasa.gov (Monty Andro) (09/29/90)
I'm attempting to use Microsoft C's _dos_keep function but I do not know how to calculate the 2'd paramter required by this function. The 2'd paramter is the desired size in 16 byte paragraphs of the program that you want to remain resident. Does anybody know how to calculate this, or is there some function call that I can use to get the desired size. Any help with my problem would be greatly appreciated. Thanks monty
nol2321@dsacg4.dsac.dla.mil (Jim Dunn) (10/02/90)
In article monty@blackhole.lerc.nasa.gov (Monty Andro) writes: > >I'm attempting to use Microsoft C's _dos_keep function but I >do not know how to calculate the 2'd paramter required by this >function. The 2'd paramter is the desired size in 16 byte paragraphs >of the program that you want to remain resident. Does anybody know how to >calculate this, or is there some function call that I can use to get >the desired size. Any help with my problem would be greatly appreciated. > >Thanks >monty Well, why don't we let MICROSOFT lend an answer for a change, OK? Here's the Example program that popped up on my screen when I inquired about the _dos_keep function in Microsoft Quick C / Quick Assembler v2.51. ---Cut Here--- /* ALARM.C illustrates in-line assembly and functions or keywords * related to terminate-and-stay-resident programs. Functions include: * _dos_setvect _dos_getvect _dos_keep * _enable _disable _chain_intr * * Keywords: * _interrupt _asm * Directive: * #pragma * Pragma: * check_stack check_pointer intrinsic * Global variables: * _psp * * WARNING: You should run ALARM from the DOS command line. Running from * inside the QuickC environment will cause subsequent memory problems. * * See MOVEMEM.C for another pragma example. */ #include <dos.h> #include <malloc.h> #include <stdio.h> #include <stdlib.h> #include <time.h> /* Stack and pointer checking off */ #pragma check_stack( off ) #pragma check_pointer( off ) #pragma intrinsic( _enable, _disable ) /* In-line assembler macro to sound a bell. Note that comments in macros must * be in the C format, not the assembler format. */ #define BEEP() _asm { \ _asm sub bx, bx /* Page 0 */ \ _asm mov ax, 0E07h /* TTY bell */ \ _asm int 10h /* BIOS 10 */ \ } #define TICKPERMIN 1092L #define MINPERHOUR 60L enum BOOLEAN { FALSE, TRUE }; /* Prototypes for interrupt functions */ void (_interrupt _far *oldtimer)( void ); void (_interrupt _far *oldvideo)( void ); void _interrupt _far newtimer( void ); void _interrupt _far newvideo( unsigned _es, unsigned _ds, unsigned _di, unsigned _si, unsigned _bp, unsigned _sp, unsigned _bx, unsigned _dx, unsigned _cx, unsigned _ax, unsigned _ip, unsigned _cs, unsigned _flags ); /* Variables that will be accessed inside TSR must be global. */ int ftimesup = FALSE, finvideo = FALSE; long goaltick; long _far *pcurtick = (long _far *)0x0000046cL; /* Huge pointers force compiler to do segment arithmetic for us. */ char _huge *tsrstack; char _huge *appstack; char _huge *tsrbottom; void main( int argc, char **argv ) { long minute, hour; unsigned tsrsize; /* Initialize stack and bottom of program. */ _asm mov WORD PTR tsrstack[0], sp _asm mov WORD PTR tsrstack[2], ss FP_SEG( tsrbottom ) = _psp; FP_OFF( tsrbottom ) = 0; /* Program size is: * top of stack * - bottom of program (converted to paragraphs) * + one extra paragraph */ tsrsize = ((tsrstack - tsrbottom) >> 4) + 1; /* If command line not given, show syntax and quit. */ if( argc < 2 ) { puts( " Syntax: ALARM <hhmm> " ); puts( " where <hhmm> is time (military format) to ring alarm" ); exit( 1 ); } /* Convert time to ticks past midnight. Time must include 0 in first * position (0930, not 930). Time must be later than current time. */ minute = atol( argv[1] + 2 ); argv[1][2] = 0; hour = atol( argv[1] ); goaltick = (hour * MINPERHOUR * TICKPERMIN) + (minute * TICKPERMIN); if( *pcurtick > goaltick ) { puts( "It's past that time now" ); exit( 1 ); } /* Replace existing timer and video routines with ours. */ oldtimer = _dos_getvect( 0x1c ); _dos_setvect( 0x1c, newtimer ); oldvideo = _dos_getvect( 0x10 ); _dos_setvect( 0x10, newvideo ); /* Free the PSP segment and terminate with program resident. */ _dos_freemem( _psp ); _dos_keep( 0, tsrsize ); } /* Our timer interrupt compares current time to goal. If earlier, * it just continues. If later, it beeps and sets a flag to quit checking. */ void _interrupt _far newtimer() { if( ftimesup ) _chain_intr( oldtimer ); else { /* First, execute the original timer interrupt. */ (*oldtimer)(); /* Activate if two conditions are met: First, it's past time for * the alarm. Second, we are not in a video interrupt. Checking * the video interrupt prevents the rare but potentially * dangerous case of calling INT 10 to beep while INT 10 is * already running. */ if( (*pcurtick > goaltick) && !finvideo ) { /* Set flag so we'll never return. */ ftimesup = TRUE; /* Save current stack of application, and set old stack of TSR. * This is for safety since we don't know the state of the * application stack, but we do know the state of our own stack. * Turn off interrupts during the stack switch. */ _disable(); _asm { mov WORD PTR appstack[0], sp ; Save current stack mov WORD PTR appstack[2], ss mov sp, WORD PTR tsrstack[0] ; Load new stack mov ss, WORD PTR tsrstack[2] } _enable(); BEEP(); BEEP(); BEEP(); /* Restore application stack. */ _disable(); _asm { mov sp, WORD PTR appstack[0] mov ss, WORD PTR appstack[2] } _enable(); } } } /* Protects against reentering INT 10 while it is already executing. * Although rare, this could be disastrous if the interrupt routine was * interrupted while it was accessing a hardware register. */ void _interrupt _far newvideo( unsigned _es, unsigned _ds, unsigned _di, unsigned _si, unsigned _bp, unsigned _sp, unsigned _bx, unsigned _dx, unsigned _cx, unsigned _ax, unsigned _ip, unsigned _cs, unsigned _flags ) { static unsigned save_bp; /* If not already inside interrupt, chain to original. */ if( !finvideo ) _chain_intr( oldvideo ); else { /* Set the inside flag, then make sure all the real registers * that might be passed to an interrupt 10h match the parameter * registers. Some of the real registers may be modified by the * preceding code. Note that BP must be saved in a static (nonstack) * variable so that it can be retrieved without modifying the stack. */ ++finvideo; _asm { mov ax, _ax mov bx, _bx mov cx, _cx mov dx, _dx mov es, _es mov di, _di mov save_bp, bp mov bp, _bp } /* Call the original interrupt. */ (*oldvideo)(); /* Make sure that any values returned in real registers by the * interrupt are updated in the parameter registers. Reset the flag. */ _asm { mov bp, save_bp mov _bp, bp mov _di, di mov _es, es mov _dx, dx mov _cx, cx mov _bx, bx mov _ax, ax } --finvideo; } } ---Cut Here--- You're welcome, and best of skill! :) Jim Dunn; jdunn@dsac.dla.mil; AV 850-9713; AT&T 614-238-9713; FAX 614-238-9936 Department of Defense-Defense Logistics Agency-Systems Automation Center, DSAC ******* Compuserve Users Send Mail To: >INTERNET:jdunn@dsac.dla.mil ******* "I thought I needed to be free-but when I was free-I just needed to be needed"
mfinegan@uceng.UC.EDU (michael k finegan) (10/06/90)
OOPS - that tsr does switch stacks ... Guess I should read the whole article before posting :-) - Mike