1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

Improved support for DPI unaware apps

This commit is contained in:
narzoul 2023-10-15 16:01:44 +02:00
parent a9ec2bbe7c
commit 97805b17b6
37 changed files with 775 additions and 511 deletions

View File

@ -12,6 +12,11 @@ struct RectF
namespace Rect namespace Rect
{ {
inline SIZE getSize(const RECT& rect)
{
return { rect.right - rect.left, rect.bottom - rect.top };
}
RectF toRectF(const RECT& rect); RectF toRectF(const RECT& rect);
bool isEqualSize(const RECT& rect1, const RECT& rect2); bool isEqualSize(const RECT& rect1, const RECT& rect2);
void transform(RECT& rect, const RECT& srcView, const RECT& dstView); void transform(RECT& rect, const RECT& srcView, const RECT& dstView);

View File

@ -4,6 +4,7 @@
#include <Common/Comparison.h> #include <Common/Comparison.h>
#include <Common/CompatVtable.h> #include <Common/CompatVtable.h>
#include <Common/Rect.h>
#include <Config/Settings/Antialiasing.h> #include <Config/Settings/Antialiasing.h>
#include <Config/Settings/DisplayAspectRatio.h> #include <Config/Settings/DisplayAspectRatio.h>
#include <Config/Settings/PalettizedTextures.h> #include <Config/Settings/PalettizedTextures.h>
@ -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(); SIZE ar = Config::displayAspectRatio.get();
if (Config::Settings::DisplayAspectRatio::APP == ar) 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) 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; return ar;
} }
Int2 Adapter::getAspectRatio() const Int2 Adapter::getAspectRatio() const
{ {
return getAspectRatio({}); return getAspectRatio({}, {});
} }
const Adapter::AdapterInfo& Adapter::findInfo() const const Adapter::AdapterInfo& Adapter::findInfo() const
@ -253,20 +254,23 @@ namespace D3dDdi
return 1; 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; Int2 targetResolution = resolutionScale;
if (Config::Settings::ResolutionScale::APP == resolutionScale) if (Config::Settings::ResolutionScale::APP == resolutionScale)
{ {
targetResolution = res.app; targetResolution = appRes;
} }
else if (Config::Settings::ResolutionScale::DISPLAY == resolutionScale) else if (Config::Settings::ResolutionScale::DISPLAY == resolutionScale)
{ {
targetResolution = res.display; targetResolution = displayRes;
} }
targetResolution *= abs(multiplier); targetResolution *= abs(multiplier);
const Int2 ar = getAspectRatio(res); const Int2 ar = getAspectRatio(appRes, displayRes);
if (targetResolution.y * ar.x / ar.y <= targetResolution.x) if (targetResolution.y * ar.x / ar.y <= targetResolution.x)
{ {
targetResolution.x = targetResolution.y * ar.x / ar.y; targetResolution.x = targetResolution.y * ar.x / ar.y;
@ -276,7 +280,7 @@ namespace D3dDdi
targetResolution.y = targetResolution.x * ar.y / ar.x; 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); return multiplier < 0 ? scaleFactor : ceil(scaleFactor);
} }

View File

@ -38,6 +38,7 @@ namespace D3dDdi
Int2 getAspectRatio() const; Int2 getAspectRatio() const;
const AdapterInfo& getInfo() const { return m_info; } const AdapterInfo& getInfo() const { return m_info; }
LUID getLuid() const { return m_luid; } LUID getLuid() const { return m_luid; }
const auto& getMonitorInfo() const { return Win32::DisplayMode::getMonitorInfo(m_deviceName); }
std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> getMultisampleConfig(D3DDDIFORMAT format) const; std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> getMultisampleConfig(D3DDDIFORMAT format) const;
const D3DDDI_ADAPTERFUNCS& getOrigVtable() const { return m_origVtable; } const D3DDDI_ADAPTERFUNCS& getOrigVtable() const { return m_origVtable; }
CompatWeakPtr<IDirectDraw7> getRepository() const { return m_repository; } CompatWeakPtr<IDirectDraw7> getRepository() const { return m_repository; }
@ -58,7 +59,7 @@ namespace D3dDdi
template <typename Data> template <typename Data>
HRESULT getCaps(D3DDDICAPS_TYPE type, Data& data, UINT size = sizeof(Data)) const; 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<D3DDDIFORMAT, FORMATOP> getFixedFormatOps(const AdapterInfo& info) const; std::map<D3DDDIFORMAT, FORMATOP> getFixedFormatOps(const AdapterInfo& info) const;
std::map<D3DDDIFORMAT, FORMATOP> getFormatOps() const; std::map<D3DDDIFORMAT, FORMATOP> getFormatOps() const;
Float2 getScaleFactor() const; Float2 getScaleFactor() const;

View File

@ -19,6 +19,7 @@
#include <Gdi/Palette.h> #include <Gdi/Palette.h>
#include <Gdi/Window.h> #include <Gdi/Window.h>
#include <Win32/DisplayMode.h> #include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
namespace namespace
{ {
@ -310,7 +311,7 @@ namespace
MONITORINFOEX mi = {}; MONITORINFOEX mi = {};
mi.cbSize = sizeof(mi); mi.cbSize = sizeof(mi);
GetMonitorInfo(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi); CALL_ORIG_FUNC(GetMonitorInfoA)(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi);
D3DKMT_OPENADAPTERFROMHDC data = {}; D3DKMT_OPENADAPTERFROMHDC data = {};
data.hDc = CreateDC(mi.szDevice, mi.szDevice, nullptr, nullptr); data.hDc = CreateDC(mi.szDevice, mi.szDevice, nullptr, nullptr);
@ -374,11 +375,11 @@ namespace D3dDdi
HWND presentationWindow = DDraw::RealPrimarySurface::getPresentationWindow(); HWND presentationWindow = DDraw::RealPrimarySurface::getPresentationWindow();
if (presentationWindow && presentationWindow == data.hWindow) if (presentationWindow && presentationWindow == data.hWindow)
{ {
rect = DDraw::RealPrimarySurface::getMonitorRect(); Win32::ScopedDpiAwareness dpiAwareness;
GetWindowRect(presentationWindow, &rect);
OffsetRect(&rect, -rect.left, -rect.top); OffsetRect(&rect, -rect.left, -rect.top);
data.SrcRect = rect; data.SrcRect = rect;
data.DstRect.right = data.DstRect.left + rect.right; data.DstRect = rect;
data.DstRect.bottom = data.DstRect.top + rect.bottom;
if (1 == data.SubRectCnt) if (1 == data.SubRectCnt)
{ {
data.pSrcSubRects = &rect; data.pSrcSubRects = &rect;

View File

@ -1270,10 +1270,8 @@ namespace D3dDdi
if (!IsRectEmpty(&g_presentationRect)) if (!IsRectEmpty(&g_presentationRect))
{ {
auto dstRect = DDraw::RealPrimarySurface::getMonitorRect(); presentLayeredWindows(*this, data.DstSubResourceIndex, getRect(data.DstSubResourceIndex),
OffsetRect(&dstRect, -dstRect.left, -dstRect.top); Gdi::Window::getVisibleOverlayWindows(), m_device.getAdapter().getMonitorInfo().rcMonitor);
presentLayeredWindows(*this, data.DstSubResourceIndex, dstRect,
Gdi::Window::getVisibleOverlayWindows(), dstRect);
} }
return LOG_RESULT(S_OK); return LOG_RESULT(S_OK);
@ -1294,7 +1292,7 @@ namespace D3dDdi
continue; 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& windowSurface = repo.getTempSysMemSurface(srcRect.right, srcRect.bottom);
auto& texture = repo.getTempTexture(srcRect.right, srcRect.bottom, D3DDDIFMT_A8R8G8B8); auto& texture = repo.getTempTexture(srcRect.right, srcRect.bottom, D3DDDIFMT_A8R8G8B8);
if (!windowSurface.resource || !texture.resource) if (!windowSurface.resource || !texture.resource)
@ -1304,9 +1302,16 @@ namespace D3dDdi
HDC srcDc = GetWindowDC(layeredWindow.hwnd); HDC srcDc = GetWindowDC(layeredWindow.hwnd);
HDC dstDc = nullptr; HDC dstDc = nullptr;
POINT srcOrig = { visibleRect.left - layeredWindow.rect.left, visibleRect.top - layeredWindow.rect.top };
windowSurface.surface->GetDC(windowSurface.surface, &dstDc); windowSurface.surface->GetDC(windowSurface.surface, &dstDc);
CALL_ORIG_FUNC(BitBlt)(dstDc, 0, 0, srcRect.right, srcRect.bottom, srcDc, CALL_ORIG_FUNC(BitBlt)(dstDc, 0, 0, srcRect.right - 1, srcRect.bottom - 1,
visibleRect.left - layeredWindow.rect.left, visibleRect.top - layeredWindow.rect.top, SRCCOPY); 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); windowSurface.surface->ReleaseDC(windowSurface.surface, dstDc);
ReleaseDC(layeredWindow.hwnd, srcDc); ReleaseDC(layeredWindow.hwnd, srcDc);
@ -1327,8 +1332,10 @@ namespace D3dDdi
} }
Rect::transform(visibleRect, monitorRect, dstRect); Rect::transform(visibleRect, monitorRect, dstRect);
blitter.textureBlt(dst, dstSubResourceIndex, visibleRect, *texture.resource, 0, srcRect, D3DTEXF_POINT, srcRect.right--;
ck, (flags & ULW_ALPHA) ? &alpha : nullptr, srcRect.bottom--;
blitter.textureBlt(dst, dstSubResourceIndex, visibleRect, *texture.resource, 0, srcRect,
D3DTEXF_LINEAR | D3DTEXF_SRGB, ck, (flags & ULW_ALPHA) ? &alpha : nullptr,
layeredWindow.region); layeredWindow.region);
} }
} }
@ -1398,14 +1405,16 @@ namespace D3dDdi
const Int2 ar = m_device.getAdapter().getAspectRatio(); const Int2 ar = m_device.getAdapter().getAspectRatio();
g_presentationRect = calculateScaledRect({ 0, 0, ar.x, ar.y }, DDraw::RealPrimarySurface::getMonitorRect()); g_presentationRect = calculateScaledRect({ 0, 0, ar.x, ar.y }, DDraw::RealPrimarySurface::getMonitorRect());
auto& si = m_origData.pSurfList[0];
RECT primaryRect = { 0, 0, static_cast<LONG>(si.Width), static_cast<LONG>(si.Height) };
Gdi::Cursor::setMonitorClipRect(DDraw::PrimarySurface::getMonitorRect()); const auto& mi = m_device.getAdapter().getMonitorInfo();
if (!EqualRect(&g_presentationRect, &primaryRect)) 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); Gdi::VirtualScreen::setFullscreenMode(m_origData.Flags.MatchGdiPrimary);
} }
else else

View File

@ -180,14 +180,6 @@ namespace DDraw
{ {
namespace DirectDraw namespace DirectDraw
{ {
DDSURFACEDESC2 getDisplayMode(CompatRef<IDirectDraw7> dd)
{
DDSURFACEDESC2 dm = {};
dm.dwSize = sizeof(dm);
dd->GetDisplayMode(&dd, &dm);
return dm;
}
DDPIXELFORMAT getRgbPixelFormat(DWORD bpp) DDPIXELFORMAT getRgbPixelFormat(DWORD bpp)
{ {
DDPIXELFORMAT pf = {}; DDPIXELFORMAT pf = {};

View File

@ -12,7 +12,6 @@ namespace DDraw
{ {
namespace DirectDraw namespace DirectDraw
{ {
DDSURFACEDESC2 getDisplayMode(CompatRef<IDirectDraw7> dd);
DDPIXELFORMAT getRgbPixelFormat(DWORD bpp); DDPIXELFORMAT getRgbPixelFormat(DWORD bpp);
LRESULT handleActivateApp(bool isActivated, std::function<LRESULT()> callOrigWndProc); LRESULT handleActivateApp(bool isActivated, std::function<LRESULT()> callOrigWndProc);
void onCreate(GUID* guid, CompatRef<IDirectDraw7> dd); void onCreate(GUID* guid, CompatRef<IDirectDraw7> dd);

View File

@ -5,8 +5,8 @@
#include <Common/CompatVtable.h> #include <Common/CompatVtable.h>
#include <D3dDdi/KernelModeThunks.h> #include <D3dDdi/KernelModeThunks.h>
#include <DDraw/DirectDrawClipper.h> #include <DDraw/DirectDrawClipper.h>
#include <DDraw/RealPrimarySurface.h>
#include <DDraw/ScopedThreadLock.h> #include <DDraw/ScopedThreadLock.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <DDraw/Surfaces/Surface.h> #include <DDraw/Surfaces/Surface.h>
#include <DDraw/Visitors/DirectDrawClipperVtblVisitor.h> #include <DDraw/Visitors/DirectDrawClipperVtblVisitor.h>
#include <Gdi/Gdi.h> #include <Gdi/Gdi.h>
@ -46,7 +46,7 @@ namespace
GetRandomRgn(dc, rgn, SYSRGN); GetRandomRgn(dc, rgn, SYSRGN);
CALL_ORIG_FUNC(ReleaseDC)(data.hwnd, dc); CALL_ORIG_FUNC(ReleaseDC)(data.hwnd, dc);
RECT primaryRect = DDraw::RealPrimarySurface::getMonitorRect(); RECT primaryRect = DDraw::PrimarySurface::getMonitorRect();
if (0 != primaryRect.left || 0 != primaryRect.top) if (0 != primaryRect.left || 0 != primaryRect.top)
{ {
rgn.offset(-primaryRect.left, -primaryRect.top); rgn.offset(-primaryRect.left, -primaryRect.top);

View File

@ -1,6 +1,9 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <Windows.h>
#include <VersionHelpers.h>
#include <Common/Comparison.h> #include <Common/Comparison.h>
#include <Common/CompatPtr.h> #include <Common/CompatPtr.h>
#include <Common/Hook.h> #include <Common/Hook.h>
@ -8,6 +11,7 @@
#include <Common/ScopedThreadPriority.h> #include <Common/ScopedThreadPriority.h>
#include <Common/Time.h> #include <Common/Time.h>
#include <Config/Settings/FpsLimiter.h> #include <Config/Settings/FpsLimiter.h>
#include <Config/Settings/FullscreenMode.h>
#include <Config/Settings/VSync.h> #include <Config/Settings/VSync.h>
#include <D3dDdi/Device.h> #include <D3dDdi/Device.h>
#include <D3dDdi/KernelModeThunks.h> #include <D3dDdi/KernelModeThunks.h>
@ -35,6 +39,7 @@
#include <Overlay/ConfigWindow.h> #include <Overlay/ConfigWindow.h>
#include <Overlay/StatsWindow.h> #include <Overlay/StatsWindow.h>
#include <Win32/DisplayMode.h> #include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
#include <Win32/Thread.h> #include <Win32/Thread.h>
namespace namespace
@ -54,6 +59,7 @@ namespace
DDraw::IReleaseNotifier g_releaseNotifier(onRelease); DDraw::IReleaseNotifier g_releaseNotifier(onRelease);
bool g_isFullscreen = false; bool g_isFullscreen = false;
bool g_isExclusiveFullscreen = false;
DDraw::Surface* g_lastFlipSurface = nullptr; DDraw::Surface* g_lastFlipSurface = nullptr;
DDraw::TagSurface* g_tagSurface = nullptr; DDraw::TagSurface* g_tagSurface = nullptr;
@ -82,6 +88,9 @@ namespace
{ {
if (!g_isFullscreen) if (!g_isFullscreen)
{ {
updatePresentationWindow();
if (g_presentationWindow)
{ {
D3dDdi::ScopedCriticalSection lock; D3dDdi::ScopedCriticalSection lock;
auto srcResource = D3dDdi::Device::findResource( auto srcResource = D3dDdi::Device::findResource(
@ -99,8 +108,7 @@ namespace
bbResource->presentationBlt(blt, srcResource); bbResource->presentationBlt(blt, srcResource);
} }
updatePresentationWindow(); Gdi::Window::present(*g_frontBuffer, g_presentationWindow ? *g_windowedBackBuffer : src, *g_clipper);
Gdi::Window::present(*g_frontBuffer, *g_windowedBackBuffer, *g_clipper);
return; return;
} }
@ -172,7 +180,7 @@ namespace
DDraw::RealPrimarySurface::destroyDefaultPrimary(); DDraw::RealPrimarySurface::destroyDefaultPrimary();
auto dm = Win32::DisplayMode::getEmulatedDisplayMode(); auto dm = Win32::DisplayMode::getEmulatedDisplayMode();
if (0 == dm.diff.cx && 0 == dm.diff.cy) if (dm.deviceName.empty())
{ {
return; return;
} }
@ -373,7 +381,7 @@ namespace
Input::updateCursor(); Input::updateCursor();
}); });
if (!g_frontBuffer || !src || DDraw::RealPrimarySurface::isLost() || FAILED(src->IsLost(src))) if (!g_frontBuffer || !src || DDraw::RealPrimarySurface::isLost())
{ {
Gdi::Window::present(nullptr); Gdi::Window::present(nullptr);
return; return;
@ -409,49 +417,67 @@ namespace
{ {
LOG_FUNC("RealPrimarySurface::updatePresentationWindow"); LOG_FUNC("RealPrimarySurface::updatePresentationWindow");
const bool isActive = isProcessActive();
HWND fullscreenWindow = nullptr; 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) if (g_windowedBackBuffer)
{ {
auto resource = D3dDdi::Device::findResource( auto resource = D3dDdi::Device::findResource(
DDraw::DirectDrawSurface::getDriverResourceHandle(*g_windowedBackBuffer)); DDraw::DirectDrawSurface::getDriverResourceHandle(*g_windowedBackBuffer));
resource->setFullscreenMode(isActive && fullscreenWindow); resource->setFullscreenMode(fullscreenPresentationWindow);
} }
if (!isActive) g_presentationWindow = fullscreenPresentationWindow;
{
return;
}
g_presentationWindow = fullscreenWindow;
if (g_presentationWindow) if (g_presentationWindow)
{ {
Gdi::GuiThread::execute([&]() 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, 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; static HWND prevFullscreenWindow = nullptr;
if (prevPresentationWindow && prevPresentationWindow != g_presentationWindow) 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*/) unsigned WINAPI updateThreadProc(LPVOID /*lpParameter*/)
@ -481,9 +507,10 @@ namespace DDraw
{ {
LOG_FUNC("RealPrimarySurface::create", &dd); LOG_FUNC("RealPrimarySurface::create", &dd);
DDraw::ScopedThreadLock lock; DDraw::ScopedThreadLock lock;
const auto& mi = Win32::DisplayMode::getMonitorInfo(
D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).deviceName);
auto prevMonitorRect = g_monitorRect; auto prevMonitorRect = g_monitorRect;
g_monitorRect = Win32::DisplayMode::getMonitorInfo( g_monitorRect = g_isExclusiveFullscreen ? mi.rcReal : mi.rcDpiAware;
D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).deviceName).rcMonitor;
DDSURFACEDESC desc = {}; DDSURFACEDESC desc = {};
desc.dwSize = sizeof(desc); desc.dwSize = sizeof(desc);
@ -499,6 +526,7 @@ namespace DDraw
if (DDERR_NOEXCLUSIVEMODE == result) if (DDERR_NOEXCLUSIVEMODE == result)
{ {
g_isFullscreen = false; g_isFullscreen = false;
g_monitorRect = mi.rcDpiAware;
desc.dwFlags = DDSD_CAPS; desc.dwFlags = DDSD_CAPS;
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
desc.dwBackBufferCount = 0; desc.dwBackBufferCount = 0;
@ -603,6 +631,7 @@ namespace DDraw
static UINT lastOverlayCheckVsyncCount = 0; static UINT lastOverlayCheckVsyncCount = 0;
if (vsyncCount != lastOverlayCheckVsyncCount) if (vsyncCount != lastOverlayCheckVsyncCount)
{ {
setPresentationWindowTopmost();
Gdi::Cursor::update(); Gdi::Cursor::update();
Gdi::Caret::blink(); Gdi::Caret::blink();
auto statsWindow = Gdi::GuiThread::getStatsWindow(); auto statsWindow = Gdi::GuiThread::getStatsWindow();
@ -676,13 +705,9 @@ namespace DDraw
auto primary(DDraw::PrimarySurface::getPrimary()); auto primary(DDraw::PrimarySurface::getPrimary());
CompatWeakPtr<IDirectDrawSurface7> src; CompatWeakPtr<IDirectDrawSurface7> src;
if (g_isDelayedFlipPending) if (primary && SUCCEEDED(primary->IsLost(primary)))
{ {
src = g_lastFlipSurface->getDDS(); src = g_isDelayedFlipPending ? g_lastFlipSurface->getDDS() : primary;
}
else if (primary && SUCCEEDED(primary->IsLost(primary)))
{
src = primary;
} }
else else
{ {
@ -734,6 +759,8 @@ namespace DDraw
void RealPrimarySurface::init() void RealPrimarySurface::init()
{ {
g_isExclusiveFullscreen = Config::Settings::FullscreenMode::EXCLUSIVE == Config::fullscreenMode.get() ||
!IsWindows8OrGreater();
Dll::createThread(&updateThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL); Dll::createThread(&updateThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL);
} }

View File

@ -92,12 +92,10 @@ namespace DDraw
LOG_FUNC("PrimarySurface::create", &dd, desc, surface); LOG_FUNC("PrimarySurface::create", &dd, desc, surface);
DDraw::RealPrimarySurface::destroyDefaultPrimary(); DDraw::RealPrimarySurface::destroyDefaultPrimary();
const auto& dm = DDraw::DirectDraw::getDisplayMode(*CompatPtr<IDirectDraw7>::from(&dd));
auto deviceName = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).deviceName; auto deviceName = D3dDdi::KernelModeThunks::getAdapterInfo(*CompatPtr<IDirectDraw7>::from(&dd)).deviceName;
const auto& mi = Win32::DisplayMode::getMonitorInfo(deviceName);
auto prevMonitorRect = g_monitorRect; auto prevMonitorRect = g_monitorRect;
g_monitorRect = Win32::DisplayMode::getMonitorInfo(deviceName).rcMonitor; g_monitorRect = mi.rcEmulated;
g_monitorRect.right = g_monitorRect.left + dm.dwWidth;
g_monitorRect.bottom = g_monitorRect.top + dm.dwHeight;
HRESULT result = RealPrimarySurface::create(*CompatPtr<IDirectDraw>::from(&dd)); HRESULT result = RealPrimarySurface::create(*CompatPtr<IDirectDraw>::from(&dd));
if (FAILED(result)) if (FAILED(result))
@ -111,12 +109,12 @@ namespace DDraw
auto data = privateData.get(); auto data = privateData.get();
desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
desc.dwWidth = dm.dwWidth; desc.dwWidth = g_monitorRect.right - g_monitorRect.left;
desc.dwHeight = dm.dwHeight; desc.dwHeight = g_monitorRect.bottom - g_monitorRect.top;
desc.ddsCaps.dwCaps &= ~(DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY | desc.ddsCaps.dwCaps &= ~(DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY |
DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM); DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM);
desc.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN; desc.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN;
desc.ddpfPixelFormat = dm.ddpfPixelFormat; desc.ddpfPixelFormat = DirectDraw::getRgbPixelFormat(mi.bpp);
result = Surface::create(dd, desc, surface, std::move(privateData)); result = Surface::create(dd, desc, surface, std::move(privateData));
if (FAILED(result)) if (FAILED(result))

View File

@ -35,7 +35,7 @@ namespace
D3dDdi::ScopedCriticalSection lock; D3dDdi::ScopedCriticalSection lock;
Gdi::Region clipRgn(DDraw::DirectDrawClipper::getClipRgn(*clipper)); Gdi::Region clipRgn(DDraw::DirectDrawClipper::getClipRgn(*clipper));
RECT monitorRect = DDraw::RealPrimarySurface::getMonitorRect(); RECT monitorRect = DDraw::PrimarySurface::getMonitorRect();
RECT virtualScreenBounds = Gdi::VirtualScreen::getBounds(); RECT virtualScreenBounds = Gdi::VirtualScreen::getBounds();
clipRgn.offset(monitorRect.left, monitorRect.top); clipRgn.offset(monitorRect.left, monitorRect.top);
clipRgn &= virtualScreenBounds; clipRgn &= virtualScreenBounds;

View File

@ -327,6 +327,7 @@
<ClInclude Include="Overlay\StatsWindow.h" /> <ClInclude Include="Overlay\StatsWindow.h" />
<ClInclude Include="Overlay\Window.h" /> <ClInclude Include="Overlay\Window.h" />
<ClInclude Include="Win32\DisplayMode.h" /> <ClInclude Include="Win32\DisplayMode.h" />
<ClInclude Include="Win32\DpiAwareness.h" />
<ClInclude Include="Win32\Log.h" /> <ClInclude Include="Win32\Log.h" />
<ClInclude Include="Win32\MemoryManagement.h" /> <ClInclude Include="Win32\MemoryManagement.h" />
<ClInclude Include="Win32\Registry.h" /> <ClInclude Include="Win32\Registry.h" />
@ -460,6 +461,7 @@
<ClCompile Include="Overlay\StatsWindow.cpp" /> <ClCompile Include="Overlay\StatsWindow.cpp" />
<ClCompile Include="Overlay\Window.cpp" /> <ClCompile Include="Overlay\Window.cpp" />
<ClCompile Include="Win32\DisplayMode.cpp" /> <ClCompile Include="Win32\DisplayMode.cpp" />
<ClCompile Include="Win32\DpiAwareness.cpp" />
<ClCompile Include="Win32\Log.cpp" /> <ClCompile Include="Win32\Log.cpp" />
<ClCompile Include="Win32\MemoryManagement.cpp" /> <ClCompile Include="Win32\MemoryManagement.cpp" />
<ClCompile Include="Win32\Registry.cpp" /> <ClCompile Include="Win32\Registry.cpp" />

View File

@ -705,6 +705,9 @@
<ClInclude Include="Config\Settings\CrashDump.h"> <ClInclude Include="Config\Settings\CrashDump.h">
<Filter>Header Files\Config\Settings</Filter> <Filter>Header Files\Config\Settings</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Win32\DpiAwareness.h">
<Filter>Header Files\Win32</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp"> <ClCompile Include="Gdi\Gdi.cpp">
@ -1100,6 +1103,9 @@
<ClCompile Include="Config\Settings\ConfigRows.cpp"> <ClCompile Include="Config\Settings\ConfigRows.cpp">
<Filter>Source Files\Config\Settings</Filter> <Filter>Source Files\Config\Settings</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Win32\DpiAwareness.cpp">
<Filter>Source Files\Win32</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="DDrawCompat.rc"> <ResourceCompile Include="DDrawCompat.rc">

View File

@ -28,6 +28,7 @@
#include <Gdi/VirtualScreen.h> #include <Gdi/VirtualScreen.h>
#include <Input/Input.h> #include <Input/Input.h>
#include <Win32/DisplayMode.h> #include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
#include <Win32/MemoryManagement.h> #include <Win32/MemoryManagement.h>
#include <Win32/Registry.h> #include <Win32/Registry.h>
#include <Win32/Thread.h> #include <Win32/Thread.h>
@ -149,12 +150,6 @@ namespace
(!Compat::isEqual(currentDllPath, dciman32DllPath) && GetModuleHandleW(dciman32DllPath.c_str())); (!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*/) void onDirectDrawCreate(GUID* lpGUID, LPDIRECTDRAW* lplpDD, IUnknown* /*pUnkOuter*/)
{ {
return DDraw::DirectDraw::onCreate(lpGUID, *CompatPtr<IDirectDraw7>::from(*lplpDD)); return DDraw::DirectDraw::onCreate(lpGUID, *CompatPtr<IDirectDraw7>::from(*lplpDD));
@ -180,71 +175,6 @@ namespace
return LOG_RESULT(CALL_ORIG_PROC(SetAppCompatData)(param1, param2)); 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<decltype(&IsValidDpiAwarenessContext)>(
Compat::getProcAddress(user32, "IsValidDpiAwarenessContext"));
auto setProcessDpiAwarenessContext = reinterpret_cast<decltype(&SetProcessDpiAwarenessContext)>(
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<decltype(&SetProcessDpiAwareness)>(
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) LPTOP_LEVEL_EXCEPTION_FILTER WINAPI setUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
{ {
LOG_FUNC("SetUnhandledExceptionFilter", Compat::funcPtrToStr(lpTopLevelExceptionFilter)); LOG_FUNC("SetUnhandledExceptionFilter", Compat::funcPtrToStr(lpTopLevelExceptionFilter));
@ -407,7 +337,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Compat::closeDbgEng(); Compat::closeDbgEng();
CALL_ORIG_FUNC(timeBeginPeriod)(1); CALL_ORIG_FUNC(timeBeginPeriod)(1);
setDpiAwareness(); Win32::DpiAwareness::init();
SetThemeAppProperties(0); SetThemeAppProperties(0);
Time::init(); Time::init();
Win32::Thread::applyConfig(); Win32::Thread::applyConfig();

View File

@ -192,7 +192,7 @@ namespace Gdi
POINT pos = {}; POINT pos = {};
CALL_ORIG_FUNC(GetCursorPos)(&pos); CALL_ORIG_FUNC(GetCursorPos)(&pos);
SetCursorPos(pos.x, pos.y); CALL_ORIG_FUNC(SetCursorPos)(pos.x, pos.y);
} }
void setMonitorClipRect(const RECT& rect) void setMonitorClipRect(const RECT& rect)

View File

@ -12,6 +12,7 @@
#include <Overlay/ConfigWindow.h> #include <Overlay/ConfigWindow.h>
#include <Overlay/StatsWindow.h> #include <Overlay/StatsWindow.h>
#include <Win32/DisplayMode.h> #include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
namespace namespace
{ {
@ -105,8 +106,8 @@ namespace Gdi
{ {
namespace GuiThread namespace GuiThread
{ {
HWND createWindow(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, HWND createWindow(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y,
int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam, bool dpiAware)
{ {
// Workaround for ForceSimpleWindow shim // Workaround for ForceSimpleWindow shim
static auto createWindowExW = reinterpret_cast<decltype(&CreateWindowExW)>( static auto createWindowExW = reinterpret_cast<decltype(&CreateWindowExW)>(
@ -115,6 +116,7 @@ namespace Gdi
HWND hwnd = nullptr; HWND hwnd = nullptr;
execute([&]() execute([&]()
{ {
Win32::ScopedDpiAwareness dpiAwareness(dpiAware);
hwnd = createWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hwnd = createWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight,
hWndParent, hMenu, hInstance, lpParam); hWndParent, hMenu, hInstance, lpParam);
}); });

View File

@ -16,8 +16,8 @@ namespace Gdi
{ {
namespace GuiThread namespace GuiThread
{ {
HWND createWindow(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, HWND createWindow(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y,
int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam, bool dpiAware);
void deleteTaskbarTab(HWND hwnd); void deleteTaskbarTab(HWND hwnd);
void destroyWindow(HWND hwnd); void destroyWindow(HWND hwnd);
void setWindowRgn(HWND hwnd, Gdi::Region rgn); void setWindowRgn(HWND hwnd, Gdi::Region rgn);

View File

@ -12,11 +12,10 @@ namespace
int getAdjustedDisplayMetrics(int nIndex, int cxIndex) int getAdjustedDisplayMetrics(int nIndex, int cxIndex)
{ {
int result = CALL_ORIG_FUNC(GetSystemMetrics)(nIndex); int result = CALL_ORIG_FUNC(GetSystemMetrics)(nIndex);
auto dm = Win32::DisplayMode::getEmulatedDisplayMode(); auto mi = Win32::DisplayMode::getMonitorInfo();
if (0 == dm.rect.left && 0 == dm.rect.top) result += (nIndex == cxIndex)
{ ? (mi.rcEmulated.right - mi.rcMonitor.right)
result += (nIndex == cxIndex) ? dm.diff.cx : dm.diff.cy; : (mi.rcEmulated.bottom - mi.rcMonitor.bottom);
}
return result; return result;
} }

View File

@ -19,9 +19,9 @@ namespace Gdi
{ {
namespace PresentationWindow 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; HWND presentationWindow = nullptr;
GuiThread::execute([&]() GuiThread::execute([&]()
{ {
@ -34,7 +34,8 @@ namespace Gdi
owner, owner,
nullptr, nullptr,
nullptr, nullptr,
nullptr); nullptr,
dpiAware);
if (presentationWindow) if (presentationWindow)
{ {

View File

@ -6,7 +6,7 @@ namespace Gdi
{ {
namespace PresentationWindow namespace PresentationWindow
{ {
HWND create(HWND owner); HWND create(HWND owner, bool dpiAware = false);
void installHooks(); void installHooks();
} }

View File

@ -11,7 +11,6 @@
#include <DDraw/ScopedThreadLock.h> #include <DDraw/ScopedThreadLock.h>
#include <DDraw/Surfaces/PrimarySurface.h> #include <DDraw/Surfaces/PrimarySurface.h>
#include <Gdi/Gdi.h> #include <Gdi/Gdi.h>
#include <Gdi/Region.h>
#include <Gdi/VirtualScreen.h> #include <Gdi/VirtualScreen.h>
#include <Gdi/Window.h> #include <Gdi/Window.h>
#include <Win32/DisplayMode.h> #include <Win32/DisplayMode.h>
@ -24,7 +23,6 @@ namespace
}; };
Compat::CriticalSection g_cs; Compat::CriticalSection g_cs;
Gdi::Region g_region;
RECT g_bounds = {}; RECT g_bounds = {};
DWORD g_bpp = 0; DWORD g_bpp = 0;
LONG g_width = 0; LONG g_width = 0;
@ -39,27 +37,6 @@ namespace
RGBQUAD g_systemPalette[256] = {}; RGBQUAD g_systemPalette[256] = {};
std::map<HDC, VirtualScreenDc> g_dcs; std::map<HDC, VirtualScreenDc> 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<Gdi::Region*>(dwData);
Gdi::Region monitorRegion(rect);
virtualScreenRegion |= monitorRegion;
return TRUE;
}
RGBQUAD convertToRgbQuad(PALETTEENTRY entry) RGBQUAD convertToRgbQuad(PALETTEENTRY entry)
{ {
RGBQUAD quad = {}; RGBQUAD quad = {};
@ -199,12 +176,6 @@ namespace Gdi
return g_bounds; return g_bounds;
} }
Region getRegion()
{
Compat::ScopedCriticalSection lock(g_cs);
return g_region;
}
DDSURFACEDESC2 getSurfaceDesc(const RECT& rect) DDSURFACEDESC2 getSurfaceDesc(const RECT& rect)
{ {
Compat::ScopedCriticalSection lock(g_cs); Compat::ScopedCriticalSection lock(g_cs);
@ -278,13 +249,14 @@ namespace Gdi
if (g_isFullscreen) if (g_isFullscreen)
{ {
g_bounds = DDraw::PrimarySurface::getMonitorRect(); g_bounds = DDraw::PrimarySurface::getMonitorRect();
g_region = g_bounds;
} }
else else
{ {
g_region.clear(); g_bounds = {};
EnumDisplayMonitors(nullptr, nullptr, addMonitorRectToRegion, reinterpret_cast<LPARAM>(&g_region)); for (const auto& mi : Win32::DisplayMode::getAllMonitorInfo())
GetRgnBox(g_region, &g_bounds); {
UnionRect(&g_bounds, &g_bounds, &mi.second.rcMonitor);
}
} }
g_bpp = Win32::DisplayMode::getBpp(); g_bpp = Win32::DisplayMode::getBpp();

View File

@ -17,7 +17,6 @@ namespace Gdi
void deleteDc(HDC dc); void deleteDc(HDC dc);
RECT getBounds(); RECT getBounds();
Region getRegion();
DDSURFACEDESC2 getSurfaceDesc(const RECT& rect); DDSURFACEDESC2 getSurfaceDesc(const RECT& rect);
void init(); void init();

View File

@ -31,6 +31,7 @@
#include <Overlay/ConfigWindow.h> #include <Overlay/ConfigWindow.h>
#include <Overlay/StatsWindow.h> #include <Overlay/StatsWindow.h>
#include <Win32/DisplayMode.h> #include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
namespace namespace
{ {
@ -51,7 +52,6 @@ namespace
}; };
decltype(&DwmSetIconicThumbnail) g_dwmSetIconicThumbnail = nullptr; decltype(&DwmSetIconicThumbnail) g_dwmSetIconicThumbnail = nullptr;
decltype(&SetThreadDpiAwarenessContext) g_setThreadDpiAwarenessContext = nullptr;
wchar_t g_dummyWindowText; wchar_t g_dummyWindowText;
std::map<HMENU, UINT> g_menuMaxHeight; std::map<HMENU, UINT> g_menuMaxHeight;
@ -327,19 +327,8 @@ namespace
DeleteDC(dstDc); DeleteDC(dstDc);
ReleaseDC(presentationWindow, srcDc); ReleaseDC(presentationWindow, srcDc);
DPI_AWARENESS_CONTEXT prevContext = nullptr; Win32::ScopedDpiAwareness dpiAwareness;
if (g_setThreadDpiAwarenessContext)
{
prevContext = g_setThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
}
g_dwmSetIconicThumbnail(hwnd, bmp, 0); g_dwmSetIconicThumbnail(hwnd, bmp, 0);
if (prevContext)
{
g_setThreadDpiAwarenessContext(prevContext);
}
DeleteObject(bmp); DeleteObject(bmp);
} }
@ -370,6 +359,11 @@ namespace
return getMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, CALL_ORIG_FUNC(GetMessageW)); 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, LONG getWindowLong(HWND hWnd, int nIndex,
decltype(&GetWindowLongA) origGetWindowLong, WNDPROC(WindowProc::* wndProc)) decltype(&GetWindowLongA) origGetWindowLong, WNDPROC(WindowProc::* wndProc))
{ {
@ -441,24 +435,22 @@ namespace
return; return;
} }
HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); auto mi = Win32::DisplayMode::getMonitorInfo(hwnd);
MONITORINFO origMi = {}; if (!EqualRect(&mi.rcEmulated, &mi.rcMonitor))
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))
{ {
RECT wr = {}; RECT wr = {};
GetWindowRect(hwnd, &wr); GetWindowRect(hwnd, &wr);
const LONG width = wr.right - wr.left; const LONG width = wr.right - wr.left;
const LONG height = wr.bottom - wr.top; 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 left = (mr.left + mr.right - width) / 2;
const LONG top = (mr.top + mr.bottom - height) / 2; const LONG top = (mr.top + mr.bottom - height) / 2;
@ -506,11 +498,9 @@ namespace
void onGetMinMaxInfo(MINMAXINFO& mmi) void onGetMinMaxInfo(MINMAXINFO& mmi)
{ {
MONITORINFOEXA mi = {}; const auto& mi = Win32::DisplayMode::getMonitorInfo();
mi.cbSize = sizeof(mi); mmi.ptMaxSize.x = mi.rcEmulated.right - 2 * mmi.ptMaxPosition.x;
GetMonitorInfoA(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi); mmi.ptMaxSize.y = mi.rcEmulated.bottom - 2 * mmi.ptMaxPosition.y;
mmi.ptMaxSize.x = mi.rcMonitor.right - 2 * mmi.ptMaxPosition.x;
mmi.ptMaxSize.y = mi.rcMonitor.bottom - 2 * mmi.ptMaxPosition.y;
} }
void onInitMenuPopup(HMENU menu) void onInitMenuPopup(HMENU menu)
@ -861,6 +851,7 @@ namespace Gdi
HOOK_FUNCTION(user32, GetCursorPos, getCursorPos); HOOK_FUNCTION(user32, GetCursorPos, getCursorPos);
HOOK_FUNCTION(user32, GetMessageA, getMessageA); HOOK_FUNCTION(user32, GetMessageA, getMessageA);
HOOK_FUNCTION(user32, GetMessageW, getMessageW); HOOK_FUNCTION(user32, GetMessageW, getMessageW);
HOOK_FUNCTION(gdi32, GetRandomRgn, getRandomRgn);
HOOK_FUNCTION(user32, GetWindowLongA, getWindowLongA); HOOK_FUNCTION(user32, GetWindowLongA, getWindowLongA);
HOOK_FUNCTION(user32, GetWindowLongW, getWindowLongW); HOOK_FUNCTION(user32, GetWindowLongW, getWindowLongW);
HOOK_FUNCTION(user32, MessageBoxA, messageBox<MessageBoxA>); HOOK_FUNCTION(user32, MessageBoxA, messageBox<MessageBoxA>);
@ -878,8 +869,6 @@ namespace Gdi
g_dwmSetIconicThumbnail = reinterpret_cast<decltype(&DwmSetIconicThumbnail)>( g_dwmSetIconicThumbnail = reinterpret_cast<decltype(&DwmSetIconicThumbnail)>(
GetProcAddress(GetModuleHandle("dwmapi"), "DwmSetIconicThumbnail")); GetProcAddress(GetModuleHandle("dwmapi"), "DwmSetIconicThumbnail"));
g_setThreadDpiAwarenessContext = reinterpret_cast<decltype(&SetThreadDpiAwarenessContext)>(
GetProcAddress(GetModuleHandle("user32"), "SetThreadDpiAwarenessContext"));
Compat::hookIatFunction(Dll::g_origDDrawModule, "SetWindowLongA", ddrawSetWindowLongA); Compat::hookIatFunction(Dll::g_origDDrawModule, "SetWindowLongA", ddrawSetWindowLongA);

View File

@ -18,6 +18,8 @@
#include <Input/Input.h> #include <Input/Input.h>
#include <Overlay/ConfigWindow.h> #include <Overlay/ConfigWindow.h>
#include <Overlay/StatsWindow.h> #include <Overlay/StatsWindow.h>
#include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
namespace namespace
{ {
@ -35,28 +37,24 @@ namespace
HWND presentationWindow; HWND presentationWindow;
RECT windowRect; RECT windowRect;
RECT clientRect; RECT clientRect;
Gdi::Region windowRegion;
Gdi::Region visibleRegion; Gdi::Region visibleRegion;
Gdi::Region invalidatedRegion; Gdi::Region invalidatedRegion;
bool isMenu; bool isMenu;
bool isLayered; bool isLayered;
bool isVisibleRegionChanged; bool isDpiAware;
Window(HWND hwnd) Window(HWND hwnd)
: hwnd(hwnd) : hwnd(hwnd)
, presentationWindow(nullptr) , presentationWindow(nullptr)
, windowRect{} , windowRect{}
, clientRect{} , clientRect{}
, windowRegion(nullptr)
, isMenu(Gdi::MENU_ATOM == GetClassLong(hwnd, GCW_ATOM)) , isMenu(Gdi::MENU_ATOM == GetClassLong(hwnd, GCW_ATOM))
, isLayered(true) , isLayered(true)
, isVisibleRegionChanged(false) , isDpiAware(false)
{ {
} }
}; };
const RECT REGION_OVERRIDE_MARKER_RECT = { 32000, 32000, 32001, 32001 };
std::map<HWND, Window> g_windows; std::map<HWND, Window> g_windows;
std::vector<Window*> g_windowZOrder; std::vector<Window*> g_windowZOrder;
@ -92,16 +90,6 @@ namespace
return true; 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<IDirectDrawSurface7> dst, void presentLayeredWindow(CompatWeakPtr<IDirectDrawSurface7> dst,
HWND hwnd, RECT wr, const RECT& monitorRect, HDC& dstDc, Gdi::Region* rgn = nullptr, bool isMenu = false) 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 LONG exStyle = CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_EXSTYLE);
const bool isLayered = it->second.isMenu || (exStyle & WS_EX_LAYERED); const bool isLayered = it->second.isMenu || (exStyle & WS_EX_LAYERED);
const bool isVisible = IsWindowVisible(hwnd) && !IsIconic(hwnd); const bool isVisible = IsWindowVisible(hwnd) && !IsIconic(hwnd);
bool setPresentationWindowRgn = false;
if (isLayered != it->second.isLayered) if (isLayered != it->second.isLayered)
{ {
it->second.isLayered = isLayered; it->second.isLayered = isLayered;
it->second.isVisibleRegionChanged = isVisible;
if (!isLayered) if (!isLayered)
{ {
it->second.presentationWindow = Gdi::PresentationWindow::create(hwnd); it->second.presentationWindow = Gdi::PresentationWindow::create(hwnd);
Gdi::WinProc::updatePresentationWindowText(hwnd); Gdi::WinProc::updatePresentationWindowText(hwnd);
setPresentationWindowRgn = true;
} }
else if (it->second.presentationWindow) 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 = {}; WINDOWINFO wi = {};
Gdi::Region visibleRegion; Gdi::Region visibleRegion;
@ -297,15 +274,24 @@ namespace
GetWindowInfo(hwnd, &wi); GetWindowInfo(hwnd, &wi);
if (!IsRectEmpty(&wi.rcWindow)) if (!IsRectEmpty(&wi.rcWindow))
{ {
if (it->second.windowRegion) if (isLayered)
{ {
visibleRegion = it->second.windowRegion; if (ERROR != GetWindowRgn(hwnd, visibleRegion))
visibleRegion.offset(wi.rcWindow.left, wi.rcWindow.top); {
visibleRegion.offset(wi.rcWindow.left, wi.rcWindow.top);
}
else
{
visibleRegion = wi.rcWindow;
}
} }
else else
{ {
visibleRegion = wi.rcWindow; HDC windowDc = GetWindowDC(hwnd);
CALL_ORIG_FUNC(GetRandomRgn)(windowDc, visibleRegion, SYSRGN);
ReleaseDC(hwnd, windowDc);
} }
visibleRegion &= context.virtualScreenRegion; visibleRegion &= context.virtualScreenRegion;
if (!it->second.isMenu) if (!it->second.isMenu)
{ {
@ -335,27 +321,11 @@ namespace
context.invalidatedRegion |= visibleRegion - it->second.visibleRegion; 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); Gdi::GuiThread::setWindowRgn(it->second.presentationWindow, Gdi::Window::getWindowRgn(hwnd));
Gdi::Window::updatePresentationWindowPos(it->second.presentationWindow, hwnd);
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);
}
} }
} }
return TRUE; return TRUE;
@ -395,7 +365,7 @@ namespace Gdi
if (statsWindow && statsWindow->isVisible()) if (statsWindow && statsWindow->isVisible())
{ {
GetWindowRect(statsWindow->getWindow(), &wr); GetWindowRect(statsWindow->getWindow(), &wr);
auto visibleRegion(getWindowRegion(statsWindow->getWindow())); auto visibleRegion(getWindowRgn(statsWindow->getWindow()));
visibleRegion.offset(wr.left, wr.top); visibleRegion.offset(wr.left, wr.top);
layeredWindows.push_back({ statsWindow->getWindow(), wr, visibleRegion }); layeredWindows.push_back({ statsWindow->getWindow(), wr, visibleRegion });
} }
@ -404,7 +374,7 @@ namespace Gdi
if (configWindow && configWindow->isVisible()) if (configWindow && configWindow->isVisible())
{ {
GetWindowRect(configWindow->getWindow(), &wr); GetWindowRect(configWindow->getWindow(), &wr);
auto visibleRegion(getWindowRegion(configWindow->getWindow())); auto visibleRegion(getWindowRgn(configWindow->getWindow()));
visibleRegion.offset(wr.left, wr.top); visibleRegion.offset(wr.left, wr.top);
layeredWindows.push_back({ configWindow->getWindow(), wr, visibleRegion }); layeredWindows.push_back({ configWindow->getWindow(), wr, visibleRegion });
auto capture = Input::getCaptureWindow(); auto capture = Input::getCaptureWindow();
@ -445,6 +415,47 @@ namespace Gdi
return nullptr; 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) bool isTopLevelWindow(HWND hwnd)
{ {
return GetDesktopWindow() == GetAncestor(hwnd, GA_PARENT); return GetDesktopWindow() == GetAncestor(hwnd, GA_PARENT);
@ -470,7 +481,6 @@ namespace Gdi
void onSyncPaint(HWND hwnd) void onSyncPaint(HWND hwnd)
{ {
LOG_FUNC("Window::onSyncPaint", hwnd); LOG_FUNC("Window::onSyncPaint", hwnd);
bool isInvalidated = false;
{ {
D3dDdi::ScopedCriticalSection lock; D3dDdi::ScopedCriticalSection lock;
@ -480,38 +490,13 @@ namespace Gdi
return; return;
} }
if (it->second.isVisibleRegionChanged) RedrawWindow(hwnd, nullptr, it->second.invalidatedRegion,
{ RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
it->second.isVisibleRegionChanged = false; it->second.invalidatedRegion.clear();
const LONG origWndProc = CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_WNDPROC);
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC, reinterpret_cast<LONG>(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();
}
} }
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<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src, void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
@ -526,12 +511,13 @@ namespace Gdi
return; return;
} }
auto mr = DDraw::PrimarySurface::getMonitorRect();
for (auto window : g_windowZOrder) for (auto window : g_windowZOrder)
{ {
if (window->presentationWindow && !window->visibleRegion.isEmpty()) if (window->presentationWindow && !window->visibleRegion.isEmpty())
{ {
clipper->SetHWnd(&clipper, 0, window->presentationWindow); 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; UpdateWindowContext context;
context.processId = GetCurrentProcessId(); context.processId = GetCurrentProcessId();
context.virtualScreenRegion = VirtualScreen::getRegion(); context.virtualScreenRegion = VirtualScreen::getBounds();
std::vector<HWND> invalidatedWindows; std::vector<HWND> invalidatedWindows;
{ {
@ -616,7 +602,7 @@ namespace Gdi
for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it) for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it)
{ {
auto& window = **it; auto& window = **it;
if (window.isVisibleRegionChanged || !window.invalidatedRegion.isEmpty()) if (!window.invalidatedRegion.isEmpty())
{ {
invalidatedWindows.push_back(window.hwnd); 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) void updatePresentationWindowPos(HWND presentationWindow, HWND owner)
{ {
if (IsIconic(owner)) if (IsIconic(owner))
@ -667,7 +678,9 @@ namespace Gdi
Gdi::GuiThread::execute([&]() Gdi::GuiThread::execute([&]()
{ {
CALL_ORIG_FUNC(SetWindowPos)(presentationWindow, 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);
}); });
} }
} }

View File

@ -21,12 +21,15 @@ namespace Gdi
std::vector<LayeredWindow> getVisibleLayeredWindows(); std::vector<LayeredWindow> getVisibleLayeredWindows();
std::vector<LayeredWindow> getVisibleOverlayWindows(); std::vector<LayeredWindow> getVisibleOverlayWindows();
HWND getFullscreenWindow(); HWND getFullscreenWindow();
int getRandomRgn(HDC hdc, HRGN hrgn, INT i);
Gdi::Region getWindowRgn(HWND hwnd);
bool isTopLevelWindow(HWND hwnd); bool isTopLevelWindow(HWND hwnd);
void onStyleChanged(HWND hwnd, WPARAM wParam); void onStyleChanged(HWND hwnd, WPARAM wParam);
void onSyncPaint(HWND hwnd); void onSyncPaint(HWND hwnd);
void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src, void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
CompatRef<IDirectDrawClipper> clipper); CompatRef<IDirectDrawClipper> clipper);
void present(Gdi::Region excludeRegion); void present(Gdi::Region excludeRegion);
void setDpiAwareness(HWND hwnd, bool dpiAware);
void updateAll(); void updateAll();
void updatePresentationWindowPos(HWND presentationWindow, HWND owner); void updatePresentationWindowPos(HWND presentationWindow, HWND owner);
} }

View File

@ -3,10 +3,12 @@
#include <tuple> #include <tuple>
#include <Windows.h> #include <Windows.h>
#include <hidusage.h> #include <winternl.h>
#include <Common/Hook.h> #include <Common/Hook.h>
#include <Common/Log.h> #include <Common/Log.h>
#include <Common/Path.h>
#include <Common/Rect.h>
#include <Config/Settings/TerminateHotKey.h> #include <Config/Settings/TerminateHotKey.h>
#include <Dll/Dll.h> #include <Dll/Dll.h>
#include <DDraw/RealPrimarySurface.h> #include <DDraw/RealPrimarySurface.h>
@ -15,9 +17,18 @@
#include <Input/Input.h> #include <Input/Input.h>
#include <Overlay/ConfigWindow.h> #include <Overlay/ConfigWindow.h>
#include <Overlay/Window.h> #include <Overlay/Window.h>
#include <Win32/DisplayMode.h>
namespace namespace
{ {
struct DInputMouseHookData
{
HOOKPROC origHookProc;
LPARAM origHookStruct;
MSLLHOOKSTRUCT hookStruct;
DWORD dpiScale;
};
struct HotKeyData struct HotKeyData
{ {
std::function<void(void*)> action; std::function<void(void*)> action;
@ -29,14 +40,19 @@ namespace
SIZE g_bmpArrowSize = {}; SIZE g_bmpArrowSize = {};
Overlay::Control* g_capture = nullptr; Overlay::Control* g_capture = nullptr;
POINT g_cursorPos = {}; POINT g_cursorPos = {};
POINT g_origCursorPos = { MAXLONG, MAXLONG };
HWND g_cursorWindow = nullptr; HWND g_cursorWindow = nullptr;
std::map<Input::HotKey, HotKeyData> g_hotKeys; std::map<Input::HotKey, HotKeyData> g_hotKeys;
RECT g_monitorRect = {}; RECT g_monitorRect = {};
HHOOK g_keyboardHook = nullptr; HHOOK g_keyboardHook = nullptr;
HHOOK g_mouseHook = nullptr; HHOOK g_mouseHook = nullptr;
DInputMouseHookData g_dinputMouseHookData = {};
decltype(&PhysicalToLogicalPointForPerMonitorDPI) g_physicalToLogicalPointForPerMonitorDPI = nullptr;
LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK lowLevelMouseProc(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) 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); return CALL_ORIG_FUNC(DefWindowProcA)(hwnd, uMsg, wParam, lParam);
} }
LRESULT WINAPI dinputCallNextHookEx(HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam)
{
if (lParam == reinterpret_cast<LPARAM>(&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<MSLLHOOKSTRUCT*>(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<LPARAM>(&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) LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{ {
if (HC_ACTION == nCode && if (HC_ACTION == nCode &&
@ -101,12 +155,25 @@ namespace
if (WM_MOUSEMOVE == wParam) if (WM_MOUSEMOVE == wParam)
{ {
POINT cp = g_cursorPos; if (MAXLONG == g_origCursorPos.y)
POINT origCp = {}; {
CALL_ORIG_FUNC(GetCursorPos)(&origCp); 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); POINT cp = g_cursorPos;
cp.y += (llHook.pt.y - origCp.y); 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.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); cp.y = std::min(std::max(g_monitorRect.top, cp.y), g_monitorRect.bottom);
g_cursorPos = cp; g_cursorPos = cp;
@ -150,6 +217,16 @@ namespace
TerminateProcess(GetCurrentProcess(), 0); 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() void resetKeyboardHook()
{ {
Gdi::GuiThread::execute([]() Gdi::GuiThread::execute([]()
@ -171,18 +248,54 @@ namespace
{ {
UnhookWindowsHookEx(g_mouseHook); UnhookWindowsHookEx(g_mouseHook);
} }
g_origCursorPos = { MAXLONG, MAXLONG };
g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)( g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)(
WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_currentModule, 0); 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, HHOOK setWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId,
decltype(&SetWindowsHookExA) origSetWindowsHookEx) 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 auto moduleName = Compat::getModulePath(hmod).stem().string();
return nullptr; 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); HHOOK result = origSetWindowsHookEx(idHook, lpfn, hmod, dwThreadId);
@ -235,11 +348,6 @@ namespace Input
return g_capture ? static_cast<Overlay::Window*>(&g_capture->getRoot()) : nullptr; return g_capture ? static_cast<Overlay::Window*>(&g_capture->getRoot()) : nullptr;
} }
POINT getCursorPos()
{
return g_cursorPos;
}
HWND getCursorWindow() HWND getCursorWindow()
{ {
return g_cursorWindow; return g_cursorWindow;
@ -272,6 +380,10 @@ namespace Input
GetObject(g_bmpArrow, sizeof(bm), &bm); GetObject(g_bmpArrow, sizeof(bm), &bm);
g_bmpArrowSize = { bm.bmWidth, bm.bmHeight }; g_bmpArrowSize = { bm.bmWidth, bm.bmHeight };
g_physicalToLogicalPointForPerMonitorDPI = reinterpret_cast<decltype(&PhysicalToLogicalPointForPerMonitorDPI)>(
GetProcAddress(GetModuleHandle("user32"), "PhysicalToLogicalPointForPerMonitorDPI"));
HOOK_FUNCTION(user32, SetCursorPos, setCursorPos);
HOOK_FUNCTION(user32, SetWindowsHookExA, setWindowsHookExA); HOOK_FUNCTION(user32, SetWindowsHookExA, setWindowsHookExA);
HOOK_FUNCTION(user32, SetWindowsHookExW, setWindowsHookExW); HOOK_FUNCTION(user32, SetWindowsHookExW, setWindowsHookExW);
@ -301,11 +413,7 @@ namespace Input
if (control) if (control)
{ {
auto window = getCaptureWindow(); auto window = getCaptureWindow();
g_monitorRect = Win32::DisplayMode::getMonitorInfo(window->getWindow()).rcMonitor;
MONITORINFO mi = {};
mi.cbSize = sizeof(mi);
CALL_ORIG_FUNC(GetMonitorInfoA)(MonitorFromWindow(window->getWindow(), MONITOR_DEFAULTTOPRIMARY), &mi);
g_monitorRect = mi.rcMonitor;
if (!g_mouseHook) if (!g_mouseHook)
{ {

View File

@ -18,7 +18,6 @@ namespace Input
Overlay::Control* getCapture(); Overlay::Control* getCapture();
Overlay::Window* getCaptureWindow(); Overlay::Window* getCaptureWindow();
POINT getCursorPos();
HWND getCursorWindow(); HWND getCursorWindow();
POINT getRelativeCursorPos(); POINT getRelativeCursorPos();
void installHooks(); void installHooks();

View File

@ -72,7 +72,8 @@ namespace
namespace Overlay namespace Overlay
{ {
ConfigWindow::ConfigWindow() 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_buttonCount(0)
, m_focus(nullptr) , m_focus(nullptr)
{ {

View File

@ -7,12 +7,12 @@
#include <Common/Log.h> #include <Common/Log.h>
#include <Dll/Dll.h> #include <Dll/Dll.h>
#include <DDraw/RealPrimarySurface.h> #include <DDraw/RealPrimarySurface.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <Gdi/GuiThread.h> #include <Gdi/GuiThread.h>
#include <Gdi/PresentationWindow.h> #include <Gdi/PresentationWindow.h>
#include <Input/Input.h> #include <Input/Input.h>
#include <Overlay/Control.h> #include <Overlay/Control.h>
#include <Overlay/Window.h> #include <Overlay/Window.h>
#include <Win32/DisplayMode.h>
namespace namespace
{ {
@ -179,42 +179,20 @@ namespace Overlay
void Window::updatePos() void Window::updatePos()
{ {
RECT monitorRect = DDraw::RealPrimarySurface::getMonitorRect(); const RECT monitorRect = Win32::DisplayMode::getMonitorInfo(GetForegroundWindow()).rcMonitor;
if (IsRectEmpty(&monitorRect)) int scaleX = (monitorRect.right - monitorRect.left) / VIRTUAL_SCREEN_WIDTH;
{ int scaleY = (monitorRect.bottom - monitorRect.top) / VIRTUAL_SCREEN_HEIGHT;
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;
m_scaleFactor = std::min(scaleX, scaleY); m_scaleFactor = std::min(scaleX, scaleY);
m_scaleFactor = std::max(1, m_scaleFactor); m_scaleFactor = std::max(1, m_scaleFactor);
m_rect = calculateRect({ monitorRect.left / m_scaleFactor, monitorRect.top / m_scaleFactor, m_rect = calculateRect({ monitorRect.left / m_scaleFactor, monitorRect.top / m_scaleFactor,
monitorRect.right / m_scaleFactor, monitorRect.bottom / 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, CALL_ORIG_FUNC(SetWindowPos)(m_hwnd, getTopmost(),
(m_rect.right - m_rect.left) * m_scaleFactor, (m_rect.bottom - m_rect.top) * m_scaleFactor, m_rect.left * m_scaleFactor, m_rect.top * m_scaleFactor,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_SHOWWINDOW); (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) if (Input::getCaptureWindow() == this)
{ {

View File

@ -13,6 +13,9 @@ namespace Overlay
class Window : public Control class Window : public Control
{ {
public: 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 = {}); Window(Window* parentWindow, const RECT& rect, DWORD style, int alpha, const Input::HotKey& hotKey = {});
virtual ~Window() override; virtual ~Window() override;

View File

@ -9,7 +9,9 @@
#include <Common/Comparison.h> #include <Common/Comparison.h>
#include <Common/CompatPtr.h> #include <Common/CompatPtr.h>
#include <Common/Hook.h> #include <Common/Hook.h>
#include <Common/ScopedSrwLock.h> #include <Common/Log.h>
#include <Common/Rect.h>
#include <Common/ScopedCriticalSection.h>
#include <Config/Settings/DesktopColorDepth.h> #include <Config/Settings/DesktopColorDepth.h>
#include <Config/Settings/DesktopResolution.h> #include <Config/Settings/DesktopResolution.h>
#include <Config/Settings/DisplayRefreshRate.h> #include <Config/Settings/DisplayRefreshRate.h>
@ -21,6 +23,7 @@
#include <Gdi/GuiThread.h> #include <Gdi/GuiThread.h>
#include <Gdi/VirtualScreen.h> #include <Gdi/VirtualScreen.h>
#include <Win32/DisplayMode.h> #include <Win32/DisplayMode.h>
#include <Win32/DpiAwareness.h>
BOOL WINAPI DWM8And16Bit_IsShimApplied_CallOut() { return FALSE; } BOOL WINAPI DWM8And16Bit_IsShimApplied_CallOut() { return FALSE; }
ULONG WINAPI GdiEntry13() { return 0; } ULONG WINAPI GdiEntry13() { return 0; }
@ -62,7 +65,10 @@ namespace
DWORD g_desktopBpp = 0; DWORD g_desktopBpp = 0;
ULONG g_displaySettingsUniquenessBias = 0; ULONG g_displaySettingsUniquenessBias = 0;
EmulatedDisplayMode g_emulatedDisplayMode = {}; EmulatedDisplayMode g_emulatedDisplayMode = {};
Compat::SrwLock g_srwLock; ULONG g_monitorInfoUniqueness = 0;
std::map<HMONITOR, Win32::DisplayMode::MonitorInfo> g_monitorInfo;
Win32::DisplayMode::MonitorInfo g_emptyMonitorInfo = {};
Compat::CriticalSection g_cs;
BOOL WINAPI dwm8And16BitIsShimAppliedCallOut(); BOOL WINAPI dwm8And16BitIsShimAppliedCallOut();
BOOL WINAPI seComHookInterface(CLSID* clsid, GUID* iid, DWORD unk1, DWORD unk2); BOOL WINAPI seComHookInterface(CLSID* clsid, GUID* iid, DWORD unk1, DWORD unk2);
@ -92,24 +98,10 @@ namespace
void setDwmDxFullscreenTransitionEvent(); 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 <typename Char> template <typename Char>
LONG changeDisplaySettingsEx(const Char* lpszDeviceName, typename DevMode<Char>* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam) LONG changeDisplaySettingsEx(const Char* lpszDeviceName, typename DevMode<Char>* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam)
{ {
DDraw::ScopedThreadLock lock; DDraw::ScopedThreadLock ddLock;
auto desktopResolution = Config::desktopResolution.get(); auto desktopResolution = Config::desktopResolution.get();
if (!lpDevMode && 0 == dwflags && Config::Settings::DesktopResolution::DESKTOP != desktopResolution) 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; ++g_displaySettingsUniquenessBias;
if (lpDevMode) if (lpDevMode)
{ {
@ -246,13 +238,7 @@ namespace
g_emulatedDisplayMode.bpp = lpDevMode->dmBitsPerPel; g_emulatedDisplayMode.bpp = lpDevMode->dmBitsPerPel;
} }
g_emulatedDisplayMode.refreshRate = currDevMode.dmDisplayFrequency; g_emulatedDisplayMode.refreshRate = currDevMode.dmDisplayFrequency;
g_emulatedDisplayMode.deviceName = getDeviceName(lpszDeviceName); 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 else
{ {
@ -322,7 +308,7 @@ namespace
BOOL result = origEnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags); BOOL result = origEnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, dwFlags);
if (result) if (result)
{ {
Compat::ScopedSrwLockShared srwLock(g_srwLock); Compat::ScopedCriticalSection lock(g_cs);
if (getDeviceName(lpszDeviceName) == g_emulatedDisplayMode.deviceName) if (getDeviceName(lpszDeviceName) == g_emulatedDisplayMode.deviceName)
{ {
lpDevMode->dmBitsPerPel = g_emulatedDisplayMode.bpp; lpDevMode->dmBitsPerPel = g_emulatedDisplayMode.bpp;
@ -388,22 +374,10 @@ namespace
ULONG WINAPI gdiEntry13() ULONG WINAPI gdiEntry13()
{ {
Compat::ScopedSrwLockShared lock(g_srwLock); Compat::ScopedCriticalSection lock(g_cs);
return CALL_ORIG_FUNC(GdiEntry13)() + g_displaySettingsUniquenessBias; 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<LONG>(g_emulatedDisplayMode.width), static_cast<LONG>(g_emulatedDisplayMode.height) };
}
}
return 0 != displayResolution.cx ? displayResolution : Win32::DisplayMode::getDisplayResolution(deviceName);
}
template <typename Char> template <typename Char>
DWORD getConfiguredRefreshRate(const Char* deviceName) DWORD getConfiguredRefreshRate(const Char* deviceName)
{ {
@ -464,17 +438,8 @@ namespace
case VERTRES: case VERTRES:
if (Gdi::isDisplayDc(hdc)) if (Gdi::isDisplayDc(hdc))
{ {
MONITORINFO mi = {}; const auto& r = Win32::DisplayMode::getMonitorInfo().rcEmulated;
mi.cbSize = sizeof(mi); return HORZRES == nIndex ? (r.right - r.left) : (r.bottom - r.top);
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);
}
} }
break; break;
@ -527,64 +492,13 @@ namespace
return mi.szDevice; return mi.szDevice;
} }
BOOL CALLBACK getMonitorFromDcEnum(HMONITOR hMonitor, HDC /*hdcMonitor*/, LPRECT /*lprcMonitor*/, LPARAM dwData)
{
auto& args = *reinterpret_cast<GetMonitorFromDcEnumArgs*>(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<LPARAM>(&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<MONITORINFOEXW*>(dwData);
if (0 == wcscmp(mi.szDevice, dest.szDevice))
{
dest = mi;
return FALSE;
}
return TRUE;
}
BOOL WINAPI getMonitorInfoA(HMONITOR hMonitor, LPMONITORINFO lpmi) BOOL WINAPI getMonitorInfoA(HMONITOR hMonitor, LPMONITORINFO lpmi)
{ {
LOG_FUNC("GetMonitorInfoA", hMonitor, lpmi); LOG_FUNC("GetMonitorInfoA", hMonitor, lpmi);
BOOL result = CALL_ORIG_FUNC(GetMonitorInfoA)(hMonitor, lpmi); BOOL result = CALL_ORIG_FUNC(GetMonitorInfoA)(hMonitor, lpmi);
if (result) if (result)
{ {
adjustMonitorInfo(*lpmi); lpmi->rcMonitor = Win32::DisplayMode::getMonitorInfo(hMonitor).rcEmulated;
} }
return LOG_RESULT(result); return LOG_RESULT(result);
} }
@ -595,7 +509,7 @@ namespace
BOOL result = CALL_ORIG_FUNC(GetMonitorInfoW)(hMonitor, lpmi); BOOL result = CALL_ORIG_FUNC(GetMonitorInfoW)(hMonitor, lpmi);
if (result) if (result)
{ {
adjustMonitorInfo(*lpmi); lpmi->rcMonitor = Win32::DisplayMode::getMonitorInfo(hMonitor).rcEmulated;
} }
return LOG_RESULT(result); return LOG_RESULT(result);
} }
@ -750,50 +664,129 @@ namespace
CloseHandle(dwmDxFullscreenTransitionEvent); 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 Win32
{ {
namespace DisplayMode 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<HMONITOR, MonitorInfo> getAllMonitorInfo()
{
Compat::ScopedCriticalSection lock(g_cs);
updateMonitorInfo();
auto mi = g_monitorInfo;
mi.erase(nullptr);
return mi;
} }
DWORD getBpp() DWORD getBpp()
{ {
return getEmulatedDisplayMode().bpp; Compat::ScopedCriticalSection lock(g_cs);
} return g_emulatedDisplayMode.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<LONG>(dm.dmPelsWidth), static_cast<LONG>(dm.dmPelsHeight) };
} }
EmulatedDisplayMode getEmulatedDisplayMode() EmulatedDisplayMode getEmulatedDisplayMode()
{ {
Compat::ScopedSrwLockShared lock(g_srwLock); Compat::ScopedCriticalSection lock(g_cs);
return g_emulatedDisplayMode; return g_emulatedDisplayMode;
} }
MONITORINFOEXW getMonitorInfo(const std::wstring& deviceName) const MonitorInfo& getMonitorInfo(HMONITOR monitor)
{ {
MONITORINFOEXW mi = {}; Compat::ScopedCriticalSection lock(g_cs);
wcscpy_s(mi.szDevice, deviceName.c_str()); updateMonitorInfo();
EnumDisplayMonitors(nullptr, nullptr, &getMonitorInfoEnum, reinterpret_cast<LPARAM>(&mi)); auto it = g_monitorInfo.find(monitor);
return mi; return it != g_monitorInfo.end() ? it->second : g_emptyMonitorInfo;
} }
Resolution getResolution(const std::wstring& deviceName) const MonitorInfo& getMonitorInfo(HWND hwnd)
{ {
Resolution res = {}; return getMonitorInfo(hwnd ? MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) : nullptr);
res.display = getDisplayResolution(deviceName); }
res.app = ::getAppResolution(deviceName, res.display);
return res; 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() ULONG queryDisplaySettingsUniqueness()

View File

@ -1,10 +1,11 @@
#pragma once #pragma once
#include <tuple> #include <map>
#include <Windows.h> #include <Windows.h>
#include <Common/Comparison.h> #include <Common/Comparison.h>
#include <Gdi/Region.h>
namespace Win32 namespace Win32
{ {
@ -21,31 +22,29 @@ namespace Win32
struct EmulatedDisplayMode : DisplayMode struct EmulatedDisplayMode : DisplayMode
{ {
std::wstring deviceName; std::wstring deviceName;
RECT rect;
SIZE diff;
}; };
struct Resolution struct MonitorInfo : MONITORINFOEXW
{ {
SIZE app; RECT rcReal;
SIZE display; 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<HMONITOR, MonitorInfo> getAllMonitorInfo();
DWORD getBpp(); DWORD getBpp();
SIZE getDisplayResolution(const std::wstring& deviceName);
EmulatedDisplayMode getEmulatedDisplayMode(); EmulatedDisplayMode getEmulatedDisplayMode();
MONITORINFOEXW getMonitorInfo(const std::wstring& deviceName); const MonitorInfo& getMonitorInfo(HMONITOR monitor = nullptr);
Resolution getResolution(const std::wstring& deviceName); const MonitorInfo& getMonitorInfo(HWND hwnd);
const MonitorInfo& getMonitorInfo(POINT pt);
const MonitorInfo& getMonitorInfo(const std::wstring& deviceName);
ULONG queryDisplaySettingsUniqueness(); ULONG queryDisplaySettingsUniqueness();
void installHooks(); void installHooks();
using ::operator<;
inline auto toTuple(const DisplayMode& dm)
{
return std::make_tuple(dm.width, dm.height, dm.bpp, dm.refreshRate);
}
} }
} }

View File

@ -0,0 +1,179 @@
#include <ShellScalingApi.h>
#include <Common/Log.h>
#include <Config/Settings/DpiAwareness.h>
#include <Win32/DpiAwareness.h>
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<decltype(&AreDpiAwarenessContextsEqual)>(
GetProcAddress(user32, "AreDpiAwarenessContextsEqual"));
g_getProcessDpiAwareness = reinterpret_cast<decltype(&GetProcessDpiAwareness)>(
GetProcAddress(shcore, "GetProcessDpiAwareness"));
g_getThreadDpiAwarenessContext = reinterpret_cast<decltype(&GetThreadDpiAwarenessContext)>(
GetProcAddress(user32, "GetThreadDpiAwarenessContext"));
g_isValidDpiAwarenessContext = reinterpret_cast<decltype(&IsValidDpiAwarenessContext)>(
GetProcAddress(user32, "IsValidDpiAwarenessContext"));
g_setProcessDpiAwareness = reinterpret_cast<decltype(&SetProcessDpiAwareness)>(
GetProcAddress(shcore, "SetProcessDpiAwareness"));
g_setProcessDpiAwarenessContext = reinterpret_cast<decltype(&SetProcessDpiAwarenessContext)>(
GetProcAddress(user32, "SetProcessDpiAwarenessContext"));
g_setThreadDpiAwarenessContext = reinterpret_cast<decltype(&SetThreadDpiAwarenessContext)>(
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;
}
}
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <Windows.h>
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);
}
}

View File

@ -2,6 +2,7 @@
#include <Common/Hook.h> #include <Common/Hook.h>
#include <Common/Log.h> #include <Common/Log.h>
#include <Common/Path.h>
#include <Win32/Log.h> #include <Win32/Log.h>
namespace namespace
@ -261,6 +262,14 @@ std::ostream& operator<<(std::ostream& os, const HFONT__& font)
<< lf; << lf;
} }
std::ostream& operator<<(std::ostream& os, const HINSTANCE__& inst)
{
os << "MOD";
return Compat::LogStruct(os)
<< static_cast<const void*>(&inst)
<< Compat::getModulePath(const_cast<HINSTANCE>(&inst));
}
std::ostream& operator<<(std::ostream& os, const HRGN__& rgn) std::ostream& operator<<(std::ostream& os, const HRGN__& rgn)
{ {
os << "RGN"; os << "RGN";

View File

@ -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 HDC__& dc);
std::ostream& operator<<(std::ostream& os, const HELPINFO& hi); 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 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 HRGN__& rgn);
std::ostream& operator<<(std::ostream& os, const HWND__& wnd); std::ostream& operator<<(std::ostream& os, const HWND__& wnd);
std::ostream& operator<<(std::ostream& os, const LOGFONT& lf); std::ostream& operator<<(std::ostream& os, const LOGFONT& lf);

View File

@ -6,6 +6,7 @@
#include <Common/Hook.h> #include <Common/Hook.h>
#include <Common/Log.h> #include <Common/Log.h>
#include <Dll/Dll.h>
#include <Win32/Registry.h> #include <Win32/Registry.h>
typedef long NTSTATUS; typedef long NTSTATUS;
@ -66,6 +67,19 @@ namespace
#undef HKLM_SOFTWARE_KEY #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) bool filterType(DWORD type, const DWORD* flags)
{ {
if (!flags) if (!flags)
@ -424,6 +438,8 @@ namespace Win32
HOOK_REGISTRY_FUNCTION(RegGetValueW, regGetValueW); HOOK_REGISTRY_FUNCTION(RegGetValueW, regGetValueW);
HOOK_REGISTRY_FUNCTION(RegQueryValueExA, regQueryValueExA); HOOK_REGISTRY_FUNCTION(RegQueryValueExA, regQueryValueExA);
HOOK_REGISTRY_FUNCTION(RegQueryValueExW, regQueryValueExW); HOOK_REGISTRY_FUNCTION(RegQueryValueExW, regQueryValueExW);
Compat::hookIatFunction(Dll::g_origDDrawModule, "RegCreateKeyExA", ddrawRegCreateKeyExA);
} }
} }
} }