To: djgpp AT delorie DOT com Subject: Re: Windows trashes my 800x600 graphics mode program References: From: Michael Bukin Date: 27 Apr 1999 22:51:07 +0700 In-Reply-To: Eli Zaretskii's message of "Mon, 26 Apr 1999 14:15:12 +0300 (IDT)" Message-ID: <20zp3uqcyc.fsf@Sky.inp.nsk.su> Lines: 154 X-Mailer: Gnus v5.5/Emacs 19.34 Reply-To: djgpp AT delorie DOT com Eli Zaretskii writes: > On Mon, 26 Apr 1999, Shawn Hargreaves wrote: > > > > That's the catch: there isn't any (at least AFAIK). If anybody knows > > > how to achieve this, I'd certainly like to add that to the FAQ. > > > > Ralph Brown does list some functions for doing this, but Windows > > never actually calls them. So either Ralph is wrong, or Microsoft > > are wrong :-) > > I think Windows does call these functions, but in a way that they aren't > passed to DPMI programs. Perhaps somebody could throw together a short > 16-bit real-mode program and see if it gets those Int 2Fh call-outs. Int 0x2F4001 and Int 0x2F4002 can be captured with both real-mode and protected mode handlers, but program should issue Int 0x2F4000 first. It seems that switching between applications does not work well after enabling these interrupts, or perhaps Windows expects some action when it sends those interrupts. Test program below sets interrupt handler, issues Int 0x2F4000 if it was called with any arguments, then switches to 0x13 graphics mode, then waits for 1 minute and then restores text mode and writes statistics to the test.log file. #include #include #include #include #include #include #include #define SIZE 4096 unsigned long num = 0; unsigned long regs[SIZE][4]; unsigned long my_ds_sel; __dpmi_paddr old_addr; __dpmi_paddr new_addr; void handler (void); void handler_end (void); void dummy (void) { __asm__ __volatile__ (".globl _handler\n" "_handler:\n" " pushf\n" " pushl %%ds\n" " pushl %%esi\n" " movw %%cs:_my_ds_sel, %%ds\n" " movl _num, %%esi\n" " cmpl %0, %%esi\n" " jae 1f\n" " leal (,%%esi,8), %%esi\n" " leal _regs(,%%esi,2), %%esi\n" " movl %%eax, (%%esi)\n" " movl %%ebx, 4(%%esi)\n" " movl %%ecx, 8(%%esi)\n" " movl %%edx, 12(%%esi)\n" " incl _num\n" "1:\n" " popl %%esi\n" " popl %%ds\n" " popf\n" " ljmp %%cs:_old_addr\n" " .globl _handler_end\n" "_handler_end:\n" " nop" : : "i" (SIZE)); } int main (int _argc, char *_argv[]) { int result = 0; __dpmi_regs r; unsigned long eax __attribute__ ((__unused__)); FILE *file; my_ds_sel = _my_ds (); if ((_go32_dpmi_lock_data (&num, sizeof (num)) != 0) || (_go32_dpmi_lock_data (regs, sizeof (regs)) != 0) || (_go32_dpmi_lock_data (&my_ds_sel, sizeof (my_ds_sel)) != 0) || (_go32_dpmi_lock_data (&old_addr, sizeof (old_addr)) != 0) || (_go32_dpmi_lock_code (handler, ((unsigned long) handler_end - (unsigned long) handler)) != 0)) { fprintf (stderr, "%s: can not lock memory\n", _argv[0]); exit (EXIT_FAILURE); } if (__dpmi_get_protected_mode_interrupt_vector (0x2F, &old_addr) != 0) { fprintf (stderr, "%s: can not get interrupt vector\n", _argv[0]); exit (EXIT_FAILURE); } new_addr.selector = _my_cs (); new_addr.offset32 = (unsigned long) handler; if (__dpmi_set_protected_mode_interrupt_vector (0x2F, &new_addr) != 0) { fprintf (stderr, "%s: can not set interrupt vector\n", _argv[0]); exit (EXIT_FAILURE); } __asm__ __volatile__ ("int $0x2F" : "=a" (eax) : "0" (0x0100)); memset (&r, 0, sizeof (r)); if (_argc > 1) { r.x.ax = 0x4000; __dpmi_int (0x2F, &r); result = r.h.al; } r.x.ax = 0x13; __dpmi_int (0x10, &r); sleep (60); r.x.ax = 0x03; __dpmi_int (0x10, &r); while (__dpmi_set_protected_mode_interrupt_vector (0x2F, &old_addr) != 0) { fprintf (stderr, "%s: can not restore interrupt vector\n", _argv[0]); system (""); } file = fopen ("test.log", "wt"); if (file != 0) { int i; for (i = 0; i < num; i++) fprintf (file, "%08lX %08lX %08lX %08lX\n", regs[i][0], regs[i][1], regs[i][2], regs[i][3]); fclose (file); } printf ("0x%02X\n", result); return 0; } -- Michael Bukin