diff --git a/DDrawCompat/Common/Rect.h b/DDrawCompat/Common/Rect.h index f3d0549..d0eb67f 100644 --- a/DDrawCompat/Common/Rect.h +++ b/DDrawCompat/Common/Rect.h @@ -12,6 +12,11 @@ struct RectF namespace Rect { + inline SIZE getSize(const RECT& rect) + { + return { rect.right - rect.left, rect.bottom - rect.top }; + } + RectF toRectF(const RECT& rect); bool isEqualSize(const RECT& rect1, const RECT& rect2); void transform(RECT& rect, const RECT& srcView, const RECT& dstView); diff --git a/DDrawCompat/D3dDdi/Adapter.cpp b/DDrawCompat/D3dDdi/Adapter.cpp index 2974a28..0a2d46c 100644 --- a/DDrawCompat/D3dDdi/Adapter.cpp +++ b/DDrawCompat/D3dDdi/Adapter.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -63,23 +64,23 @@ namespace D3dDdi { } - Int2 Adapter::getAspectRatio(Win32::DisplayMode::Resolution res) const + Int2 Adapter::getAspectRatio(SIZE appRes, SIZE displayRes) const { SIZE ar = Config::displayAspectRatio.get(); if (Config::Settings::DisplayAspectRatio::APP == ar) { - return 0 != res.app.cx ? res.app : Win32::DisplayMode::getAppResolution(m_deviceName); + return 0 != appRes.cx ? appRes : Rect::getSize(Win32::DisplayMode::getMonitorInfo(m_deviceName).rcEmulated); } else if (Config::Settings::DisplayAspectRatio::DISPLAY == ar) { - return 0 != res.display.cx ? res.display : Win32::DisplayMode::getDisplayResolution(m_deviceName); + return 0 != displayRes.cx ? displayRes : Rect::getSize(Win32::DisplayMode::getMonitorInfo(m_deviceName).rcReal); } return ar; } Int2 Adapter::getAspectRatio() const { - return getAspectRatio({}); + return getAspectRatio({}, {}); } const Adapter::AdapterInfo& Adapter::findInfo() const @@ -253,20 +254,23 @@ namespace D3dDdi return 1; } - const auto res = Win32::DisplayMode::getResolution(m_deviceName); + const auto& mi = Win32::DisplayMode::getMonitorInfo(m_deviceName); + auto displayRes = Rect::getSize(mi.rcReal); + auto appRes = Rect::getSize(mi.isEmulated ? mi.rcEmulated : mi.rcReal); + Int2 targetResolution = resolutionScale; if (Config::Settings::ResolutionScale::APP == resolutionScale) { - targetResolution = res.app; + targetResolution = appRes; } else if (Config::Settings::ResolutionScale::DISPLAY == resolutionScale) { - targetResolution = res.display; + targetResolution = displayRes; } targetResolution *= abs(multiplier); - const Int2 ar = getAspectRatio(res); + const Int2 ar = getAspectRatio(appRes, displayRes); if (targetResolution.y * ar.x / ar.y <= targetResolution.x) { targetResolution.x = targetResolution.y * ar.x / ar.y; @@ -276,7 +280,7 @@ namespace D3dDdi targetResolution.y = targetResolution.x * ar.y / ar.x; } - const auto scaleFactor = Float2(targetResolution) / Float2(res.app); + const auto scaleFactor = Float2(targetResolution) / Float2(appRes); return multiplier < 0 ? scaleFactor : ceil(scaleFactor); } diff --git a/DDrawCompat/D3dDdi/Adapter.h b/DDrawCompat/D3dDdi/Adapter.h index ee0f342..8f2c39f 100644 --- a/DDrawCompat/D3dDdi/Adapter.h +++ b/DDrawCompat/D3dDdi/Adapter.h @@ -38,6 +38,7 @@ namespace D3dDdi Int2 getAspectRatio() const; const AdapterInfo& getInfo() const { return m_info; } LUID getLuid() const { return m_luid; } + const auto& getMonitorInfo() const { return Win32::DisplayMode::getMonitorInfo(m_deviceName); } std::pair getMultisampleConfig(D3DDDIFORMAT format) const; const D3DDDI_ADAPTERFUNCS& getOrigVtable() const { return m_origVtable; } CompatWeakPtr getRepository() const { return m_repository; } @@ -58,7 +59,7 @@ namespace D3dDdi template HRESULT getCaps(D3DDDICAPS_TYPE type, Data& data, UINT size = sizeof(Data)) const; - Int2 getAspectRatio(Win32::DisplayMode::Resolution res) const; + Int2 getAspectRatio(SIZE appRes, SIZE displayRes) const; std::map getFixedFormatOps(const AdapterInfo& info) const; std::map getFormatOps() const; Float2 getScaleFactor() const; diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.cpp b/DDrawCompat/D3dDdi/KernelModeThunks.cpp index db18871..65d5ab1 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.cpp +++ b/DDrawCompat/D3dDdi/KernelModeThunks.cpp @@ -19,6 +19,7 @@ #include #include #include +#include namespace { @@ -310,7 +311,7 @@ namespace MONITORINFOEX mi = {}; mi.cbSize = sizeof(mi); - GetMonitorInfo(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi); + CALL_ORIG_FUNC(GetMonitorInfoA)(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi); D3DKMT_OPENADAPTERFROMHDC data = {}; data.hDc = CreateDC(mi.szDevice, mi.szDevice, nullptr, nullptr); @@ -374,11 +375,11 @@ namespace D3dDdi HWND presentationWindow = DDraw::RealPrimarySurface::getPresentationWindow(); if (presentationWindow && presentationWindow == data.hWindow) { - rect = DDraw::RealPrimarySurface::getMonitorRect(); + Win32::ScopedDpiAwareness dpiAwareness; + GetWindowRect(presentationWindow, &rect); OffsetRect(&rect, -rect.left, -rect.top); data.SrcRect = rect; - data.DstRect.right = data.DstRect.left + rect.right; - data.DstRect.bottom = data.DstRect.top + rect.bottom; + data.DstRect = rect; if (1 == data.SubRectCnt) { data.pSrcSubRects = ▭ diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index 4e8c3cf..b17bc7b 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -1270,10 +1270,8 @@ namespace D3dDdi if (!IsRectEmpty(&g_presentationRect)) { - auto dstRect = DDraw::RealPrimarySurface::getMonitorRect(); - OffsetRect(&dstRect, -dstRect.left, -dstRect.top); - presentLayeredWindows(*this, data.DstSubResourceIndex, dstRect, - Gdi::Window::getVisibleOverlayWindows(), dstRect); + presentLayeredWindows(*this, data.DstSubResourceIndex, getRect(data.DstSubResourceIndex), + Gdi::Window::getVisibleOverlayWindows(), m_device.getAdapter().getMonitorInfo().rcMonitor); } return LOG_RESULT(S_OK); @@ -1294,7 +1292,7 @@ namespace D3dDdi continue; } - RECT srcRect = { 0, 0, visibleRect.right - visibleRect.left, visibleRect.bottom - visibleRect.top }; + RECT srcRect = { 0, 0, visibleRect.right - visibleRect.left + 1, visibleRect.bottom - visibleRect.top + 1 }; auto& windowSurface = repo.getTempSysMemSurface(srcRect.right, srcRect.bottom); auto& texture = repo.getTempTexture(srcRect.right, srcRect.bottom, D3DDDIFMT_A8R8G8B8); if (!windowSurface.resource || !texture.resource) @@ -1304,9 +1302,16 @@ namespace D3dDdi HDC srcDc = GetWindowDC(layeredWindow.hwnd); HDC dstDc = nullptr; + POINT srcOrig = { visibleRect.left - layeredWindow.rect.left, visibleRect.top - layeredWindow.rect.top }; windowSurface.surface->GetDC(windowSurface.surface, &dstDc); - CALL_ORIG_FUNC(BitBlt)(dstDc, 0, 0, srcRect.right, srcRect.bottom, srcDc, - visibleRect.left - layeredWindow.rect.left, visibleRect.top - layeredWindow.rect.top, SRCCOPY); + CALL_ORIG_FUNC(BitBlt)(dstDc, 0, 0, srcRect.right - 1, srcRect.bottom - 1, + srcDc, srcOrig.x, srcOrig.y, SRCCOPY); + CALL_ORIG_FUNC(BitBlt)(dstDc, srcRect.right - 1, 0, 1, srcRect.bottom - 1, + srcDc, srcOrig.x + srcRect.right - 2, srcOrig.y, SRCCOPY); + CALL_ORIG_FUNC(BitBlt)(dstDc, 0, srcRect.bottom - 1, srcRect.right - 1, 1, + srcDc, srcOrig.x, srcOrig.y + srcRect.bottom - 2, SRCCOPY); + CALL_ORIG_FUNC(BitBlt)(dstDc, srcRect.right - 1, srcRect.bottom - 1, 1, 1, + srcDc, srcOrig.x + srcRect.right - 2, srcOrig.y + srcRect.bottom - 2, SRCCOPY); windowSurface.surface->ReleaseDC(windowSurface.surface, dstDc); ReleaseDC(layeredWindow.hwnd, srcDc); @@ -1327,8 +1332,10 @@ namespace D3dDdi } Rect::transform(visibleRect, monitorRect, dstRect); - blitter.textureBlt(dst, dstSubResourceIndex, visibleRect, *texture.resource, 0, srcRect, D3DTEXF_POINT, - ck, (flags & ULW_ALPHA) ? &alpha : nullptr, + srcRect.right--; + srcRect.bottom--; + blitter.textureBlt(dst, dstSubResourceIndex, visibleRect, *texture.resource, 0, srcRect, + D3DTEXF_LINEAR | D3DTEXF_SRGB, ck, (flags & ULW_ALPHA) ? &alpha : nullptr, layeredWindow.region); } } @@ -1398,14 +1405,16 @@ namespace D3dDdi const Int2 ar = m_device.getAdapter().getAspectRatio(); g_presentationRect = calculateScaledRect({ 0, 0, ar.x, ar.y }, DDraw::RealPrimarySurface::getMonitorRect()); - auto& si = m_origData.pSurfList[0]; - RECT primaryRect = { 0, 0, static_cast(si.Width), static_cast(si.Height) }; - Gdi::Cursor::setMonitorClipRect(DDraw::PrimarySurface::getMonitorRect()); - if (!EqualRect(&g_presentationRect, &primaryRect)) + const auto& mi = m_device.getAdapter().getMonitorInfo(); + auto clipRect = mi.rcEmulated; + if (!EqualRect(&mi.rcMonitor, &mi.rcReal)) { - Gdi::Cursor::setEmulated(true); + InflateRect(&clipRect, -1, -1); } + + Gdi::Cursor::setMonitorClipRect(clipRect); + Gdi::Cursor::setEmulated(mi.isEmulated); Gdi::VirtualScreen::setFullscreenMode(m_origData.Flags.MatchGdiPrimary); } else diff --git a/DDrawCompat/DDraw/DirectDraw.cpp b/DDrawCompat/DDraw/DirectDraw.cpp index dcb4d1c..71a4126 100644 --- a/DDrawCompat/DDraw/DirectDraw.cpp +++ b/DDrawCompat/DDraw/DirectDraw.cpp @@ -180,14 +180,6 @@ namespace DDraw { namespace DirectDraw { - DDSURFACEDESC2 getDisplayMode(CompatRef dd) - { - DDSURFACEDESC2 dm = {}; - dm.dwSize = sizeof(dm); - dd->GetDisplayMode(&dd, &dm); - return dm; - } - DDPIXELFORMAT getRgbPixelFormat(DWORD bpp) { DDPIXELFORMAT pf = {}; diff --git a/DDrawCompat/DDraw/DirectDraw.h b/DDrawCompat/DDraw/DirectDraw.h index 16e1a45..71d730b 100644 --- a/DDrawCompat/DDraw/DirectDraw.h +++ b/DDrawCompat/DDraw/DirectDraw.h @@ -12,7 +12,6 @@ namespace DDraw { namespace DirectDraw { - DDSURFACEDESC2 getDisplayMode(CompatRef dd); DDPIXELFORMAT getRgbPixelFormat(DWORD bpp); LRESULT handleActivateApp(bool isActivated, std::function callOrigWndProc); void onCreate(GUID* guid, CompatRef dd); diff --git a/DDrawCompat/DDraw/DirectDrawClipper.cpp b/DDrawCompat/DDraw/DirectDrawClipper.cpp index 3b2865b..32b9f99 100644 --- a/DDrawCompat/DDraw/DirectDrawClipper.cpp +++ b/DDrawCompat/DDraw/DirectDrawClipper.cpp @@ -5,8 +5,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -46,7 +46,7 @@ namespace GetRandomRgn(dc, rgn, SYSRGN); CALL_ORIG_FUNC(ReleaseDC)(data.hwnd, dc); - RECT primaryRect = DDraw::RealPrimarySurface::getMonitorRect(); + RECT primaryRect = DDraw::PrimarySurface::getMonitorRect(); if (0 != primaryRect.left || 0 != primaryRect.top) { rgn.offset(-primaryRect.left, -primaryRect.top); diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index 1b4a289..ddda5f0 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -1,6 +1,9 @@ #include #include +#include +#include + #include #include #include @@ -8,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +39,7 @@ #include #include #include +#include #include namespace @@ -54,6 +59,7 @@ namespace DDraw::IReleaseNotifier g_releaseNotifier(onRelease); bool g_isFullscreen = false; + bool g_isExclusiveFullscreen = false; DDraw::Surface* g_lastFlipSurface = nullptr; DDraw::TagSurface* g_tagSurface = nullptr; @@ -82,6 +88,9 @@ namespace { if (!g_isFullscreen) { + updatePresentationWindow(); + + if (g_presentationWindow) { D3dDdi::ScopedCriticalSection lock; auto srcResource = D3dDdi::Device::findResource( @@ -99,8 +108,7 @@ namespace bbResource->presentationBlt(blt, srcResource); } - updatePresentationWindow(); - Gdi::Window::present(*g_frontBuffer, *g_windowedBackBuffer, *g_clipper); + Gdi::Window::present(*g_frontBuffer, g_presentationWindow ? *g_windowedBackBuffer : src, *g_clipper); return; } @@ -172,7 +180,7 @@ namespace DDraw::RealPrimarySurface::destroyDefaultPrimary(); auto dm = Win32::DisplayMode::getEmulatedDisplayMode(); - if (0 == dm.diff.cx && 0 == dm.diff.cy) + if (dm.deviceName.empty()) { return; } @@ -373,7 +381,7 @@ namespace Input::updateCursor(); }); - if (!g_frontBuffer || !src || DDraw::RealPrimarySurface::isLost() || FAILED(src->IsLost(src))) + if (!g_frontBuffer || !src || DDraw::RealPrimarySurface::isLost()) { Gdi::Window::present(nullptr); return; @@ -409,49 +417,67 @@ namespace { LOG_FUNC("RealPrimarySurface::updatePresentationWindow"); - const bool isActive = isProcessActive(); HWND fullscreenWindow = nullptr; - if (g_isFullscreen && IsWindowVisible(g_deviceWindow) && !IsIconic(g_deviceWindow)) + if (isProcessActive()) { - fullscreenWindow = g_deviceWindow; + if (g_isFullscreen && IsWindowVisible(g_deviceWindow) && !IsIconic(g_deviceWindow)) + { + if (g_isExclusiveFullscreen) + { + return; + } + fullscreenWindow = g_deviceWindow; + } + else if (g_frontBuffer && DDraw::PrimarySurface::getPrimary() && SUCCEEDED(g_frontBuffer->IsLost(g_frontBuffer))) + { + fullscreenWindow = Gdi::Window::getFullscreenWindow(); + } } - else if (g_frontBuffer && DDraw::PrimarySurface::getPrimary() && SUCCEEDED(g_frontBuffer->IsLost(g_frontBuffer))) + else if (g_isFullscreen) { - fullscreenWindow = Gdi::Window::getFullscreenWindow(); + return; } - fullscreenWindow = fullscreenWindow ? Gdi::Window::getPresentationWindow(fullscreenWindow) : nullptr; + HWND fullscreenPresentationWindow = nullptr; + if (fullscreenWindow) + { + Gdi::Window::setDpiAwareness(fullscreenWindow, true); + fullscreenPresentationWindow = Gdi::Window::getPresentationWindow(fullscreenWindow); + } if (g_windowedBackBuffer) { auto resource = D3dDdi::Device::findResource( DDraw::DirectDrawSurface::getDriverResourceHandle(*g_windowedBackBuffer)); - resource->setFullscreenMode(isActive && fullscreenWindow); + resource->setFullscreenMode(fullscreenPresentationWindow); } - if (!isActive) - { - return; - } - - g_presentationWindow = fullscreenWindow; + g_presentationWindow = fullscreenPresentationWindow; if (g_presentationWindow) { Gdi::GuiThread::execute([&]() { - CALL_ORIG_FUNC(SetWindowPos)(g_presentationWindow, HWND_TOPMOST, g_monitorRect.left, g_monitorRect.top, + Win32::ScopedDpiAwareness dpiAwareness; + CALL_ORIG_FUNC(SetWindowPos)(g_presentationWindow, HWND_TOPMOST, g_monitorRect.left, g_monitorRect.top, 0, 0, + SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOSIZE); + CALL_ORIG_FUNC(SetWindowPos)(g_presentationWindow, nullptr, 0, 0, g_monitorRect.right - g_monitorRect.left, g_monitorRect.bottom - g_monitorRect.top, - SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOOWNERZORDER | SWP_SHOWWINDOW); + SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE); }); } - static HWND prevPresentationWindow = nullptr; - if (prevPresentationWindow && prevPresentationWindow != g_presentationWindow) + static HWND prevFullscreenWindow = nullptr; + if (prevFullscreenWindow && prevFullscreenWindow != fullscreenWindow) { - Gdi::Window::updatePresentationWindowPos(prevPresentationWindow, GetParent(prevPresentationWindow)); + Gdi::Window::setDpiAwareness(prevFullscreenWindow, false); + HWND prevFullscreenPresentationWindow = Gdi::Window::getPresentationWindow(prevFullscreenWindow); + if (prevFullscreenPresentationWindow) + { + Gdi::Window::updatePresentationWindowPos(prevFullscreenPresentationWindow, prevFullscreenWindow); + } } - prevPresentationWindow = g_presentationWindow; + prevFullscreenWindow = fullscreenWindow; } unsigned WINAPI updateThreadProc(LPVOID /*lpParameter*/) @@ -481,9 +507,10 @@ namespace DDraw { LOG_FUNC("RealPrimarySurface::create", &dd); DDraw::ScopedThreadLock lock; + const auto& mi = Win32::DisplayMode::getMonitorInfo( + D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr::from(&dd)).deviceName); auto prevMonitorRect = g_monitorRect; - g_monitorRect = Win32::DisplayMode::getMonitorInfo( - D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr::from(&dd)).deviceName).rcMonitor; + g_monitorRect = g_isExclusiveFullscreen ? mi.rcReal : mi.rcDpiAware; DDSURFACEDESC desc = {}; desc.dwSize = sizeof(desc); @@ -499,6 +526,7 @@ namespace DDraw if (DDERR_NOEXCLUSIVEMODE == result) { g_isFullscreen = false; + g_monitorRect = mi.rcDpiAware; desc.dwFlags = DDSD_CAPS; desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; desc.dwBackBufferCount = 0; @@ -603,6 +631,7 @@ namespace DDraw static UINT lastOverlayCheckVsyncCount = 0; if (vsyncCount != lastOverlayCheckVsyncCount) { + setPresentationWindowTopmost(); Gdi::Cursor::update(); Gdi::Caret::blink(); auto statsWindow = Gdi::GuiThread::getStatsWindow(); @@ -676,13 +705,9 @@ namespace DDraw auto primary(DDraw::PrimarySurface::getPrimary()); CompatWeakPtr src; - if (g_isDelayedFlipPending) + if (primary && SUCCEEDED(primary->IsLost(primary))) { - src = g_lastFlipSurface->getDDS(); - } - else if (primary && SUCCEEDED(primary->IsLost(primary))) - { - src = primary; + src = g_isDelayedFlipPending ? g_lastFlipSurface->getDDS() : primary; } else { @@ -734,6 +759,8 @@ namespace DDraw void RealPrimarySurface::init() { + g_isExclusiveFullscreen = Config::Settings::FullscreenMode::EXCLUSIVE == Config::fullscreenMode.get() || + !IsWindows8OrGreater(); Dll::createThread(&updateThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL); } diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp index fe2b9cd..790eb5b 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp @@ -92,12 +92,10 @@ namespace DDraw LOG_FUNC("PrimarySurface::create", &dd, desc, surface); DDraw::RealPrimarySurface::destroyDefaultPrimary(); - const auto& dm = DDraw::DirectDraw::getDisplayMode(*CompatPtr::from(&dd)); auto deviceName = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr::from(&dd)).deviceName; + const auto& mi = Win32::DisplayMode::getMonitorInfo(deviceName); auto prevMonitorRect = g_monitorRect; - g_monitorRect = Win32::DisplayMode::getMonitorInfo(deviceName).rcMonitor; - g_monitorRect.right = g_monitorRect.left + dm.dwWidth; - g_monitorRect.bottom = g_monitorRect.top + dm.dwHeight; + g_monitorRect = mi.rcEmulated; HRESULT result = RealPrimarySurface::create(*CompatPtr::from(&dd)); if (FAILED(result)) @@ -111,12 +109,12 @@ namespace DDraw auto data = privateData.get(); desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; - desc.dwWidth = dm.dwWidth; - desc.dwHeight = dm.dwHeight; + desc.dwWidth = g_monitorRect.right - g_monitorRect.left; + desc.dwHeight = g_monitorRect.bottom - g_monitorRect.top; desc.ddsCaps.dwCaps &= ~(DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM); desc.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN; - desc.ddpfPixelFormat = dm.ddpfPixelFormat; + desc.ddpfPixelFormat = DirectDraw::getRgbPixelFormat(mi.bpp); result = Surface::create(dd, desc, surface, std::move(privateData)); if (FAILED(result)) diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp index 2d1a9f0..152fbca 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp @@ -35,7 +35,7 @@ namespace D3dDdi::ScopedCriticalSection lock; Gdi::Region clipRgn(DDraw::DirectDrawClipper::getClipRgn(*clipper)); - RECT monitorRect = DDraw::RealPrimarySurface::getMonitorRect(); + RECT monitorRect = DDraw::PrimarySurface::getMonitorRect(); RECT virtualScreenBounds = Gdi::VirtualScreen::getBounds(); clipRgn.offset(monitorRect.left, monitorRect.top); clipRgn &= virtualScreenBounds; diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index f54625c..d798f2b 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -327,6 +327,7 @@ + @@ -460,6 +461,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 53e4fb8..019bd34 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -705,6 +705,9 @@ Header Files\Config\Settings + + Header Files\Win32 + @@ -1100,6 +1103,9 @@ Source Files\Config\Settings + + Source Files\Win32 + diff --git a/DDrawCompat/Dll/DllMain.cpp b/DDrawCompat/Dll/DllMain.cpp index b7083fd..c53959a 100644 --- a/DDrawCompat/Dll/DllMain.cpp +++ b/DDrawCompat/Dll/DllMain.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -149,12 +150,6 @@ namespace (!Compat::isEqual(currentDllPath, dciman32DllPath) && GetModuleHandleW(dciman32DllPath.c_str())); } - void logDpiAwareness(bool isSuccessful, DPI_AWARENESS_CONTEXT dpiAwareness, const char* funcName) - { - LOG_INFO << (isSuccessful ? "DPI awareness was successfully changed" : "Failed to change process DPI awareness") - << " to \"" << Config::dpiAwareness.convertToString(dpiAwareness) << "\" via " << funcName; - } - void onDirectDrawCreate(GUID* lpGUID, LPDIRECTDRAW* lplpDD, IUnknown* /*pUnkOuter*/) { return DDraw::DirectDraw::onCreate(lpGUID, *CompatPtr::from(*lplpDD)); @@ -180,71 +175,6 @@ namespace return LOG_RESULT(CALL_ORIG_PROC(SetAppCompatData)(param1, param2)); } - void setDpiAwareness() - { - auto dpiAwareness = Config::dpiAwareness.get(); - if (!dpiAwareness) - { - return; - } - - HMODULE user32 = LoadLibrary("user32"); - auto isValidDpiAwarenessContext = reinterpret_cast( - Compat::getProcAddress(user32, "IsValidDpiAwarenessContext")); - auto setProcessDpiAwarenessContext = reinterpret_cast( - Compat::getProcAddress(user32, "SetProcessDpiAwarenessContext")); - if (isValidDpiAwarenessContext && setProcessDpiAwarenessContext) - { - if (DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 == dpiAwareness && - !isValidDpiAwarenessContext(dpiAwareness)) - { - dpiAwareness = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE; - } - - if (DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED == dpiAwareness && - !isValidDpiAwarenessContext(dpiAwareness)) - { - dpiAwareness = DPI_AWARENESS_CONTEXT_UNAWARE; - } - - logDpiAwareness(setProcessDpiAwarenessContext(dpiAwareness), dpiAwareness, "SetProcessDpiAwarenessContext"); - return; - } - - auto setProcessDpiAwareness = reinterpret_cast( - Compat::getProcAddress(LoadLibrary("shcore"), "SetProcessDpiAwareness")); - if (setProcessDpiAwareness) - { - HRESULT result = S_OK; - if (DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE == dpiAwareness || - DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 == dpiAwareness) - { - dpiAwareness = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE; - result = setProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); - } - else if (DPI_AWARENESS_CONTEXT_SYSTEM_AWARE == dpiAwareness) - { - result = setProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE); - } - else - { - dpiAwareness = DPI_AWARENESS_CONTEXT_UNAWARE; - result = setProcessDpiAwareness(PROCESS_DPI_UNAWARE); - } - - logDpiAwareness(SUCCEEDED(result), dpiAwareness, "SetProcessDpiAwareness"); - return; - } - - if (DPI_AWARENESS_CONTEXT_UNAWARE == dpiAwareness || - DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED == dpiAwareness) - { - LOG_INFO << "DPI awareness was not changed"; - } - - logDpiAwareness(SetProcessDPIAware(), DPI_AWARENESS_CONTEXT_SYSTEM_AWARE, "SetProcessDPIAware"); - } - LPTOP_LEVEL_EXCEPTION_FILTER WINAPI setUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) { LOG_FUNC("SetUnhandledExceptionFilter", Compat::funcPtrToStr(lpTopLevelExceptionFilter)); @@ -407,7 +337,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) Compat::closeDbgEng(); CALL_ORIG_FUNC(timeBeginPeriod)(1); - setDpiAwareness(); + Win32::DpiAwareness::init(); SetThemeAppProperties(0); Time::init(); Win32::Thread::applyConfig(); diff --git a/DDrawCompat/Gdi/Cursor.cpp b/DDrawCompat/Gdi/Cursor.cpp index 8f0779a..ccc9037 100644 --- a/DDrawCompat/Gdi/Cursor.cpp +++ b/DDrawCompat/Gdi/Cursor.cpp @@ -192,7 +192,7 @@ namespace Gdi POINT pos = {}; CALL_ORIG_FUNC(GetCursorPos)(&pos); - SetCursorPos(pos.x, pos.y); + CALL_ORIG_FUNC(SetCursorPos)(pos.x, pos.y); } void setMonitorClipRect(const RECT& rect) diff --git a/DDrawCompat/Gdi/GuiThread.cpp b/DDrawCompat/Gdi/GuiThread.cpp index 868a5e7..ae6eace 100644 --- a/DDrawCompat/Gdi/GuiThread.cpp +++ b/DDrawCompat/Gdi/GuiThread.cpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace { @@ -105,8 +106,8 @@ namespace Gdi { namespace GuiThread { - HWND createWindow(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, - int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) + HWND createWindow(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y, + int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam, bool dpiAware) { // Workaround for ForceSimpleWindow shim static auto createWindowExW = reinterpret_cast( @@ -115,6 +116,7 @@ namespace Gdi HWND hwnd = nullptr; execute([&]() { + Win32::ScopedDpiAwareness dpiAwareness(dpiAware); hwnd = createWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); }); diff --git a/DDrawCompat/Gdi/GuiThread.h b/DDrawCompat/Gdi/GuiThread.h index 269e916..d3469f9 100644 --- a/DDrawCompat/Gdi/GuiThread.h +++ b/DDrawCompat/Gdi/GuiThread.h @@ -16,8 +16,8 @@ namespace Gdi { namespace GuiThread { - HWND createWindow(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, - int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); + HWND createWindow(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y, + int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam, bool dpiAware); void deleteTaskbarTab(HWND hwnd); void destroyWindow(HWND hwnd); void setWindowRgn(HWND hwnd, Gdi::Region rgn); diff --git a/DDrawCompat/Gdi/Metrics.cpp b/DDrawCompat/Gdi/Metrics.cpp index 74d5244..4359622 100644 --- a/DDrawCompat/Gdi/Metrics.cpp +++ b/DDrawCompat/Gdi/Metrics.cpp @@ -12,11 +12,10 @@ namespace int getAdjustedDisplayMetrics(int nIndex, int cxIndex) { int result = CALL_ORIG_FUNC(GetSystemMetrics)(nIndex); - auto dm = Win32::DisplayMode::getEmulatedDisplayMode(); - if (0 == dm.rect.left && 0 == dm.rect.top) - { - result += (nIndex == cxIndex) ? dm.diff.cx : dm.diff.cy; - } + auto mi = Win32::DisplayMode::getMonitorInfo(); + result += (nIndex == cxIndex) + ? (mi.rcEmulated.right - mi.rcMonitor.right) + : (mi.rcEmulated.bottom - mi.rcMonitor.bottom); return result; } diff --git a/DDrawCompat/Gdi/PresentationWindow.cpp b/DDrawCompat/Gdi/PresentationWindow.cpp index 564b49f..3b6a211 100644 --- a/DDrawCompat/Gdi/PresentationWindow.cpp +++ b/DDrawCompat/Gdi/PresentationWindow.cpp @@ -19,9 +19,9 @@ namespace Gdi { namespace PresentationWindow { - HWND create(HWND owner) + HWND create(HWND owner, bool dpiAware) { - LOG_FUNC("PresentationWindow::create", owner); + LOG_FUNC("PresentationWindow::create", owner, dpiAware); HWND presentationWindow = nullptr; GuiThread::execute([&]() { @@ -34,7 +34,8 @@ namespace Gdi owner, nullptr, nullptr, - nullptr); + nullptr, + dpiAware); if (presentationWindow) { diff --git a/DDrawCompat/Gdi/PresentationWindow.h b/DDrawCompat/Gdi/PresentationWindow.h index 4f5f519..d183aa1 100644 --- a/DDrawCompat/Gdi/PresentationWindow.h +++ b/DDrawCompat/Gdi/PresentationWindow.h @@ -6,7 +6,7 @@ namespace Gdi { namespace PresentationWindow { - HWND create(HWND owner); + HWND create(HWND owner, bool dpiAware = false); void installHooks(); } diff --git a/DDrawCompat/Gdi/VirtualScreen.cpp b/DDrawCompat/Gdi/VirtualScreen.cpp index 678b639..4cbbea5 100644 --- a/DDrawCompat/Gdi/VirtualScreen.cpp +++ b/DDrawCompat/Gdi/VirtualScreen.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -24,7 +23,6 @@ namespace }; Compat::CriticalSection g_cs; - Gdi::Region g_region; RECT g_bounds = {}; DWORD g_bpp = 0; LONG g_width = 0; @@ -39,27 +37,6 @@ namespace RGBQUAD g_systemPalette[256] = {}; std::map g_dcs; - BOOL CALLBACK addMonitorRectToRegion( - HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT lprcMonitor, LPARAM dwData) - { - MONITORINFOEXW mi = {}; - mi.cbSize = sizeof(mi); - CALL_ORIG_FUNC(GetMonitorInfoW)(hMonitor, &mi); - - auto res = Win32::DisplayMode::getDisplayResolution(mi.szDevice); - RECT rect = *lprcMonitor; - if (0 != res.cx && 0 != res.cy) - { - rect.right = rect.left + res.cx; - rect.bottom = rect.top + res.cy; - } - - Gdi::Region& virtualScreenRegion = *reinterpret_cast(dwData); - Gdi::Region monitorRegion(rect); - virtualScreenRegion |= monitorRegion; - return TRUE; - } - RGBQUAD convertToRgbQuad(PALETTEENTRY entry) { RGBQUAD quad = {}; @@ -199,12 +176,6 @@ namespace Gdi return g_bounds; } - Region getRegion() - { - Compat::ScopedCriticalSection lock(g_cs); - return g_region; - } - DDSURFACEDESC2 getSurfaceDesc(const RECT& rect) { Compat::ScopedCriticalSection lock(g_cs); @@ -278,13 +249,14 @@ namespace Gdi if (g_isFullscreen) { g_bounds = DDraw::PrimarySurface::getMonitorRect(); - g_region = g_bounds; } else { - g_region.clear(); - EnumDisplayMonitors(nullptr, nullptr, addMonitorRectToRegion, reinterpret_cast(&g_region)); - GetRgnBox(g_region, &g_bounds); + g_bounds = {}; + for (const auto& mi : Win32::DisplayMode::getAllMonitorInfo()) + { + UnionRect(&g_bounds, &g_bounds, &mi.second.rcMonitor); + } } g_bpp = Win32::DisplayMode::getBpp(); diff --git a/DDrawCompat/Gdi/VirtualScreen.h b/DDrawCompat/Gdi/VirtualScreen.h index dcac31d..707b0d9 100644 --- a/DDrawCompat/Gdi/VirtualScreen.h +++ b/DDrawCompat/Gdi/VirtualScreen.h @@ -17,7 +17,6 @@ namespace Gdi void deleteDc(HDC dc); RECT getBounds(); - Region getRegion(); DDSURFACEDESC2 getSurfaceDesc(const RECT& rect); void init(); diff --git a/DDrawCompat/Gdi/WinProc.cpp b/DDrawCompat/Gdi/WinProc.cpp index 5afceea..203277e 100644 --- a/DDrawCompat/Gdi/WinProc.cpp +++ b/DDrawCompat/Gdi/WinProc.cpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace { @@ -51,7 +52,6 @@ namespace }; decltype(&DwmSetIconicThumbnail) g_dwmSetIconicThumbnail = nullptr; - decltype(&SetThreadDpiAwarenessContext) g_setThreadDpiAwarenessContext = nullptr; wchar_t g_dummyWindowText; std::map g_menuMaxHeight; @@ -327,19 +327,8 @@ namespace DeleteDC(dstDc); ReleaseDC(presentationWindow, srcDc); - DPI_AWARENESS_CONTEXT prevContext = nullptr; - if (g_setThreadDpiAwarenessContext) - { - prevContext = g_setThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); - } - + Win32::ScopedDpiAwareness dpiAwareness; g_dwmSetIconicThumbnail(hwnd, bmp, 0); - - if (prevContext) - { - g_setThreadDpiAwarenessContext(prevContext); - } - DeleteObject(bmp); } @@ -370,6 +359,11 @@ namespace return getMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, CALL_ORIG_FUNC(GetMessageW)); } + int WINAPI getRandomRgn(HDC hdc, HRGN hrgn, INT i) + { + return Gdi::Window::getRandomRgn(hdc, hrgn, i); + } + LONG getWindowLong(HWND hWnd, int nIndex, decltype(&GetWindowLongA) origGetWindowLong, WNDPROC(WindowProc::* wndProc)) { @@ -441,24 +435,22 @@ namespace return; } - HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); + auto mi = Win32::DisplayMode::getMonitorInfo(hwnd); - MONITORINFO origMi = {}; - origMi.cbSize = sizeof(origMi); - CALL_ORIG_FUNC(GetMonitorInfoA)(monitor, &origMi); - - MONITORINFO mi = {}; - mi.cbSize = sizeof(mi); - GetMonitorInfoA(monitor, &mi); - - if (!EqualRect(&origMi.rcMonitor, &mi.rcMonitor)) + if (!EqualRect(&mi.rcEmulated, &mi.rcMonitor)) { RECT wr = {}; GetWindowRect(hwnd, &wr); const LONG width = wr.right - wr.left; const LONG height = wr.bottom - wr.top; - const RECT& mr = 0 == g_inMessageBox ? mi.rcWork : mi.rcMonitor; + if (0 == g_inMessageBox) + { + mi.rcWork.right = mi.rcWork.left + mi.rcEmulated.right - mi.rcEmulated.left; + mi.rcWork.bottom = mi.rcWork.top + mi.rcEmulated.bottom - mi.rcEmulated.top; + } + + const RECT& mr = 0 == g_inMessageBox ? mi.rcWork : mi.rcEmulated; const LONG left = (mr.left + mr.right - width) / 2; const LONG top = (mr.top + mr.bottom - height) / 2; @@ -506,11 +498,9 @@ namespace void onGetMinMaxInfo(MINMAXINFO& mmi) { - MONITORINFOEXA mi = {}; - mi.cbSize = sizeof(mi); - GetMonitorInfoA(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi); - mmi.ptMaxSize.x = mi.rcMonitor.right - 2 * mmi.ptMaxPosition.x; - mmi.ptMaxSize.y = mi.rcMonitor.bottom - 2 * mmi.ptMaxPosition.y; + const auto& mi = Win32::DisplayMode::getMonitorInfo(); + mmi.ptMaxSize.x = mi.rcEmulated.right - 2 * mmi.ptMaxPosition.x; + mmi.ptMaxSize.y = mi.rcEmulated.bottom - 2 * mmi.ptMaxPosition.y; } void onInitMenuPopup(HMENU menu) @@ -861,6 +851,7 @@ namespace Gdi HOOK_FUNCTION(user32, GetCursorPos, getCursorPos); HOOK_FUNCTION(user32, GetMessageA, getMessageA); HOOK_FUNCTION(user32, GetMessageW, getMessageW); + HOOK_FUNCTION(gdi32, GetRandomRgn, getRandomRgn); HOOK_FUNCTION(user32, GetWindowLongA, getWindowLongA); HOOK_FUNCTION(user32, GetWindowLongW, getWindowLongW); HOOK_FUNCTION(user32, MessageBoxA, messageBox); @@ -878,8 +869,6 @@ namespace Gdi g_dwmSetIconicThumbnail = reinterpret_cast( GetProcAddress(GetModuleHandle("dwmapi"), "DwmSetIconicThumbnail")); - g_setThreadDpiAwarenessContext = reinterpret_cast( - GetProcAddress(GetModuleHandle("user32"), "SetThreadDpiAwarenessContext")); Compat::hookIatFunction(Dll::g_origDDrawModule, "SetWindowLongA", ddrawSetWindowLongA); diff --git a/DDrawCompat/Gdi/Window.cpp b/DDrawCompat/Gdi/Window.cpp index caea535..f6be18c 100644 --- a/DDrawCompat/Gdi/Window.cpp +++ b/DDrawCompat/Gdi/Window.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include namespace { @@ -35,28 +37,24 @@ namespace HWND presentationWindow; RECT windowRect; RECT clientRect; - Gdi::Region windowRegion; Gdi::Region visibleRegion; Gdi::Region invalidatedRegion; bool isMenu; bool isLayered; - bool isVisibleRegionChanged; + bool isDpiAware; Window(HWND hwnd) : hwnd(hwnd) , presentationWindow(nullptr) , windowRect{} , clientRect{} - , windowRegion(nullptr) , isMenu(Gdi::MENU_ATOM == GetClassLong(hwnd, GCW_ATOM)) , isLayered(true) - , isVisibleRegionChanged(false) + , isDpiAware(false) { } }; - const RECT REGION_OVERRIDE_MARKER_RECT = { 32000, 32000, 32001, 32001 }; - std::map g_windows; std::vector g_windowZOrder; @@ -92,16 +90,6 @@ namespace return true; } - Gdi::Region getWindowRegion(HWND hwnd) - { - Gdi::Region rgn; - if (ERROR == CALL_ORIG_FUNC(GetWindowRgn)(hwnd, rgn)) - { - return nullptr; - } - return rgn; - } - void presentLayeredWindow(CompatWeakPtr dst, HWND hwnd, RECT wr, const RECT& monitorRect, HDC& dstDc, Gdi::Region* rgn = nullptr, bool isMenu = false) { @@ -261,17 +249,14 @@ namespace const LONG exStyle = CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_EXSTYLE); const bool isLayered = it->second.isMenu || (exStyle & WS_EX_LAYERED); const bool isVisible = IsWindowVisible(hwnd) && !IsIconic(hwnd); - bool setPresentationWindowRgn = false; if (isLayered != it->second.isLayered) { it->second.isLayered = isLayered; - it->second.isVisibleRegionChanged = isVisible; if (!isLayered) { it->second.presentationWindow = Gdi::PresentationWindow::create(hwnd); Gdi::WinProc::updatePresentationWindowText(hwnd); - setPresentationWindowRgn = true; } else if (it->second.presentationWindow) { @@ -280,14 +265,6 @@ namespace } } - Gdi::Region windowRegion(getWindowRegion(hwnd)); - if (windowRegion && !PtInRegion(windowRegion, REGION_OVERRIDE_MARKER_RECT.left, REGION_OVERRIDE_MARKER_RECT.top) || - !windowRegion && it->second.windowRegion) - { - swap(it->second.windowRegion, windowRegion); - setPresentationWindowRgn = true; - } - WINDOWINFO wi = {}; Gdi::Region visibleRegion; @@ -297,15 +274,24 @@ namespace GetWindowInfo(hwnd, &wi); if (!IsRectEmpty(&wi.rcWindow)) { - if (it->second.windowRegion) + if (isLayered) { - visibleRegion = it->second.windowRegion; - visibleRegion.offset(wi.rcWindow.left, wi.rcWindow.top); + if (ERROR != GetWindowRgn(hwnd, visibleRegion)) + { + visibleRegion.offset(wi.rcWindow.left, wi.rcWindow.top); + } + else + { + visibleRegion = wi.rcWindow; + } } else { - visibleRegion = wi.rcWindow; + HDC windowDc = GetWindowDC(hwnd); + CALL_ORIG_FUNC(GetRandomRgn)(windowDc, visibleRegion, SYSRGN); + ReleaseDC(hwnd, windowDc); } + visibleRegion &= context.virtualScreenRegion; if (!it->second.isMenu) { @@ -335,27 +321,11 @@ namespace context.invalidatedRegion |= visibleRegion - it->second.visibleRegion; } - if (isVisible && !it->second.isVisibleRegionChanged) + if (it->second.presentationWindow && + (!isVisible || it->second.presentationWindow != DDraw::RealPrimarySurface::getPresentationWindow())) { - visibleRegion.offset(it->second.windowRect.left - wi.rcWindow.left, it->second.windowRect.top - wi.rcWindow.top); - - if (it->second.visibleRegion != visibleRegion) - { - it->second.isVisibleRegionChanged = true; - } - } - - if (it->second.presentationWindow) - { - if (setPresentationWindowRgn) - { - Gdi::GuiThread::setWindowRgn(it->second.presentationWindow, it->second.windowRegion); - } - - if (it->second.presentationWindow != DDraw::RealPrimarySurface::getPresentationWindow()) - { - Gdi::Window::updatePresentationWindowPos(it->second.presentationWindow, hwnd); - } + Gdi::GuiThread::setWindowRgn(it->second.presentationWindow, Gdi::Window::getWindowRgn(hwnd)); + Gdi::Window::updatePresentationWindowPos(it->second.presentationWindow, hwnd); } } return TRUE; @@ -395,7 +365,7 @@ namespace Gdi if (statsWindow && statsWindow->isVisible()) { GetWindowRect(statsWindow->getWindow(), &wr); - auto visibleRegion(getWindowRegion(statsWindow->getWindow())); + auto visibleRegion(getWindowRgn(statsWindow->getWindow())); visibleRegion.offset(wr.left, wr.top); layeredWindows.push_back({ statsWindow->getWindow(), wr, visibleRegion }); } @@ -404,7 +374,7 @@ namespace Gdi if (configWindow && configWindow->isVisible()) { GetWindowRect(configWindow->getWindow(), &wr); - auto visibleRegion(getWindowRegion(configWindow->getWindow())); + auto visibleRegion(getWindowRgn(configWindow->getWindow())); visibleRegion.offset(wr.left, wr.top); layeredWindows.push_back({ configWindow->getWindow(), wr, visibleRegion }); auto capture = Input::getCaptureWindow(); @@ -445,6 +415,47 @@ namespace Gdi return nullptr; } + int getRandomRgn(HDC hdc, HRGN hrgn, INT i) + { + auto result = CALL_ORIG_FUNC(GetRandomRgn)(hdc, hrgn, i); + if (1 != result || SYSRGN != i) + { + return result; + } + + HWND hwnd = WindowFromDC(hdc); + if (!hwnd) + { + return result; + } + + HWND root = GetAncestor(hwnd, GA_ROOT); + if (!root) + { + return result; + } + + D3dDdi::ScopedCriticalSection lock; + auto it = g_windows.find(root); + if (it == g_windows.end()) + { + return result; + } + + CombineRgn(hrgn, hrgn, it->second.visibleRegion, RGN_AND); + return result; + } + + Gdi::Region getWindowRgn(HWND hwnd) + { + Gdi::Region rgn; + if (ERROR == CALL_ORIG_FUNC(GetWindowRgn)(hwnd, rgn)) + { + return nullptr; + } + return rgn; + } + bool isTopLevelWindow(HWND hwnd) { return GetDesktopWindow() == GetAncestor(hwnd, GA_PARENT); @@ -470,7 +481,6 @@ namespace Gdi void onSyncPaint(HWND hwnd) { LOG_FUNC("Window::onSyncPaint", hwnd); - bool isInvalidated = false; { D3dDdi::ScopedCriticalSection lock; @@ -480,38 +490,13 @@ namespace Gdi return; } - if (it->second.isVisibleRegionChanged) - { - it->second.isVisibleRegionChanged = false; - const LONG origWndProc = CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_WNDPROC); - CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC, reinterpret_cast(CALL_ORIG_FUNC(DefWindowProcA))); - Gdi::Region rgn(it->second.isLayered ? it->second.windowRegion : it->second.visibleRegion); - if (!it->second.isLayered) - { - rgn.offset(-it->second.windowRect.left, -it->second.windowRect.top); - rgn |= REGION_OVERRIDE_MARKER_RECT; - } - if (SetWindowRgn(hwnd, rgn, FALSE)) - { - rgn.release(); - } - CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC, origWndProc); - } - - isInvalidated = !it->second.invalidatedRegion.isEmpty(); - if (isInvalidated) - { - RedrawWindow(hwnd, nullptr, it->second.invalidatedRegion, - RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN); - it->second.invalidatedRegion.clear(); - } + RedrawWindow(hwnd, nullptr, it->second.invalidatedRegion, + RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN); + it->second.invalidatedRegion.clear(); } - if (isInvalidated) - { - RECT emptyRect = {}; - RedrawWindow(hwnd, &emptyRect, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ERASENOW); - } + RECT emptyRect = {}; + RedrawWindow(hwnd, &emptyRect, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ERASENOW); } void present(CompatRef dst, CompatRef src, @@ -526,12 +511,13 @@ namespace Gdi return; } + auto mr = DDraw::PrimarySurface::getMonitorRect(); for (auto window : g_windowZOrder) { if (window->presentationWindow && !window->visibleRegion.isEmpty()) { clipper->SetHWnd(&clipper, 0, window->presentationWindow); - dst->Blt(&dst, nullptr, &src, nullptr, DDBLT_WAIT, nullptr); + dst->Blt(&dst, &mr, &src, nullptr, DDBLT_WAIT, nullptr); } } } @@ -589,7 +575,7 @@ namespace Gdi UpdateWindowContext context; context.processId = GetCurrentProcessId(); - context.virtualScreenRegion = VirtualScreen::getRegion(); + context.virtualScreenRegion = VirtualScreen::getBounds(); std::vector invalidatedWindows; { @@ -616,7 +602,7 @@ namespace Gdi for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it) { auto& window = **it; - if (window.isVisibleRegionChanged || !window.invalidatedRegion.isEmpty()) + if (!window.invalidatedRegion.isEmpty()) { invalidatedWindows.push_back(window.hwnd); } @@ -629,6 +615,31 @@ namespace Gdi } } + void setDpiAwareness(HWND hwnd, bool dpiAware) + { + if (!Win32::DpiAwareness::isMixedModeSupported()) + { + return; + } + + D3dDdi::ScopedCriticalSection lock; + auto it = g_windows.find(hwnd); + if (it != g_windows.end() && it->second.isDpiAware != dpiAware) + { + it->second.isDpiAware = dpiAware; + auto prevPresentationWindow = it->second.presentationWindow; + it->second.presentationWindow = Gdi::PresentationWindow::create(hwnd, dpiAware); + + if (it->second.presentationWindow) + { + Gdi::WinProc::updatePresentationWindowText(hwnd); + Gdi::GuiThread::setWindowRgn(it->second.presentationWindow, getWindowRgn(hwnd)); + } + + Gdi::GuiThread::destroyWindow(prevPresentationWindow); + } + } + void updatePresentationWindowPos(HWND presentationWindow, HWND owner) { if (IsIconic(owner)) @@ -667,7 +678,9 @@ namespace Gdi Gdi::GuiThread::execute([&]() { CALL_ORIG_FUNC(SetWindowPos)(presentationWindow, - wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags); + wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags | SWP_NOMOVE); + CALL_ORIG_FUNC(SetWindowPos)(presentationWindow, + wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags | SWP_NOSIZE); }); } } diff --git a/DDrawCompat/Gdi/Window.h b/DDrawCompat/Gdi/Window.h index e9e37e8..2cf8ddb 100644 --- a/DDrawCompat/Gdi/Window.h +++ b/DDrawCompat/Gdi/Window.h @@ -21,12 +21,15 @@ namespace Gdi std::vector getVisibleLayeredWindows(); std::vector getVisibleOverlayWindows(); HWND getFullscreenWindow(); + int getRandomRgn(HDC hdc, HRGN hrgn, INT i); + Gdi::Region getWindowRgn(HWND hwnd); bool isTopLevelWindow(HWND hwnd); void onStyleChanged(HWND hwnd, WPARAM wParam); void onSyncPaint(HWND hwnd); void present(CompatRef dst, CompatRef src, CompatRef clipper); void present(Gdi::Region excludeRegion); + void setDpiAwareness(HWND hwnd, bool dpiAware); void updateAll(); void updatePresentationWindowPos(HWND presentationWindow, HWND owner); } diff --git a/DDrawCompat/Input/Input.cpp b/DDrawCompat/Input/Input.cpp index 6ba4c45..3dfbdb0 100644 --- a/DDrawCompat/Input/Input.cpp +++ b/DDrawCompat/Input/Input.cpp @@ -3,10 +3,12 @@ #include #include -#include +#include #include #include +#include +#include #include #include #include @@ -15,9 +17,18 @@ #include #include #include +#include namespace { + struct DInputMouseHookData + { + HOOKPROC origHookProc; + LPARAM origHookStruct; + MSLLHOOKSTRUCT hookStruct; + DWORD dpiScale; + }; + struct HotKeyData { std::function action; @@ -29,14 +40,19 @@ namespace SIZE g_bmpArrowSize = {}; Overlay::Control* g_capture = nullptr; POINT g_cursorPos = {}; + POINT g_origCursorPos = { MAXLONG, MAXLONG }; HWND g_cursorWindow = nullptr; std::map g_hotKeys; RECT g_monitorRect = {}; HHOOK g_keyboardHook = nullptr; HHOOK g_mouseHook = nullptr; + DInputMouseHookData g_dinputMouseHookData = {}; + decltype(&PhysicalToLogicalPointForPerMonitorDPI) g_physicalToLogicalPointForPerMonitorDPI = nullptr; + LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK lowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam); + POINT physicalToLogicalPoint(POINT pt, DWORD dpiScale); LRESULT CALLBACK cursorWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { @@ -67,6 +83,44 @@ namespace return CALL_ORIG_FUNC(DefWindowProcA)(hwnd, uMsg, wParam, lParam); } + LRESULT WINAPI dinputCallNextHookEx(HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam) + { + if (lParam == reinterpret_cast(&g_dinputMouseHookData.hookStruct)) + { + lParam = g_dinputMouseHookData.origHookStruct; + } + return CallNextHookEx(hhk, nCode, wParam, lParam); + } + + LRESULT CALLBACK dinputLowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) + { + if (HC_ACTION == nCode) + { + auto& data = g_dinputMouseHookData; + data.origHookStruct = lParam; + data.hookStruct = *reinterpret_cast(lParam); + + if (WM_MOUSEMOVE == wParam) + { + data.hookStruct.pt = physicalToLogicalPoint(data.hookStruct.pt, data.dpiScale); + } + else + { + CALL_ORIG_FUNC(GetCursorPos)(&data.hookStruct.pt); + } + + lParam = reinterpret_cast(&g_dinputMouseHookData.hookStruct); + } + return g_dinputMouseHookData.origHookProc(nCode, wParam, lParam); + } + + DWORD getDpiScaleForCursorPos() + { + POINT cp = {}; + CALL_ORIG_FUNC(GetCursorPos)(&cp); + return Win32::DisplayMode::getMonitorInfo(cp).dpiScale; + } + LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { if (HC_ACTION == nCode && @@ -101,12 +155,25 @@ namespace if (WM_MOUSEMOVE == wParam) { - POINT cp = g_cursorPos; - POINT origCp = {}; - CALL_ORIG_FUNC(GetCursorPos)(&origCp); + if (MAXLONG == g_origCursorPos.y) + { + if (llHook.flags & LLMHF_INJECTED) + { + if (MAXLONG == g_origCursorPos.x) + { + g_origCursorPos.x = llHook.pt.x; + } + else + { + g_origCursorPos.y = llHook.pt.y; + } + } + return 1; + } - cp.x += (llHook.pt.x - origCp.x); - cp.y += (llHook.pt.y - origCp.y); + POINT cp = g_cursorPos; + cp.x += llHook.pt.x - g_origCursorPos.x; + cp.y += llHook.pt.y - g_origCursorPos.y; cp.x = std::min(std::max(g_monitorRect.left, cp.x), g_monitorRect.right); cp.y = std::min(std::max(g_monitorRect.top, cp.y), g_monitorRect.bottom); g_cursorPos = cp; @@ -150,6 +217,16 @@ namespace TerminateProcess(GetCurrentProcess(), 0); } + POINT physicalToLogicalPoint(POINT pt, DWORD dpiScale) + { + if (g_physicalToLogicalPointForPerMonitorDPI) + { + g_physicalToLogicalPointForPerMonitorDPI(nullptr, &pt); + return pt; + } + return { MulDiv(pt.x, 100, dpiScale), MulDiv(pt.y, 100, dpiScale) }; + } + void resetKeyboardHook() { Gdi::GuiThread::execute([]() @@ -171,18 +248,54 @@ namespace { UnhookWindowsHookEx(g_mouseHook); } + + g_origCursorPos = { MAXLONG, MAXLONG }; g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)( WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_currentModule, 0); + + INPUT inputs[2] = {}; + inputs[0].mi.dy = 1; + inputs[0].mi.dwFlags = MOUSEEVENTF_MOVE; + inputs[1].mi.dx = 1; + inputs[1].mi.dwFlags = MOUSEEVENTF_MOVE; + SendInput(2, inputs, sizeof(INPUT)); }); } + BOOL WINAPI setCursorPos(int X, int Y) + { + LOG_FUNC("SetCursorPos", X, Y); + auto result = CALL_ORIG_FUNC(SetCursorPos)(X, Y); + if (result && g_mouseHook) + { + resetMouseHook(); + } + return LOG_RESULT(result); + } + HHOOK setWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId, decltype(&SetWindowsHookExA) origSetWindowsHookEx) { - if (WH_KEYBOARD_LL == idHook && hmod && GetModuleHandle("AcGenral") == hmod) + if (hmod && (WH_KEYBOARD_LL == idHook || WH_MOUSE_LL == idHook)) { - // Disable the IgnoreAltTab shim - return nullptr; + auto moduleName = Compat::getModulePath(hmod).stem().string(); + if (WH_KEYBOARD_LL == idHook && 0 == _stricmp(moduleName.c_str(), "acgenral")) + { + // Disable the IgnoreAltTab shim + return nullptr; + } + else if (WH_MOUSE_LL == idHook && + (0 == _stricmp(moduleName.c_str(), "dinput") || 0 == _stricmp(moduleName.c_str(), "dinput8"))) + { + g_dinputMouseHookData.origHookProc = lpfn; + if (!g_physicalToLogicalPointForPerMonitorDPI) + { + g_dinputMouseHookData.dpiScale = getDpiScaleForCursorPos(); + } + + lpfn = dinputLowLevelMouseProc; + Compat::hookIatFunction(hmod, "CallNextHookEx", dinputCallNextHookEx); + } } HHOOK result = origSetWindowsHookEx(idHook, lpfn, hmod, dwThreadId); @@ -235,11 +348,6 @@ namespace Input return g_capture ? static_cast(&g_capture->getRoot()) : nullptr; } - POINT getCursorPos() - { - return g_cursorPos; - } - HWND getCursorWindow() { return g_cursorWindow; @@ -272,6 +380,10 @@ namespace Input GetObject(g_bmpArrow, sizeof(bm), &bm); g_bmpArrowSize = { bm.bmWidth, bm.bmHeight }; + g_physicalToLogicalPointForPerMonitorDPI = reinterpret_cast( + GetProcAddress(GetModuleHandle("user32"), "PhysicalToLogicalPointForPerMonitorDPI")); + + HOOK_FUNCTION(user32, SetCursorPos, setCursorPos); HOOK_FUNCTION(user32, SetWindowsHookExA, setWindowsHookExA); HOOK_FUNCTION(user32, SetWindowsHookExW, setWindowsHookExW); @@ -301,11 +413,7 @@ namespace Input if (control) { auto window = getCaptureWindow(); - - MONITORINFO mi = {}; - mi.cbSize = sizeof(mi); - CALL_ORIG_FUNC(GetMonitorInfoA)(MonitorFromWindow(window->getWindow(), MONITOR_DEFAULTTOPRIMARY), &mi); - g_monitorRect = mi.rcMonitor; + g_monitorRect = Win32::DisplayMode::getMonitorInfo(window->getWindow()).rcMonitor; if (!g_mouseHook) { diff --git a/DDrawCompat/Input/Input.h b/DDrawCompat/Input/Input.h index 5140480..3ad3de7 100644 --- a/DDrawCompat/Input/Input.h +++ b/DDrawCompat/Input/Input.h @@ -18,7 +18,6 @@ namespace Input Overlay::Control* getCapture(); Overlay::Window* getCaptureWindow(); - POINT getCursorPos(); HWND getCursorWindow(); POINT getRelativeCursorPos(); void installHooks(); diff --git a/DDrawCompat/Overlay/ConfigWindow.cpp b/DDrawCompat/Overlay/ConfigWindow.cpp index a3fb88f..4e0e56d 100644 --- a/DDrawCompat/Overlay/ConfigWindow.cpp +++ b/DDrawCompat/Overlay/ConfigWindow.cpp @@ -72,7 +72,8 @@ namespace namespace Overlay { ConfigWindow::ConfigWindow() - : Window(nullptr, { 0, 0, 640, 480 }, WS_BORDER, Config::configTransparency.get(), Config::configHotKey.get()) + : Window(nullptr, { 0, 0, VIRTUAL_SCREEN_WIDTH, VIRTUAL_SCREEN_HEIGHT }, + WS_BORDER, Config::configTransparency.get(), Config::configHotKey.get()) , m_buttonCount(0) , m_focus(nullptr) { diff --git a/DDrawCompat/Overlay/Window.cpp b/DDrawCompat/Overlay/Window.cpp index 11d513d..8f35b93 100644 --- a/DDrawCompat/Overlay/Window.cpp +++ b/DDrawCompat/Overlay/Window.cpp @@ -7,12 +7,12 @@ #include #include #include -#include #include #include #include #include #include +#include namespace { @@ -179,42 +179,20 @@ namespace Overlay void Window::updatePos() { - RECT monitorRect = DDraw::RealPrimarySurface::getMonitorRect(); - if (IsRectEmpty(&monitorRect)) - { - HMONITOR monitor = nullptr; - HWND foregroundWindow = GetForegroundWindow(); - if (foregroundWindow) - { - monitor = MonitorFromWindow(foregroundWindow, MONITOR_DEFAULTTONEAREST); - } - else - { - monitor = MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY); - } - - MONITORINFO mi = {}; - mi.cbSize = sizeof(mi); - CALL_ORIG_FUNC(GetMonitorInfoA)(monitor, &mi); - monitorRect = mi.rcMonitor; - - if (IsRectEmpty(&monitorRect)) - { - monitorRect = { 0, 0, m_rect.right - m_rect.left, m_rect.bottom - m_rect.top }; - } - } - - int scaleX = (monitorRect.right - monitorRect.left) / 640; - int scaleY = (monitorRect.bottom - monitorRect.top) / 480; + const RECT monitorRect = Win32::DisplayMode::getMonitorInfo(GetForegroundWindow()).rcMonitor; + int scaleX = (monitorRect.right - monitorRect.left) / VIRTUAL_SCREEN_WIDTH; + int scaleY = (monitorRect.bottom - monitorRect.top) / VIRTUAL_SCREEN_HEIGHT; m_scaleFactor = std::min(scaleX, scaleY); m_scaleFactor = std::max(1, m_scaleFactor); m_rect = calculateRect({ monitorRect.left / m_scaleFactor, monitorRect.top / m_scaleFactor, monitorRect.right / m_scaleFactor, monitorRect.bottom / m_scaleFactor }); - CALL_ORIG_FUNC(SetWindowPos)(m_hwnd, getTopmost(), - m_rect.left * m_scaleFactor, m_rect.top * m_scaleFactor, - (m_rect.right - m_rect.left) * m_scaleFactor, (m_rect.bottom - m_rect.top) * m_scaleFactor, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_SHOWWINDOW); + { + CALL_ORIG_FUNC(SetWindowPos)(m_hwnd, getTopmost(), + m_rect.left * m_scaleFactor, m_rect.top * m_scaleFactor, + (m_rect.right - m_rect.left) * m_scaleFactor, (m_rect.bottom - m_rect.top) * m_scaleFactor, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_SHOWWINDOW); + } if (Input::getCaptureWindow() == this) { diff --git a/DDrawCompat/Overlay/Window.h b/DDrawCompat/Overlay/Window.h index ad318f8..3f565c8 100644 --- a/DDrawCompat/Overlay/Window.h +++ b/DDrawCompat/Overlay/Window.h @@ -13,6 +13,9 @@ namespace Overlay class Window : public Control { public: + static const LONG VIRTUAL_SCREEN_WIDTH = 640; + static const LONG VIRTUAL_SCREEN_HEIGHT = 480; + Window(Window* parentWindow, const RECT& rect, DWORD style, int alpha, const Input::HotKey& hotKey = {}); virtual ~Window() override; diff --git a/DDrawCompat/Win32/DisplayMode.cpp b/DDrawCompat/Win32/DisplayMode.cpp index 99e83f4..d1457a3 100644 --- a/DDrawCompat/Win32/DisplayMode.cpp +++ b/DDrawCompat/Win32/DisplayMode.cpp @@ -9,7 +9,9 @@ #include #include #include -#include +#include +#include +#include #include #include #include @@ -21,6 +23,7 @@ #include #include #include +#include BOOL WINAPI DWM8And16Bit_IsShimApplied_CallOut() { return FALSE; } ULONG WINAPI GdiEntry13() { return 0; } @@ -62,7 +65,10 @@ namespace DWORD g_desktopBpp = 0; ULONG g_displaySettingsUniquenessBias = 0; EmulatedDisplayMode g_emulatedDisplayMode = {}; - Compat::SrwLock g_srwLock; + ULONG g_monitorInfoUniqueness = 0; + std::map g_monitorInfo; + Win32::DisplayMode::MonitorInfo g_emptyMonitorInfo = {}; + Compat::CriticalSection g_cs; BOOL WINAPI dwm8And16BitIsShimAppliedCallOut(); BOOL WINAPI seComHookInterface(CLSID* clsid, GUID* iid, DWORD unk1, DWORD unk2); @@ -92,24 +98,10 @@ namespace void setDwmDxFullscreenTransitionEvent(); - void adjustMonitorInfo(MONITORINFO& mi) - { - Compat::ScopedSrwLockShared srwLock(g_srwLock); - if (!g_emulatedDisplayMode.deviceName.empty() && - g_emulatedDisplayMode.rect.left == mi.rcMonitor.left && - g_emulatedDisplayMode.rect.top == mi.rcMonitor.top) - { - mi.rcMonitor.right += g_emulatedDisplayMode.diff.cx; - mi.rcMonitor.bottom += g_emulatedDisplayMode.diff.cy; - mi.rcWork.right += g_emulatedDisplayMode.diff.cx; - mi.rcWork.bottom += g_emulatedDisplayMode.diff.cy; - } - } - template LONG changeDisplaySettingsEx(const Char* lpszDeviceName, typename DevMode* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) { - DDraw::ScopedThreadLock lock; + DDraw::ScopedThreadLock ddLock; auto desktopResolution = Config::desktopResolution.get(); if (!lpDevMode && 0 == dwflags && Config::Settings::DesktopResolution::DESKTOP != desktopResolution) { @@ -235,7 +227,7 @@ namespace } { - Compat::ScopedSrwLockExclusive srwLock(g_srwLock); + Compat::ScopedCriticalSection lock(g_cs); ++g_displaySettingsUniquenessBias; if (lpDevMode) { @@ -246,13 +238,7 @@ namespace g_emulatedDisplayMode.bpp = lpDevMode->dmBitsPerPel; } g_emulatedDisplayMode.refreshRate = currDevMode.dmDisplayFrequency; - g_emulatedDisplayMode.deviceName = getDeviceName(lpszDeviceName); - g_emulatedDisplayMode.rect = Win32::DisplayMode::getMonitorInfo(g_emulatedDisplayMode.deviceName).rcMonitor; - g_emulatedDisplayMode.rect.right = g_emulatedDisplayMode.rect.left + emulatedResolution.cx; - g_emulatedDisplayMode.rect.bottom = g_emulatedDisplayMode.rect.top + emulatedResolution.cy; - g_emulatedDisplayMode.diff.cx = emulatedResolution.cx - currDevMode.dmPelsWidth; - g_emulatedDisplayMode.diff.cy = emulatedResolution.cy - currDevMode.dmPelsHeight; } else { @@ -322,7 +308,7 @@ namespace BOOL result = origEnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags); if (result) { - Compat::ScopedSrwLockShared srwLock(g_srwLock); + Compat::ScopedCriticalSection lock(g_cs); if (getDeviceName(lpszDeviceName) == g_emulatedDisplayMode.deviceName) { lpDevMode->dmBitsPerPel = g_emulatedDisplayMode.bpp; @@ -388,22 +374,10 @@ namespace ULONG WINAPI gdiEntry13() { - Compat::ScopedSrwLockShared lock(g_srwLock); + Compat::ScopedCriticalSection lock(g_cs); return CALL_ORIG_FUNC(GdiEntry13)() + g_displaySettingsUniquenessBias; } - SIZE getAppResolution(const std::wstring& deviceName, SIZE displayResolution = {}) - { - { - Compat::ScopedSrwLockShared srwLock(g_srwLock); - if (deviceName == g_emulatedDisplayMode.deviceName) - { - return { static_cast(g_emulatedDisplayMode.width), static_cast(g_emulatedDisplayMode.height) }; - } - } - return 0 != displayResolution.cx ? displayResolution : Win32::DisplayMode::getDisplayResolution(deviceName); - } - template DWORD getConfiguredRefreshRate(const Char* deviceName) { @@ -464,17 +438,8 @@ namespace case VERTRES: if (Gdi::isDisplayDc(hdc)) { - MONITORINFO mi = {}; - mi.cbSize = sizeof(mi); - GetMonitorInfo(getMonitorFromDc(hdc), &mi); - if (HORZRES == nIndex) - { - return LOG_RESULT(mi.rcMonitor.right - mi.rcMonitor.left); - } - else - { - return LOG_RESULT(mi.rcMonitor.bottom - mi.rcMonitor.top); - } + const auto& r = Win32::DisplayMode::getMonitorInfo().rcEmulated; + return HORZRES == nIndex ? (r.right - r.left) : (r.bottom - r.top); } break; @@ -527,64 +492,13 @@ namespace return mi.szDevice; } - BOOL CALLBACK getMonitorFromDcEnum(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM dwData) - { - auto& args = *reinterpret_cast(dwData); - - MONITORINFOEX mi = {}; - mi.cbSize = sizeof(mi); - CALL_ORIG_FUNC(GetMonitorInfoA)(hMonitor, &mi); - - HDC dc = CreateDC(mi.szDevice, nullptr, nullptr, nullptr); - if (dc) - { - POINT org = {}; - GetDCOrgEx(dc, &org); - DeleteDC(dc); - if (org == args.org) - { - args.hmonitor = hMonitor; - return FALSE; - } - } - return TRUE; - } - - HMONITOR getMonitorFromDc(HDC dc) - { - HWND hwnd = CALL_ORIG_FUNC(WindowFromDC)(dc); - if (hwnd) - { - return MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); - } - - GetMonitorFromDcEnumArgs args = {}; - GetDCOrgEx(dc, &args.org); - EnumDisplayMonitors(nullptr, nullptr, getMonitorFromDcEnum, reinterpret_cast(&args)); - return args.hmonitor ? args.hmonitor : MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY); - } - - BOOL CALLBACK getMonitorInfoEnum(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM dwData) - { - MONITORINFOEXW mi = {}; - mi.cbSize = sizeof(mi); - CALL_ORIG_FUNC(GetMonitorInfoW)(hMonitor, &mi); - auto& dest = *reinterpret_cast(dwData); - if (0 == wcscmp(mi.szDevice, dest.szDevice)) - { - dest = mi; - return FALSE; - } - return TRUE; - } - BOOL WINAPI getMonitorInfoA(HMONITOR hMonitor, LPMONITORINFO lpmi) { LOG_FUNC("GetMonitorInfoA", hMonitor, lpmi); BOOL result = CALL_ORIG_FUNC(GetMonitorInfoA)(hMonitor, lpmi); if (result) { - adjustMonitorInfo(*lpmi); + lpmi->rcMonitor = Win32::DisplayMode::getMonitorInfo(hMonitor).rcEmulated; } return LOG_RESULT(result); } @@ -595,7 +509,7 @@ namespace BOOL result = CALL_ORIG_FUNC(GetMonitorInfoW)(hMonitor, lpmi); if (result) { - adjustMonitorInfo(*lpmi); + lpmi->rcMonitor = Win32::DisplayMode::getMonitorInfo(hMonitor).rcEmulated; } return LOG_RESULT(result); } @@ -750,50 +664,129 @@ namespace CloseHandle(dwmDxFullscreenTransitionEvent); } } + + BOOL CALLBACK updateMonitorInfoEnum(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM /*dwData*/) + { + auto& mi = g_monitorInfo[hMonitor]; + mi.cbSize = sizeof(MONITORINFOEXW); + CALL_ORIG_FUNC(GetMonitorInfoW)(hMonitor, &mi); + + DEVMODEW dm = {}; + dm.dmSize = sizeof(dm); + CALL_ORIG_FUNC(EnumDisplaySettingsExW)(mi.szDevice, ENUM_CURRENT_SETTINGS, &dm, 0); + mi.rcReal.left = dm.dmPosition.x; + mi.rcReal.top = dm.dmPosition.y; + mi.rcReal.right = dm.dmPosition.x + dm.dmPelsWidth; + mi.rcReal.bottom = dm.dmPosition.y + dm.dmPelsHeight; + + mi.rcDpiAware = Win32::DpiAwareness::isMixedModeSupported() ? mi.rcReal : mi.rcMonitor; + + mi.rcEmulated = mi.rcMonitor; + if (g_emulatedDisplayMode.deviceName == mi.szDevice) + { + mi.rcEmulated.right = mi.rcEmulated.left + g_emulatedDisplayMode.width; + mi.rcEmulated.bottom = mi.rcEmulated.top + g_emulatedDisplayMode.height; + mi.bpp = g_emulatedDisplayMode.bpp; + mi.isEmulated = true; + } + else + { + mi.bpp = g_desktopBpp; + } + + mi.dpiScale = MulDiv(100, mi.rcReal.right - mi.rcReal.left, mi.rcMonitor.right - mi.rcMonitor.left); + + if (0 == mi.rcMonitor.left && 0 == mi.rcMonitor.top) + { + g_monitorInfo[nullptr] = mi; + } + + LOG_DEBUG << "updateMonitorInfoEnum: " << hMonitor << " " << mi; + return TRUE; + } + + void updateMonitorInfo() + { + const auto uniqueness = gdiEntry13(); + if (uniqueness != g_monitorInfoUniqueness || g_monitorInfo.empty()) + { + g_monitorInfo.clear(); + g_monitorInfoUniqueness = uniqueness; + EnumDisplayMonitors(nullptr, nullptr, &updateMonitorInfoEnum, 0); + } + } } namespace Win32 { namespace DisplayMode { - SIZE getAppResolution(const std::wstring& deviceName) + std::ostream& operator<<(std::ostream& os, const MonitorInfo& mi) { - return ::getAppResolution(deviceName); + return Compat::LogStruct(os) + << mi.rcMonitor + << mi.rcWork + << Compat::hex(mi.dwFlags) + << mi.szDevice + << mi.rcReal + << mi.rcDpiAware + << mi.rcEmulated + << mi.bpp + << mi.dpiScale + << mi.isEmulated; + } + + std::map getAllMonitorInfo() + { + Compat::ScopedCriticalSection lock(g_cs); + updateMonitorInfo(); + auto mi = g_monitorInfo; + mi.erase(nullptr); + return mi; } DWORD getBpp() { - return getEmulatedDisplayMode().bpp; - } - - SIZE getDisplayResolution(const std::wstring& deviceName) - { - DEVMODEW dm = {}; - dm.dmSize = sizeof(dm); - CALL_ORIG_FUNC(EnumDisplaySettingsExW)(deviceName.c_str(), ENUM_CURRENT_SETTINGS, &dm, 0); - return { static_cast(dm.dmPelsWidth), static_cast(dm.dmPelsHeight) }; + Compat::ScopedCriticalSection lock(g_cs); + return g_emulatedDisplayMode.bpp; } EmulatedDisplayMode getEmulatedDisplayMode() { - Compat::ScopedSrwLockShared lock(g_srwLock); + Compat::ScopedCriticalSection lock(g_cs); return g_emulatedDisplayMode; } - MONITORINFOEXW getMonitorInfo(const std::wstring& deviceName) + const MonitorInfo& getMonitorInfo(HMONITOR monitor) { - MONITORINFOEXW mi = {}; - wcscpy_s(mi.szDevice, deviceName.c_str()); - EnumDisplayMonitors(nullptr, nullptr, &getMonitorInfoEnum, reinterpret_cast(&mi)); - return mi; + Compat::ScopedCriticalSection lock(g_cs); + updateMonitorInfo(); + auto it = g_monitorInfo.find(monitor); + return it != g_monitorInfo.end() ? it->second : g_emptyMonitorInfo; } - Resolution getResolution(const std::wstring& deviceName) + const MonitorInfo& getMonitorInfo(HWND hwnd) { - Resolution res = {}; - res.display = getDisplayResolution(deviceName); - res.app = ::getAppResolution(deviceName, res.display); - return res; + return getMonitorInfo(hwnd ? MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) : nullptr); + } + + const MonitorInfo& getMonitorInfo(POINT pt) + { + return getMonitorInfo(MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST)); + } + + const MonitorInfo& getMonitorInfo(const std::wstring& deviceName) + { + Compat::ScopedCriticalSection lock(g_cs); + updateMonitorInfo(); + for (const auto& mi : g_monitorInfo) + { + if (deviceName == mi.second.szDevice) + { + return mi.second; + } + } + return g_emptyMonitorInfo; } ULONG queryDisplaySettingsUniqueness() diff --git a/DDrawCompat/Win32/DisplayMode.h b/DDrawCompat/Win32/DisplayMode.h index 16f579c..a3b9efb 100644 --- a/DDrawCompat/Win32/DisplayMode.h +++ b/DDrawCompat/Win32/DisplayMode.h @@ -1,10 +1,11 @@ #pragma once -#include +#include #include #include +#include namespace Win32 { @@ -21,31 +22,29 @@ namespace Win32 struct EmulatedDisplayMode : DisplayMode { std::wstring deviceName; - RECT rect; - SIZE diff; }; - struct Resolution + struct MonitorInfo : MONITORINFOEXW { - SIZE app; - SIZE display; + RECT rcReal; + RECT rcDpiAware; + RECT rcEmulated; + DWORD bpp; + DWORD dpiScale; + bool isEmulated; }; - SIZE getAppResolution(const std::wstring& deviceName); + std::ostream& operator<<(std::ostream& os, const MonitorInfo& mi); + + std::map getAllMonitorInfo(); DWORD getBpp(); - SIZE getDisplayResolution(const std::wstring& deviceName); EmulatedDisplayMode getEmulatedDisplayMode(); - MONITORINFOEXW getMonitorInfo(const std::wstring& deviceName); - Resolution getResolution(const std::wstring& deviceName); + const MonitorInfo& getMonitorInfo(HMONITOR monitor = nullptr); + const MonitorInfo& getMonitorInfo(HWND hwnd); + const MonitorInfo& getMonitorInfo(POINT pt); + const MonitorInfo& getMonitorInfo(const std::wstring& deviceName); ULONG queryDisplaySettingsUniqueness(); void installHooks(); - - using ::operator<; - - inline auto toTuple(const DisplayMode& dm) - { - return std::make_tuple(dm.width, dm.height, dm.bpp, dm.refreshRate); - } } } diff --git a/DDrawCompat/Win32/DpiAwareness.cpp b/DDrawCompat/Win32/DpiAwareness.cpp new file mode 100644 index 0000000..a56e5db --- /dev/null +++ b/DDrawCompat/Win32/DpiAwareness.cpp @@ -0,0 +1,179 @@ +#include + +#include +#include +#include + +namespace +{ + decltype(&AreDpiAwarenessContextsEqual) g_areDpiAwarenessContextsEqual = nullptr; + decltype(&GetProcessDpiAwareness) g_getProcessDpiAwareness = nullptr; + decltype(&GetThreadDpiAwarenessContext) g_getThreadDpiAwarenessContext = nullptr; + decltype(&IsValidDpiAwarenessContext) g_isValidDpiAwarenessContext = nullptr; + decltype(&SetProcessDpiAwareness) g_setProcessDpiAwareness = nullptr; + decltype(&SetProcessDpiAwarenessContext) g_setProcessDpiAwarenessContext = nullptr; + decltype(&SetThreadDpiAwarenessContext) g_setThreadDpiAwarenessContext = nullptr; + + void logDpiAwareness(bool isSuccessful, DPI_AWARENESS_CONTEXT dpiAwareness, const char* funcName) + { + LOG_INFO << (isSuccessful ? "DPI awareness was successfully changed" : "Failed to change DPI awareness") + << " to \"" << Config::dpiAwareness.convertToString(dpiAwareness) << "\" via " << funcName; + } +} + +namespace Win32 +{ + ScopedDpiAwareness::ScopedDpiAwareness(bool dpiAware) + : m_prevContext(dpiAware ? DpiAwareness::setThreadContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) : nullptr) + { + } + + ScopedDpiAwareness::~ScopedDpiAwareness() + { + if (m_prevContext) + { + DpiAwareness::setThreadContext(m_prevContext); + } + } + + namespace DpiAwareness + { + DPI_AWARENESS_CONTEXT getThreadContext() + { + if (g_getThreadDpiAwarenessContext && g_areDpiAwarenessContextsEqual) + { + auto context = g_getThreadDpiAwarenessContext(); + if (g_areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE)) + { + return DPI_AWARENESS_CONTEXT_UNAWARE; + } + else if (g_areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_SYSTEM_AWARE)) + { + return DPI_AWARENESS_CONTEXT_SYSTEM_AWARE; + } + else if (g_areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE)) + { + return DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE; + } + else if (g_areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) + { + return DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2; + } + else if (g_areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED)) + { + return DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED; + } + } + + if (g_getProcessDpiAwareness) + { + PROCESS_DPI_AWARENESS awareness = PROCESS_DPI_UNAWARE; + if (SUCCEEDED(g_getProcessDpiAwareness(nullptr, &awareness))) + { + switch (awareness) + { + case PROCESS_DPI_UNAWARE: + return DPI_AWARENESS_CONTEXT_UNAWARE; + case PROCESS_SYSTEM_DPI_AWARE: + return DPI_AWARENESS_CONTEXT_SYSTEM_AWARE; + case PROCESS_PER_MONITOR_DPI_AWARE: + return DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE; + } + } + + } + + return IsProcessDPIAware() ? DPI_AWARENESS_CONTEXT_SYSTEM_AWARE : DPI_AWARENESS_CONTEXT_UNAWARE; + } + + void init() + { + auto user32 = GetModuleHandle("user32"); + auto shcore = LoadLibrary("shcore"); + + g_areDpiAwarenessContextsEqual = reinterpret_cast( + GetProcAddress(user32, "AreDpiAwarenessContextsEqual")); + g_getProcessDpiAwareness = reinterpret_cast( + GetProcAddress(shcore, "GetProcessDpiAwareness")); + g_getThreadDpiAwarenessContext = reinterpret_cast( + GetProcAddress(user32, "GetThreadDpiAwarenessContext")); + g_isValidDpiAwarenessContext = reinterpret_cast( + GetProcAddress(user32, "IsValidDpiAwarenessContext")); + g_setProcessDpiAwareness = reinterpret_cast( + GetProcAddress(shcore, "SetProcessDpiAwareness")); + g_setProcessDpiAwarenessContext = reinterpret_cast( + GetProcAddress(user32, "SetProcessDpiAwarenessContext")); + g_setThreadDpiAwarenessContext = reinterpret_cast( + GetProcAddress(user32, "SetThreadDpiAwarenessContext")); + + LOG_INFO << "Initial DPI awareness: " << Config::dpiAwareness.convertToString(getThreadContext()); + + auto dpiAwareness = Config::dpiAwareness.get(); + if (!dpiAwareness) + { + return; + } + + if (g_isValidDpiAwarenessContext && g_setProcessDpiAwarenessContext) + { + if (DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 == dpiAwareness && + !g_isValidDpiAwarenessContext(dpiAwareness)) + { + dpiAwareness = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE; + } + + if (DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED == dpiAwareness && + !g_isValidDpiAwarenessContext(dpiAwareness)) + { + dpiAwareness = DPI_AWARENESS_CONTEXT_UNAWARE; + } + + logDpiAwareness(g_setProcessDpiAwarenessContext(dpiAwareness), dpiAwareness, "SetProcessDpiAwarenessContext"); + return; + } + + if (g_setProcessDpiAwareness) + { + HRESULT result = S_OK; + if (DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE == dpiAwareness || + DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 == dpiAwareness) + { + dpiAwareness = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE; + result = g_setProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); + } + else if (DPI_AWARENESS_CONTEXT_SYSTEM_AWARE == dpiAwareness) + { + result = g_setProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE); + } + else + { + dpiAwareness = DPI_AWARENESS_CONTEXT_UNAWARE; + result = g_setProcessDpiAwareness(PROCESS_DPI_UNAWARE); + } + + logDpiAwareness(SUCCEEDED(result), dpiAwareness, "SetProcessDpiAwareness"); + return; + } + + if (DPI_AWARENESS_CONTEXT_UNAWARE == dpiAwareness || + DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED == dpiAwareness) + { + LOG_INFO << "DPI awareness was not changed"; + } + else + { + logDpiAwareness(SetProcessDPIAware(), DPI_AWARENESS_CONTEXT_SYSTEM_AWARE, "SetProcessDPIAware"); + } + } + + bool isMixedModeSupported() + { + return g_setThreadDpiAwarenessContext; + } + + DPI_AWARENESS_CONTEXT setThreadContext(DPI_AWARENESS_CONTEXT context) + { + return g_setThreadDpiAwarenessContext ? g_setThreadDpiAwarenessContext(context) : nullptr; + } + } +} diff --git a/DDrawCompat/Win32/DpiAwareness.h b/DDrawCompat/Win32/DpiAwareness.h new file mode 100644 index 0000000..d6ba06e --- /dev/null +++ b/DDrawCompat/Win32/DpiAwareness.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +namespace Win32 +{ + class ScopedDpiAwareness + { + public: + ScopedDpiAwareness(bool dpiAware = true); + ~ScopedDpiAwareness(); + + private: + DPI_AWARENESS_CONTEXT m_prevContext; + }; + + namespace DpiAwareness + { + void init(); + + bool isMixedModeSupported(); + + DPI_AWARENESS_CONTEXT getThreadContext(); + DPI_AWARENESS_CONTEXT setThreadContext(DPI_AWARENESS_CONTEXT context); + } +} diff --git a/DDrawCompat/Win32/Log.cpp b/DDrawCompat/Win32/Log.cpp index 539acb9..b32742e 100644 --- a/DDrawCompat/Win32/Log.cpp +++ b/DDrawCompat/Win32/Log.cpp @@ -2,6 +2,7 @@ #include #include +#include #include namespace @@ -261,6 +262,14 @@ std::ostream& operator<<(std::ostream& os, const HFONT__& font) << lf; } +std::ostream& operator<<(std::ostream& os, const HINSTANCE__& inst) +{ + os << "MOD"; + return Compat::LogStruct(os) + << static_cast(&inst) + << Compat::getModulePath(const_cast(&inst)); +} + std::ostream& operator<<(std::ostream& os, const HRGN__& rgn) { os << "RGN"; diff --git a/DDrawCompat/Win32/Log.h b/DDrawCompat/Win32/Log.h index e0c8349..9a1cd00 100644 --- a/DDrawCompat/Win32/Log.h +++ b/DDrawCompat/Win32/Log.h @@ -21,6 +21,7 @@ std::ostream& operator<<(std::ostream& os, const GESTURENOTIFYSTRUCT& gns); std::ostream& operator<<(std::ostream& os, const HDC__& dc); std::ostream& operator<<(std::ostream& os, const HELPINFO& hi); std::ostream& operator<<(std::ostream& os, const HFONT__& font); +std::ostream& operator<<(std::ostream& os, const HINSTANCE__& inst); std::ostream& operator<<(std::ostream& os, const HRGN__& rgn); std::ostream& operator<<(std::ostream& os, const HWND__& wnd); std::ostream& operator<<(std::ostream& os, const LOGFONT& lf); diff --git a/DDrawCompat/Win32/Registry.cpp b/DDrawCompat/Win32/Registry.cpp index c0b6d14..3835f0c 100644 --- a/DDrawCompat/Win32/Registry.cpp +++ b/DDrawCompat/Win32/Registry.cpp @@ -6,6 +6,7 @@ #include #include +#include #include typedef long NTSTATUS; @@ -66,6 +67,19 @@ namespace #undef HKLM_SOFTWARE_KEY + LSTATUS WINAPI ddrawRegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions, + REGSAM samDesired, const LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition) + { + LOG_FUNC("ddrawRegCreateKeyExA", hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, + lpSecurityAttributes, phkResult, lpdwDisposition); + if (0 == lstrcmpi(lpSubKey, "Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers")) + { + return LOG_RESULT(E_ABORT); + } + return LOG_RESULT(RegCreateKeyExA(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, + lpSecurityAttributes, phkResult, lpdwDisposition)); + } + bool filterType(DWORD type, const DWORD* flags) { if (!flags) @@ -424,6 +438,8 @@ namespace Win32 HOOK_REGISTRY_FUNCTION(RegGetValueW, regGetValueW); HOOK_REGISTRY_FUNCTION(RegQueryValueExA, regQueryValueExA); HOOK_REGISTRY_FUNCTION(RegQueryValueExW, regQueryValueExW); + + Compat::hookIatFunction(Dll::g_origDDrawModule, "RegCreateKeyExA", ddrawRegCreateKeyExA); } } }