diff --git a/ddraw.def b/ddraw.def index c2b0db0..20f0c25 100644 --- a/ddraw.def +++ b/ddraw.def @@ -6,3 +6,4 @@ EXPORTS GameHandlesClose DATA NvOptimusEnablement DATA AmdPowerXpressRequestHighPerformance DATA + pvBmpBits DATA diff --git a/inc/hook.h b/inc/hook.h index 0d46b81..d67e45b 100644 --- a/inc/hook.h +++ b/inc/hook.h @@ -20,6 +20,9 @@ typedef BOOL (WINAPI* SETWINDOWPOSPROC)(HWND, HWND, int, int, int, int, UINT); typedef BOOL (WINAPI* MOVEWINDOWPROC)(HWND, int, int, int, int, BOOL); typedef LRESULT (WINAPI* SENDMESSAGEAPROC)(HWND, UINT, WPARAM, LPARAM); typedef LONG (WINAPI* SETWINDOWLONGAPROC)(HWND, int, LONG); +typedef BOOL (WINAPI* ENABLEWINDOWPROC)(HWND, BOOL); +typedef HWND (WINAPI* CREATEWINDOWEXAPROC)(DWORD, LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, LPVOID); +typedef BOOL (WINAPI* DESTROYWINDOWPROC)(HWND); extern GETCURSORPOSPROC real_GetCursorPos; extern CLIPCURSORPROC real_ClipCursor; @@ -38,6 +41,9 @@ extern SETWINDOWPOSPROC real_SetWindowPos; extern MOVEWINDOWPROC real_MoveWindow; extern SENDMESSAGEAPROC real_SendMessageA; extern SETWINDOWLONGAPROC real_SetWindowLongA; +extern ENABLEWINDOWPROC real_EnableWindow; +extern CREATEWINDOWEXAPROC real_CreateWindowExA; +extern DESTROYWINDOWPROC real_DestroyWindow; extern int HookingMethod; extern BOOL Hook_Active; diff --git a/inc/main.h b/inc/main.h index 8161349..19b8e5f 100644 --- a/inc/main.h +++ b/inc/main.h @@ -37,6 +37,7 @@ extern BOOL ChildWindowExists; BOOL detect_cutscene(); void LimitGameTicks(); +void ToggleFullscreen(); DWORD WINAPI render_main(void); DWORD WINAPI render_soft_main(void); BOOL CALLBACK EnumChildProc(HWND hWnd, LPARAM lParam); @@ -124,6 +125,8 @@ typedef struct IDirectDrawImpl BOOL altenter; BOOL hidecursor; BOOL accurateTimers; + BOOL bnetActive; + BOOL bnetWasFullscreen; SpeedLimiter ticksLimiter; SpeedLimiter flipLimiter; SpeedLimiter fpsLimiter; diff --git a/inc/mouse.h b/inc/mouse.h index dd18506..a11fd3d 100644 --- a/inc/mouse.h +++ b/inc/mouse.h @@ -23,5 +23,10 @@ BOOL WINAPI fake_SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int BOOL WINAPI fake_MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint); LRESULT WINAPI fake_SendMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); LONG WINAPI fake_SetWindowLongA(HWND hWnd, int nIndex, LONG dwNewLong); +BOOL WINAPI fake_EnableWindow(HWND hWnd, BOOL bEnable); +BOOL WINAPI fake_DestroyWindow(HWND hWnd); +HWND WINAPI fake_CreateWindowExA( + DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, + int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); #endif diff --git a/src/hook.c b/src/hook.c index 49a9841..743f255 100644 --- a/src/hook.c +++ b/src/hook.c @@ -27,6 +27,10 @@ SETWINDOWPOSPROC real_SetWindowPos = SetWindowPos; MOVEWINDOWPROC real_MoveWindow = MoveWindow; SENDMESSAGEAPROC real_SendMessageA = SendMessageA; SETWINDOWLONGAPROC real_SetWindowLongA = SetWindowLongA; +ENABLEWINDOWPROC real_EnableWindow = EnableWindow; +CREATEWINDOWEXAPROC real_CreateWindowExA = CreateWindowExA; +DESTROYWINDOWPROC real_DestroyWindow = DestroyWindow; + void Hook_PatchIAT(HMODULE hMod, char *moduleName, char *functionName, PROC newFunction) { @@ -100,7 +104,10 @@ void Hook_Create(char *moduleName, char *functionName, PROC newFunction, PROC *f #endif if (HookingMethod == 1) + { Hook_PatchIAT(GetModuleHandle(NULL), moduleName, functionName, newFunction); + Hook_PatchIAT(GetModuleHandle("storm.dll"), moduleName, functionName, newFunction); + } } void Hook_Revert(char *moduleName, char *functionName, PROC newFunction, PROC *function) @@ -122,6 +129,12 @@ void Hook_Revert(char *moduleName, char *functionName, PROC newFunction, PROC *f moduleName, functionName, GetProcAddress(GetModuleHandle(moduleName), functionName)); + + Hook_PatchIAT( + GetModuleHandle("storm.dll"), + moduleName, + functionName, + GetProcAddress(GetModuleHandle(moduleName), functionName)); } } @@ -148,6 +161,9 @@ void Hook_Init() Hook_Create("user32.dll", "MoveWindow", (PROC)fake_MoveWindow, (PROC *)&real_MoveWindow); Hook_Create("user32.dll", "SendMessageA", (PROC)fake_SendMessageA, (PROC *)&real_SendMessageA); Hook_Create("user32.dll", "SetWindowLongA", (PROC)fake_SetWindowLongA, (PROC *)&real_SetWindowLongA); + Hook_Create("user32.dll", "EnableWindow", (PROC)fake_EnableWindow, (PROC *)&real_EnableWindow); + Hook_Create("user32.dll", "CreateWindowExA", (PROC)fake_CreateWindowExA, (PROC *)&real_CreateWindowExA); + Hook_Create("user32.dll", "DestroyWindow", (PROC)fake_DestroyWindow, (PROC *)&real_DestroyWindow); } } @@ -174,5 +190,8 @@ void Hook_Exit() Hook_Revert("user32.dll", "MoveWindow", (PROC)fake_MoveWindow, (PROC *)&real_MoveWindow); Hook_Revert("user32.dll", "SendMessageA", (PROC)fake_SendMessageA, (PROC *)&real_SendMessageA); Hook_Revert("user32.dll", "SetWindowLongA", (PROC)fake_SetWindowLongA, (PROC *)&real_SetWindowLongA); + Hook_Revert("user32.dll", "EnableWindow", (PROC)fake_EnableWindow, (PROC *)&real_EnableWindow); + Hook_Revert("user32.dll", "CreateWindowExA", (PROC)fake_CreateWindowExA, (PROC *)&real_CreateWindowExA); + Hook_Revert("user32.dll", "DestroyWindow", (PROC)fake_DestroyWindow, (PROC *)&real_DestroyWindow); } } diff --git a/src/main.c b/src/main.c index 942ab15..8c65c79 100644 --- a/src/main.c +++ b/src/main.c @@ -226,6 +226,86 @@ void LimitGameTicks() } } +void UpdateBnetPos(int newX, int newY) +{ + static int oldX = -32000; + static int oldY = -32000; + + if (oldX == -32000 || oldY == -32000 || !ddraw->bnetActive) + { + oldX = newX; + oldY = newY; + return; + } + + POINT pt = { 0, 0 }; + real_ClientToScreen(ddraw->hWnd, &pt); + + RECT mainrc; + SetRect(&mainrc, pt.x, pt.y, pt.x + ddraw->width, pt.y + ddraw->height); + + int adjY = 0; + int adjX = 0; + + HWND hWnd = FindWindowEx(HWND_DESKTOP, NULL, "SDlgDialog", NULL); + + while (hWnd != NULL) + { + RECT rc; + real_GetWindowRect(hWnd, &rc); + + OffsetRect(&rc, newX - oldX, newY - oldY); + + real_SetWindowPos( + hWnd, + 0, + rc.left, + rc.top, + 0, + 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + + if (rc.bottom > mainrc.bottom && abs(mainrc.bottom - rc.bottom) > abs(adjY)) + adjY = mainrc.bottom - rc.bottom; + else if (rc.top < mainrc.top && abs(mainrc.top - rc.top) > abs(adjY)) + adjY = mainrc.top - rc.top; + + if (rc.right > mainrc.right && abs(mainrc.right - rc.right) > abs(adjX)) + adjX = mainrc.right - rc.right; + else if (rc.left < mainrc.left && abs(mainrc.left - rc.left) > abs(adjX)) + adjX = mainrc.left - rc.left; + + hWnd = FindWindowEx(HWND_DESKTOP, hWnd, "SDlgDialog", NULL); + } + + if (adjX || adjY) + { + HWND hWnd = FindWindowEx(HWND_DESKTOP, NULL, "SDlgDialog", NULL); + + while (hWnd != NULL) + { + RECT rc; + real_GetWindowRect(hWnd, &rc); + + OffsetRect(&rc, adjX, adjY); + + real_SetWindowPos( + hWnd, + 0, + rc.left, + rc.top, + 0, + 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + + hWnd = FindWindowEx(HWND_DESKTOP, hWnd, "SDlgDialog", NULL); + } + } + + oldX = newX; + oldY = newY; +} + HRESULT __stdcall ddraw_Compact(IDirectDrawImpl *This) { printf("??? DirectDraw::Compact(This=%p)\n", This); @@ -861,6 +941,9 @@ HRESULT __stdcall ddraw_SetDisplayMode2(IDirectDrawImpl *This, DWORD width, DWOR void ToggleFullscreen() { + if (ddraw->bnetActive) + return; + if (ddraw->windowed) { mouse_unlock(); @@ -868,6 +951,7 @@ void ToggleFullscreen() real_SetWindowLongA(ddraw->hWnd, GWL_STYLE, GetWindowLong(ddraw->hWnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU)); ddraw->altenter = TRUE; ddraw_SetDisplayMode(ddraw, ddraw->width, ddraw->height, ddraw->bpp); + UpdateBnetPos(0, 0); mouse_lock(); } else @@ -878,7 +962,7 @@ void ToggleFullscreen() if (Direct3D9Active) Direct3D9_Reset(); else - ChangeDisplaySettings(&ddraw->mode, 0); + ChangeDisplaySettings(&ddraw->mode, CDS_FULLSCREEN); ddraw_SetDisplayMode(ddraw, ddraw->width, ddraw->height, ddraw->bpp); mouse_lock(); @@ -1158,11 +1242,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (ddraw->windowed) { + int x = (int)(short)LOWORD(lParam); + int y = (int)(short)HIWORD(lParam); + + if (x != -32000 && y != -32000) + UpdateBnetPos(x, y); + if (inSizeMove || ddraw->wine) { - int x = (int)(short)LOWORD(lParam); - int y = (int)(short)HIWORD(lParam); - if (x != -32000) WindowRect.left = x; // -32000 = Exit/Minimize @@ -1246,7 +1333,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) if (!Direct3D9Active) { ShowWindow(ddraw->hWnd, SW_MINIMIZE); - ChangeDisplaySettings(&ddraw->mode, 0); + ChangeDisplaySettings(&ddraw->mode, CDS_FULLSCREEN); } } } diff --git a/src/mouse.c b/src/mouse.c index d3aacd2..4d00de1 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -19,6 +19,7 @@ #include "main.h" #include "surface.h" #include "hook.h" +#include "render_d3d9.h" int yAdjust = 0; @@ -142,6 +143,9 @@ void mouse_lock() { RECT rc; + if (ddraw->bnetActive) + return; + if (ddraw->devmode) { if (ddraw->handlemouse) @@ -407,3 +411,77 @@ LONG WINAPI fake_SetWindowLongA(HWND hWnd, int nIndex, LONG dwNewLong) return real_SetWindowLongA(hWnd, nIndex, dwNewLong); } + +BOOL WINAPI fake_EnableWindow(HWND hWnd, BOOL bEnable) +{ + if (ddraw && ddraw->hWnd == hWnd) + { + return FALSE; + } + + return real_EnableWindow(hWnd, bEnable); +} + +BOOL WINAPI fake_DestroyWindow(HWND hWnd) +{ + BOOL result = real_DestroyWindow(hWnd); + + if (ddraw && ddraw->hWnd != hWnd && ddraw->bnetActive) + { + RedrawWindow(NULL, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN); + + if (!FindWindowEx(HWND_DESKTOP, NULL, "SDlgDialog", NULL)) + { + ddraw->bnetActive = FALSE; + mouse_lock(); + + if (ddraw->windowed && ddraw->bnetWasFullscreen) + { + ToggleFullscreen(); + ddraw->bnetWasFullscreen = FALSE; + } + } + } + + return result; +} + +HWND WINAPI fake_CreateWindowExA( + DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, + int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) +{ + if (lpClassName && _strcmpi(lpClassName, "SDlgDialog") == 0 && ddraw) + { + if (!ddraw->bnetActive) + { + if (!ddraw->windowed && !ddraw->bnetWasFullscreen) + { + ToggleFullscreen(); + ddraw->bnetWasFullscreen = TRUE; + } + + ddraw->bnetActive = TRUE; + mouse_unlock(); + } + + POINT pt = { 0, 0 }; + real_ClientToScreen(ddraw->hWnd, &pt); + + X += pt.x; + Y += pt.y; + } + + return real_CreateWindowExA( + dwExStyle, + lpClassName, + lpWindowName, + dwStyle | WS_CLIPCHILDREN, + X, + Y, + nWidth, + nHeight, + hWndParent, + hMenu, + hInstance, + lpParam); +} diff --git a/src/render.c b/src/render.c index 674dc75..a4d3249 100644 --- a/src/render.c +++ b/src/render.c @@ -790,6 +790,9 @@ static void Render() glEnd(); } + if (ddraw->bnetActive) + glClear(GL_COLOR_BUFFER_BIT); + SwapBuffers(ddraw->render.hDC); #if _DEBUG diff --git a/src/render_d3d9.c b/src/render_d3d9.c index 3087c38..4dd47c4 100644 --- a/src/render_d3d9.c +++ b/src/render_d3d9.c @@ -404,6 +404,9 @@ DWORD WINAPI render_d3d9_main(void) IDirect3DDevice9_DrawPrimitive(D3dDev, D3DPT_TRIANGLESTRIP, 0, 2); IDirect3DDevice9_EndScene(D3dDev); + if (ddraw->bnetActive) + IDirect3DDevice9_Clear(D3dDev, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); + if (FAILED(IDirect3DDevice9_Present(D3dDev, NULL, NULL, NULL, NULL))) { DWORD_PTR dwResult; diff --git a/src/render_soft.c b/src/render_soft.c index 250f86a..f36ef4b 100644 --- a/src/render_soft.c +++ b/src/render_soft.c @@ -105,7 +105,12 @@ DWORD WINAPI render_soft_main(void) EnumChildWindows(ddraw->hWnd, EnumChildProc, (LPARAM)ddraw->primary); } - if (scaleCutscene) + if (ddraw->bnetActive) + { + RECT rc = { 0, 0, ddraw->render.width, ddraw->render.height }; + FillRect(ddraw->render.hDC, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH)); + } + else if (scaleCutscene) { StretchDIBits( ddraw->render.hDC, diff --git a/src/surface.c b/src/surface.c index bb227c8..5de71f1 100644 --- a/src/surface.c +++ b/src/surface.c @@ -20,6 +20,7 @@ #include "main.h" #include "hook.h" #include "surface.h" +#include "mouse.h" #include "scale_pattern.h" // enables redraw via blt/unlock if there wasn't any flip for X ms @@ -29,6 +30,7 @@ void dump_ddbltflags(DWORD dwFlags); void dump_ddscaps(DWORD dwCaps); void dump_ddsd(DWORD dwFlags); DWORD WINAPI render_soft_main(void); +void *pvBmpBits; HRESULT __stdcall ddraw_surface_QueryInterface(IDirectDrawSurfaceImpl *This, REFIID riid, void **obj) { @@ -1003,6 +1005,55 @@ HRESULT __stdcall ddraw_surface_Unlock(IDirectDrawSurfaceImpl *This, LPVOID lpRe printf("DirectDrawSurface::Unlock(This=%p, lpRect=%p)\n", This, lpRect); #endif + HWND hWnd = ddraw->bnetActive ? FindWindowEx(HWND_DESKTOP, NULL, "SDlgDialog", NULL) : NULL; + if (hWnd && (This->caps & DDSCAPS_PRIMARYSURFACE)) + { + if (ddraw->primary->palette && ddraw->primary->palette->data_rgb) + SetDIBColorTable(ddraw->primary->hDC, 0, 256, ddraw->primary->palette->data_rgb); + + //GdiTransparentBlt idea taken from Aqrit's war2 ddraw + + RGBQUAD quad; + GetDIBColorTable(ddraw->primary->hDC, 0xFE, 1, &quad); + COLORREF color = RGB(quad.rgbRed, quad.rgbGreen, quad.rgbBlue); + BOOL erase = FALSE; + + do + { + RECT rc; + if (fake_GetWindowRect(hWnd, &rc)) + { + if (rc.bottom - rc.top == 479) + erase = TRUE; + + HDC hDC = GetDCEx(hWnd, NULL, DCX_PARENTCLIP | DCX_CACHE); + + GdiTransparentBlt( + hDC, + 0, + 0, + rc.right - rc.left, + rc.bottom - rc.top, + ddraw->primary->hDC, + rc.left, + rc.top, + rc.right - rc.left, + rc.bottom - rc.top, + color + ); + + ReleaseDC(hWnd, hDC); + } + + } while ((hWnd = FindWindowEx(HWND_DESKTOP, hWnd, "SDlgDialog", NULL))); + + if (erase) + { + DDBLTFX fx = { .dwFillColor = 0xFE }; + IDirectDrawSurface_Blt(This, NULL, NULL, NULL, DDBLT_COLORFILL, &fx); + } + } + if (This->caps & DDSCAPS_PRIMARYSURFACE && ddraw->render.run && (!(This->flags & DDSD_BACKBUFFERCOUNT) || This->lastFlipTick + FLIP_REDRAW_TIMEOUT < timeGetTime())) @@ -1160,6 +1211,9 @@ HRESULT __stdcall ddraw_CreateSurface(IDirectDrawImpl *This, LPDDSURFACEDESC lpD if (!Surface->bitmap) Surface->surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Surface->lPitch * (Surface->height + 200) * Surface->lXPitch); + if (lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) + pvBmpBits = Surface->surface; + SelectObject(Surface->hDC, Surface->bitmap); }