/***************************************************************************** This is an example of how to set up a real mode callback and hook the BIOS timer tick interrupt (INT 1Ch) in protected mode. For speed purposes, PMODE/W does not normally pass this interrupt up to protected mode automatically from realmode. Therefore, it must be hooked in realmode first and then passed up to protected mode by way of a DPMI callback. In this example, a character is incremented in the upper right hand corner of the screen on every tick (in protected mode). This will ONLY work under PMODE/W if there are DPMI callbacks available (specified in PMWSETUP). If PMODE/W is running under the control of a DPMI host, the DPMI host must provide PMODE/W with realmode callbacks. Under DOS/4GW this is not necessary since DOS/4GW passes up 1Ch all the time. PMODE/W does not pass it up in order to prevent redundant mode switches which consequently slow down the system. Hooking INT 8 for timing is a much better idea. *****************************************************************************/ #include #include unsigned char *vidmem=0xb8000; unsigned int rmvector; union REGS r; void(__interrupt __far timerproc)(void); main(void) /********/ { r.x.eax=0x205; r.h.bl=0x1c; r.x.ecx=FP_SEG(timerproc); r.x.edx=FP_OFF(timerproc); int386(0x31,&r,&r); /* Hook Protected Mode INT 1Ch */ setpassup_1C(&rmvector); /* Initialize 1Ch Passup Handler */ getch(); resetpassup_1C(&rmvector); /* Reset 1Ch Passup Handler */ } void(__interrupt __far timerproc)(void) /*************************************/ { vidmem[158]++; } int setpassup_1C(unsigned *oldvector) /***********************************/ { void int1C_handler(void); union REGS pr; struct SREGS psr; unsigned char regbuf[0x32]; unsigned short int cbseg,cboff; pr.x.eax=0x303; psr.ds=FP_SEG(int1C_handler); pr.x.esi=FP_OFF(int1C_handler); psr.es=FP_SEG(regbuf); pr.x.edi=FP_OFF(regbuf); int386x(0x31,&pr,&pr,&psr); /* Allocate A Realmode Callback */ if(pr.x.cflag!=0) return -1; /* Exit If Error Allocating Callback */ cbseg=(unsigned short)pr.x.ecx; cboff=(unsigned short)pr.x.edx; pr.x.eax=0x200; pr.h.bl=0x1c; int386(0x31,&pr,&pr); /* Save The Realmode INT 1Ch Vector */ *((unsigned short *)oldvector+1)=pr.x.ecx; *((unsigned short *)oldvector)=pr.x.edx; pr.x.eax=0x201; pr.h.bl=0x1c; pr.x.ecx=cbseg; pr.x.edx=cboff; int386(0x31,&pr,&pr); /* Point INT 1Ch To Callback Address */ return 0; } int resetpassup_1C(unsigned *oldvector) /*************************************/ { union REGS pr; pr.x.eax=0x201; pr.h.bl=0x1c; pr.x.ecx=*((unsigned short *)oldvector+1); pr.x.edx=*((unsigned short *)oldvector); int386(0x31,&pr,&pr); /* Reset Old Realmode INT 1Ch Vector */ return 0; } /* This handler is called by the realmode INT 1Ch by way of a DPMI callback. It takes the return address & flags from the realmode stack (DS:ESI) and places them into the DPMI register structure (ES:EDI) so that the routine may return to the proper place on termination. It then initiates an INT 1Ch in protected mode before returning control with an IRETD */ #pragma off (check_stack); void int1C_handler(void) { #pragma aux intp="push eax",\ "mov ax,[esi]",\ "mov es:[edi+2ah],ax",\ "mov ax,[esi+2]",\ "mov es:[edi+2ch],ax",\ "mov ax,[esi+4]",\ "mov es:[edi+20h],ax",\ "add word ptr es:[edi+2eh],6",\ "pop eax",\ "int 1ch",\ "iretd",\ modify [eax]; intp(); } #pragma on (check_stack);