mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
parent
d5a89cad94
commit
ec9cf32e91
@ -22,10 +22,17 @@
|
||||
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||
#include <DDraw/Surfaces/TagSurface.h>
|
||||
#include <DDraw/Visitors/DirectDrawVtblVisitor.h>
|
||||
#include <Gdi/WinProc.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
#include <Win32/Thread.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
WNDPROC g_origDDrawWindowProc = nullptr;
|
||||
|
||||
LRESULT handleActivateApp(HWND hwnd, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc);
|
||||
LRESULT handleSize(HWND hwnd, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
template <typename TDirectDraw, typename TSurfaceDesc, typename TSurface>
|
||||
HRESULT STDMETHODCALLTYPE CreateSurface(
|
||||
TDirectDraw* This, TSurfaceDesc* lpDDSurfaceDesc, TSurface** lplpDDSurface, IUnknown* pUnkOuter)
|
||||
@ -156,6 +163,99 @@ namespace
|
||||
return getOrigVtable(This).WaitForVerticalBlank(This, dwFlags, hEvent);
|
||||
}
|
||||
|
||||
LRESULT WINAPI ddrawWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LOG_FUNC("ddrawWindowProc", hwnd, uMsg, wParam, lParam);
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_ACTIVATEAPP:
|
||||
return LOG_RESULT(handleActivateApp(hwnd, wParam, lParam, Gdi::WinProc::getDDrawOrigWndProc(hwnd)));
|
||||
case WM_SIZE:
|
||||
return LOG_RESULT(handleSize(hwnd, wParam, lParam));
|
||||
}
|
||||
return LOG_RESULT(g_origDDrawWindowProc(hwnd, uMsg, wParam, lParam));
|
||||
}
|
||||
|
||||
LRESULT handleActivateApp(HWND hwnd, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
||||
{
|
||||
LOG_FUNC("DirectDraw::handleActivateApp", hwnd, wParam, lParam, origWndProc);
|
||||
|
||||
if (origWndProc)
|
||||
{
|
||||
auto tagSurface = DDraw::TagSurface::findFullscreenWindow();
|
||||
if (tagSurface && tagSurface->getExclusiveOwnerThreadId() != GetCurrentThreadId())
|
||||
{
|
||||
if (!wParam)
|
||||
{
|
||||
ShowWindow(hwnd, SW_SHOWMINNOACTIVE);
|
||||
}
|
||||
return LOG_RESULT(CallWindowProcA(origWndProc, hwnd, WM_ACTIVATEAPP, wParam, lParam));
|
||||
}
|
||||
}
|
||||
|
||||
if (Config::Settings::AltTabFix::OFF == Config::altTabFix.get())
|
||||
{
|
||||
return LOG_RESULT(g_origDDrawWindowProc(hwnd, WM_ACTIVATEAPP, wParam, lParam));
|
||||
}
|
||||
|
||||
DDraw::ScopedThreadLock lock;
|
||||
const bool keepPrimary = Config::Settings::AltTabFix::KEEPVIDMEM == Config::altTabFix.get();
|
||||
std::set<DDRAWI_DDRAWSURFACE_LCL*> surfacesToRestore;
|
||||
DDraw::Surface::enumSurfaces([&](const DDraw::Surface& surface)
|
||||
{
|
||||
auto lcl = DDraw::DirectDrawSurface::getInt(*surface.getDDS()).lpLcl;
|
||||
if (!(lcl->dwFlags & DDRAWISURF_INVALID) &&
|
||||
(keepPrimary || !(surface.getOrigCaps() & DDSCAPS_PRIMARYSURFACE)))
|
||||
{
|
||||
lcl->dwFlags |= DDRAWISURF_INVALID;
|
||||
surfacesToRestore.insert(lcl);
|
||||
}
|
||||
});
|
||||
|
||||
LRESULT result = g_origDDrawWindowProc(hwnd, WM_ACTIVATEAPP, wParam, lParam);
|
||||
|
||||
DDraw::Surface::enumSurfaces([&](const DDraw::Surface& surface)
|
||||
{
|
||||
auto lcl = DDraw::DirectDrawSurface::getInt(*surface.getDDS()).lpLcl;
|
||||
auto it = surfacesToRestore.find(lcl);
|
||||
if (it != surfacesToRestore.end())
|
||||
{
|
||||
lcl->dwFlags &= ~DDRAWISURF_INVALID;
|
||||
surfacesToRestore.erase(it);
|
||||
}
|
||||
});
|
||||
|
||||
if (wParam && keepPrimary)
|
||||
{
|
||||
auto realPrimary(DDraw::RealPrimarySurface::getSurface());
|
||||
if (realPrimary)
|
||||
{
|
||||
realPrimary->Restore(realPrimary);
|
||||
auto gdiResource = DDraw::PrimarySurface::getGdiResource();
|
||||
if (gdiResource)
|
||||
{
|
||||
D3dDdi::Device::setGdiResourceHandle(gdiResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
LRESULT handleSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LOG_FUNC("DirectDraw::handleSize", hwnd, wParam, lParam);
|
||||
LRESULT result = 0;
|
||||
auto tagSurface = DDraw::TagSurface::findFullscreenWindow();
|
||||
if (tagSurface && tagSurface->getExclusiveOwnerThreadId() != GetCurrentThreadId())
|
||||
{
|
||||
Win32::Thread::skipWaitingForExclusiveModeMutex(true);
|
||||
}
|
||||
result = g_origDDrawWindowProc(hwnd, WM_SIZE, wParam, lParam);
|
||||
Win32::Thread::skipWaitingForExclusiveModeMutex(false);
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
template <typename Vtable>
|
||||
constexpr void setCompatVtable(Vtable& vtable)
|
||||
{
|
||||
@ -213,56 +313,19 @@ namespace DDraw
|
||||
return pf;
|
||||
}
|
||||
|
||||
LRESULT handleActivateApp(bool isActivated, std::function<LRESULT()> callOrigWndProc)
|
||||
void hookDDrawWindowProc(WNDPROC ddrawWndProc)
|
||||
{
|
||||
LOG_FUNC("handleActivateApp", isActivated, callOrigWndProc);
|
||||
if (Config::Settings::AltTabFix::OFF == Config::altTabFix.get())
|
||||
LOG_FUNC("DirectDraw::hookDDrawWindowProc", ddrawWndProc);
|
||||
static bool isHooked = false;
|
||||
if (isHooked)
|
||||
{
|
||||
return LOG_RESULT(callOrigWndProc());
|
||||
return;
|
||||
}
|
||||
isHooked = true;
|
||||
|
||||
DDraw::ScopedThreadLock lock;
|
||||
const bool keepPrimary = Config::Settings::AltTabFix::KEEPVIDMEM == Config::altTabFix.get();
|
||||
std::set<DDRAWI_DDRAWSURFACE_LCL*> surfacesToRestore;
|
||||
DDraw::Surface::enumSurfaces([&](const Surface& surface)
|
||||
{
|
||||
auto lcl = DDraw::DirectDrawSurface::getInt(*surface.getDDS()).lpLcl;
|
||||
if (!(lcl->dwFlags & DDRAWISURF_INVALID) &&
|
||||
(keepPrimary || !(surface.getOrigCaps() & DDSCAPS_PRIMARYSURFACE)))
|
||||
{
|
||||
lcl->dwFlags |= DDRAWISURF_INVALID;
|
||||
surfacesToRestore.insert(lcl);
|
||||
}
|
||||
});
|
||||
|
||||
LRESULT result = callOrigWndProc();
|
||||
|
||||
DDraw::Surface::enumSurfaces([&](const Surface& surface)
|
||||
{
|
||||
auto lcl = DDraw::DirectDrawSurface::getInt(*surface.getDDS()).lpLcl;
|
||||
auto it = surfacesToRestore.find(lcl);
|
||||
if (it != surfacesToRestore.end())
|
||||
{
|
||||
lcl->dwFlags &= ~DDRAWISURF_INVALID;
|
||||
surfacesToRestore.erase(it);
|
||||
}
|
||||
});
|
||||
|
||||
if (isActivated && keepPrimary)
|
||||
{
|
||||
auto realPrimary(DDraw::RealPrimarySurface::getSurface());
|
||||
if (realPrimary)
|
||||
{
|
||||
realPrimary->Restore(realPrimary);
|
||||
auto gdiResource = DDraw::PrimarySurface::getGdiResource();
|
||||
if (gdiResource)
|
||||
{
|
||||
D3dDdi::Device::setGdiResourceHandle(gdiResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return LOG_RESULT(result);
|
||||
g_origDDrawWindowProc = ddrawWndProc;
|
||||
Compat::hookFunction(reinterpret_cast<void*&>(g_origDDrawWindowProc), ddrawWindowProc, "ddrawWindowProc");
|
||||
Compat::closeDbgEng();
|
||||
}
|
||||
|
||||
void onCreate(GUID* guid, CompatRef<IDirectDraw7> dd)
|
||||
|
@ -13,7 +13,7 @@ namespace DDraw
|
||||
namespace DirectDraw
|
||||
{
|
||||
DDPIXELFORMAT getRgbPixelFormat(DWORD bpp);
|
||||
LRESULT handleActivateApp(bool isActivated, std::function<LRESULT()> callOrigWndProc);
|
||||
void hookDDrawWindowProc(WNDPROC ddrawWndProc);
|
||||
void onCreate(GUID* guid, CompatRef<IDirectDraw7> dd);
|
||||
void suppressEmulatedDirectDraw(GUID*& guid);
|
||||
|
||||
|
@ -14,6 +14,7 @@ namespace DDraw
|
||||
TagSurface::TagSurface(DWORD origFlags, DWORD origCaps, DDRAWI_DIRECTDRAW_LCL* ddLcl)
|
||||
: Surface(origFlags, origCaps)
|
||||
, m_ddInt{}
|
||||
, m_exclusiveOwnerThreadId(0)
|
||||
, m_fullscreenWindow(nullptr)
|
||||
, m_fullscreenWindowStyle(0)
|
||||
, m_fullscreenWindowExStyle(0)
|
||||
@ -100,6 +101,7 @@ namespace DDraw
|
||||
}
|
||||
HWND prevFullscreenWindow = m_fullscreenWindow;
|
||||
m_fullscreenWindow = hwnd;
|
||||
m_exclusiveOwnerThreadId = hwnd ? GetCurrentThreadId() : 0;
|
||||
|
||||
if (Config::removeBorders.get())
|
||||
{
|
||||
|
@ -19,6 +19,7 @@ namespace DDraw
|
||||
static TagSurface* findFullscreenWindow(HWND hwnd = nullptr);
|
||||
|
||||
CompatPtr<IDirectDraw7> getDD();
|
||||
DWORD getExclusiveOwnerThreadId() { return m_exclusiveOwnerThreadId; }
|
||||
bool isFullscreen() const { return m_fullscreenWindow; }
|
||||
void setFullscreenWindow(HWND hwnd);
|
||||
LONG setWindowStyle(LONG style);
|
||||
@ -28,6 +29,7 @@ namespace DDraw
|
||||
static HRESULT create(CompatRef<IDirectDraw> dd);
|
||||
|
||||
DDRAWI_DIRECTDRAW_INT m_ddInt;
|
||||
DWORD m_exclusiveOwnerThreadId;
|
||||
HWND m_fullscreenWindow;
|
||||
LONG m_fullscreenWindowStyle;
|
||||
LONG m_fullscreenWindowExStyle;
|
||||
|
@ -49,6 +49,7 @@ namespace
|
||||
{
|
||||
WNDPROC wndProcA;
|
||||
WNDPROC wndProcW;
|
||||
WNDPROC ddrawOrigWndProc;
|
||||
};
|
||||
|
||||
decltype(&DwmSetIconicThumbnail) g_dwmSetIconicThumbnail = nullptr;
|
||||
@ -175,17 +176,7 @@ namespace
|
||||
break;
|
||||
}
|
||||
|
||||
LRESULT result = 0;
|
||||
if (WM_ACTIVATEAPP == uMsg && Dll::g_origDDrawModule == Compat::getModuleHandleFromAddress(
|
||||
reinterpret_cast<void*>(GetWindowLongA(hwnd, GWL_WNDPROC))))
|
||||
{
|
||||
result = DDraw::DirectDraw::handleActivateApp(wParam, [=]() {
|
||||
return callWindowProc(wndProc, hwnd, uMsg, wParam, lParam); });
|
||||
}
|
||||
else
|
||||
{
|
||||
result = callWindowProc(wndProc, hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
LRESULT result = callWindowProc(wndProc, hwnd, uMsg, wParam, lParam);
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
@ -282,7 +273,18 @@ namespace
|
||||
LOG_FUNC("ddrawSetWindowLongA", hWnd, nIndex, dwNewLong);
|
||||
if (GWL_WNDPROC == nIndex)
|
||||
{
|
||||
return setWindowLongA(hWnd, GWL_WNDPROC, dwNewLong);
|
||||
auto origWndProc = setWindowLongA(hWnd, GWL_WNDPROC, dwNewLong);
|
||||
if (Dll::g_origDDrawModule == Compat::getModuleHandleFromAddress(reinterpret_cast<void*>(dwNewLong)))
|
||||
{
|
||||
Compat::ScopedSrwLockExclusive lock(g_windowProcSrwLock);
|
||||
auto it = g_windowProc.find(hWnd);
|
||||
if (it != g_windowProc.end())
|
||||
{
|
||||
it->second.ddrawOrigWndProc = reinterpret_cast<WNDPROC>(origWndProc);
|
||||
}
|
||||
DDraw::DirectDraw::hookDDrawWindowProc(reinterpret_cast<WNDPROC>(dwNewLong));
|
||||
}
|
||||
return origWndProc;
|
||||
}
|
||||
|
||||
if (GWL_STYLE == nIndex)
|
||||
@ -381,7 +383,7 @@ namespace
|
||||
{
|
||||
if (GWL_WNDPROC == nIndex)
|
||||
{
|
||||
Compat::ScopedSrwLockExclusive lock(g_windowProcSrwLock);
|
||||
Compat::ScopedSrwLockShared lock(g_windowProcSrwLock);
|
||||
auto it = g_windowProc.find(hWnd);
|
||||
if (it != g_windowProc.end())
|
||||
{
|
||||
@ -405,8 +407,9 @@ namespace
|
||||
|
||||
WindowProc getWindowProc(HWND hwnd)
|
||||
{
|
||||
Compat::ScopedSrwLockExclusive lock(g_windowProcSrwLock);
|
||||
return g_windowProc[hwnd];
|
||||
Compat::ScopedSrwLockShared lock(g_windowProcSrwLock);
|
||||
auto it = g_windowProc.find(hwnd);
|
||||
return it != g_windowProc.end() ? it->second : WindowProc{};
|
||||
}
|
||||
|
||||
std::wstring getWindowText(HWND hwnd, WNDPROC wndProc)
|
||||
@ -883,6 +886,13 @@ namespace Gdi
|
||||
}
|
||||
}
|
||||
|
||||
WNDPROC getDDrawOrigWndProc(HWND hwnd)
|
||||
{
|
||||
Compat::ScopedSrwLockShared lock(g_windowProcSrwLock);
|
||||
auto it = g_windowProc.find(hwnd);
|
||||
return it != g_windowProc.end() ? it->second.ddrawOrigWndProc : nullptr;
|
||||
}
|
||||
|
||||
void installHooks()
|
||||
{
|
||||
HOOK_FUNCTION(user32, AnimateWindow, animateWindow);
|
||||
|
@ -7,6 +7,7 @@ namespace Gdi
|
||||
namespace WinProc
|
||||
{
|
||||
void dllThreadDetach();
|
||||
WNDPROC getDDrawOrigWndProc(HWND hwnd);
|
||||
void installHooks();
|
||||
void onCreateWindow(HWND hwnd);
|
||||
void startFrame();
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <Common/Hook.h>
|
||||
#include <Common/Log.h>
|
||||
#include <Common/ScopedCriticalSection.h>
|
||||
#include <Common/Time.h>
|
||||
#include <Config/Settings/CpuAffinity.h>
|
||||
#include <Config/Settings/CpuAffinityRotation.h>
|
||||
@ -20,9 +21,33 @@ namespace
|
||||
bool g_cpuAffinityRotationEnabled = false;
|
||||
std::map<BYTE, BYTE> g_nextProcessor;
|
||||
|
||||
HANDLE g_exclusiveModeMutex = nullptr;
|
||||
thread_local bool g_skipWaitingForExclusiveModeMutex = false;
|
||||
|
||||
std::string maskToString(ULONG_PTR mask);
|
||||
void setNextProcessorSet(DWORD fromSet, DWORD toSet);
|
||||
|
||||
HANDLE WINAPI ddrawOpenMutexW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName)
|
||||
{
|
||||
LOG_FUNC("ddrawOpenMutexW", dwDesiredAccess, bInheritHandle, lpName);
|
||||
auto result = CALL_ORIG_FUNC(OpenMutexW)(dwDesiredAccess, bInheritHandle, lpName);
|
||||
if (SUCCEEDED(result) && lpName && 0 == lstrcmpW(lpName, L"Local\\__DDrawExclMode__"))
|
||||
{
|
||||
g_exclusiveModeMutex = result;
|
||||
}
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
DWORD WINAPI ddrawWaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
|
||||
{
|
||||
LOG_FUNC("ddrawWaitForSingleObject", hHandle, dwMilliseconds);
|
||||
if (hHandle && hHandle == g_exclusiveModeMutex && g_skipWaitingForExclusiveModeMutex)
|
||||
{
|
||||
return WAIT_OBJECT_0;
|
||||
}
|
||||
return LOG_RESULT(CALL_ORIG_FUNC(WaitForSingleObject)(hHandle, dwMilliseconds));
|
||||
}
|
||||
|
||||
std::map<BYTE, std::vector<DWORD>> getProcessorSets()
|
||||
{
|
||||
std::map<BYTE, std::vector<DWORD>> result;
|
||||
@ -280,6 +305,9 @@ namespace Win32
|
||||
HOOK_FUNCTION(kernel32, SetProcessAffinityMask, setProcessAffinityMask);
|
||||
HOOK_FUNCTION(kernel32, SetProcessPriorityBoost, setProcessPriorityBoost);
|
||||
HOOK_FUNCTION(kernel32, SetThreadPriorityBoost, setThreadPriorityBoost);
|
||||
|
||||
Compat::hookIatFunction(Dll::g_origDDrawModule, "OpenMutexW", ddrawOpenMutexW);
|
||||
Compat::hookIatFunction(Dll::g_origDDrawModule, "WaitForSingleObject", ddrawWaitForSingleObject);
|
||||
}
|
||||
|
||||
void rotateCpuAffinity()
|
||||
@ -303,5 +331,10 @@ namespace Win32
|
||||
LOG_ONCE("ERROR: Failed to set rotated CPU affinity: " << maskToString(g_cpuAffinity));
|
||||
}
|
||||
}
|
||||
|
||||
void skipWaitingForExclusiveModeMutex(bool skip)
|
||||
{
|
||||
g_skipWaitingForExclusiveModeMutex = skip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,5 +7,6 @@ namespace Win32
|
||||
void applyConfig();
|
||||
void installHooks();
|
||||
void rotateCpuAffinity();
|
||||
void skipWaitingForExclusiveModeMutex(bool skip);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user