Skip to content

Commit dff72a1

Browse files
committed
add support for int and ioport hooks and use in dispdib to get software which uses dispdib but writes directly to the framebuffer while expecting windows input messages to still work
1 parent a553cd2 commit dff72a1

File tree

5 files changed

+210
-15
lines changed

5 files changed

+210
-15
lines changed

dispdib/dispdib.c

Lines changed: 176 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
#include <stdarg.h>
2222
#include <string.h>
23-
#include <stdlib.h>
2423
#include "windef.h"
2524
#include "winbase.h"
2625
#include "wingdi.h"
@@ -29,17 +28,26 @@
2928
#include "wine/wingdi16.h"
3029
#include "windows/dispdib.h"
3130
#include "wine/debug.h"
31+
#include "../krnl386/dosexe.h"
3232

3333
WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
3434

35-
static HTASK owner = 0;
35+
#define width 320
36+
37+
static HTASK16 owner = 0;
3638
static HDC dddc;
3739
static int height;
3840
static HWND ddhwnd;
41+
static INTPROC oldproc;
42+
static OUTPROC oldout[0x20];
43+
static INPROC oldin[0x20];
44+
static HANDLE running = 0;
45+
static BOOL vsync;
46+
static LPVOID vram;
3947

40-
LRESULT CALLBACK ddwndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
48+
static LRESULT CALLBACK ddwndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4149
{
42-
HWND parhwnd = GetWindowLongA(hwnd, GWL_HWNDPARENT);
50+
HWND parhwnd = (HWND)GetWindowLongA(hwnd, GWL_HWNDPARENT);
4351
switch (uMsg)
4452
{
4553
case WM_KEYDOWN:
@@ -54,13 +62,150 @@ LRESULT CALLBACK ddwndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
5462
case WM_TIMER:
5563
case WM_SETFOCUS:
5664
case WM_KILLFOCUS:
57-
return CallWindowProcA(GetWindowLongA(parhwnd, GWL_WNDPROC), parhwnd, uMsg, wParam, lParam);
65+
case WM_CLOSE:
66+
return CallWindowProcA((WNDPROC)GetWindowLongA(parhwnd, GWL_WNDPROC), parhwnd, uMsg, wParam, lParam);
5867
}
5968
if (uMsg >= MM_JOY1MOVE)
60-
return CallWindowProcA(GetWindowLongA(parhwnd, GWL_WNDPROC), parhwnd, uMsg, wParam, lParam);
69+
return CallWindowProcA((WNDPROC)GetWindowLongA(parhwnd, GWL_WNDPROC), parhwnd, uMsg, wParam, lParam);
6170
return DefWindowProcA(hwnd, uMsg, wParam, lParam);
6271
}
6372

73+
static void CALLBACK retrace_cb(LPVOID arg, DWORD low, DWORD high)
74+
{
75+
vsync = TRUE;
76+
if (WaitForSingleObject(running, 0))
77+
{
78+
SetEvent(running);
79+
ExitThread(0);
80+
}
81+
RECT ddrect;
82+
GetClientRect(ddhwnd, &ddrect);
83+
HDC dc = GetDC(ddhwnd);
84+
SetBitmapBits(GetCurrentObject(dddc, OBJ_BITMAP), width * height, vram);
85+
StretchBlt(dc, 0, 0, ddrect.right, ddrect.bottom, dddc, 0, 0, width, height, SRCCOPY);
86+
ReleaseDC(ddhwnd, dc);
87+
}
88+
89+
static DWORD CALLBACK retrace_th(LPVOID arg)
90+
{
91+
LARGE_INTEGER when;
92+
HANDLE timer;
93+
94+
if (!(timer = CreateWaitableTimerA( NULL, FALSE, NULL ))) return 0;
95+
96+
when.u.LowPart = when.u.HighPart = 0;
97+
SetWaitableTimer(timer, &when, 17, retrace_cb, arg, FALSE);
98+
for (;;) SleepEx(INFINITE, TRUE);
99+
}
100+
101+
static void start_retrace_timer()
102+
{
103+
if (running) return;
104+
if (height == 240) FIXME("240 px height doesn't work properly with direct fb access\n");
105+
running = CreateEventA(NULL, TRUE, TRUE, NULL);
106+
vram = MapSL((DWORD)GetProcAddress16(GetModuleHandle16("KERNEL"), (LPCSTR)174) << 16);
107+
CloseHandle(CreateThread(NULL, 0, retrace_th, NULL, 0, NULL));
108+
}
109+
110+
static void WINAPI ddInt10Handler(CONTEXT *context)
111+
{
112+
if (GetCurrentTask() != owner)
113+
{
114+
oldproc(context);
115+
return;
116+
}
117+
118+
switch (AH_reg(context))
119+
{
120+
case 0x00:
121+
start_retrace_timer();
122+
switch (AL_reg(context))
123+
{
124+
case 0x13:
125+
height = 200;
126+
break;
127+
default:
128+
FIXME("Vid mode %#x not supported\n", AL_reg(context));
129+
break;
130+
}
131+
break;
132+
default:
133+
FIXME("Int 10 func: %#x unimplemented\n", AH_reg(context));
134+
break;
135+
}
136+
}
137+
138+
static DWORD WINAPI ddVGAinHandler(int port, int size)
139+
{
140+
if (GetCurrentTask() != owner)
141+
return oldin[port - 0x3c0] ? oldin[port - 0x3c0](port, size) : 0;
142+
143+
DWORD ret = -1;
144+
145+
switch (port)
146+
{
147+
case 0x3da:
148+
{
149+
start_retrace_timer();
150+
ret = vsync ? 9 : 0;
151+
vsync = FALSE;
152+
break;
153+
}
154+
default:
155+
FIXME("vga port %#x unimplemented\n", port);
156+
break;
157+
}
158+
return ret;
159+
}
160+
161+
static void WINAPI ddVGAoutHandler(int port, int size, DWORD value)
162+
{
163+
if (GetCurrentTask() != owner)
164+
{
165+
if (oldout[port - 0x3c0])
166+
oldout[port - 0x3c0](port, size, value);
167+
return;
168+
}
169+
170+
if ((port & ~3) != 0x3c8) start_retrace_timer();
171+
172+
static BYTE dacidx;
173+
static BYTE dacclr = 0;
174+
175+
switch (port)
176+
{
177+
case 0x3c8:
178+
dacidx = value & 0xff;
179+
dacclr = 0;
180+
if (size == 1) break;
181+
value >>= 8;
182+
case 0x3c9:
183+
{
184+
RGBQUAD color;
185+
GetDIBColorTable(dddc, dacidx, 1, &color);
186+
switch (dacclr++)
187+
{
188+
case 0:
189+
color.rgbRed = (BYTE)value << 2;
190+
break;
191+
case 1:
192+
color.rgbGreen = (BYTE)value << 2;
193+
break;
194+
case 2:
195+
color.rgbBlue = (BYTE)value << 2;
196+
dacclr = 0;
197+
break;
198+
}
199+
SetDIBColorTable(dddc, dacidx, 1, &color);
200+
if (!dacclr) dacidx++;
201+
break;
202+
}
203+
default:
204+
FIXME("vga port %#x unimplemented\n", port);
205+
break;
206+
}
207+
}
208+
64209
/*********************************************************************
65210
* DisplayDib (DISPDIB.1)
66211
*
@@ -95,7 +240,7 @@ WORD WINAPI DisplayDib(
95240
WORD wFlags /* [in] */
96241
)
97242
{
98-
HTASK task = GetCurrentTask();
243+
HTASK16 task = GetCurrentTask();
99244
if ((wFlags & DISPLAYDIB_BEGIN) && !owner)
100245
{
101246
switch (wFlags & DISPLAYDIB_MODE)
@@ -114,34 +259,41 @@ WORD WINAPI DisplayDib(
114259
if (!GetClassInfoA(GetModuleHandleA(NULL), "DispDibClass", &wc))
115260
{
116261
WNDCLASSA ddwc = {0};
117-
ddwc.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
262+
ddwc.style = CS_HREDRAW | CS_VREDRAW;
118263
ddwc.lpfnWndProc = ddwndproc;
119264
ddwc.hInstance = GetModuleHandleA(NULL);
120265
ddwc.lpszClassName = "DispDibClass";
121266
if (!RegisterClassA(&ddwc))
122267
return DISPLAYDIB_NOTSUPPORTED;
123268
}
124269

270+
owner = task;
125271
dddc = CreateCompatibleDC(0);
126272
BITMAPINFO *bmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 256*4 + sizeof(BITMAPINFOHEADER));
127273
VOID *section;
128274
bmap->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
129-
bmap->bmiHeader.biWidth = 320;
275+
bmap->bmiHeader.biWidth = width;
130276
bmap->bmiHeader.biHeight = height;
131277
bmap->bmiHeader.biPlanes = 1;
132278
bmap->bmiHeader.biBitCount = 8;
133279
HBITMAP ddbmap = CreateDIBSection(dddc, bmap, DIB_RGB_COLORS, &section, NULL, 0);
134280
HeapFree(GetProcessHeap(), 0, bmap);
135281
SelectObject(dddc, ddbmap);
136282

137-
char title[32] = "DispDib";
283+
char title[32] = "\0";
138284
HWND parhwnd = GetActiveWindow();
139285
GetWindowTextA(parhwnd, title, 32);
286+
if (title[0] == '\0') GetModuleName16(GetCurrentTask(), title, 32);
140287
ddhwnd = CreateWindowExA(0, "DispDibClass", title, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT,
141288
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, parhwnd, NULL, GetModuleHandleA(NULL), NULL);
142289
if (!ddhwnd)
290+
{
291+
owner = 0;
143292
return DISPLAYDIB_NOTSUPPORTED;
144-
owner = task;
293+
}
294+
oldproc = DOSVM_SetBuiltinVector(0x10, ddInt10Handler);
295+
for (int i = 0; i < 0x20; i++)
296+
DOSVM_setportcb(ddVGAoutHandler, ddVGAinHandler, i + 0x3c0, &oldout[i], &oldin[i]);
145297
return DISPLAYDIB_NOERROR;
146298
}
147299
else if ((owner != task) || !owner)
@@ -150,14 +302,24 @@ WORD WINAPI DisplayDib(
150302
{
151303
DestroyWindow(ddhwnd);
152304
DeleteDC(dddc);
305+
DOSVM_SetBuiltinVector(0x10, oldproc);
306+
for (int i = 0; i < 0x20; i++)
307+
DOSVM_setportcb(oldout[i], oldin[i], i + 0x3c0, &oldout[i], &oldin[i]);
308+
if (running)
309+
{
310+
ResetEvent(running);
311+
WaitForSingleObject(running, INFINITE);
312+
CloseHandle(running);
313+
running = 0;
314+
}
153315
owner = 0;
154316
return DISPLAYDIB_NOERROR;
155317
}
156318
if (!(wFlags & DISPLAYDIB_NOPALETTE))
157319
{
158320
if (!lpbi)
159321
return DISPLAYDIB_INVALIDDIB;
160-
SetDIBColorTable(dddc, 0, lpbi->bmiHeader.biClrUsed, &lpbi->bmiColors);
322+
SetDIBColorTable(dddc, 0, lpbi->bmiHeader.biClrUsed, (RGBQUAD *)&lpbi->bmiColors);
161323
}
162324
if(!(wFlags & /*DISPLAYDIB_NOIMAGE*/ 0x80))
163325
{
@@ -166,8 +328,8 @@ WORD WINAPI DisplayDib(
166328
RECT ddrect;
167329
GetClientRect(ddhwnd, &ddrect);
168330
HDC dc = GetDC(ddhwnd);
169-
SetDIBitsToDevice(dddc, 0, 0, 320, height, 0, 0, 0, 320, lpBits, lpbi, DIB_RGB_COLORS);
170-
StretchBlt(dc, 0, 0, ddrect.right, ddrect.bottom, dddc, 0, 0, 320, height, SRCCOPY);
331+
SetDIBitsToDevice(dddc, 0, 0, width, height, 0, 0, 0, height, lpBits, lpbi, DIB_RGB_COLORS);
332+
StretchBlt(dc, 0, 0, ddrect.right, ddrect.bottom, dddc, 0, 0, width, height, SRCCOPY);
171333
ReleaseDC(ddhwnd, dc);
172334
}
173335
return DISPLAYDIB_NOERROR;

krnl386/dosexe.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ typedef struct {
6868
typedef void (*DOSRELAY)(CONTEXT*,void*);
6969
typedef void (WINAPI *RMCBPROC)(CONTEXT*);
7070
typedef void (WINAPI *INTPROC)(CONTEXT*);
71+
typedef void (WINAPI *OUTPROC)(int port, int size, DWORD value);
72+
typedef DWORD (WINAPI *INPROC)(int port, int size);
7173

7274
#define DOS_PRIORITY_REALTIME 0 /* IRQ0 */
7375
#define DOS_PRIORITY_KEYBOARD 1 /* IRQ1 */
@@ -456,6 +458,7 @@ extern void DOSVM_SetRMHandler( BYTE, FARPROC16 ) DECLSPEC_HIDDEN;
456458
/* ioports.c */
457459
extern DWORD DOSVM_inport( int port, int size ) DECLSPEC_HIDDEN;
458460
extern void DOSVM_outport( int port, int size, DWORD value ) DECLSPEC_HIDDEN;
461+
extern void DOSVM_setportcb(OUTPROC outproc, INPROC inproc, int port, OUTPROC *oldout, INPROC* oldin) DECLSPEC_HIDDEN;
459462

460463
/* relay.c */
461464
void DOSVM_RelayHandler( CONTEXT * ) DECLSPEC_HIDDEN;

krnl386/interrupts.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ static void WINAPI DOSVM_DefaultHandler(CONTEXT*);
4949

5050
static FARPROC16 DOSVM_Vectors16[256];
5151
static FARPROC48 DOSVM_Vectors48[256];
52-
static const INTPROC DOSVM_VectorsBuiltin[] =
52+
static INTPROC DOSVM_VectorsBuiltin[] =
5353
{
5454
/* 00 */ 0, 0, 0, 0,
5555
/* 04 */ 0, 0, 0, 0,
@@ -88,6 +88,16 @@ static const INTPROC DOSVM_VectorsBuiltin[] =
8888
#define DOSVM_STUB_PM16 5
8989
#define DOSVM_STUB_PM48 6
9090

91+
INTPROC DOSVM_SetBuiltinVector(BYTE intnum, INTPROC handler)
92+
{
93+
if (intnum < ARRAY_SIZE(DOSVM_VectorsBuiltin)) {
94+
INTPROC ret = DOSVM_VectorsBuiltin[intnum];
95+
DOSVM_VectorsBuiltin[intnum] = handler;
96+
return ret;
97+
}
98+
WARN("failed to set builtin int%x\n", intnum );
99+
return NULL;
100+
}
91101

92102
/**********************************************************************
93103
* DOSVM_GetRMVector

krnl386/ioports.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(int);
6666
# undef DIRECT_IO_ACCESS
6767
#endif
6868

69+
OUTPROC outcb[1024] = {0};
70+
INPROC incb[1024] = {0};
71+
6972
static struct {
7073
WORD countmax;
7174
WORD latch;
@@ -728,6 +731,16 @@ static BOOL IO_pp_outp(int port, DWORD* res)
728731

729732
#endif /* HAVE_PPDEV */
730733

734+
void DOSVM_setportcb(OUTPROC outproc, INPROC inproc, int port, OUTPROC *oldout, INPROC *oldin)
735+
{
736+
if (port > 1024)
737+
return;
738+
739+
*oldout = outcb[port];
740+
*oldin = incb[port];
741+
outcb[port] = outproc;
742+
incb[port] = inproc;
743+
}
731744

732745
/**********************************************************************
733746
* DOSVM_inport
@@ -741,6 +754,8 @@ DWORD DOSVM_inport( int port, int size )
741754

742755
TRACE("%d-byte value from port 0x%04x\n", size, port );
743756

757+
if (incb[port]) return incb[port](port, size);
758+
744759
DOSMEM_InitDosMemory();
745760

746761
#ifdef HAVE_PPDEV
@@ -936,6 +951,8 @@ void DOSVM_outport( int port, int size, DWORD value )
936951
{
937952
TRACE("IO: 0x%x (%d-byte value) to port 0x%04x\n", value, size, port );
938953

954+
if (outcb[port]) return outcb[port](port, size, value);
955+
939956
DOSMEM_InitDosMemory();
940957

941958
#ifdef HAVE_PPDEV

krnl386/krnl386.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ EXPORTS
193193
krnl386_set_compat_path
194194

195195
GetModuleFileName16
196+
GetModuleName16
196197
_EnterWin16Lock
197198
_LeaveWin16Lock
198199
IsRealModeTask
@@ -214,3 +215,5 @@ EXPORTS
214215

215216
DOSVM_inport
216217
DOSVM_outport
218+
DOSVM_setportcb
219+
DOSVM_SetBuiltinVector

0 commit comments

Comments
 (0)