delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1999/04/27/12:09:41

To: djgpp AT delorie DOT com
Subject: Re: Windows trashes my 800x600 graphics mode program
References: <Pine DOT SUN DOT 3 DOT 91 DOT 990426141341 DOT 22711I-100000 AT is>
From: Michael Bukin <M DOT A DOT Bukin AT inp DOT nsk DOT su>
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 <eliz AT is DOT elta DOT co DOT il> 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 <go32.h>
#include <dpmi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/segments.h>

#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

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019