From 5e972cf056b3d321d9f30c8cc014b6ff91d9c7a1 Mon Sep 17 00:00:00 2001 From: narzoul Date: Sun, 1 May 2016 18:31:49 +0200 Subject: [PATCH] Handle WM_ACTIVATEAPP messages Aiming to fix Alt-Tabbing issues (such as black screen instead of desktop) by temporarily setting the cooperative level to windowed mode, restoring the display mode and minimizing the main window when the app is inactive. --- DDrawCompat/CompatActivateAppHandler.cpp | 96 ++++++++++++++++++++++++ DDrawCompat/CompatActivateAppHandler.h | 12 +++ DDrawCompat/CompatDirectDraw.cpp | 29 ++++++- DDrawCompat/CompatDirectDraw.h | 3 +- DDrawCompat/CompatPrimarySurface.cpp | 2 + DDrawCompat/CompatPrimarySurface.h | 2 + DDrawCompat/DDrawCompat.vcxproj | 2 + DDrawCompat/DDrawCompat.vcxproj.filters | 6 ++ DDrawCompat/DDrawLog.cpp | 6 ++ DDrawCompat/DDrawLog.h | 1 + DDrawCompat/DllMain.cpp | 3 + 11 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 DDrawCompat/CompatActivateAppHandler.cpp create mode 100644 DDrawCompat/CompatActivateAppHandler.h diff --git a/DDrawCompat/CompatActivateAppHandler.cpp b/DDrawCompat/CompatActivateAppHandler.cpp new file mode 100644 index 0000000..b40e4e0 --- /dev/null +++ b/DDrawCompat/CompatActivateAppHandler.cpp @@ -0,0 +1,96 @@ +#include "CompatActivateAppHandler.h" +#include "CompatDirectDraw.h" +#include "CompatDirectDrawSurface.h" +#include "CompatPrimarySurface.h" +#include "DDrawLog.h" +#include "RealPrimarySurface.h" + +extern HWND g_mainWindow; + +namespace +{ + HWND g_fullScreenCooperativeWindow = nullptr; + DWORD g_fullScreenCooperativeFlags = 0; + HHOOK g_callWndProcHook = nullptr; + + void handleActivateApp(bool isActivated); + + LRESULT CALLBACK callWndProc(int nCode, WPARAM wParam, LPARAM lParam) + { + auto ret = reinterpret_cast(lParam); + Compat::LogEnter("callWndProc", nCode, wParam, ret); + + if (HC_ACTION == nCode && WM_ACTIVATEAPP == ret->message) + { + const bool isActivated = TRUE == ret->wParam; + handleActivateApp(isActivated); + } + + LRESULT result = CallNextHookEx(nullptr, nCode, wParam, lParam); + Compat::LogLeave("callWndProc", nCode, wParam, ret) << result; + return result; + } + + void handleActivateApp(bool isActivated) + { + Compat::LogEnter("handleActivateApp", isActivated); + + static bool isActive = true; + if (isActivated != isActive && RealPrimarySurface::isFullScreen()) + { + IUnknown* ddIntf = nullptr; + CompatDirectDrawSurface::s_origVtable.GetDDInterface( + RealPrimarySurface::getSurface(), reinterpret_cast(&ddIntf)); + IDirectDraw7* dd = nullptr; + ddIntf->lpVtbl->QueryInterface(ddIntf, IID_IDirectDraw7, reinterpret_cast(&dd)); + + if (isActivated) + { + CompatDirectDraw::s_origVtable.SetCooperativeLevel( + dd, g_fullScreenCooperativeWindow, g_fullScreenCooperativeFlags); + if (CompatPrimarySurface::isDisplayModeChanged) + { + const CompatPrimarySurface::DisplayMode& dm = CompatPrimarySurface::displayMode; + CompatDirectDraw::s_origVtable.SetDisplayMode( + dd, dm.width, dm.height, 32, dm.refreshRate, 0); + } + } + else + { + if (CompatPrimarySurface::isDisplayModeChanged) + { + CompatDirectDraw::s_origVtable.RestoreDisplayMode(dd); + } + CompatDirectDraw::s_origVtable.SetCooperativeLevel( + dd, g_fullScreenCooperativeWindow, DDSCL_NORMAL); + ShowWindow(g_fullScreenCooperativeWindow, SW_MINIMIZE); + } + + dd->lpVtbl->Release(dd); + ddIntf->lpVtbl->Release(ddIntf); + } + + isActive = isActivated; + Compat::LogLeave("handleActivateApp", isActivated); + } +} + +namespace CompatActivateAppHandler +{ + void installHooks() + { + const DWORD threadId = GetCurrentThreadId(); + g_callWndProcHook = SetWindowsHookEx(WH_CALLWNDPROC, callWndProc, nullptr, threadId); + } + + void setFullScreenCooperativeLevel(HWND hwnd, DWORD flags) + { + g_fullScreenCooperativeWindow = hwnd; + g_fullScreenCooperativeFlags = flags; + } + + void uninstallHooks() + { + UnhookWindowsHookEx(g_callWndProcHook); + } +} diff --git a/DDrawCompat/CompatActivateAppHandler.h b/DDrawCompat/CompatActivateAppHandler.h new file mode 100644 index 0000000..8d04ee9 --- /dev/null +++ b/DDrawCompat/CompatActivateAppHandler.h @@ -0,0 +1,12 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN + +#include + +namespace CompatActivateAppHandler +{ + void installHooks(); + void setFullScreenCooperativeLevel(HWND hwnd, DWORD flags); + void uninstallHooks(); +} diff --git a/DDrawCompat/CompatDirectDraw.cpp b/DDrawCompat/CompatDirectDraw.cpp index 0047567..55d6415 100644 --- a/DDrawCompat/CompatDirectDraw.cpp +++ b/DDrawCompat/CompatDirectDraw.cpp @@ -1,3 +1,4 @@ +#include "CompatActivateAppHandler.h" #include "CompatDirectDraw.h" #include "CompatDirectDrawSurface.h" #include "CompatPrimarySurface.h" @@ -15,6 +16,16 @@ namespace } return DDENUMRET_CANCEL; } + + DWORD getRefreshRate() + { + return 0; + } + + DWORD getRefreshRate(DWORD dwRefreshRate, DWORD /*dwFlags*/) + { + return dwRefreshRate; + } } template @@ -22,6 +33,7 @@ void CompatDirectDraw::setCompatVtable(Vtable& vtable) { vtable.CreateSurface = &CreateSurface; vtable.RestoreDisplayMode = &RestoreDisplayMode; + vtable.SetCooperativeLevel = &SetCooperativeLevel; vtable.SetDisplayMode = &SetDisplayMode; } @@ -78,13 +90,26 @@ HRESULT STDMETHODCALLTYPE CompatDirectDraw::RestoreDisplayMode(TDir if (SUCCEEDED(result)) { CompatPrimarySurface::displayMode = CompatPrimarySurface::getDisplayMode(*This); + CompatPrimarySurface::isDisplayModeChanged = false; + } + return result; +} + +template +HRESULT STDMETHODCALLTYPE CompatDirectDraw::SetCooperativeLevel( + TDirectDraw* This, HWND hWnd, DWORD dwFlags) +{ + HRESULT result = s_origVtable.SetCooperativeLevel(This, hWnd, dwFlags); + if (dwFlags & DDSCL_FULLSCREEN) + { + CompatActivateAppHandler::setFullScreenCooperativeLevel(hWnd, dwFlags); } return result; } template template -static HRESULT STDMETHODCALLTYPE CompatDirectDraw::SetDisplayMode( +HRESULT STDMETHODCALLTYPE CompatDirectDraw::SetDisplayMode( TDirectDraw* This, DWORD dwWidth, DWORD dwHeight, @@ -130,6 +155,8 @@ static HRESULT STDMETHODCALLTYPE CompatDirectDraw::SetDisplayMode( CompatPrimarySurface::displayMode.width = dwWidth; CompatPrimarySurface::displayMode.height = dwHeight; CompatPrimarySurface::displayMode.pixelFormat = pf; + CompatPrimarySurface::displayMode.refreshRate = getRefreshRate(params...); + CompatPrimarySurface::isDisplayModeChanged = true; } else { diff --git a/DDrawCompat/CompatDirectDraw.h b/DDrawCompat/CompatDirectDraw.h index e5d9bad..2b44d27 100644 --- a/DDrawCompat/CompatDirectDraw.h +++ b/DDrawCompat/CompatDirectDraw.h @@ -20,7 +20,8 @@ public: IUnknown* pUnkOuter); static HRESULT STDMETHODCALLTYPE RestoreDisplayMode(TDirectDraw* This); - + static HRESULT STDMETHODCALLTYPE SetCooperativeLevel(TDirectDraw* This, HWND hWnd, DWORD dwFlags); + template static HRESULT STDMETHODCALLTYPE SetDisplayMode( TDirectDraw* This, diff --git a/DDrawCompat/CompatPrimarySurface.cpp b/DDrawCompat/CompatPrimarySurface.cpp index 2085d11..2e35a97 100644 --- a/DDrawCompat/CompatPrimarySurface.cpp +++ b/DDrawCompat/CompatPrimarySurface.cpp @@ -41,6 +41,7 @@ namespace CompatPrimarySurface dm.width = desc.dwWidth; dm.height = desc.dwHeight; dm.pixelFormat = desc.ddpfPixelFormat; + dm.refreshRate = desc.dwRefreshRate; return dm; } @@ -50,6 +51,7 @@ namespace CompatPrimarySurface template DisplayMode getDisplayMode(IDirectDraw7& dd); DisplayMode displayMode = {}; + bool isDisplayModeChanged = false; IDirectDrawSurface7* surface = nullptr; LPDIRECTDRAWPALETTE palette = nullptr; PALETTEENTRY paletteEntries[256] = {}; diff --git a/DDrawCompat/CompatPrimarySurface.h b/DDrawCompat/CompatPrimarySurface.h index 4c1ee71..265c043 100644 --- a/DDrawCompat/CompatPrimarySurface.h +++ b/DDrawCompat/CompatPrimarySurface.h @@ -13,12 +13,14 @@ namespace CompatPrimarySurface LONG width; LONG height; DDPIXELFORMAT pixelFormat; + DWORD refreshRate; }; template DisplayMode getDisplayMode(TDirectDraw& dd); extern DisplayMode displayMode; + extern bool isDisplayModeChanged; extern IDirectDrawSurface7* surface; extern LPDIRECTDRAWPALETTE palette; extern PALETTEENTRY paletteEntries[256]; diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 2fdf64e..5166c04 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -144,6 +144,7 @@ + @@ -178,6 +179,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 53158a7..4a16f61 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -111,6 +111,9 @@ Header Files + + Header Files + @@ -191,6 +194,9 @@ Source Files + + Source Files + diff --git a/DDrawCompat/DDrawLog.cpp b/DDrawCompat/DDrawLog.cpp index b9cdce2..973882c 100644 --- a/DDrawCompat/DDrawLog.cpp +++ b/DDrawCompat/DDrawLog.cpp @@ -106,6 +106,12 @@ std::ostream& operator<<(std::ostream& os, const DDSURFACEDESC2& sd) sd.lpSurface << "," << sd.ddpfPixelFormat << "," << sd.ddsCaps << "," << sd.dwTextureStage << ')'; } +std::ostream& operator<<(std::ostream& os, const CWPSTRUCT& cwrp) +{ + return os << "CWP(" << std::hex << cwrp.message << "," << std::dec << cwrp.hwnd << "," << + std::hex << cwrp.wParam << "," << cwrp.lParam << std::dec << ")"; +} + std::ostream& operator<<(std::ostream& os, const CWPRETSTRUCT& cwrp) { return os << "CWRP(" << std::hex << cwrp.message << "," << std::dec << cwrp.hwnd << "," << diff --git a/DDrawCompat/DDrawLog.h b/DDrawCompat/DDrawLog.h index 108be79..41aac76 100644 --- a/DDrawCompat/DDrawLog.h +++ b/DDrawCompat/DDrawLog.h @@ -25,6 +25,7 @@ std::ostream& operator<<(std::ostream& os, const DDSCAPS2& caps); std::ostream& operator<<(std::ostream& os, const DDPIXELFORMAT& pf); std::ostream& operator<<(std::ostream& os, const DDSURFACEDESC& sd); std::ostream& operator<<(std::ostream& os, const DDSURFACEDESC2& sd); +std::ostream& operator<<(std::ostream& os, const CWPSTRUCT& cwrp); std::ostream& operator<<(std::ostream& os, const CWPRETSTRUCT& cwrp); template diff --git a/DDrawCompat/DllMain.cpp b/DDrawCompat/DllMain.cpp index db3878d..f8c32f2 100644 --- a/DDrawCompat/DllMain.cpp +++ b/DDrawCompat/DllMain.cpp @@ -5,6 +5,7 @@ #include #include +#include "CompatActivateAppHandler.h" #include "CompatDirectDraw.h" #include "CompatDirectDrawSurface.h" #include "CompatDirectDrawPalette.h" @@ -99,6 +100,7 @@ namespace hookDirectDraw(*dd); hookDirectDrawSurface(*dd); hookDirectDrawPalette(*dd); + CompatActivateAppHandler::installHooks(); Compat::Log() << "Installing GDI hooks"; CompatGdi::installHooks(); @@ -188,6 +190,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/) { Compat::Log() << "Detaching DDrawCompat"; RealPrimarySurface::removeUpdateThread(); + CompatActivateAppHandler::uninstallHooks(); CompatGdi::uninstallHooks(); Compat::unhookAllFunctions(); FreeLibrary(g_origDInputModule);