diff --git a/DDrawCompat/Common/Hook.cpp b/DDrawCompat/Common/Hook.cpp index 77ed6b1..65ff706 100644 --- a/DDrawCompat/Common/Hook.cpp +++ b/DDrawCompat/Common/Hook.cpp @@ -2,10 +2,14 @@ #include #include +#include +#include +#include #include #include #include +#include #include "Common/Hook.h" #include "Common/Log.h" @@ -27,42 +31,79 @@ namespace [=](const auto& i) { return origFunc == i.first || origFunc == i.second.trampoline; }); } - FARPROC getProcAddress(HMODULE module, const char* procName) + std::vector getProcessModules(HANDLE process) { - if (!module || !procName) + std::vector modules(10000); + DWORD bytesNeeded = 0; + if (EnumProcessModules(process, modules.data(), modules.size(), &bytesNeeded)) { - return nullptr; + modules.resize(bytesNeeded / sizeof(modules[0])); + } + return modules; + } + + std::set getIatHookFunctions(const char* moduleName, const char* funcName) + { + std::set hookFunctions; + if (!moduleName || !funcName) + { + return hookFunctions; } - PIMAGE_DOS_HEADER dosHeader = reinterpret_cast(module); - if (IMAGE_DOS_SIGNATURE != dosHeader->e_magic) { - return nullptr; - } - char* moduleBase = reinterpret_cast(module); + auto modules = getProcessModules(GetCurrentProcess()); + const HMODULE targetModule = GetModuleHandle(moduleName); - PIMAGE_NT_HEADERS ntHeader = reinterpret_cast( - reinterpret_cast(dosHeader) + dosHeader->e_lfanew); - if (IMAGE_NT_SIGNATURE != ntHeader->Signature) + for (auto module : modules) { - return nullptr; - } - - PIMAGE_EXPORT_DIRECTORY exportDir = reinterpret_cast( - moduleBase + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); - - DWORD* rvaOfNames = reinterpret_cast(moduleBase + exportDir->AddressOfNames); - - for (DWORD i = 0; i < exportDir->NumberOfNames; ++i) - { - if (0 == strcmp(procName, moduleBase + rvaOfNames[i])) + FARPROC func = Compat::getProcAddressFromIat(module, moduleName, funcName); + if (!func) { - WORD* nameOrds = reinterpret_cast(moduleBase + exportDir->AddressOfNameOrdinals); - DWORD* rvaOfFunctions = reinterpret_cast(moduleBase + exportDir->AddressOfFunctions); - return reinterpret_cast(moduleBase + rvaOfFunctions[nameOrds[i]]); + typedef decltype(GetProcAddress)* GetProcAddressFunc; + static const auto origGetProcAddressFunc = reinterpret_cast( + Compat::getProcAddress(GetModuleHandle("kernel32"), "GetProcAddress")); + + auto getProcAddressFunc = reinterpret_cast( + Compat::getProcAddressFromIat(module, "kernel32", "GetProcAddress")); + if (getProcAddressFunc && *getProcAddressFunc != origGetProcAddressFunc) + { + func = getProcAddressFunc(targetModule, funcName); + } + } + + if (func) + { + hookFunctions.insert(func); } } - return nullptr; + return hookFunctions; + } + + PIMAGE_NT_HEADERS getImageNtHeaders(HMODULE module) + { + PIMAGE_DOS_HEADER dosHeader = reinterpret_cast(module); + if (IMAGE_DOS_SIGNATURE != dosHeader->e_magic) + { + return nullptr; + } + + PIMAGE_NT_HEADERS ntHeaders = reinterpret_cast( + reinterpret_cast(dosHeader) + dosHeader->e_lfanew); + if (IMAGE_NT_SIGNATURE != ntHeaders->Signature) + { + return nullptr; + } + + return ntHeaders; + } + + std::string getModuleBaseName(HMODULE module) + { + char path[MAX_PATH] = {}; + GetModuleFileName(module, path, sizeof(path)); + const char* lastBackSlash = strrchr(path, '\\'); + const char* baseName = lastBackSlash ? lastBackSlash + 1 : path; + return baseName; } void hookFunction(const char* funcName, void*& origFuncPtr, void* newFuncPtr) @@ -114,6 +155,115 @@ namespace namespace Compat { + void redirectIatHooks(const char* moduleName, const char* funcName, void* newFunc) + { + auto hookFunctions(getIatHookFunctions(moduleName, funcName)); + + for (auto hookFunc : hookFunctions) + { + HMODULE module = nullptr; + if (!GetModuleHandleEx( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + static_cast(hookFunc), &module)) + { + continue; + } + + std::string moduleBaseName(getModuleBaseName(module)); + if (0 != _stricmp(moduleBaseName.c_str(), moduleName)) + { + Compat::Log() << "Disabling external hook to " << funcName << " in " << moduleBaseName; + hookFunction(hookFunc, newFunc); + } + } + } + + FARPROC* findProcAddressInIat(HMODULE module, const char* importedModuleName, const char* procName) + { + if (!module || !importedModuleName || !procName) + { + return nullptr; + } + + PIMAGE_NT_HEADERS ntHeaders = getImageNtHeaders(module); + if (!ntHeaders) + { + return nullptr; + } + + char* moduleBase = reinterpret_cast(module); + PIMAGE_IMPORT_DESCRIPTOR importDesc = reinterpret_cast(moduleBase + + ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + + for (PIMAGE_IMPORT_DESCRIPTOR desc = importDesc; + 0 != desc->Characteristics && 0xFFFF != desc->Name; + ++desc) + { + if (0 != _stricmp(moduleBase + desc->Name, importedModuleName)) + { + continue; + } + + auto thunk = reinterpret_cast(moduleBase + desc->FirstThunk); + auto origThunk = reinterpret_cast(moduleBase + desc->OriginalFirstThunk); + while (0 != thunk->u1.AddressOfData && 0 != origThunk->u1.AddressOfData) + { + auto origImport = reinterpret_cast( + moduleBase + origThunk->u1.AddressOfData); + + if (0 == strcmp(origImport->Name, procName)) + { + return reinterpret_cast(&thunk->u1.Function); + } + + ++thunk; + ++origThunk; + } + + break; + } + + return nullptr; + } + + FARPROC getProcAddress(HMODULE module, const char* procName) + { + if (!module || !procName) + { + return nullptr; + } + + PIMAGE_NT_HEADERS ntHeaders = getImageNtHeaders(module); + if (!ntHeaders) + { + return nullptr; + } + + char* moduleBase = reinterpret_cast(module); + PIMAGE_EXPORT_DIRECTORY exportDir = reinterpret_cast( + moduleBase + ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + + DWORD* rvaOfNames = reinterpret_cast(moduleBase + exportDir->AddressOfNames); + + for (DWORD i = 0; i < exportDir->NumberOfNames; ++i) + { + if (0 == strcmp(procName, moduleBase + rvaOfNames[i])) + { + WORD* nameOrds = reinterpret_cast(moduleBase + exportDir->AddressOfNameOrdinals); + DWORD* rvaOfFunctions = reinterpret_cast(moduleBase + exportDir->AddressOfFunctions); + return reinterpret_cast(moduleBase + rvaOfFunctions[nameOrds[i]]); + } + } + + return nullptr; + } + + FARPROC getProcAddressFromIat(HMODULE module, const char* importedModuleName, const char* procName) + { + FARPROC* proc = findProcAddressInIat(module, importedModuleName, procName); + return proc ? *proc : nullptr; + } + void hookFunction(void*& origFuncPtr, void* newFuncPtr) { ::hookFunction(nullptr, origFuncPtr, newFuncPtr); @@ -143,6 +293,20 @@ namespace Compat FreeLibrary(module); } + void hookIatFunction(HMODULE module, const char* importedModuleName, const char* funcName, void* newFuncPtr) + { + FARPROC* func = findProcAddressInIat(module, importedModuleName, funcName); + if (func) + { + Compat::LogDebug() << "Hooking function via IAT: " << funcName; + DWORD oldProtect = 0; + VirtualProtect(func, sizeof(func), PAGE_READWRITE, &oldProtect); + *func = static_cast(newFuncPtr); + DWORD dummy = 0; + VirtualProtect(func, sizeof(func), oldProtect, &dummy); + } + } + void unhookAllFunctions() { while (!g_hookedFunctions.empty()) diff --git a/DDrawCompat/Common/Hook.h b/DDrawCompat/Common/Hook.h index 4e8dd0d..ff8e3b7 100644 --- a/DDrawCompat/Common/Hook.h +++ b/DDrawCompat/Common/Hook.h @@ -15,6 +15,8 @@ namespace Compat { + void redirectIatHooks(const char* moduleName, const char* funcName, void* newFunc); + template OrigFuncPtr& getOrigFuncPtr() { @@ -22,9 +24,13 @@ namespace Compat return origFuncPtr; } + FARPROC* findProcAddressInIat(HMODULE module, const char* importedModuleName, const char* procName); + FARPROC getProcAddress(HMODULE module, const char* procName); + FARPROC getProcAddressFromIat(HMODULE module, const char* importedModuleName, const char* procName); void hookFunction(void*& origFuncPtr, void* newFuncPtr); void hookFunction(HMODULE module, const char* funcName, void*& origFuncPtr, void* newFuncPtr); void hookFunction(const char* moduleName, const char* funcName, void*& origFuncPtr, void* newFuncPtr); + void hookIatFunction(HMODULE module, const char* importedModuleName, const char* funcName, void* newFuncPtr); template void hookFunction(const char* moduleName, const char* funcName, OrigFuncPtr newFuncPtr) diff --git a/DDrawCompat/DDraw/ActivateAppHandler.cpp b/DDrawCompat/DDraw/ActivateAppHandler.cpp index 6e611af..b990a49 100644 --- a/DDrawCompat/DDraw/ActivateAppHandler.cpp +++ b/DDrawCompat/DDraw/ActivateAppHandler.cpp @@ -5,6 +5,7 @@ #include "Common/Hook.h" #include "DDraw/ActivateAppHandler.h" #include "Gdi/Gdi.h" +#include "Win32/DisplayMode.h" #include "Win32/FontSmoothing.h" namespace diff --git a/DDrawCompat/DDraw/DirectDraw.cpp b/DDrawCompat/DDraw/DirectDraw.cpp index f6c62e2..3675112 100644 --- a/DDrawCompat/DDraw/DirectDraw.cpp +++ b/DDrawCompat/DDraw/DirectDraw.cpp @@ -1,12 +1,86 @@ #include "Common/CompatPtr.h" #include "DDraw/ActivateAppHandler.h" #include "DDraw/DirectDraw.h" -#include "DDraw/DisplayMode.h" +#include "DDraw/Repository.h" #include "DDraw/Surfaces/TagSurface.h" #include "DDraw/Surfaces/PrimarySurface.h" +#include "Win32/DisplayMode.h" + +namespace +{ + DDPIXELFORMAT getRgbPixelFormat(DWORD bpp) + { + DDPIXELFORMAT pf = {}; + pf.dwSize = sizeof(pf); + pf.dwFlags = DDPF_RGB; + pf.dwRGBBitCount = bpp; + + switch (bpp) + { + case 1: + pf.dwFlags |= DDPF_PALETTEINDEXED1; + break; + case 2: + pf.dwFlags |= DDPF_PALETTEINDEXED2; + break; + case 4: + pf.dwFlags |= DDPF_PALETTEINDEXED4; + break; + case 8: + pf.dwFlags |= DDPF_PALETTEINDEXED8; + break; + case 16: + pf.dwRBitMask = 0xF800; + pf.dwGBitMask = 0x07E0; + pf.dwBBitMask = 0x001F; + break; + case 24: + case 32: + pf.dwRBitMask = 0xFF0000; + pf.dwGBitMask = 0x00FF00; + pf.dwBBitMask = 0x0000FF; + break; + } + + return pf; + } + + template + HRESULT setDisplayMode(TDirectDraw* This, DWORD width, DWORD height, DWORD bpp) + { + return DDraw::DirectDraw::s_origVtable.SetDisplayMode(This, width, height, bpp); + } + + template + HRESULT setDisplayMode(TDirectDraw* This, DWORD width, DWORD height, DWORD bpp, + DWORD refreshRate, DWORD flags) + { + Win32::DisplayMode::setDDrawBpp(bpp); + HRESULT result = DDraw::DirectDraw::s_origVtable.SetDisplayMode( + This, width, height, bpp, refreshRate, flags); + Win32::DisplayMode::setDDrawBpp(0); + return result; + } +} namespace DDraw { + CompatPtr createCompatibleSurface(DWORD bpp) + { + DDSURFACEDESC2 desc = {}; + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT; + desc.dwWidth = 1; + desc.dwHeight = 1; + desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + desc.ddpfPixelFormat = getRgbPixelFormat(bpp); + + CompatPtr surface; + auto dd = DDraw::Repository::getDirectDraw(); + dd->CreateSurface(dd, &desc, &surface.getRef(), nullptr); + return surface; + } + template void* getDdObject(TDirectDraw& dd) { @@ -18,14 +92,20 @@ namespace DDraw template void* getDdObject(IDirectDraw4&); template void* getDdObject(IDirectDraw7&); + DDSURFACEDESC2 getDisplayMode(CompatRef dd) + { + DDSURFACEDESC2 dm = {}; + dm.dwSize = sizeof(dm); + dd->GetDisplayMode(&dd, &dm); + return dm; + } + template void DirectDraw::setCompatVtable(Vtable& vtable) { vtable.CreateSurface = &CreateSurface; vtable.FlipToGDISurface = &FlipToGDISurface; - vtable.GetDisplayMode = &GetDisplayMode; vtable.GetGDISurface = &GetGDISurface; - vtable.RestoreDisplayMode = &RestoreDisplayMode; vtable.SetCooperativeLevel = &SetCooperativeLevel; vtable.SetDisplayMode = &SetDisplayMode; } @@ -64,24 +144,6 @@ namespace DDraw return PrimarySurface::flipToGdiSurface(); } - template - HRESULT STDMETHODCALLTYPE DirectDraw::GetDisplayMode( - TDirectDraw* This, TSurfaceDesc* lpDDSurfaceDesc) - { - const DWORD size = lpDDSurfaceDesc ? lpDDSurfaceDesc->dwSize : 0; - if (sizeof(DDSURFACEDESC) != size && sizeof(DDSURFACEDESC2) != size) - { - return DDERR_INVALIDPARAMS; - } - - CompatPtr dd(Compat::queryInterface(This)); - const DDSURFACEDESC2 dm = DisplayMode::getDisplayMode(*dd); - CopyMemory(lpDDSurfaceDesc, &dm, size); - lpDDSurfaceDesc->dwSize = size; - - return DD_OK; - } - template HRESULT STDMETHODCALLTYPE DirectDraw::GetGDISurface( TDirectDraw* /*This*/, TSurface** lplpGDIDDSSurface) @@ -101,13 +163,6 @@ namespace DDraw return DD_OK; } - template - HRESULT STDMETHODCALLTYPE DirectDraw::RestoreDisplayMode(TDirectDraw* This) - { - CompatPtr dd(Compat::queryInterface(This)); - return DisplayMode::restoreDisplayMode(*dd); - } - template HRESULT STDMETHODCALLTYPE DirectDraw::SetCooperativeLevel( TDirectDraw* This, HWND hWnd, DWORD dwFlags) @@ -138,8 +193,7 @@ namespace DDraw DWORD dwBPP, Params... params) { - CompatPtr dd(Compat::queryInterface(This)); - return DisplayMode::setDisplayMode(*dd, dwWidth, dwHeight, dwBPP, params...); + return setDisplayMode(This, dwWidth, dwHeight, dwBPP, params...); } template DirectDraw; diff --git a/DDrawCompat/DDraw/DirectDraw.h b/DDrawCompat/DDraw/DirectDraw.h index 89186fb..041b588 100644 --- a/DDrawCompat/DDraw/DirectDraw.h +++ b/DDrawCompat/DDraw/DirectDraw.h @@ -1,14 +1,24 @@ #pragma once +#define CINTERFACE + +#include + +#include "Common/CompatPtr.h" +#include "Common/CompatRef.h" #include "Common/CompatVtable.h" #include "DDraw/Visitors/DirectDrawVtblVisitor.h" #include "DDraw/Types.h" namespace DDraw { + CompatPtr createCompatibleSurface(DWORD bpp); + template void* getDdObject(TDirectDraw& dd); + DDSURFACEDESC2 getDisplayMode(CompatRef dd); + template class DirectDraw: public CompatVtable> { @@ -25,9 +35,7 @@ namespace DDraw IUnknown* pUnkOuter); static HRESULT STDMETHODCALLTYPE FlipToGDISurface(TDirectDraw* This); - static HRESULT STDMETHODCALLTYPE GetDisplayMode(TDirectDraw* This, TSurfaceDesc* lpDDSurfaceDesc); static HRESULT STDMETHODCALLTYPE GetGDISurface(TDirectDraw* This, TSurface** lplpGDIDDSSurface); - static HRESULT STDMETHODCALLTYPE RestoreDisplayMode(TDirectDraw* This); static HRESULT STDMETHODCALLTYPE SetCooperativeLevel(TDirectDraw* This, HWND hWnd, DWORD dwFlags); template diff --git a/DDrawCompat/DDraw/DisplayMode.cpp b/DDrawCompat/DDraw/DisplayMode.cpp deleted file mode 100644 index 8fad834..0000000 --- a/DDrawCompat/DDraw/DisplayMode.cpp +++ /dev/null @@ -1,251 +0,0 @@ -#include "Common/CompatPtr.h" -#include "Common/Hook.h" -#include "DDraw/DisplayMode.h" -#include "DDraw/Repository.h" -#include "Dll/Procs.h" - -namespace -{ - CompatWeakPtr g_compatibleSurface = {}; - HDC g_compatibleDc = nullptr; - DDSURFACEDESC2 g_emulatedDisplayMode = {}; - - template - LONG changeDisplaySettingsEx( - ChangeDisplaySettingsExPtr origChangeDisplaySettings, - EnumDisplaySettingsPtr origEnumDisplaySettings, - CStr lpszDeviceName, DevMode* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) - { - DevMode targetDevMode = {}; - if (lpDevMode) - { - targetDevMode = *lpDevMode; - } - else - { - targetDevMode.dmSize = sizeof(targetDevMode); - origEnumDisplaySettings(lpszDeviceName, ENUM_REGISTRY_SETTINGS, &targetDevMode); - } - - if (targetDevMode.dmPelsWidth) - { - DevMode currentDevMode = {}; - currentDevMode.dmSize = sizeof(currentDevMode); - origEnumDisplaySettings(lpszDeviceName, ENUM_CURRENT_SETTINGS, ¤tDevMode); - - if (targetDevMode.dmPelsWidth == currentDevMode.dmPelsWidth && - targetDevMode.dmPelsHeight == currentDevMode.dmPelsHeight && - targetDevMode.dmBitsPerPel == currentDevMode.dmBitsPerPel && - targetDevMode.dmDisplayFrequency == currentDevMode.dmDisplayFrequency && - targetDevMode.dmDisplayFlags == currentDevMode.dmDisplayFlags) - { - LONG result = origChangeDisplaySettings( - lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); - if (SUCCEEDED(result)) - { - HANDLE dwmDxFullScreenTransitionEvent = OpenEventW( - EVENT_MODIFY_STATE, FALSE, L"DWM_DX_FULLSCREEN_TRANSITION_EVENT"); - SetEvent(dwmDxFullScreenTransitionEvent); - CloseHandle(dwmDxFullScreenTransitionEvent); - } - return result; - } - } - - return origChangeDisplaySettings(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); - } - - LONG WINAPI changeDisplaySettingsExA( - LPCSTR lpszDeviceName, DEVMODEA* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) - { - return changeDisplaySettingsEx(CALL_ORIG_FUNC(ChangeDisplaySettingsExA), - CALL_ORIG_FUNC(EnumDisplaySettingsA), lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); - } - - LONG WINAPI changeDisplaySettingsExW( - LPCWSTR lpszDeviceName, DEVMODEW* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) - { - return changeDisplaySettingsEx(CALL_ORIG_FUNC(ChangeDisplaySettingsExW), - CALL_ORIG_FUNC(EnumDisplaySettingsW), lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); - } - - CompatPtr createCompatibleSurface() - { - DDSURFACEDESC2 desc = {}; - desc.dwSize = sizeof(desc); - desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS; - desc.dwWidth = 1; - desc.dwHeight = 1; - desc.ddpfPixelFormat = g_emulatedDisplayMode.ddpfPixelFormat; - desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; - - auto dd = DDraw::Repository::getDirectDraw(); - CompatPtr surface; - dd->CreateSurface(dd, &desc, &surface.getRef(), nullptr); - return surface; - } - - template - HRESULT PASCAL enumDisplayModesCallback( - TSurfaceDesc* lpDDSurfaceDesc, - LPVOID lpContext) - { - if (lpDDSurfaceDesc) - { - *static_cast(lpContext) = lpDDSurfaceDesc->ddpfPixelFormat; - } - return DDENUMRET_CANCEL; - } - - DDPIXELFORMAT getDisplayModePixelFormat( - CompatRef dd, DWORD width, DWORD height, DWORD bpp) - { - DDSURFACEDESC2 desc = {}; - desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat); - desc.ddpfPixelFormat.dwFlags = DDPF_RGB; - desc.ddpfPixelFormat.dwRGBBitCount = bpp; - - if (bpp <= 8) - { - switch (bpp) - { - case 1: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED1; break; - case 2: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED2; break; - case 4: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED4; break; - case 8: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED8; break; - default: return DDPIXELFORMAT(); - } - return desc.ddpfPixelFormat; - } - - desc.dwSize = sizeof(desc); - desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; - desc.dwWidth = width; - desc.dwHeight = height; - - DDPIXELFORMAT pf = {}; - if (FAILED(dd->EnumDisplayModes(&dd, 0, &desc, &pf, &enumDisplayModesCallback)) || - 0 == pf.dwSize) - { - Compat::Log() << "Failed to find the requested display mode: " << - width << "x" << height << "x" << bpp; - } - - return pf; - } - - DDSURFACEDESC2 getRealDisplayMode(CompatRef dd) - { - DDSURFACEDESC2 desc = {}; - desc.dwSize = sizeof(desc); - dd->GetDisplayMode(&dd, &desc); - return desc; - } - - void releaseCompatibleDc() - { - if (g_compatibleDc) - { - Dll::g_origProcs.AcquireDDThreadLock(); - g_compatibleSurface->ReleaseDC(g_compatibleSurface, g_compatibleDc); - g_compatibleDc = nullptr; - g_compatibleSurface.release(); - } - } - - void replaceDc(HDC& hdc) - { - if (g_compatibleDc && hdc && OBJ_DC == GetObjectType(hdc) && - DT_RASDISPLAY == GetDeviceCaps(hdc, TECHNOLOGY)) - { - hdc = g_compatibleDc; - } - } - - void updateCompatibleDc() - { - releaseCompatibleDc(); - g_compatibleSurface = createCompatibleSurface().detach(); - if (g_compatibleSurface && - SUCCEEDED(g_compatibleSurface->GetDC(g_compatibleSurface, &g_compatibleDc))) - { - Dll::g_origProcs.ReleaseDDThreadLock(); - } - } -} - -namespace DDraw -{ - namespace DisplayMode - { - HBITMAP WINAPI createCompatibleBitmap(HDC hdc, int cx, int cy) - { - replaceDc(hdc); - return CALL_ORIG_FUNC(CreateCompatibleBitmap)(hdc, cx, cy); - } - - HBITMAP WINAPI createDIBitmap(HDC hdc, const BITMAPINFOHEADER* lpbmih, DWORD fdwInit, - const void* lpbInit, const BITMAPINFO* lpbmi, UINT fuUsage) - { - replaceDc(hdc); - return CALL_ORIG_FUNC(CreateDIBitmap)(hdc, lpbmih, fdwInit, lpbInit, lpbmi, fuUsage); - } - - HBITMAP WINAPI createDiscardableBitmap(HDC hdc, int nWidth, int nHeight) - { - replaceDc(hdc); - return CALL_ORIG_FUNC(createDiscardableBitmap)(hdc, nWidth, nHeight); - } - - DDSURFACEDESC2 getDisplayMode(CompatRef dd) - { - if (0 == g_emulatedDisplayMode.dwSize) - { - g_emulatedDisplayMode = getRealDisplayMode(dd); - } - return g_emulatedDisplayMode; - } - - void installHooks() - { - HOOK_FUNCTION(user32, ChangeDisplaySettingsExA, changeDisplaySettingsExA); - HOOK_FUNCTION(user32, ChangeDisplaySettingsExW, changeDisplaySettingsExW); - } - - HRESULT restoreDisplayMode(CompatRef dd) - { - const HRESULT result = dd->RestoreDisplayMode(&dd); - if (SUCCEEDED(result)) - { - ZeroMemory(&g_emulatedDisplayMode, sizeof(g_emulatedDisplayMode)); - releaseCompatibleDc(); - } - return result; - } - - HRESULT setDisplayMode(CompatRef dd, - DWORD width, DWORD height, DWORD bpp, DWORD refreshRate, DWORD flags) - { - DDPIXELFORMAT pf = getDisplayModePixelFormat(dd, width, height, bpp); - if (0 == pf.dwSize) - { - return DDERR_INVALIDMODE; - } - - const HRESULT result = dd->SetDisplayMode(&dd, width, height, 32, refreshRate, flags); - if (FAILED(result)) - { - Compat::Log() << "Failed to set the display mode to " << width << "x" << height << - "x" << bpp << " (" << std::hex << result << std::dec << ')'; - return result; - } - - g_emulatedDisplayMode = getRealDisplayMode(dd); - g_emulatedDisplayMode.ddpfPixelFormat = pf; - updateCompatibleDc(); - - return DD_OK; - } - } -} diff --git a/DDrawCompat/DDraw/DisplayMode.h b/DDrawCompat/DDraw/DisplayMode.h deleted file mode 100644 index 67b09e1..0000000 --- a/DDrawCompat/DDraw/DisplayMode.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#define CINTERFACE - -#include - -#include "Common/CompatRef.h" - -namespace DDraw -{ - namespace DisplayMode - { - void installHooks(); - - HBITMAP WINAPI createCompatibleBitmap(HDC hdc, int cx, int cy); - HBITMAP WINAPI createDIBitmap(HDC hdc, const BITMAPINFOHEADER* lpbmih, DWORD fdwInit, - const void* lpbInit, const BITMAPINFO* lpbmi, UINT fuUsage); - HBITMAP WINAPI createDiscardableBitmap(HDC hdc, int nWidth, int nHeight); - - DDSURFACEDESC2 getDisplayMode(CompatRef dd); - HRESULT restoreDisplayMode(CompatRef dd); - HRESULT setDisplayMode(CompatRef dd, - DWORD width, DWORD height, DWORD bpp, DWORD refreshRate = 0, DWORD flags = 0); - }; -} diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index cbb5966..9eb6e7d 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -4,14 +4,15 @@ #include "Common/Hook.h" #include "Common/Time.h" #include "Config/Config.h" +#include "DDraw/DirectDraw.h" #include "DDraw/DirectDrawSurface.h" -#include "DDraw/DisplayMode.h" #include "DDraw/IReleaseNotifier.h" #include "DDraw/RealPrimarySurface.h" #include "DDraw/ScopedThreadLock.h" #include "DDraw/Surfaces/PrimarySurface.h" #include "DDraw/Types.h" #include "Gdi/Gdi.h" +#include "Win32/DisplayMode.h" namespace { @@ -90,8 +91,7 @@ namespace template HRESULT createPaletteConverter(CompatRef dd) { - auto dd7(CompatPtr::from(&dd)); - auto dm = DDraw::DisplayMode::getDisplayMode(*dd7); + auto dm = DDraw::getDisplayMode(*CompatPtr::from(&dd)); if (dm.ddpfPixelFormat.dwRGBBitCount > 8) { return DD_OK; diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp index 7742e54..1ad1db6 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp @@ -1,5 +1,5 @@ #include "Common/CompatPtr.h" -#include "DDraw/DisplayMode.h" +#include "DDraw/DirectDraw.h" #include "DDraw/RealPrimarySurface.h" #include "DDraw/Surfaces/PrimarySurface.h" #include "DDraw/Surfaces/PrimarySurfaceImpl.h" @@ -42,8 +42,7 @@ namespace DDraw return result; } - CompatPtr dd7(Compat::queryInterface(&dd)); - const auto& dm = DisplayMode::getDisplayMode(*dd7); + const auto& dm = DDraw::getDisplayMode(*CompatPtr::from(&dd)); desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; desc.dwWidth = dm.dwWidth; desc.dwHeight = dm.dwHeight; diff --git a/DDrawCompat/DDraw/Surfaces/Surface.cpp b/DDrawCompat/DDraw/Surfaces/Surface.cpp index 5048e2a..7ef3d1a 100644 --- a/DDrawCompat/DDraw/Surfaces/Surface.cpp +++ b/DDrawCompat/DDraw/Surfaces/Surface.cpp @@ -3,7 +3,6 @@ #include "Common/CompatPtr.h" #include "DDraw/DirectDraw.h" #include "DDraw/DirectDrawSurface.h" -#include "DDraw/DisplayMode.h" #include "DDraw/Surfaces/Surface.h" #include "DDraw/Surfaces/SurfaceImpl.h" @@ -44,7 +43,7 @@ namespace { if (!(flags & DDSD_PIXELFORMAT)) { - auto dm = DDraw::DisplayMode::getDisplayMode(dd); + auto dm = DDraw::getDisplayMode(dd); flags |= DDSD_PIXELFORMAT; pf = dm.ddpfPixelFormat; } diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index ba16c3c..aa04093 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -90,7 +90,7 @@ Level4 - WIN32;_DEBUG;_WINDOWS;_USRDLL;DDRAWCOMPAT_EXPORTS;%(PreprocessorDefinitions) + PSAPI_VERSION=1;WIN32;_DEBUG;_WINDOWS;_USRDLL;DDRAWCOMPAT_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDebug true false @@ -99,7 +99,7 @@ Dll/DDrawCompat.def - dxguid.lib;detours.lib;msimg32.lib;oleacc.lib;uxtheme.lib;dwmapi.lib;winmm.lib;%(AdditionalDependencies) + dxguid.lib;detours.lib;msimg32.lib;oleacc.lib;psapi.lib;uxtheme.lib;dwmapi.lib;winmm.lib;%(AdditionalDependencies) UseLinkTimeCodeGeneration @@ -122,14 +122,14 @@ Level4 - WIN32;NDEBUG;_WINDOWS;_USRDLL;DDRAWCOMPAT_EXPORTS;%(PreprocessorDefinitions) + PSAPI_VERSION=1;WIN32;NDEBUG;_WINDOWS;_USRDLL;DDRAWCOMPAT_EXPORTS;%(PreprocessorDefinitions) MultiThreaded true $(IntDir)%(RelativeDir) Dll/DDrawCompat.def - dxguid.lib;detours.lib;msimg32.lib;oleacc.lib;uxtheme.lib;dwmapi.lib;winmm.lib;%(AdditionalDependencies) + dxguid.lib;detours.lib;msimg32.lib;oleacc.lib;psapi.lib;uxtheme.lib;dwmapi.lib;winmm.lib;%(AdditionalDependencies) No UseLinkTimeCodeGeneration @@ -185,7 +185,6 @@ - @@ -225,6 +224,7 @@ + @@ -250,7 +250,6 @@ - @@ -280,6 +279,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 0923468..2f2d03b 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -120,9 +120,6 @@ Header Files\DDraw - - Header Files\DDraw - Header Files\DDraw @@ -306,6 +303,9 @@ Header Files\DDraw + + Header Files\Win32 + @@ -347,9 +347,6 @@ Source Files\DDraw - - Source Files\DDraw - Source Files\DDraw @@ -467,6 +464,9 @@ Source Files\DDraw + + Source Files\Win32 + diff --git a/DDrawCompat/Dll/DllMain.cpp b/DDrawCompat/Dll/DllMain.cpp index 00376df..d56783d 100644 --- a/DDrawCompat/Dll/DllMain.cpp +++ b/DDrawCompat/Dll/DllMain.cpp @@ -5,13 +5,15 @@ #include #include +#include "Common/Hook.h" +#include "Common/Log.h" #include "Common/Time.h" #include "D3dDdi/Hooks.h" -#include "DDraw/DisplayMode.h" #include "DDraw/Hooks.h" #include "Direct3d/Hooks.h" #include "Dll/Procs.h" #include "Gdi/Gdi.h" +#include "Win32/DisplayMode.h" #include "Win32/FontSmoothing.h" #include "Win32/MsgHooks.h" #include "Win32/Registry.h" @@ -30,6 +32,7 @@ namespace static bool isAlreadyInstalled = false; if (!isAlreadyInstalled) { + Win32::DisplayMode::disableDwm8And16BitMitigation(); Compat::Log() << "Installing registry hooks"; Win32::Registry::installHooks(); Compat::Log() << "Installing Direct3D driver hooks"; @@ -40,6 +43,8 @@ namespace Direct3d::installHooks(); Compat::Log() << "Installing GDI hooks"; Gdi::installHooks(); + Compat::Log() << "Installing display mode hooks"; + Win32::DisplayMode::installHooks(g_origDDrawModule); Compat::Log() << "Finished installing hooks"; isAlreadyInstalled = true; } @@ -82,7 +87,7 @@ namespace } #define LOAD_ORIGINAL_PROC(procName) \ - Dll::g_origProcs.procName = GetProcAddress(g_origDDrawModule, #procName); + Dll::g_origProcs.procName = Compat::getProcAddress(g_origDDrawModule, #procName); BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/) { @@ -122,7 +127,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/) SetProcessAffinityMask(GetCurrentProcess(), 1); SetThemeAppProperties(0); - DDraw::DisplayMode::installHooks(); + Compat::redirectIatHooks("ddraw.dll", "DirectDrawCreate", + Compat::getProcAddress(hinstDLL, "DirectDrawCreate")); + Compat::redirectIatHooks("ddraw.dll", "DirectDrawCreateEx", + Compat::getProcAddress(hinstDLL, "DirectDrawCreateEx")); Win32::FontSmoothing::g_origSystemSettings = Win32::FontSmoothing::getSystemSettings(); Win32::MsgHooks::installHooks(); Time::init(); diff --git a/DDrawCompat/Gdi/DcFunctions.cpp b/DDrawCompat/Gdi/DcFunctions.cpp index c381bb7..e4cb20a 100644 --- a/DDrawCompat/Gdi/DcFunctions.cpp +++ b/DDrawCompat/Gdi/DcFunctions.cpp @@ -2,10 +2,10 @@ #include "Common/Hook.h" #include "Common/Log.h" -#include "DDraw/DisplayMode.h" #include "Gdi/Dc.h" #include "Gdi/DcFunctions.h" #include "Gdi/Gdi.h" +#include "Win32/DisplayMode.h" namespace { @@ -307,9 +307,9 @@ namespace Gdi // Bitmap functions HOOK_GDI_DC_FUNCTION(msimg32, AlphaBlend); HOOK_GDI_DC_FUNCTION(gdi32, BitBlt); - HOOK_FUNCTION(gdi32, CreateCompatibleBitmap, DDraw::DisplayMode::createCompatibleBitmap); - HOOK_FUNCTION(gdi32, CreateDIBitmap, DDraw::DisplayMode::createDIBitmap); - HOOK_FUNCTION(gdi32, CreateDiscardableBitmap, DDraw::DisplayMode::createDiscardableBitmap); + HOOK_FUNCTION(gdi32, CreateCompatibleBitmap, Win32::DisplayMode::createCompatibleBitmap); + HOOK_FUNCTION(gdi32, CreateDIBitmap, Win32::DisplayMode::createDIBitmap); + HOOK_FUNCTION(gdi32, CreateDiscardableBitmap, Win32::DisplayMode::createDiscardableBitmap); HOOK_GDI_DC_FUNCTION(gdi32, ExtFloodFill); HOOK_GDI_DC_FUNCTION(gdi32, GdiAlphaBlend); HOOK_GDI_DC_FUNCTION(gdi32, GdiGradientFill); diff --git a/DDrawCompat/Win32/DisplayMode.cpp b/DDrawCompat/Win32/DisplayMode.cpp new file mode 100644 index 0000000..ef3770b --- /dev/null +++ b/DDrawCompat/Win32/DisplayMode.cpp @@ -0,0 +1,413 @@ +#include +#include + +#include "Common/CompatPtr.h" +#include "Common/Hook.h" +#include "DDraw/DirectDraw.h" +#include "Win32/DisplayMode.h" + +BOOL WINAPI DWM8And16Bit_IsShimApplied_CallOut() { return FALSE; }; + +namespace +{ + template + struct EnumParams + { + std::basic_string deviceName; + DWORD flags; + + bool operator==(const EnumParams& other) const + { + return deviceName == other.deviceName && flags == other.flags; + } + + bool operator!=(const EnumParams& other) const + { + return !(*this == other); + } + }; + + CompatWeakPtr g_compatibleSurface = {}; + HDC g_compatibleDc = nullptr; + DWORD g_origBpp = 0; + DWORD g_currentBpp = 0; + DWORD g_lastBpp = 0; + DWORD g_ddrawBpp = 0; + + BOOL WINAPI enumDisplaySettingsExA( + LPCSTR lpszDeviceName, DWORD iModeNum, DEVMODEA* lpDevMode, DWORD dwFlags); + BOOL WINAPI enumDisplaySettingsExW( + LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode, DWORD dwFlags); + void updateCompatibleDc(); + + template + LONG changeDisplaySettingsEx( + ChangeDisplaySettingsExFunc origChangeDisplaySettingsEx, + EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, + CStr lpszDeviceName, DevMode* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) + { + DevMode prevDevMode = {}; + if (!(dwflags & CDS_TEST)) + { + prevDevMode.dmSize = sizeof(prevDevMode); + origEnumDisplaySettingsEx(lpszDeviceName, ENUM_CURRENT_SETTINGS, &prevDevMode, 0); + } + + BOOL result = FALSE; + if (lpDevMode) + { + DWORD origBpp = lpDevMode->dmBitsPerPel; + lpDevMode->dmBitsPerPel = 32; + result = origChangeDisplaySettingsEx(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); + lpDevMode->dmBitsPerPel = origBpp; + } + else + { + result = origChangeDisplaySettingsEx(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); + } + + if (SUCCEEDED(result) && !(dwflags & CDS_TEST)) + { + if (lpDevMode) + { + g_currentBpp = lpDevMode->dmBitsPerPel; + g_lastBpp = lpDevMode->dmBitsPerPel; + } + else + { + g_currentBpp = g_origBpp; + } + updateCompatibleDc(); + + DevMode currDevMode = {}; + currDevMode.dmSize = sizeof(currDevMode); + origEnumDisplaySettingsEx(lpszDeviceName, ENUM_CURRENT_SETTINGS, &currDevMode, 0); + + if (currDevMode.dmPelsWidth == prevDevMode.dmPelsWidth && + currDevMode.dmPelsHeight == prevDevMode.dmPelsHeight && + currDevMode.dmBitsPerPel == prevDevMode.dmBitsPerPel && + currDevMode.dmDisplayFrequency == prevDevMode.dmDisplayFrequency && + currDevMode.dmDisplayFlags == prevDevMode.dmDisplayFlags) + { + HANDLE dwmDxFullScreenTransitionEvent = OpenEventW( + EVENT_MODIFY_STATE, FALSE, L"DWM_DX_FULLSCREEN_TRANSITION_EVENT"); + SetEvent(dwmDxFullScreenTransitionEvent); + CloseHandle(dwmDxFullScreenTransitionEvent); + } + } + + return result; + } + + LONG WINAPI changeDisplaySettingsExA( + LPCSTR lpszDeviceName, DEVMODEA* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) + { + Compat::LogEnter("ChangeDisplaySettingsExA", lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); + LONG result = changeDisplaySettingsEx( + CALL_ORIG_FUNC(ChangeDisplaySettingsExA), + CALL_ORIG_FUNC(EnumDisplaySettingsExA), + lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); + Compat::LogLeave("ChangeDisplaySettingsExA", lpszDeviceName, lpDevMode, hwnd, dwflags, lParam) << result; + return result; + } + + LONG WINAPI changeDisplaySettingsExW( + LPCWSTR lpszDeviceName, DEVMODEW* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) + { + Compat::LogEnter("ChangeDisplaySettingsExW", lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); + LONG result = changeDisplaySettingsEx( + CALL_ORIG_FUNC(ChangeDisplaySettingsExW), + CALL_ORIG_FUNC(EnumDisplaySettingsExW), + lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); + Compat::LogLeave("ChangeDisplaySettingsExW", lpszDeviceName, lpDevMode, hwnd, dwflags, lParam) << result; + return result; + } + + template + LONG ddrawChangeDisplaySettingsEx( + ChangeDisplaySettingsExFunc changeDisplaySettingsEx, + CStr lpszDeviceName, DevMode* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) + { + if (lpDevMode && 0 != lpDevMode->dmBitsPerPel) + { + lpDevMode->dmBitsPerPel = (0 != g_ddrawBpp) ? g_ddrawBpp : g_lastBpp; + } + return changeDisplaySettingsEx(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); + } + + LONG WINAPI ddrawChangeDisplaySettingsA( + DEVMODEA* lpDevMode, DWORD dwflags) + { + return ddrawChangeDisplaySettingsEx(&changeDisplaySettingsExA, + nullptr, lpDevMode, nullptr, dwflags, nullptr); + } + + LONG WINAPI ddrawChangeDisplaySettingsW( + DEVMODEW* lpDevMode, DWORD dwflags) + { + return ddrawChangeDisplaySettingsEx(&changeDisplaySettingsExW, + nullptr, lpDevMode, nullptr, dwflags, nullptr); + } + + LONG WINAPI ddrawChangeDisplaySettingsExA( + LPCSTR lpszDeviceName, DEVMODEA* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) + { + return ddrawChangeDisplaySettingsEx(&changeDisplaySettingsExA, + lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); + } + + LONG WINAPI ddrawChangeDisplaySettingsExW( + LPCWSTR lpszDeviceName, DEVMODEW* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) + { + return ddrawChangeDisplaySettingsEx(&changeDisplaySettingsExW, + lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); + } + + template + BOOL WINAPI ddrawEnumDisplaySettingsEx( + EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, + EnumDisplaySettingsExFunc enumDisplaySettingsEx, + CStr lpszDeviceName, DWORD iModeNum, DevMode* lpDevMode, DWORD dwFlags) + { + if (ENUM_CURRENT_SETTINGS == iModeNum) + { + return origEnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags); + } + return enumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags); + } + + BOOL WINAPI ddrawEnumDisplaySettingsA(LPCSTR lpszDeviceName, DWORD iModeNum, DEVMODEA* lpDevMode) + { + return ddrawEnumDisplaySettingsEx(CALL_ORIG_FUNC(EnumDisplaySettingsExA), &enumDisplaySettingsExA, + lpszDeviceName, iModeNum, lpDevMode, 0); + } + + BOOL WINAPI ddrawEnumDisplaySettingsW(LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode) + { + return ddrawEnumDisplaySettingsEx(CALL_ORIG_FUNC(EnumDisplaySettingsExW), &enumDisplaySettingsExW, + lpszDeviceName, iModeNum, lpDevMode, 0); + } + + BOOL WINAPI ddrawEnumDisplaySettingsExA( + LPCSTR lpszDeviceName, DWORD iModeNum, DEVMODEA* lpDevMode, DWORD dwFlags) + { + return ddrawEnumDisplaySettingsEx(CALL_ORIG_FUNC(EnumDisplaySettingsExA), &enumDisplaySettingsExA, + lpszDeviceName, iModeNum, lpDevMode, dwFlags); + } + + BOOL WINAPI ddrawEnumDisplaySettingsExW( + LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode, DWORD dwFlags) + { + return ddrawEnumDisplaySettingsEx(CALL_ORIG_FUNC(EnumDisplaySettingsExW), &enumDisplaySettingsExW, + lpszDeviceName, iModeNum, lpDevMode, dwFlags); + } + + BOOL WINAPI dwm8And16BitIsShimAppliedCallOut() + { + return FALSE; + } + + template + BOOL enumDisplaySettingsEx(EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, + const Char* lpszDeviceName, DWORD iModeNum, DevMode* lpDevMode, DWORD dwFlags) + { + if (ENUM_REGISTRY_SETTINGS == iModeNum || !lpDevMode) + { + BOOL result = origEnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags); + return result; + } + + if (ENUM_CURRENT_SETTINGS == iModeNum) + { + BOOL result = origEnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags); + if (result) + { + lpDevMode->dmBitsPerPel = g_currentBpp; + } + return result; + } + + thread_local std::vector devModes; + thread_local EnumParams lastEnumParams = {}; + + EnumParams currentEnumParams = { + lpszDeviceName ? lpszDeviceName : std::basic_string(), dwFlags }; + + if (0 == iModeNum || devModes.empty() || currentEnumParams != lastEnumParams) + { + devModes.clear(); + lastEnumParams = currentEnumParams; + + DWORD modeNum = 0; + DevMode dm = {}; + dm.dmSize = sizeof(dm); + while (origEnumDisplaySettingsEx(lpszDeviceName, modeNum, &dm, dwFlags)) + { + if (32 == dm.dmBitsPerPel) + { + dm.dmBitsPerPel = 8; + devModes.push_back(dm); + dm.dmBitsPerPel = 16; + devModes.push_back(dm); + dm.dmBitsPerPel = 32; + devModes.push_back(dm); + } + ++modeNum; + } + } + + if (iModeNum >= devModes.size()) + { + return FALSE; + } + + *lpDevMode = devModes[iModeNum]; + return TRUE; + } + + BOOL WINAPI enumDisplaySettingsExA( + LPCSTR lpszDeviceName, DWORD iModeNum, DEVMODEA* lpDevMode, DWORD dwFlags) + { + Compat::LogEnter("EnumDisplaySettingsExA", lpszDeviceName, iModeNum, lpDevMode, dwFlags); + BOOL result = enumDisplaySettingsEx(CALL_ORIG_FUNC(EnumDisplaySettingsExA), + lpszDeviceName, iModeNum, lpDevMode, dwFlags); + Compat::LogLeave("EnumDisplaySettingsExA", lpszDeviceName, iModeNum, lpDevMode, dwFlags) << result; + return result; + } + + BOOL WINAPI enumDisplaySettingsExW( + LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode, DWORD dwFlags) + { + Compat::LogEnter("EnumDisplaySettingsExW", lpszDeviceName, iModeNum, lpDevMode, dwFlags); + BOOL result = enumDisplaySettingsEx(CALL_ORIG_FUNC(EnumDisplaySettingsExW), + lpszDeviceName, iModeNum, lpDevMode, dwFlags); + Compat::LogLeave("EnumDisplaySettingsExW", lpszDeviceName, iModeNum, lpDevMode, dwFlags) << result; + return result; + } + + int WINAPI getDeviceCaps(HDC hdc, int nIndex) + { + Compat::LogEnter("GetDeviceCaps", hdc, nIndex); + if (hdc && BITSPIXEL == nIndex && + DT_RASDISPLAY == GetDeviceCaps(hdc, TECHNOLOGY) && OBJ_DC == GetObjectType(hdc)) + { + Compat::LogLeave("GetDeviceCaps", hdc, nIndex) << g_currentBpp; + return g_currentBpp; + } + int result = CALL_ORIG_FUNC(GetDeviceCaps)(hdc, nIndex); + Compat::LogLeave("GetDeviceCaps", hdc, nIndex) << result; + return result; + } + + void releaseCompatibleDc() + { + if (g_compatibleDc) + { + Dll::g_origProcs.AcquireDDThreadLock(); + g_compatibleSurface->ReleaseDC(g_compatibleSurface, g_compatibleDc); + g_compatibleDc = nullptr; + g_compatibleSurface.release(); + } + } + + void replaceDc(HDC& hdc) + { + if (g_compatibleDc && hdc && + OBJ_DC == GetObjectType(hdc) && DT_RASDISPLAY == GetDeviceCaps(hdc, TECHNOLOGY)) + { + hdc = g_compatibleDc; + } + } + + void updateCompatibleDc() + { + releaseCompatibleDc(); + g_compatibleSurface = DDraw::createCompatibleSurface(g_currentBpp).detach(); + if (g_compatibleSurface && + SUCCEEDED(g_compatibleSurface->GetDC(g_compatibleSurface, &g_compatibleDc))) + { + Dll::g_origProcs.ReleaseDDThreadLock(); + } + } +} + +namespace Win32 +{ + namespace DisplayMode + { + HBITMAP WINAPI createCompatibleBitmap(HDC hdc, int cx, int cy) + { + Compat::LogEnter("CreateCompatibleBitmap", hdc, cx, cy); + replaceDc(hdc); + HBITMAP result = CALL_ORIG_FUNC(CreateCompatibleBitmap)(hdc, cx, cy); + Compat::LogLeave("CreateCompatibleBitmap", hdc, cx, cy) << result; + return result; + } + + HBITMAP WINAPI createDIBitmap(HDC hdc, const BITMAPINFOHEADER* lpbmih, DWORD fdwInit, + const void* lpbInit, const BITMAPINFO* lpbmi, UINT fuUsage) + { + Compat::LogEnter("CreateDIBitmap", hdc, lpbmih, fdwInit, lpbInit, lpbmi, fuUsage); + replaceDc(hdc); + HBITMAP result = CALL_ORIG_FUNC(CreateDIBitmap)(hdc, lpbmih, fdwInit, lpbInit, lpbmi, fuUsage); + Compat::LogLeave("CreateDIBitmap", hdc, lpbmih, fdwInit, lpbInit, lpbmi, fuUsage) + << result; + return result; + } + + HBITMAP WINAPI createDiscardableBitmap(HDC hdc, int nWidth, int nHeight) + { + Compat::LogEnter("CreateDiscardableBitmap", hdc, nWidth, nHeight); + replaceDc(hdc); + HBITMAP result = CALL_ORIG_FUNC(createDiscardableBitmap)(hdc, nWidth, nHeight); + Compat::LogLeave("CreateDiscardableBitmap", hdc, nWidth, nHeight) << result; + return result; + } + + void setDDrawBpp(DWORD bpp) + { + g_ddrawBpp = bpp; + } + + void disableDwm8And16BitMitigation() + { + HOOK_FUNCTION(apphelp, DWM8And16Bit_IsShimApplied_CallOut, dwm8And16BitIsShimAppliedCallOut); + } + + void installHooks(HMODULE origDDrawModule) + { + DEVMODEA devMode = {}; + devMode.dmSize = sizeof(devMode); + EnumDisplaySettingsEx(nullptr, ENUM_CURRENT_SETTINGS, &devMode, 0); + g_origBpp = devMode.dmBitsPerPel; + g_currentBpp = g_origBpp; + g_lastBpp = g_origBpp; + + HOOK_FUNCTION(user32, ChangeDisplaySettingsExA, changeDisplaySettingsExA); + HOOK_FUNCTION(user32, ChangeDisplaySettingsExW, changeDisplaySettingsExW); + HOOK_FUNCTION(user32, EnumDisplaySettingsExA, enumDisplaySettingsExA); + HOOK_FUNCTION(user32, EnumDisplaySettingsExW, enumDisplaySettingsExW); + HOOK_FUNCTION(gdi32, GetDeviceCaps, getDeviceCaps); + + Compat::hookIatFunction(origDDrawModule, "user32.dll", "ChangeDisplaySettingsA", + &ddrawChangeDisplaySettingsA); + Compat::hookIatFunction(origDDrawModule, "user32.dll", "ChangeDisplaySettingsW", + &ddrawChangeDisplaySettingsW); + Compat::hookIatFunction(origDDrawModule, "user32.dll", "ChangeDisplaySettingsExA", + &ddrawChangeDisplaySettingsExA); + Compat::hookIatFunction(origDDrawModule, "user32.dll", "ChangeDisplaySettingsExW", + &ddrawChangeDisplaySettingsExW); + Compat::hookIatFunction(origDDrawModule, "user32.dll", "EnumDisplaySettingsA", + &ddrawEnumDisplaySettingsA); + Compat::hookIatFunction(origDDrawModule, "user32.dll", "EnumDisplaySettingsW", + &ddrawEnumDisplaySettingsW); + Compat::hookIatFunction(origDDrawModule, "user32.dll", "EnumDisplaySettingsExA", + &ddrawEnumDisplaySettingsExA); + Compat::hookIatFunction(origDDrawModule, "user32.dll", "EnumDisplaySettingsExW", + &ddrawEnumDisplaySettingsExW); + + updateCompatibleDc(); + } + } +} diff --git a/DDrawCompat/Win32/DisplayMode.h b/DDrawCompat/Win32/DisplayMode.h new file mode 100644 index 0000000..5ea21a3 --- /dev/null +++ b/DDrawCompat/Win32/DisplayMode.h @@ -0,0 +1,21 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN + +#include + +namespace Win32 +{ + namespace DisplayMode + { + HBITMAP WINAPI createCompatibleBitmap(HDC hdc, int cx, int cy); + HBITMAP WINAPI createDIBitmap(HDC hdc, const BITMAPINFOHEADER* lpbmih, DWORD fdwInit, + const void* lpbInit, const BITMAPINFO* lpbmi, UINT fuUsage); + HBITMAP WINAPI createDiscardableBitmap(HDC hdc, int nWidth, int nHeight); + + void setDDrawBpp(DWORD bpp); + + void disableDwm8And16BitMitigation(); + void installHooks(HMODULE origDDrawModule); + } +}