Path: utzoo!mnetor!uunet!lll-winken!lll-lcc!ames!ll-xn!mit-eddie!husc6!ut-sally!nather From: nather@ut-sally.UUCP (Ed Nather) Newsgroups: comp.sys.ibm.pc Subject: Ctrl-C trapping -- a hideous MS-DOS "feature" Message-ID: <10277@ut-sally.UUCP> Date: 31 Jan 88 17:31:15 GMT Organization: U. Texas CS Dept., Austin, Texas Lines: 103 Keywords: bug There are several ways to trap a "Ctrl-C" or "Ctrl-Break" keystroke if you have cleanup to do before your program exits. I include one way in the attached sample program, but I have tried the interrupt intercept as described in Norton's "Programmers' Guide to the IBM PC" as well. Both fail with the code below. Ctrl-C is NOT trapped by either method. (Both Microsoft C v4.0 and Turbo C v1.0 behave the same way; I'm sure MS-DOS is the culprit, since the "kbhit()" routine just accesses the MS-DOS interrupt 06h). It appears that the "Direct Console Interrupt 06 hex" has a wired-in trap for "Ctrl-C." If that code arrives and then 06h is used to ask if a keystroke is waiting, the program is immediately aborted. I cannot find this behavior documented anywhere. It is a nifty MS-DOS "feature" that will blow your program out of the water without warning. Beware. (I had to write an assembly-code keyboard intercept program just to stop Ctrl-C, so if I sound irritable, that's why.) -------------------------------------------------------------------- #include #include main() { set_raw(); /* set MS-DOS to raw mode */ printf("Hit Ctrl-C twice.\n"); if(!kbhit()) /* if no keystroke waiting */ ; /* do nothing */ bdos(7,0,0); /* wait for a keystroke */ if(!kbhit()) /* do it again ... */ ; bdos(7,0,0); printf("ok so far, now once more ...\n"); while(!kbhit()) ; /* watch until a keystroke appears */ bdos(7,0,0); /* try to get it */ printf("Never gets here.\n"); restore_raw(); exit(0); } /* Following code is by Dan Kegel, author of "nansi.sys" */ /* Use the IOCTL DOS function call to change stdin and stdout to raw mode. * For stdin, this prevents MSDOS from trapping ^P, ^S, ^C, thus freeing us * of ^P toggling 'echo to printer'. * For stdout, this radically speeds up the output because there is no * checking for these special characters in the input buffer whenever * screen output is occurring. * Note that only the stdin OR stdout ioctl need be changed since * apparently they are handled as the same device. * Thanks to Mark Zbikowski (markz@microsoft.UUCP) for helping me with * this. * --- This stolen from sources to the mighty game HACK --- */ #define DEVICE 0x80 #define RAW 0x20 #define IOCTL 0x44 #define STDIN fileno(stdin) #define STDOUT fileno(stdout) #define GETBITS 0 #define SETBITS 1 static unsigned old_stdin, old_stdout, ioctl(); /*--- set_raw() ---------- Call this to set raw mode; call restore_raw() later to restore console to old rawness state. --------------------------*/ set_raw() { old_stdin = ioctl(STDIN, GETBITS, 0); old_stdout = ioctl(STDOUT, GETBITS, 0); if (old_stdin & DEVICE) ioctl(STDIN, SETBITS, old_stdin | RAW); if (old_stdout & DEVICE) ioctl(STDOUT, SETBITS, old_stdout | RAW); } restore_raw() { if (old_stdin) (void) ioctl(STDIN, SETBITS, old_stdin); if (old_stdout) (void) ioctl(STDOUT, SETBITS, old_stdout); } static unsigned ioctl(handle, mode, setvalue) unsigned setvalue; { union REGS regs; regs.h.ah = IOCTL; regs.h.al = mode; regs.x.bx = handle; regs.h.dl = setvalue; regs.h.dh = 0; /* Zero out dh */ intdos(®s, ®s); return (regs.x.dx); } /*-- end of setraw.msc --*/ -- Ed Nather Astronomy Dept, U of Texas @ Austin {allegra,ihnp4}!{noao,ut-sally}!utastro!nather nather@astro.AS.UTEXAS.EDU