diff --git a/Makefile b/Makefile index b10930b..ba2ed6d 100644 --- a/Makefile +++ b/Makefile @@ -1,53 +1,25 @@ -include config.mk -WINDRES ?= windres -LDFLAGS = -Iinc -Wall -Wl,--enable-stdcall-fixup -s -CFLAGS = -std=c99 -O2 -march=i486 -LIBS = -lgdi32 -lwinmm -lpsapi -ldbghelp -lole32 +TARGET ?= ddraw.dll -FILES = src/IDirect3D/IDirect3D.c \ - src/IDirect3D/IDirect3D2.c \ - src/IDirect3D/IDirect3D3.c \ - src/IDirect3D/IDirect3D7.c \ - src/IDirectDraw/IDirectDraw.c \ - src/IDirectDraw/IDirectDrawPalette.c \ - src/IDirectDraw/IDirectDrawClipper.c \ - src/IDirectDraw/IDirectDrawSurface.c \ - src/IDirectDraw/IDirectDrawGammaControl.c \ - src/IAMMediaStream/IAMMediaStream.c \ - src/crc32.c \ - src/blt.c \ - src/dd.c \ - src/ddpalette.c \ - src/ddsurface.c \ - src/ddclipper.c \ - src/render_ogl.c \ - src/render_gdi.c \ - src/render_d3d9.c \ - src/debug.c \ - src/mouse.c \ - src/winapi_hooks.c \ - src/screenshot.c \ - src/config.c \ - src/lodepng.c \ - src/directinput.c \ - src/hook.c \ - src/dllmain.c \ - src/wndproc.c \ - src/utils.c \ - src/fps_limiter.c \ - src/opengl_utils.c +LDFLAGS ?= -Wl,--enable-stdcall-fixup -s -static -shared +CFLAGS ?= -Iinc -O2 -Wall -std=c99 -Wno-incompatible-pointer-types +LIBS = -lgdi32 -lwinmm -lole32 -lmsimg32 -lpsapi -all: - $(info ) - $(info **********************************************************************************************) - $(info WARNING: This build is outdated and does not support all cnc-ddraw features [Detours/SEH]) - $(info WARNING: Some games that require hooks may crash or glitch, please use the msvc build instead) - $(info **********************************************************************************************) - $(info ) - $(WINDRES) -J rc ddraw.rc ddraw.rc.o - $(CC) $(CFLAGS) $(LDFLAGS) -shared -o ddraw.dll $(FILES) ddraw.def ddraw.rc.o $(LIBS) -# $(CC) $(CFLAGS) $(LDFLAGS) -nostdlib -shared -o ddraw.dll $(FILES) ddraw.def ddraw.rc.o $(LIBS) -lkernel32 -luser32 -lmsvcrt +CC = i686-w64-mingw32-gcc +WINDRES ?= i686-w64-mingw32-windres + +SRCS := $(wildcard src/*.c) $(wildcard src/*/*.c) ddraw.rc +OBJS := $(addsuffix .o, $(basename $(SRCS))) + +.PHONY: clean all +all: $(TARGET) + +%.o: %.rc + $(WINDRES) -J rc $< $@ || windres -J rc $< $@ + +$(TARGET): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ ddraw.def $(LIBS) clean: - $(RM) ddraw.dll ddraw.rc.o + $(RM) $(TARGET) $(OBJS) || del $(TARGET) $(subst /,\\,$(OBJS)) diff --git a/build.bat b/build.bat index 85a89a6..b3508d8 100644 --- a/build.bat +++ b/build.bat @@ -2,7 +2,7 @@ REM REM cnc-patch environment config REM -set PATH=C:\win-builds-patch-32\bin -gmake clean -gmake +set PATH=C:\w64devkit\bin +make clean +make pause diff --git a/inc/dd.h b/inc/dd.h index 1d0aa8f..1ab5d64 100644 --- a/inc/dd.h +++ b/inc/dd.h @@ -136,6 +136,7 @@ typedef struct CNCDDRAW void* last_freed_palette; /* Dungeon Keeper hack */ void* last_freed_surface; /* Nox hack */ BOOL child_window_exists; + HWND video_window_hwnd; BOOL got_child_windows; DWORD last_set_window_pos_tick; /* WINE hack */ SPEEDLIMITER ticks_limiter; diff --git a/inc/fps_limiter.h b/inc/fps_limiter.h index 5c8049f..019c3ef 100644 --- a/inc/fps_limiter.h +++ b/inc/fps_limiter.h @@ -48,6 +48,7 @@ typedef struct FPSLIMITER D3DKMTCLOSEADAPTERPROC D3DKMTCloseAdapter; BOOL got_adapter; BOOL initialized; + BOOL is_wine; } FPSLIMITER; extern FPSLIMITER g_fpsl; diff --git a/inc/hook.h b/inc/hook.h index 908c832..7f9c017 100644 --- a/inc/hook.h +++ b/inc/hook.h @@ -1,11 +1,10 @@ #ifndef HOOK_H #define HOOK_H -#define WIN32_LEAN_AND_MEAN #include - -#define SKIP_HOOK2 0x00000001l +#define HOOK_SKIP_2 0x00000001l +#define HOOK_LOCAL_ONLY 0x00000002l typedef struct HOOKLISTDATA { char function_name[32]; PROC new_function; PROC* function; DWORD flags; } HOOKLISTDATA; typedef struct HOOKLIST { char module_name[32]; HOOKLISTDATA data[30]; } HOOKLIST; @@ -58,6 +57,8 @@ typedef HMODULE(WINAPI* LOADLIBRARYEXWPROC)(LPCWSTR, HANDLE, DWORD); typedef FARPROC(WINAPI* GETPROCADDRESSPROC)(HMODULE, LPCSTR); typedef BOOL(WINAPI* GETDISKFREESPACEAPROC)(LPCSTR, LPDWORD, LPDWORD, LPDWORD, LPDWORD); typedef HRESULT(WINAPI* COCREATEINSTANCEPROC)(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID*); +typedef MCIERROR(WINAPI* MCISENDCOMMANDAPROC)(MCIDEVICEID, UINT, DWORD_PTR, DWORD_PTR); + typedef LPTOP_LEVEL_EXCEPTION_FILTER(WINAPI* SETUNHANDLEDEXCEPTIONFILTERPROC)(LPTOP_LEVEL_EXCEPTION_FILTER); extern GETCURSORPOSPROC real_GetCursorPos; @@ -101,6 +102,7 @@ extern LOADLIBRARYEXWPROC real_LoadLibraryExW; extern GETPROCADDRESSPROC real_GetProcAddress; extern GETDISKFREESPACEAPROC real_GetDiskFreeSpaceA; extern COCREATEINSTANCEPROC real_CoCreateInstance; +extern MCISENDCOMMANDAPROC real_mciSendCommandA; extern SETUNHANDLEDEXCEPTIONFILTERPROC real_SetUnhandledExceptionFilter; extern BOOL g_hook_active; @@ -109,7 +111,7 @@ extern HOOKLIST g_hook_hooklist[]; void hook_init(BOOL initial_hook); void hook_exit(); void hook_patch_iat(HMODULE hmod, BOOL unhook, char* module_name, char* function_name, PROC new_function); -void hook_patch_iat_list(HMODULE hmod, BOOL unhook, HOOKLIST* hooks); +void hook_patch_iat_list(HMODULE hmod, BOOL unhook, HOOKLIST* hooks, BOOL is_local); void hook_create(HOOKLIST* hooks, BOOL initial_hook); void hook_revert(HOOKLIST* hooks); diff --git a/inc/version.h b/inc/version.h index 510cf80..5276877 100644 --- a/inc/version.h +++ b/inc/version.h @@ -7,7 +7,7 @@ #define VERSION_MAJOR 5 #define VERSION_MINOR 7 #define VERSION_BUILD 0 -#define VERSION_REVISION 6 +#define VERSION_REVISION 7 #define VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD, VERSION_REVISION #define VERSION_STRING ver_str(VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD, VERSION_REVISION) diff --git a/inc/winapi_hooks.h b/inc/winapi_hooks.h index b2962da..f99fde1 100644 --- a/inc/winapi_hooks.h +++ b/inc/winapi_hooks.h @@ -1,7 +1,6 @@ #ifndef WINAPI_HOOKS_H #define WINAPI_HOOKS_H -#define WIN32_LEAN_AND_MEAN #include @@ -66,6 +65,8 @@ HWND WINAPI fake_CreateWindowExA( HRESULT WINAPI fake_CoCreateInstance( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID* ppv); +MCIERROR WINAPI fake_mciSendCommandA(MCIDEVICEID IDDevice, UINT uMsg, DWORD_PTR fdwCommand, DWORD_PTR dwParam); + LPTOP_LEVEL_EXCEPTION_FILTER WINAPI fake_SetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); diff --git a/src/IDirectDraw/IDirectDraw.c b/src/IDirectDraw/IDirectDraw.c index 3bf3861..166d388 100644 --- a/src/IDirectDraw/IDirectDraw.c +++ b/src/IDirectDraw/IDirectDraw.c @@ -1,3 +1,4 @@ +#include #include #include "IDirectDraw.h" #include "IDirect3D.h" diff --git a/src/config.c b/src/config.c index cb8b656..2b66ab2 100644 --- a/src/config.c +++ b/src/config.c @@ -34,7 +34,7 @@ void cfg_load() GET_INT(g_config.window_rect.bottom, "height", 0); GET_BOOL(g_config.fullscreen, "fullscreen", FALSE); GET_BOOL(g_config.windowed, "windowed", FALSE); - GET_BOOL(g_config.maintas, "maintas", FALSE); + GET_BOOL(g_config.maintas, "maintas", TRUE); GET_BOOL(g_config.boxing, "boxing", FALSE); GET_INT(g_config.maxfps, "maxfps", -1); GET_BOOL(g_config.vsync, "vsync", FALSE); @@ -167,13 +167,13 @@ static void cfg_create_ini() "\n" "; Override the width/height settings shown above and always stretch to fullscreen\n" "; Note: Can be combined with 'windowed=true' to get windowed-fullscreen aka borderless mode\n" - "fullscreen=false\n" + "fullscreen=true\n" "\n" "; Run in windowed mode rather than going fullscreen\n" - "windowed=false\n" + "windowed=true\n" "\n" "; Maintain aspect ratio\n" - "maintas=false\n" + "maintas=true\n" "\n" "; Windowboxing / Integer Scaling\n" "boxing=false\n" @@ -201,7 +201,7 @@ static void cfg_create_ini() "posY=-32000\n" "\n" "; Renderer, possible values: auto, opengl, openglcore, gdi, direct3d9, direct3d9on12 (auto = try direct3d9/opengl, fallback = gdi)\n" - "renderer=auto\n" + "renderer=opengl\n" "\n" "; Developer mode (don't lock the cursor)\n" "devmode=false\n" @@ -227,7 +227,7 @@ static void cfg_create_ini() "screenshotdir=.\\Screenshots\\\n" "\n" "; Switch between windowed/borderless modes with alt+enter rather than windowed/fullscreen modes\n" - "toggle_borderless=false\n" + "toggle_borderless=true\n" "\n" "\n" "\n" @@ -236,7 +236,7 @@ static void cfg_create_ini() "\n" "\n" "; Hide WM_ACTIVATEAPP and WM_NCACTIVATE messages to prevent problems on alt+tab\n" - "noactivateapp=false\n" + "noactivateapp=true\n" "\n" "; Max game ticks per second, possible values: -1 = disabled, -2 = refresh rate, 0 = emulate 60hz vblank, 1-1000 = custom game speed\n" "; Note: Can be used to slow down a too fast running game, fix flickering or too fast animations\n" @@ -249,7 +249,7 @@ static void cfg_create_ini() "\n" "; Disable fullscreen-exclusive mode for the direct3d9*/opengl* renderers\n" "; Note: Can be used in case some GUI elements like buttons/textboxes/videos/etc.. are invisible\n" - "nonexclusive=false\n" + "nonexclusive=true\n" "\n" "; Force CPU0 affinity, avoids crashes/freezing, *might* have a performance impact\n" "; Note: Disable this if the game is not running smooth or there are sound issues\n" diff --git a/src/dd.c b/src/dd.c index 9027306..14b0874 100644 --- a/src/dd.c +++ b/src/dd.c @@ -590,6 +590,11 @@ HRESULT dd_SetDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwBPP, DWORD dwFl g_config.fullscreen = FALSE; } } + + if (g_config.maxgameticks == 0 && g_ddraw->mode.dmDisplayFrequency == 60) + { + g_config.maxgameticks = -2; + } } g_ddraw->render.width = g_config.window_rect.right; @@ -1006,13 +1011,31 @@ HRESULT dd_SetDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwBPP, DWORD dwFl } } - if ((!d3d9_active || g_config.nonexclusive) && - ChangeDisplaySettings(&g_ddraw->render.mode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) + if (!d3d9_active || g_config.nonexclusive) { - g_ddraw->render.run = FALSE; - g_config.windowed = TRUE; - g_config.fullscreen = TRUE; - return dd_SetDisplayMode(dwWidth, dwHeight, dwBPP, dwFlags); + if (ChangeDisplaySettings(&g_ddraw->render.mode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) + { + g_ddraw->render.run = FALSE; + g_config.windowed = TRUE; + g_config.fullscreen = TRUE; + return dd_SetDisplayMode(dwWidth, dwHeight, dwBPP, dwFlags); + } + + /* + Fix wayland bug: + ChangeDisplaySettings fails silently - enable borderless mode in case display resolution was not changed + */ + if (g_ddraw->wine && + (g_ddraw->render.mode.dmPelsWidth != real_GetSystemMetrics(SM_CXSCREEN) || + g_ddraw->render.mode.dmPelsHeight != real_GetSystemMetrics(SM_CYSCREEN))) + { + ChangeDisplaySettings(NULL, 0); + + g_ddraw->render.run = FALSE; + g_config.windowed = TRUE; + g_config.fullscreen = TRUE; + return dd_SetDisplayMode(dwWidth, dwHeight, dwBPP, dwFlags); + } } if (g_ddraw->wine) @@ -1189,7 +1212,7 @@ HRESULT dd_WaitForVerticalBlank(DWORD dwFlags, HANDLE hEvent) { if (g_config.maxgameticks == -2) { - if (fpsl_dwm_flush() || fpsl_wait_for_vblank(g_config.maxfps >= 0 && !g_config.vsync)) + if (fpsl_wait_for_vblank(g_config.maxfps >= 0 && !g_config.vsync) || fpsl_dwm_flush()) return DD_OK; } diff --git a/src/ddsurface.c b/src/ddsurface.c index 3ca910d..5aa9fcc 100644 --- a/src/ddsurface.c +++ b/src/ddsurface.c @@ -1442,7 +1442,8 @@ HRESULT dd_CreateSurface( if (InterlockedExchangeAdd(&g_dds_gdi_handles, 0) < 4000 || - (dst_surface->width == g_ddraw->width && dst_surface->height == g_ddraw->height)) + (dst_surface->width == g_ddraw->width && dst_surface->height == g_ddraw->height) || + (dst_surface->width == 128 && dst_surface->height == 128)) { dst_surface->hdc = CreateCompatibleDC(g_ddraw->render.hdc); diff --git a/src/dllmain.c b/src/dllmain.c index ff55417..b6c5f2b 100644 --- a/src/dllmain.c +++ b/src/dllmain.c @@ -9,6 +9,7 @@ #include "debug.h" #include "config.h" #include "hook.h" +#include "patch.h" /* export for cncnet cnc games */ @@ -38,6 +39,70 @@ BOOL WINAPI DllMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved) #endif g_ddraw_module = hDll; + + + /* Claw DVD Movie experiments */ + + /* change file extension .vob to .avi */ + HMODULE game_exe = GetModuleHandleA(NULL); + + PIMAGE_DOS_HEADER dos_hdr = (void*)game_exe; + PIMAGE_NT_HEADERS nt_hdr = (void*)((char*)game_exe + dos_hdr->e_lfanew); + + for (int i = 0; i < nt_hdr->FileHeader.NumberOfSections; i++) + { + PIMAGE_SECTION_HEADER sct_hdr = IMAGE_FIRST_SECTION(nt_hdr) + i; + + if (strcmp(".data", (char*)sct_hdr->Name) == 0) + { + char* s = (char*)((char*)game_exe + sct_hdr->VirtualAddress); + int s_len = sct_hdr->Misc.VirtualSize; + + for (int i = 0; i < s_len; i++, s++) + { + if (*s == '.' && memcmp(s, "\x2E\x76\x6F\x62\x00", 5) == 0) /* .vob */ + { + memcpy(s, "\x2E\x61\x76\x69", 4); /* .avi */ + } + } + + break; + } + sct_hdr++; + } + + /* add registry key for x264vfw */ + + BOOL is_wine = real_GetProcAddress(GetModuleHandleA("ntdll.dll"), "wine_get_version") != 0; + + HKEY hkey; + LONG status = + RegCreateKeyExA( + is_wine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32", + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_WRITE | KEY_QUERY_VALUE, + NULL, + &hkey, + NULL); + + if (status == ERROR_SUCCESS) + { + LPCTSTR x264 = "x264vfw.dll"; + RegSetValueExA(hkey,"vidc.x264", 0, REG_SZ, (const BYTE*)x264, strlen(x264) + 1); + + LPCTSTR xvid = "xvidvfw.dll"; + RegSetValueExA(hkey, "vidc.xvid", 0, REG_SZ, (const BYTE*)xvid, strlen(xvid) + 1); + + RegCloseKey(hkey); + } + + + + + char buf[1024]; if (GetEnvironmentVariable("__COMPAT_LAYER", buf, sizeof(buf))) diff --git a/src/fps_limiter.c b/src/fps_limiter.c index 094f902..2652598 100644 --- a/src/fps_limiter.c +++ b/src/fps_limiter.c @@ -75,6 +75,8 @@ void fpsl_init() (D3DKMTCLOSEADAPTERPROC)real_GetProcAddress(g_fpsl.gdi32_dll, "D3DKMTCloseAdapter"); } + g_fpsl.is_wine = real_GetProcAddress(GetModuleHandleA("ntdll.dll"), "wine_get_version") != 0; + g_fpsl.initialized = TRUE; } @@ -104,7 +106,12 @@ BOOL fpsl_wait_for_vblank(BOOL open_adapter) BOOL fpsl_dwm_flush() { - return g_fpsl.initialized && fpsl_dwm_is_enabled() && g_fpsl.DwmFlush && SUCCEEDED(g_fpsl.DwmFlush()); + return + g_fpsl.initialized && + fpsl_dwm_is_enabled() && + g_fpsl.DwmFlush && + !g_fpsl.is_wine && + SUCCEEDED(g_fpsl.DwmFlush()); } BOOL fpsl_dwm_is_enabled() diff --git a/src/hook.c b/src/hook.c index a1e3407..b40977f 100644 --- a/src/hook.c +++ b/src/hook.c @@ -1,4 +1,3 @@ -#define WIN32_LEAN_AND_MEAN #include #include #include @@ -57,6 +56,7 @@ LOADLIBRARYEXWPROC real_LoadLibraryExW = LoadLibraryExW; GETPROCADDRESSPROC real_GetProcAddress = GetProcAddress; GETDISKFREESPACEAPROC real_GetDiskFreeSpaceA = GetDiskFreeSpaceA; COCREATEINSTANCEPROC real_CoCreateInstance = CoCreateInstance; +MCISENDCOMMANDAPROC real_mciSendCommandA = mciSendCommandA; SETUNHANDLEDEXCEPTIONFILTERPROC real_SetUnhandledExceptionFilter = SetUnhandledExceptionFilter; HOOKLIST g_hook_hooklist[] = @@ -98,33 +98,40 @@ HOOKLIST g_hook_hooklist[] = { "ole32.dll", { - { "CoCreateInstance", (PROC)fake_CoCreateInstance, (PROC*)&real_CoCreateInstance, SKIP_HOOK2 }, + { "CoCreateInstance", (PROC)fake_CoCreateInstance, (PROC*)&real_CoCreateInstance, HOOK_SKIP_2 }, + { "", NULL, NULL, 0 } + } + }, + { + "winmm.dll", + { + { "mciSendCommandA", (PROC)fake_mciSendCommandA, (PROC*)&real_mciSendCommandA, HOOK_SKIP_2 }, { "", NULL, NULL, 0 } } }, { "dinput.dll", { - { "DirectInputCreateA", (PROC)fake_DirectInputCreateA, (PROC*)&real_DirectInputCreateA, SKIP_HOOK2 }, - //{ "DirectInputCreateW", (PROC)fake_DirectInputCreateW, (PROC*)&real_DirectInputCreateW, SKIP_HOOK2 }, - { "DirectInputCreateEx", (PROC)fake_DirectInputCreateEx, (PROC*)&real_DirectInputCreateEx, SKIP_HOOK2 }, + { "DirectInputCreateA", (PROC)fake_DirectInputCreateA, (PROC*)&real_DirectInputCreateA, HOOK_SKIP_2 }, + //{ "DirectInputCreateW", (PROC)fake_DirectInputCreateW, (PROC*)&real_DirectInputCreateW, HOOK_SKIP_2 }, + { "DirectInputCreateEx", (PROC)fake_DirectInputCreateEx, (PROC*)&real_DirectInputCreateEx, HOOK_SKIP_2 }, { "", NULL, NULL, 0 } } }, { "dinput8.dll", { - { "DirectInput8Create", (PROC)fake_DirectInput8Create, (PROC*)&real_DirectInput8Create, SKIP_HOOK2 }, + { "DirectInput8Create", (PROC)fake_DirectInput8Create, (PROC*)&real_DirectInput8Create, HOOK_SKIP_2 }, { "", NULL, NULL, 0 } } }, { "gdi32.dll", { - { "StretchBlt", (PROC)fake_StretchBlt, (PROC*)&real_StretchBlt, SKIP_HOOK2 }, - { "SetDIBitsToDevice", (PROC)fake_SetDIBitsToDevice, (PROC*)&real_SetDIBitsToDevice, SKIP_HOOK2 }, - { "StretchDIBits", (PROC)fake_StretchDIBits, (PROC*)&real_StretchDIBits, SKIP_HOOK2 }, - { "GetDeviceCaps", (PROC)fake_GetDeviceCaps, (PROC*)&real_GetDeviceCaps, 0 }, + { "StretchBlt", (PROC)fake_StretchBlt, (PROC*)&real_StretchBlt, HOOK_SKIP_2 }, + { "SetDIBitsToDevice", (PROC)fake_SetDIBitsToDevice, (PROC*)&real_SetDIBitsToDevice, HOOK_SKIP_2 }, + { "StretchDIBits", (PROC)fake_StretchDIBits, (PROC*)&real_StretchDIBits, HOOK_SKIP_2 }, + { "GetDeviceCaps", (PROC)fake_GetDeviceCaps, (PROC*)&real_GetDeviceCaps, HOOK_LOCAL_ONLY }, { "CreateFontA", (PROC)fake_CreateFontA, (PROC*)&real_CreateFontA, 0 }, { "CreateFontIndirectA", (PROC)fake_CreateFontIndirectA, (PROC*)&real_CreateFontIndirectA, 0 }, { "", NULL, NULL, 0 } @@ -133,12 +140,12 @@ HOOKLIST g_hook_hooklist[] = { "kernel32.dll", { - { "LoadLibraryA", (PROC)fake_LoadLibraryA, (PROC*)&real_LoadLibraryA, SKIP_HOOK2 }, - { "LoadLibraryW", (PROC)fake_LoadLibraryW, (PROC*)&real_LoadLibraryW, SKIP_HOOK2 }, - { "LoadLibraryExA", (PROC)fake_LoadLibraryExA, (PROC*)&real_LoadLibraryExA, SKIP_HOOK2 }, - { "LoadLibraryExW", (PROC)fake_LoadLibraryExW, (PROC*)&real_LoadLibraryExW, SKIP_HOOK2 }, - { "GetProcAddress", (PROC)fake_GetProcAddress, (PROC*)&real_GetProcAddress, SKIP_HOOK2 }, - { "GetDiskFreeSpaceA", (PROC)fake_GetDiskFreeSpaceA, (PROC*)&real_GetDiskFreeSpaceA, SKIP_HOOK2 }, + { "LoadLibraryA", (PROC)fake_LoadLibraryA, (PROC*)&real_LoadLibraryA, HOOK_SKIP_2 }, + { "LoadLibraryW", (PROC)fake_LoadLibraryW, (PROC*)&real_LoadLibraryW, HOOK_SKIP_2 }, + { "LoadLibraryExA", (PROC)fake_LoadLibraryExA, (PROC*)&real_LoadLibraryExA, HOOK_SKIP_2 }, + { "LoadLibraryExW", (PROC)fake_LoadLibraryExW, (PROC*)&real_LoadLibraryExW, HOOK_SKIP_2 }, + { "GetProcAddress", (PROC)fake_GetProcAddress, (PROC*)&real_GetProcAddress, HOOK_SKIP_2 }, + { "GetDiskFreeSpaceA", (PROC)fake_GetDiskFreeSpaceA, (PROC*)&real_GetDiskFreeSpaceA, HOOK_SKIP_2 }, { "", NULL, NULL, 0 } } }, @@ -160,10 +167,10 @@ void hook_patch_iat(HMODULE hmod, BOOL unhook, char* module_name, char* function strncpy(hooks[0].module_name, module_name, sizeof(hooks[0].module_name) - 1); strncpy(hooks[0].data[0].function_name, function_name, sizeof(hooks[0].data[0].function_name) - 1); - hook_patch_iat_list(hmod, unhook, (HOOKLIST*)&hooks); + hook_patch_iat_list(hmod, unhook, (HOOKLIST*)&hooks, FALSE); } -void hook_patch_obfuscated_iat_list(HMODULE hmod, BOOL unhook, HOOKLIST* hooks) +void hook_patch_obfuscated_iat_list(HMODULE hmod, BOOL unhook, HOOKLIST* hooks, BOOL is_local) { if (!hmod || hmod == INVALID_HANDLE_VALUE || !hooks) return; @@ -178,14 +185,22 @@ void hook_patch_obfuscated_iat_list(HMODULE hmod, BOOL unhook, HOOKLIST* hooks) if (nt_headers->Signature != IMAGE_NT_SIGNATURE) return; - PIMAGE_IMPORT_DESCRIPTOR import_desc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)dos_header + - (DWORD)(nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)); + DWORD import_desc_rva = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; + DWORD import_desc_size = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size; - if (import_desc == (PIMAGE_IMPORT_DESCRIPTOR)nt_headers) + if (import_desc_rva == 0 || import_desc_size == 0) return; + PIMAGE_IMPORT_DESCRIPTOR import_desc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)dos_header + import_desc_rva); + while (import_desc->FirstThunk) { + if (!import_desc->Name) + { + import_desc++; + continue; + } + for (int i = 0; hooks[i].module_name[0]; i++) { char* imp_module_name = (char*)((DWORD)dos_header + (DWORD)(import_desc->Name)); @@ -212,6 +227,9 @@ void hook_patch_obfuscated_iat_list(HMODULE hmod, BOOL unhook, HOOKLIST* hooks) if (!hooks[i].data[x].new_function || !org_function) continue; + if (!is_local && (hooks[i].data[x].flags & HOOK_LOCAL_ONLY)) + continue; + if (unhook) { if (first_thunk->u1.Function == (DWORD)hooks[i].data[x].new_function) @@ -268,9 +286,9 @@ void hook_patch_obfuscated_iat_list(HMODULE hmod, BOOL unhook, HOOKLIST* hooks) } } -void hook_patch_iat_list(HMODULE hmod, BOOL unhook, HOOKLIST* hooks) +void hook_patch_iat_list(HMODULE hmod, BOOL unhook, HOOKLIST* hooks, BOOL is_local) { - hook_patch_obfuscated_iat_list(hmod, unhook, hooks); + hook_patch_obfuscated_iat_list(hmod, unhook, hooks, is_local); if (!hmod || hmod == INVALID_HANDLE_VALUE || !hooks) return; @@ -285,39 +303,53 @@ void hook_patch_iat_list(HMODULE hmod, BOOL unhook, HOOKLIST* hooks) if (nt_headers->Signature != IMAGE_NT_SIGNATURE) return; - PIMAGE_IMPORT_DESCRIPTOR import_desc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)dos_header + - (DWORD)(nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)); + DWORD import_desc_rva = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; + DWORD import_desc_size = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size; - if (import_desc == (PIMAGE_IMPORT_DESCRIPTOR)nt_headers) + if (import_desc_rva == 0 || import_desc_size == 0) return; + PIMAGE_IMPORT_DESCRIPTOR import_desc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)dos_header + import_desc_rva); + while (import_desc->FirstThunk) { + if (!import_desc->OriginalFirstThunk || !import_desc->Name) + { + import_desc++; + continue; + } + for (int i = 0; hooks[i].module_name[0]; i++) { - char* imp_module_name = (char*)((DWORD)dos_header + (DWORD)(import_desc->Name)); + char* imp_module_name = (char*)((DWORD)dos_header + import_desc->Name); if (_stricmp(imp_module_name, hooks[i].module_name) == 0) { - PIMAGE_THUNK_DATA first_thunk = - (PIMAGE_THUNK_DATA)((DWORD)dos_header + (DWORD)import_desc->FirstThunk); + PIMAGE_THUNK_DATA first_thunk = (void*)((DWORD)dos_header + import_desc->FirstThunk); + PIMAGE_THUNK_DATA o_first_thunk = (void*)((DWORD)dos_header + import_desc->OriginalFirstThunk); - PIMAGE_THUNK_DATA original_first_thunk = - (PIMAGE_THUNK_DATA)((DWORD)dos_header + (DWORD)import_desc->OriginalFirstThunk); - - while (first_thunk->u1.Function && original_first_thunk->u1.AddressOfData) + while (first_thunk->u1.Function) { - PIMAGE_IMPORT_BY_NAME import = - (PIMAGE_IMPORT_BY_NAME)((DWORD)dos_header + original_first_thunk->u1.AddressOfData); + if (!o_first_thunk->u1.AddressOfData) + { + first_thunk++; + o_first_thunk++; + continue; + } - if ((original_first_thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) == 0) + PIMAGE_IMPORT_BY_NAME import = (void*)((DWORD)dos_header + o_first_thunk->u1.AddressOfData); + + if ((o_first_thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) == 0) { for (int x = 0; hooks[i].data[x].function_name[0]; x++) { if (!unhook && !hooks[i].data[x].new_function) continue; - if (_stricmp((const char*)import->Name, hooks[i].data[x].function_name) == 0) + if (!is_local && (hooks[i].data[x].flags & HOOK_LOCAL_ONLY)) + continue; + + if (strcmp((const char*)import->Name, hooks[i].data[x].function_name) == 0) { DWORD op; @@ -354,7 +386,7 @@ void hook_patch_iat_list(HMODULE hmod, BOOL unhook, HOOKLIST* hooks) } first_thunk++; - original_first_thunk++; + o_first_thunk++; } } } @@ -415,7 +447,7 @@ void hook_create(HOOKLIST* hooks, BOOL initial_hook) { for (int x = 0; hooks[i].data[x].function_name[0]; x++) { - if ((hooks[i].data[x].flags & SKIP_HOOK2)) + if ((hooks[i].data[x].flags & HOOK_SKIP_2)) continue; DetourTransactionBegin(); @@ -470,12 +502,18 @@ void hook_create(HOOKLIST* hooks, BOOL initial_hook) _strcmpi(mod_filename, "Shw32") == 0) continue; - if (_strnicmp(game_dir, mod_dir, strlen(game_dir)) == 0 || + BOOL is_local = _strnicmp(game_dir, mod_dir, strlen(game_dir)) == 0; + BOOL is_wine = real_GetProcAddress(GetModuleHandleA("ntdll.dll"), "wine_get_version") != 0; + + BOOL wine_hook = is_wine && _strcmpi(mod_filename, "mciavi32") == 0; + + if (is_local || + wine_hook || _strcmpi(mod_filename, "MSVFW32") == 0 || _strcmpi(mod_filename, "quartz") == 0 || _strcmpi(mod_filename, "winmm") == 0) { - hook_patch_iat_list(hmod, FALSE, hooks); + hook_patch_iat_list(hmod, FALSE, hooks, is_local); } } } @@ -487,7 +525,7 @@ void hook_create(HOOKLIST* hooks, BOOL initial_hook) if (g_config.hook == 1) { - hook_patch_iat_list(GetModuleHandle(NULL), FALSE, hooks); + hook_patch_iat_list(GetModuleHandle(NULL), FALSE, hooks, TRUE); } } @@ -500,7 +538,7 @@ void hook_revert(HOOKLIST* hooks) { for (int x = 0; hooks[i].data[x].function_name[0]; x++) { - if ((hooks[i].data[x].flags & SKIP_HOOK2)) + if ((hooks[i].data[x].flags & HOOK_SKIP_2)) continue; DetourTransactionBegin(); @@ -544,12 +582,18 @@ void hook_revert(HOOKLIST* hooks) { _splitpath(mod_path, NULL, mod_dir, mod_filename, NULL); - if (_strnicmp(game_dir, mod_dir, strlen(game_dir)) == 0 || + BOOL is_local = _strnicmp(game_dir, mod_dir, strlen(game_dir)) == 0; + BOOL is_wine = real_GetProcAddress(GetModuleHandleA("ntdll.dll"), "wine_get_version") != 0; + + BOOL wine_hook = is_wine && _strcmpi(mod_filename, "mciavi32") == 0; + + if (is_local || + wine_hook || _strcmpi(mod_filename, "MSVFW32") == 0 || _strcmpi(mod_filename, "quartz") == 0 || _strcmpi(mod_filename, "winmm") == 0) { - hook_patch_iat_list(hmod, TRUE, hooks); + hook_patch_iat_list(hmod, TRUE, hooks, is_local); } } } @@ -561,7 +605,7 @@ void hook_revert(HOOKLIST* hooks) if (g_config.hook == 1) { - hook_patch_iat_list(GetModuleHandle(NULL), TRUE, hooks); + hook_patch_iat_list(GetModuleHandle(NULL), TRUE, hooks, TRUE); } } diff --git a/src/render_d3d9.c b/src/render_d3d9.c index 66511ad..8898df4 100644 --- a/src/render_d3d9.c +++ b/src/render_d3d9.c @@ -10,7 +10,7 @@ #include "wndproc.h" #include "blt.h" #include "debug.h" -#include "D3d9types.h" +#include "d3d9types.h" #include "hook.h" #include "config.h" @@ -541,6 +541,7 @@ DWORD WINAPI d3d9_render_main(void) if (g_config.fixchilds) { g_ddraw->child_window_exists = FALSE; + InterlockedExchangePointer(&g_ddraw->video_window_hwnd, NULL); EnumChildWindows(g_ddraw->hwnd, util_enum_child_proc, (LPARAM)g_ddraw->primary); if (g_ddraw->render.width != g_ddraw->width || g_ddraw->render.height != g_ddraw->height) diff --git a/src/render_gdi.c b/src/render_gdi.c index c3f339f..4a24747 100644 --- a/src/render_gdi.c +++ b/src/render_gdi.c @@ -84,6 +84,7 @@ DWORD WINAPI gdi_render_main(void) if (g_config.fixchilds) { g_ddraw->child_window_exists = FALSE; + InterlockedExchangePointer(&g_ddraw->video_window_hwnd, NULL); EnumChildWindows(g_ddraw->hwnd, util_enum_child_proc, (LPARAM)g_ddraw->primary); } diff --git a/src/render_ogl.c b/src/render_ogl.c index cc87e92..79b1477 100644 --- a/src/render_ogl.c +++ b/src/render_ogl.c @@ -770,6 +770,7 @@ static void ogl_render() if (g_config.fixchilds) { g_ddraw->child_window_exists = FALSE; + InterlockedExchangePointer(&g_ddraw->video_window_hwnd, NULL); EnumChildWindows(g_ddraw->hwnd, util_enum_child_proc, (LPARAM)g_ddraw->primary); if (g_ddraw->render.width != g_ddraw->width || g_ddraw->render.height != g_ddraw->height) diff --git a/src/utils.c b/src/utils.c index 8477297..028b93c 100644 --- a/src/utils.c +++ b/src/utils.c @@ -472,24 +472,18 @@ BOOL CALLBACK util_enum_child_proc(HWND hwnd, LPARAM lparam) if (g_config.fixchilds == FIX_CHILDS_DETECT_HIDE || strcmp(class_name, "VideoRenderer") == 0 || + strcmp(class_name, "MCIAVI") == 0 || strcmp(class_name, "AVIWnd32") == 0 || + strcmp(class_name, "Afx:400000:3") == 0 || strcmp(class_name, "MCIWndClass") == 0) { + InterlockedExchangePointer(&g_ddraw->video_window_hwnd, hwnd); + LONG style = real_GetWindowLongA(hwnd, GWL_EXSTYLE); if (!(style & WS_EX_TRANSPARENT)) { real_SetWindowLongA(hwnd, GWL_EXSTYLE, style | WS_EX_TRANSPARENT); - - real_SetWindowPos( - hwnd, - 0, - 0, - 0, - 0, - 0, - SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER - ); } } else diff --git a/src/winapi_hooks.c b/src/winapi_hooks.c index f795b27..bb7da5d 100644 --- a/src/winapi_hooks.c +++ b/src/winapi_hooks.c @@ -738,9 +738,11 @@ BOOL WINAPI fake_StretchBlt( (g_config.fixchilds && IsChild(g_ddraw->hwnd, hwnd) && (g_config.fixchilds == FIX_CHILDS_DETECT_HIDE || strcmp(class_name, "AVIWnd32") == 0 || + strcmp(class_name, "Afx:400000:3") == 0 || + strcmp(class_name, "VideoRenderer") == 0 || strcmp(class_name, "MCIWndClass") == 0)))) { - if (g_ddraw->primary && (g_ddraw->primary->bpp == 16 || g_ddraw->primary->bpp == 32 || g_ddraw->primary->palette)) + if (0)//g_ddraw->primary && (g_ddraw->primary->bpp == 16 || g_ddraw->primary->bpp == 32 || g_ddraw->primary->palette)) { HDC primary_dc; dds_GetDC(g_ddraw->primary, &primary_dc); @@ -757,12 +759,30 @@ BOOL WINAPI fake_StretchBlt( } else if (g_ddraw->width > 0 && g_ddraw->render.hdc) { + // new logic by emoon + // g_ddraw->width check detects new widescreen patch + if (g_ddraw->width > 640 && g_config.maintas) + { + int base_width = g_ddraw->height * 4.0 / 3.0; + double scaling_factor = (double)g_ddraw->render.height / g_ddraw->height; + wDest = base_width * scaling_factor; + hDest = g_ddraw->render.height; + xDest += (g_ddraw->render.width - wDest) / 2; + } + else // original 4:3 logic + { + xDest += g_ddraw->render.viewport.x; + yDest += g_ddraw->render.viewport.y; + wDest = (int)(wDest * g_ddraw->render.scale_w); + hDest = (int)(hDest * g_ddraw->render.scale_h); + } + return real_StretchBlt( g_ddraw->render.hdc, - xDest + g_ddraw->render.viewport.x, - yDest + g_ddraw->render.viewport.y, - (int)(wDest * g_ddraw->render.scale_w), - (int)(hDest * g_ddraw->render.scale_h), + xDest, + yDest, + wDest, + hDest, hdcSrc, xSrc, ySrc, @@ -838,9 +858,26 @@ int WINAPI fake_StretchDIBits( UINT iUsage, DWORD rop) { - if (g_ddraw && g_ddraw->hwnd && WindowFromDC(hdc) == g_ddraw->hwnd) + HWND hwnd = WindowFromDC(hdc); + + char class_name[MAX_PATH] = { 0 }; + + if (g_ddraw && g_ddraw->hwnd && hwnd && hwnd != g_ddraw->hwnd) { - if (g_ddraw->primary && (g_ddraw->primary->bpp == 16 || g_ddraw->primary->bpp == 32 || g_ddraw->primary->palette)) + GetClassNameA(hwnd, class_name, sizeof(class_name) - 1); + } + + if (g_ddraw && g_ddraw->hwnd && + (hwnd == g_ddraw->hwnd || + (g_config.fixchilds && IsChild(g_ddraw->hwnd, hwnd) && + (g_config.fixchilds == FIX_CHILDS_DETECT_HIDE || + strcmp(class_name, "MCIAVI") == 0 || + strcmp(class_name, "AVIWnd32") == 0 || + strcmp(class_name, "Afx:400000:3") == 0 || + strcmp(class_name, "VideoRenderer") == 0 || + strcmp(class_name, "MCIWndClass") == 0)))) + { + if (0) // g_ddraw->primary && (g_ddraw->primary->bpp == 16 || g_ddraw->primary->bpp == 32 || g_ddraw->primary->palette)) { HDC primary_dc; dds_GetDC(g_ddraw->primary, &primary_dc); @@ -868,15 +905,33 @@ int WINAPI fake_StretchDIBits( return result; } } - else if (g_ddraw->width > 0) + else if (g_ddraw->width > 0 && g_ddraw->render.hdc) { + // new logic by emoon + // g_ddraw->width check detects new widescreen patch + if (g_ddraw->width > 640 && g_config.maintas) + { + int base_width = g_ddraw->height * 4.0 / 3.0; + double scaling_factor = (double)g_ddraw->render.height / g_ddraw->height; + DestWidth = base_width * scaling_factor; + DestHeight = g_ddraw->render.height; + xDest += (g_ddraw->render.width - DestWidth) / 2; + } + else // original 4:3 logic + { + xDest += g_ddraw->render.viewport.x; + yDest += g_ddraw->render.viewport.y; + DestWidth = (int)(DestWidth * g_ddraw->render.scale_w); + DestHeight = (int)(DestHeight * g_ddraw->render.scale_h); + } + return real_StretchDIBits( - hdc, - xDest + g_ddraw->render.viewport.x, - yDest + g_ddraw->render.viewport.y, - (int)(DestWidth * g_ddraw->render.scale_w), - (int)(DestHeight * g_ddraw->render.scale_h), + g_ddraw->render.hdc, + xDest, + yDest, + DestWidth, + DestHeight, xSrc, ySrc, SrcWidth, @@ -1190,22 +1245,15 @@ 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) { - /* Center Claw DVD movies */ - if (HIWORD(lpClassName) && - _strcmpi(lpClassName, "Afx:400000:3") == 0 && - g_ddraw && g_ddraw->hwnd && g_ddraw->width && + /* Claw DVD movies */ + if (HIWORD(lpClassName) && _strcmpi(lpClassName, "Afx:400000:3") == 0 && + g_ddraw && g_ddraw->hwnd && (dwStyle & (WS_POPUP | WS_CHILD)) == (WS_POPUP | WS_CHILD)) { - POINT pt = { 0, 0 }; - real_ClientToScreen(g_ddraw->hwnd, &pt); - - int added_height = g_ddraw->render.height - g_ddraw->height; - int added_width = g_ddraw->render.width - g_ddraw->width; - int align_y = added_height > 0 ? added_height / 2 : 0; - int align_x = added_width > 0 ? added_width / 2 : 0; - - X = pt.x + align_x; - Y = pt.y + align_y; + dwStyle &= ~WS_POPUP; + LoadLibraryA("quartz.dll"); + LoadLibraryA("MSVFW32.dll"); + hook_init(FALSE); } /* Fix for SMACKW32.DLL creating another window that steals the focus */ @@ -1312,7 +1360,36 @@ HRESULT WINAPI fake_CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD } } - return real_CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv); + /* These dlls must be hooked for cutscene uscaling and windowed mode */ + HMODULE quartz_dll = GetModuleHandleA("quartz"); + HMODULE msvfw32_dll = GetModuleHandleA("msvfw32"); + + HRESULT result = real_CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv); + + if ((!quartz_dll && GetModuleHandleA("quartz")) || + (!msvfw32_dll && GetModuleHandleA("msvfw32"))) + { + hook_init(FALSE); + } + + return result; +} + +MCIERROR WINAPI fake_mciSendCommandA(MCIDEVICEID IDDevice, UINT uMsg, DWORD_PTR fdwCommand, DWORD_PTR dwParam) +{ + /* These dlls must be hooked for cutscene uscaling and windowed mode */ + HMODULE quartz_dll = GetModuleHandleA("quartz"); + HMODULE msvfw32_dll = GetModuleHandleA("msvfw32"); + + MCIERROR result = real_mciSendCommandA(IDDevice, uMsg, fdwCommand, dwParam); + + if ((!quartz_dll && GetModuleHandleA("quartz")) || + (!msvfw32_dll && GetModuleHandleA("msvfw32"))) + { + hook_init(FALSE); + } + + return result; } LPTOP_LEVEL_EXCEPTION_FILTER WINAPI fake_SetUnhandledExceptionFilter( diff --git a/src/wndproc.c b/src/wndproc.c index 96cf44e..e812f9b 100644 --- a/src/wndproc.c +++ b/src/wndproc.c @@ -729,6 +729,13 @@ LRESULT CALLBACK fake_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam } } + HWND video_hwnd = (HWND)InterlockedExchangeAdd((LONG*)&g_ddraw->video_window_hwnd, 0); + if (video_hwnd) + { + PostMessageA(video_hwnd, uMsg, wParam, lParam); + return 0; + } + break; } case WM_KEYUP: @@ -736,6 +743,13 @@ LRESULT CALLBACK fake_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam if (g_config.hotkeys.screenshot && wParam == g_config.hotkeys.screenshot) ss_take_screenshot(g_ddraw->primary); + HWND video_hwnd = (HWND)InterlockedExchangeAdd((LONG*)&g_ddraw->video_window_hwnd, 0); + if (video_hwnd) + { + PostMessageA(video_hwnd, uMsg, wParam, lParam); + return 0; + } + break; } /* button up messages reactivate cursor lock */ @@ -817,6 +831,13 @@ LRESULT CALLBACK fake_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam lParam = MAKELPARAM(x, y); + HWND video_hwnd = (HWND)InterlockedExchangeAdd((LONG*)&g_ddraw->video_window_hwnd, 0); + if (video_hwnd) + { + PostMessageA(video_hwnd, uMsg, wParam, lParam); + return 0; + } + break; } case WM_PARENTNOTIFY: @@ -854,9 +875,7 @@ LRESULT CALLBACK fake_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); } - EnterCriticalSection(&g_ddraw->cs); ReleaseSemaphore(g_ddraw->render.sem, 1, NULL); - LeaveCriticalSection(&g_ddraw->cs); break; } case WM_ERASEBKGND: