In OpenWatcom, which was used in the example given in the question, the intr
function performs transparent translation between segment values and protected-mode selectors, presumably using DPMI service 0x0002. This means that for example this program runs correctly whether compiled for real or protected mode:
#include <stdio.h>
#include <string.h>
#include <i86.h>
int main(int argc, char *argv[]) {
union REGPACK r;
unsigned char _far *font;
int i;
memset(&r, 0, sizeof(r));
r.w.ax = 0x1130;
r.h.bh = 6;
intr(0x10, &r);
printf("%04x:%04x\n", r.w.es, r.w.bp);
font = MK_FP(r.w.es, r.w.bp);
for (i = 0; i < 64; ++i) {
printf("%02x ", font[i]);
if ((i & 15) == 15)
printf("\n");
}
return 0;
}
Its output on my laptop when compiled for real mode (with wcl
) is:
c000:9761
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 7e 81 a5 81 81 bd 99 81 81 7e 00 00 00 00
00 00 7e ff db ff ff c3 e7 ff ff 7e 00 00 00 00
00 00 00 00 6c ee fe fe fe 7c 38 10 00 00 00 00
And this is the output when compiled for protected mode (with wcl386
) and run under DOS/4GW’s DPMI host:
01c8:9761
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 7e 81 a5 81 81 bd 99 81 81 7e 00 00 00 00
00 00 7e ff db ff ff c3 e7 ff ff 7e 00 00 00 00
00 00 00 00 6c ee fe fe fe 7c 38 10 00 00 00 00
While this is the output when the protected-mode program is run under Windows 3.11:
0287:9761
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 7e 81 a5 81 81 bd 99 81 81 7e 00 00 00 00
00 00 7e ff db ff ff c3 e7 ff ff 7e 00 00 00 00
00 00 00 00 6c ee fe fe fe 7c 38 10 00 00 00 00
The only difference is the value of the ES register, which is a segment value in real mode and a selector in protected mode. The actual interrupt handler returns a real-mode segment; it’s the DPMI host which translates it to a protected-mode selector on behalf of the C library. The selector points to the same memory as the segment does in real mode; the only difference is that you cannot perform segment arithmetic on selectors.
Other APIs may fail to perform such transparent translation. When that happens, you may have to either manually invoke the appropriate DPMI calls to allocate selectors (service 0x0000 to allocate, then service 0x0007 to set the base address and service 0x0008 to set the segment limit), or use a pre-allocated selector for the entire range of conventional memory, and use linear memory addresses as offsets relative to that selector. Open Watcom C/C++ Programmer’s Guide §5.4 describes how DOS extenders provide such pre-allocated selectors for that purpose, but you will need to check whether you are in fact running under that extender’s DPMI implementation to know whether you can actually use them. (While under DOS/4GW selector 0 addresses conventional memory, in a Windows DOS box it is an unusable null selector that will crash your program! Beware.)
es
andbp
? Are you running in 32-bit or 16-bit protected mode? I’d assume you need to use an appropriate conventional-memory far pointer selector, as protected-mode DOS programs don’t run in a linear address space. I don’t know how that’s done in OpenWatcom, though.%WATCOM%\DOS4GW.DOC
, and in the online help under the DOS/4GW section of the user's guide" recommended by Paul Hsieh's Watcom C/C++ FAQ for DPMI-related questions?