From fe8abe9d5afc4843b7492ec25e0f091e796455c5 Mon Sep 17 00:00:00 2001 From: narzoul Date: Mon, 2 May 2016 23:53:36 +0200 Subject: [PATCH] Avoid side effects when method implementations are delegated to higher versions Some DirectDraw methods are implemented by delegating to the same method in a higher interface version. In this case, the hooking logic could be executed twice, leading to unwanted side effects. This is now avoided. --- DDrawCompat/CompatDirectDraw.cpp | 112 +++++++++++++----------- DDrawCompat/CompatDirectDrawSurface.cpp | 4 +- 2 files changed, 62 insertions(+), 54 deletions(-) diff --git a/DDrawCompat/CompatDirectDraw.cpp b/DDrawCompat/CompatDirectDraw.cpp index 55d6415..21d1f45 100644 --- a/DDrawCompat/CompatDirectDraw.cpp +++ b/DDrawCompat/CompatDirectDraw.cpp @@ -17,14 +17,69 @@ namespace return DDENUMRET_CANCEL; } - DWORD getRefreshRate() + template + HRESULT setDisplayMode(TDirectDraw* This, DWORD dwWidth, DWORD dwHeight, DWORD dwBPP, + DWORD dwRefreshRate, DWORD dwFlags) { - return 0; + typename Types::TSurfaceDesc desc = {}; + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + desc.dwWidth = dwWidth; + desc.dwHeight = dwHeight; + desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat); + desc.ddpfPixelFormat.dwFlags = DDPF_RGB; + desc.ddpfPixelFormat.dwRGBBitCount = dwBPP; + + switch (dwBPP) + { + case 1: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED1; break; + case 2: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED2; break; + case 4: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED4; break; + case 8: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED8; break; + } + + DDPIXELFORMAT pf = {}; + if (dwBPP > 8) + { + if (FAILED(CompatDirectDraw::s_origVtable.EnumDisplayModes( + This, 0, &desc, &pf, &enumDisplayModesCallback)) || 0 == pf.dwSize) + { + Compat::Log() << "Failed to find the requested display mode: " << + dwWidth << "x" << dwHeight << "x" << dwBPP; + return DDERR_INVALIDMODE; + } + } + else + { + pf = desc.ddpfPixelFormat; + } + + HRESULT result = CompatDirectDraw::s_origVtable.SetDisplayMode( + This, dwWidth, dwHeight, 32, dwRefreshRate, dwFlags); + if (SUCCEEDED(result)) + { + CompatPrimarySurface::displayMode.width = dwWidth; + CompatPrimarySurface::displayMode.height = dwHeight; + CompatPrimarySurface::displayMode.pixelFormat = pf; + CompatPrimarySurface::displayMode.refreshRate = dwRefreshRate; + CompatPrimarySurface::isDisplayModeChanged = true; + } + else + { + Compat::Log() << "Failed to set the display mode to " << dwWidth << "x" << dwHeight << "x32"; + } + + return result; } - DWORD getRefreshRate(DWORD dwRefreshRate, DWORD /*dwFlags*/) + HRESULT setDisplayMode(IDirectDraw* This, DWORD dwWidth, DWORD dwHeight, DWORD dwBPP) { - return dwRefreshRate; + IDirectDraw7* dd = nullptr; + CompatDirectDraw::s_origVtable.QueryInterface( + This, IID_IDirectDraw7, reinterpret_cast(&dd)); + HRESULT result = setDisplayMode(dd, dwWidth, dwHeight, dwBPP, 0, 0); + CompatDirectDraw::s_origVtable.Release(dd); + return result; } } @@ -116,54 +171,7 @@ HRESULT STDMETHODCALLTYPE CompatDirectDraw::SetDisplayMode( DWORD dwBPP, Params... params) { - TSurfaceDesc desc = {}; - desc.dwSize = sizeof(desc); - desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; - desc.dwWidth = dwWidth; - desc.dwHeight = dwHeight; - desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat); - desc.ddpfPixelFormat.dwFlags = DDPF_RGB; - desc.ddpfPixelFormat.dwRGBBitCount = dwBPP; - - switch (dwBPP) - { - case 1: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED1; break; - case 2: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED2; break; - case 4: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED4; break; - case 8: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED8; break; - } - - DDPIXELFORMAT pf = {}; - if (dwBPP > 8) - { - if (FAILED(s_origVtable.EnumDisplayModes(This, 0, &desc, &pf, &enumDisplayModesCallback)) || - 0 == pf.dwSize) - { - Compat::Log() << "Failed to find the requested display mode: " << - dwWidth << "x" << dwHeight << "x" << dwBPP; - return DDERR_INVALIDMODE; - } - } - else - { - pf = desc.ddpfPixelFormat; - } - - HRESULT result = s_origVtable.SetDisplayMode(This, dwWidth, dwHeight, 32, params...); - if (SUCCEEDED(result)) - { - CompatPrimarySurface::displayMode.width = dwWidth; - CompatPrimarySurface::displayMode.height = dwHeight; - CompatPrimarySurface::displayMode.pixelFormat = pf; - CompatPrimarySurface::displayMode.refreshRate = getRefreshRate(params...); - CompatPrimarySurface::isDisplayModeChanged = true; - } - else - { - Compat::Log() << "Failed to set the display mode to " << dwWidth << "x" << dwHeight << "x32"; - } - - return result; + return setDisplayMode(This, dwWidth, dwHeight, dwBPP, params...); } template CompatDirectDraw; diff --git a/DDrawCompat/CompatDirectDrawSurface.cpp b/DDrawCompat/CompatDirectDrawSurface.cpp index 5e3ece2..3538eae 100644 --- a/DDrawCompat/CompatDirectDrawSurface.cpp +++ b/DDrawCompat/CompatDirectDrawSurface.cpp @@ -565,8 +565,8 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface::Unlock(TSurface* Th template void CompatDirectDrawSurface::restorePrimaryCaps(TDdsCaps& caps) { - caps.dwCaps ^= DDSCAPS_OFFSCREENPLAIN; - caps.dwCaps |= DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE; + caps.dwCaps &= ~(DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY); + caps.dwCaps |= DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; } template <> const IID& CompatDirectDrawSurface::s_iid = IID_IDirectDrawSurface;