Path: utzoo!utgpu!news-server.csri.toronto.edu!rutgers!cs.utexas.edu!uunet!tut.cis.ohio-state.edu!dsac.dla.mil!dsacg3.dsac.dla.mil!dsacg4.dsac.dla.mil!nol2321 From: nol2321@dsacg4.dsac.dla.mil (Jim Dunn) Newsgroups: comp.os.msdos.programmer Subject: Re: Calc. program size for Microsoft C _dos_keep function ? Keywords: TSR Message-ID: <2584@dsacg4.dsac.dla.mil> Date: 2 Oct 90 15:08:10 GMT References: <1990Sep29.125312.20416@eagle.lerc.nasa.gov> Distribution: usa Organization: Defense Logistics Agency Systems Automation Center, Columbus Lines: 251 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 #include #include #include #include /* 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 " ); puts( " where 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"