From dff72a100b046ae71509296b2d8ec3ece35886a0 Mon Sep 17 00:00:00 2001 From: cracyc Date: Thu, 1 Nov 2018 09:33:17 -0500 Subject: [PATCH 1/2] 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 --- dispdib/dispdib.c | 190 +++++++++++++++++++++++++++++++++++++++---- krnl386/dosexe.h | 3 + krnl386/interrupts.c | 12 ++- krnl386/ioports.c | 17 ++++ krnl386/krnl386.def | 3 + 5 files changed, 210 insertions(+), 15 deletions(-) diff --git a/dispdib/dispdib.c b/dispdib/dispdib.c index 12ccc0c1239..62c1e30d030 100644 --- a/dispdib/dispdib.c +++ b/dispdib/dispdib.c @@ -20,7 +20,6 @@ #include #include -#include #include "windef.h" #include "winbase.h" #include "wingdi.h" @@ -29,17 +28,26 @@ #include "wine/wingdi16.h" #include "windows/dispdib.h" #include "wine/debug.h" +#include "../krnl386/dosexe.h" WINE_DEFAULT_DEBUG_CHANNEL(ddraw); -static HTASK owner = 0; +#define width 320 + +static HTASK16 owner = 0; static HDC dddc; static int height; static HWND ddhwnd; +static INTPROC oldproc; +static OUTPROC oldout[0x20]; +static INPROC oldin[0x20]; +static HANDLE running = 0; +static BOOL vsync; +static LPVOID vram; -LRESULT CALLBACK ddwndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +static LRESULT CALLBACK ddwndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - HWND parhwnd = GetWindowLongA(hwnd, GWL_HWNDPARENT); + HWND parhwnd = (HWND)GetWindowLongA(hwnd, GWL_HWNDPARENT); switch (uMsg) { case WM_KEYDOWN: @@ -54,13 +62,150 @@ LRESULT CALLBACK ddwndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_TIMER: case WM_SETFOCUS: case WM_KILLFOCUS: - return CallWindowProcA(GetWindowLongA(parhwnd, GWL_WNDPROC), parhwnd, uMsg, wParam, lParam); + case WM_CLOSE: + return CallWindowProcA((WNDPROC)GetWindowLongA(parhwnd, GWL_WNDPROC), parhwnd, uMsg, wParam, lParam); } if (uMsg >= MM_JOY1MOVE) - return CallWindowProcA(GetWindowLongA(parhwnd, GWL_WNDPROC), parhwnd, uMsg, wParam, lParam); + return CallWindowProcA((WNDPROC)GetWindowLongA(parhwnd, GWL_WNDPROC), parhwnd, uMsg, wParam, lParam); return DefWindowProcA(hwnd, uMsg, wParam, lParam); } +static void CALLBACK retrace_cb(LPVOID arg, DWORD low, DWORD high) +{ + vsync = TRUE; + if (WaitForSingleObject(running, 0)) + { + SetEvent(running); + ExitThread(0); + } + RECT ddrect; + GetClientRect(ddhwnd, &ddrect); + HDC dc = GetDC(ddhwnd); + SetBitmapBits(GetCurrentObject(dddc, OBJ_BITMAP), width * height, vram); + StretchBlt(dc, 0, 0, ddrect.right, ddrect.bottom, dddc, 0, 0, width, height, SRCCOPY); + ReleaseDC(ddhwnd, dc); +} + +static DWORD CALLBACK retrace_th(LPVOID arg) +{ + LARGE_INTEGER when; + HANDLE timer; + + if (!(timer = CreateWaitableTimerA( NULL, FALSE, NULL ))) return 0; + + when.u.LowPart = when.u.HighPart = 0; + SetWaitableTimer(timer, &when, 17, retrace_cb, arg, FALSE); + for (;;) SleepEx(INFINITE, TRUE); +} + +static void start_retrace_timer() +{ + if (running) return; + if (height == 240) FIXME("240 px height doesn't work properly with direct fb access\n"); + running = CreateEventA(NULL, TRUE, TRUE, NULL); + vram = MapSL((DWORD)GetProcAddress16(GetModuleHandle16("KERNEL"), (LPCSTR)174) << 16); + CloseHandle(CreateThread(NULL, 0, retrace_th, NULL, 0, NULL)); +} + +static void WINAPI ddInt10Handler(CONTEXT *context) +{ + if (GetCurrentTask() != owner) + { + oldproc(context); + return; + } + + switch (AH_reg(context)) + { + case 0x00: + start_retrace_timer(); + switch (AL_reg(context)) + { + case 0x13: + height = 200; + break; + default: + FIXME("Vid mode %#x not supported\n", AL_reg(context)); + break; + } + break; + default: + FIXME("Int 10 func: %#x unimplemented\n", AH_reg(context)); + break; + } +} + +static DWORD WINAPI ddVGAinHandler(int port, int size) +{ + if (GetCurrentTask() != owner) + return oldin[port - 0x3c0] ? oldin[port - 0x3c0](port, size) : 0; + + DWORD ret = -1; + + switch (port) + { + case 0x3da: + { + start_retrace_timer(); + ret = vsync ? 9 : 0; + vsync = FALSE; + break; + } + default: + FIXME("vga port %#x unimplemented\n", port); + break; + } + return ret; +} + +static void WINAPI ddVGAoutHandler(int port, int size, DWORD value) +{ + if (GetCurrentTask() != owner) + { + if (oldout[port - 0x3c0]) + oldout[port - 0x3c0](port, size, value); + return; + } + + if ((port & ~3) != 0x3c8) start_retrace_timer(); + + static BYTE dacidx; + static BYTE dacclr = 0; + + switch (port) + { + case 0x3c8: + dacidx = value & 0xff; + dacclr = 0; + if (size == 1) break; + value >>= 8; + case 0x3c9: + { + RGBQUAD color; + GetDIBColorTable(dddc, dacidx, 1, &color); + switch (dacclr++) + { + case 0: + color.rgbRed = (BYTE)value << 2; + break; + case 1: + color.rgbGreen = (BYTE)value << 2; + break; + case 2: + color.rgbBlue = (BYTE)value << 2; + dacclr = 0; + break; + } + SetDIBColorTable(dddc, dacidx, 1, &color); + if (!dacclr) dacidx++; + break; + } + default: + FIXME("vga port %#x unimplemented\n", port); + break; + } +} + /********************************************************************* * DisplayDib (DISPDIB.1) * @@ -95,7 +240,7 @@ WORD WINAPI DisplayDib( WORD wFlags /* [in] */ ) { - HTASK task = GetCurrentTask(); + HTASK16 task = GetCurrentTask(); if ((wFlags & DISPLAYDIB_BEGIN) && !owner) { switch (wFlags & DISPLAYDIB_MODE) @@ -114,7 +259,7 @@ WORD WINAPI DisplayDib( if (!GetClassInfoA(GetModuleHandleA(NULL), "DispDibClass", &wc)) { WNDCLASSA ddwc = {0}; - ddwc.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE; + ddwc.style = CS_HREDRAW | CS_VREDRAW; ddwc.lpfnWndProc = ddwndproc; ddwc.hInstance = GetModuleHandleA(NULL); ddwc.lpszClassName = "DispDibClass"; @@ -122,11 +267,12 @@ WORD WINAPI DisplayDib( return DISPLAYDIB_NOTSUPPORTED; } + owner = task; dddc = CreateCompatibleDC(0); BITMAPINFO *bmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 256*4 + sizeof(BITMAPINFOHEADER)); VOID *section; bmap->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmap->bmiHeader.biWidth = 320; + bmap->bmiHeader.biWidth = width; bmap->bmiHeader.biHeight = height; bmap->bmiHeader.biPlanes = 1; bmap->bmiHeader.biBitCount = 8; @@ -134,14 +280,20 @@ WORD WINAPI DisplayDib( HeapFree(GetProcessHeap(), 0, bmap); SelectObject(dddc, ddbmap); - char title[32] = "DispDib"; + char title[32] = "\0"; HWND parhwnd = GetActiveWindow(); GetWindowTextA(parhwnd, title, 32); + if (title[0] == '\0') GetModuleName16(GetCurrentTask(), title, 32); ddhwnd = CreateWindowExA(0, "DispDibClass", title, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, parhwnd, NULL, GetModuleHandleA(NULL), NULL); if (!ddhwnd) + { + owner = 0; return DISPLAYDIB_NOTSUPPORTED; - owner = task; + } + oldproc = DOSVM_SetBuiltinVector(0x10, ddInt10Handler); + for (int i = 0; i < 0x20; i++) + DOSVM_setportcb(ddVGAoutHandler, ddVGAinHandler, i + 0x3c0, &oldout[i], &oldin[i]); return DISPLAYDIB_NOERROR; } else if ((owner != task) || !owner) @@ -150,6 +302,16 @@ WORD WINAPI DisplayDib( { DestroyWindow(ddhwnd); DeleteDC(dddc); + DOSVM_SetBuiltinVector(0x10, oldproc); + for (int i = 0; i < 0x20; i++) + DOSVM_setportcb(oldout[i], oldin[i], i + 0x3c0, &oldout[i], &oldin[i]); + if (running) + { + ResetEvent(running); + WaitForSingleObject(running, INFINITE); + CloseHandle(running); + running = 0; + } owner = 0; return DISPLAYDIB_NOERROR; } @@ -157,7 +319,7 @@ WORD WINAPI DisplayDib( { if (!lpbi) return DISPLAYDIB_INVALIDDIB; - SetDIBColorTable(dddc, 0, lpbi->bmiHeader.biClrUsed, &lpbi->bmiColors); + SetDIBColorTable(dddc, 0, lpbi->bmiHeader.biClrUsed, (RGBQUAD *)&lpbi->bmiColors); } if(!(wFlags & /*DISPLAYDIB_NOIMAGE*/ 0x80)) { @@ -166,8 +328,8 @@ WORD WINAPI DisplayDib( RECT ddrect; GetClientRect(ddhwnd, &ddrect); HDC dc = GetDC(ddhwnd); - SetDIBitsToDevice(dddc, 0, 0, 320, height, 0, 0, 0, 320, lpBits, lpbi, DIB_RGB_COLORS); - StretchBlt(dc, 0, 0, ddrect.right, ddrect.bottom, dddc, 0, 0, 320, height, SRCCOPY); + SetDIBitsToDevice(dddc, 0, 0, width, height, 0, 0, 0, height, lpBits, lpbi, DIB_RGB_COLORS); + StretchBlt(dc, 0, 0, ddrect.right, ddrect.bottom, dddc, 0, 0, width, height, SRCCOPY); ReleaseDC(ddhwnd, dc); } return DISPLAYDIB_NOERROR; diff --git a/krnl386/dosexe.h b/krnl386/dosexe.h index d8ccff16115..25e9fbc5fca 100644 --- a/krnl386/dosexe.h +++ b/krnl386/dosexe.h @@ -68,6 +68,8 @@ typedef struct { typedef void (*DOSRELAY)(CONTEXT*,void*); typedef void (WINAPI *RMCBPROC)(CONTEXT*); typedef void (WINAPI *INTPROC)(CONTEXT*); +typedef void (WINAPI *OUTPROC)(int port, int size, DWORD value); +typedef DWORD (WINAPI *INPROC)(int port, int size); #define DOS_PRIORITY_REALTIME 0 /* IRQ0 */ #define DOS_PRIORITY_KEYBOARD 1 /* IRQ1 */ @@ -456,6 +458,7 @@ extern void DOSVM_SetRMHandler( BYTE, FARPROC16 ) DECLSPEC_HIDDEN; /* ioports.c */ extern DWORD DOSVM_inport( int port, int size ) DECLSPEC_HIDDEN; extern void DOSVM_outport( int port, int size, DWORD value ) DECLSPEC_HIDDEN; +extern void DOSVM_setportcb(OUTPROC outproc, INPROC inproc, int port, OUTPROC *oldout, INPROC* oldin) DECLSPEC_HIDDEN; /* relay.c */ void DOSVM_RelayHandler( CONTEXT * ) DECLSPEC_HIDDEN; diff --git a/krnl386/interrupts.c b/krnl386/interrupts.c index 364c99054cb..d92be965521 100644 --- a/krnl386/interrupts.c +++ b/krnl386/interrupts.c @@ -49,7 +49,7 @@ static void WINAPI DOSVM_DefaultHandler(CONTEXT*); static FARPROC16 DOSVM_Vectors16[256]; static FARPROC48 DOSVM_Vectors48[256]; -static const INTPROC DOSVM_VectorsBuiltin[] = +static INTPROC DOSVM_VectorsBuiltin[] = { /* 00 */ 0, 0, 0, 0, /* 04 */ 0, 0, 0, 0, @@ -88,6 +88,16 @@ static const INTPROC DOSVM_VectorsBuiltin[] = #define DOSVM_STUB_PM16 5 #define DOSVM_STUB_PM48 6 +INTPROC DOSVM_SetBuiltinVector(BYTE intnum, INTPROC handler) +{ + if (intnum < ARRAY_SIZE(DOSVM_VectorsBuiltin)) { + INTPROC ret = DOSVM_VectorsBuiltin[intnum]; + DOSVM_VectorsBuiltin[intnum] = handler; + return ret; + } + WARN("failed to set builtin int%x\n", intnum ); + return NULL; +} /********************************************************************** * DOSVM_GetRMVector diff --git a/krnl386/ioports.c b/krnl386/ioports.c index 56a5c3d95da..8bd25f958f8 100644 --- a/krnl386/ioports.c +++ b/krnl386/ioports.c @@ -66,6 +66,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(int); # undef DIRECT_IO_ACCESS #endif +OUTPROC outcb[1024] = {0}; +INPROC incb[1024] = {0}; + static struct { WORD countmax; WORD latch; @@ -728,6 +731,16 @@ static BOOL IO_pp_outp(int port, DWORD* res) #endif /* HAVE_PPDEV */ +void DOSVM_setportcb(OUTPROC outproc, INPROC inproc, int port, OUTPROC *oldout, INPROC *oldin) +{ + if (port > 1024) + return; + + *oldout = outcb[port]; + *oldin = incb[port]; + outcb[port] = outproc; + incb[port] = inproc; +} /********************************************************************** * DOSVM_inport @@ -741,6 +754,8 @@ DWORD DOSVM_inport( int port, int size ) TRACE("%d-byte value from port 0x%04x\n", size, port ); + if (incb[port]) return incb[port](port, size); + DOSMEM_InitDosMemory(); #ifdef HAVE_PPDEV @@ -936,6 +951,8 @@ void DOSVM_outport( int port, int size, DWORD value ) { TRACE("IO: 0x%x (%d-byte value) to port 0x%04x\n", value, size, port ); + if (outcb[port]) return outcb[port](port, size, value); + DOSMEM_InitDosMemory(); #ifdef HAVE_PPDEV diff --git a/krnl386/krnl386.def b/krnl386/krnl386.def index b1e7b0357b8..33c4e3dc6f1 100644 --- a/krnl386/krnl386.def +++ b/krnl386/krnl386.def @@ -193,6 +193,7 @@ EXPORTS krnl386_set_compat_path GetModuleFileName16 + GetModuleName16 _EnterWin16Lock _LeaveWin16Lock IsRealModeTask @@ -214,3 +215,5 @@ EXPORTS DOSVM_inport DOSVM_outport + DOSVM_setportcb + DOSVM_SetBuiltinVector From 68454b7239dca32603d00c3039361aa17594468f Mon Sep 17 00:00:00 2001 From: cracyc Date: Thu, 1 Nov 2018 12:27:20 -0500 Subject: [PATCH 2/2] fix build --- krnl386/dosexe.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/krnl386/dosexe.h b/krnl386/dosexe.h index 25e9fbc5fca..abd9aa400c9 100644 --- a/krnl386/dosexe.h +++ b/krnl386/dosexe.h @@ -32,6 +32,10 @@ #include "winnt.h" /* for PCONTEXT */ #include "wincon.h" /* for MOUSE_EVENT_RECORD */ +#ifndef DECLSPEC_HIDDEN +#define DECLSPEC_HIDDEN +#endif + #define MAX_DOS_DRIVES 26 struct _DOSEVENT;