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

Hook all GDI threads

This commit is contained in:
narzoul 2018-10-26 14:05:25 +02:00
parent 4717b9aa1b
commit 58aba66ca2
26 changed files with 334 additions and 261 deletions

View File

@ -6,6 +6,20 @@
namespace Compat
{
class CriticalSection : public CRITICAL_SECTION
{
public:
CriticalSection()
{
InitializeCriticalSection(this);
}
~CriticalSection()
{
DeleteCriticalSection(this);
}
};
class ScopedCriticalSection
{
public:

View File

@ -39,7 +39,7 @@ namespace
D3DKMT_HANDLE g_lastPresentContext = 0;
UINT g_presentCount = 0;
std::atomic<long long> g_qpcLastVerticalBlank = 0;
CRITICAL_SECTION g_vblankCs = {};
Compat::CriticalSection g_vblankCs;
decltype(D3DKMTCreateContextVirtual)* g_origD3dKmtCreateContextVirtual = nullptr;
@ -313,7 +313,6 @@ namespace D3dDdi
void installHooks()
{
InitializeCriticalSection(&g_vblankCs);
HOOK_FUNCTION(gdi32, D3DKMTCloseAdapter, closeAdapter);
HOOK_FUNCTION(gdi32, D3DKMTCreateContext, createContext);
HOOK_FUNCTION(gdi32, D3DKMTCreateDevice, createDevice);

View File

@ -3,7 +3,6 @@
#include "DDraw/ActivateAppHandler.h"
#include "DDraw/DirectDraw.h"
#include "DDraw/Repository.h"
#include "DDraw/Surfaces/TagSurface.h"
#include "DDraw/Surfaces/PrimarySurface.h"
#include "Win32/DisplayMode.h"
@ -182,15 +181,6 @@ namespace DDraw
HRESULT result = s_origVtable.SetCooperativeLevel(This, hWnd, dwFlags);
if (SUCCEEDED(result))
{
void* ddObject = getDdObject(*This);
TagSurface* tagSurface = TagSurface::get(ddObject);
if (!tagSurface)
{
CompatPtr<IDirectDraw> dd(Compat::queryInterface<IDirectDraw>(This));
TagSurface::create(*dd);
tagSurface = TagSurface::get(ddObject);
}
ActivateAppHandler::setCooperativeLevel(hWnd, dwFlags);
}
return result;

View File

@ -50,7 +50,11 @@ namespace
BOOL CALLBACK addVisibleLayeredWindowToVector(HWND hwnd, LPARAM lParam)
{
if (IsWindowVisible(hwnd) && (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) &&
DWORD windowPid = 0;
GetWindowThreadProcessId(hwnd, &windowPid);
if (GetCurrentProcessId() == windowPid &&
IsWindowVisible(hwnd) &&
(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) &&
!Gdi::Window::isPresentationWindow(hwnd))
{
auto& visibleLayeredWindows = *reinterpret_cast<std::vector<HWND>*>(lParam);
@ -119,8 +123,7 @@ namespace
void bltVisibleLayeredWindowsToBackBuffer()
{
std::vector<HWND> visibleLayeredWindows;
EnumThreadWindows(Gdi::getGdiThreadId(), addVisibleLayeredWindowToVector,
reinterpret_cast<LPARAM>(&visibleLayeredWindows));
EnumWindows(addVisibleLayeredWindowToVector, reinterpret_cast<LPARAM>(&visibleLayeredWindows));
if (visibleLayeredWindows.empty())
{

View File

@ -151,7 +151,6 @@ namespace DDraw
if (SUCCEEDED(result))
{
PrimarySurface::onRestore();
Gdi::redraw(nullptr);
}
}
}

View File

@ -1,48 +0,0 @@
#include <algorithm>
#include <map>
#include "DDraw/DirectDraw.h"
#include "DDraw/Repository.h"
#include "DDraw/Surfaces/TagSurface.h"
namespace
{
std::map<void*, DDraw::TagSurface*> g_tagSurfaces;
}
namespace DDraw
{
TagSurface::~TagSurface()
{
Repository::onRelease(m_ddObject);
g_tagSurfaces.erase(std::find_if(g_tagSurfaces.begin(), g_tagSurfaces.end(),
[=](auto& i) { return i.second == this; }));
}
HRESULT TagSurface::create(CompatRef<IDirectDraw> dd)
{
DDSURFACEDESC desc = {};
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
desc.dwWidth = 1;
desc.dwHeight = 1;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
IDirectDrawSurface* surface = nullptr;
HRESULT result = Surface::create(dd, desc, surface);
if (SUCCEEDED(result))
{
std::unique_ptr<Surface> privateData(new TagSurface());
g_tagSurfaces[getDdObject(dd.get())] = static_cast<TagSurface*>(privateData.get());
CompatPtr<IDirectDrawSurface7> surface7(Compat::queryInterface<IDirectDrawSurface7>(surface));
attach(*surface7, privateData);
}
return result;
}
TagSurface* TagSurface::get(void* ddObject)
{
auto it = g_tagSurfaces.find(ddObject);
return it != g_tagSurfaces.end() ? it->second : nullptr;
}
}

View File

@ -1,15 +0,0 @@
#pragma once
#include "DDraw/Surfaces/Surface.h"
namespace DDraw
{
class TagSurface : public Surface
{
public:
virtual ~TagSurface();
static HRESULT create(CompatRef<IDirectDraw> dd);
static TagSurface* get(void* ddObject);
};
}

View File

@ -188,7 +188,6 @@
<ClInclude Include="DDraw\Hooks.h" />
<ClInclude Include="DDraw\Repository.h" />
<ClInclude Include="DDraw\ScopedThreadLock.h" />
<ClInclude Include="DDraw\Surfaces\TagSurface.h" />
<ClInclude Include="DDraw\Surfaces\PrimarySurface.h" />
<ClInclude Include="DDraw\Surfaces\PrimarySurfaceImpl.h" />
<ClInclude Include="DDraw\Surfaces\Surface.h" />
@ -261,7 +260,6 @@
<ClCompile Include="DDraw\Repository.cpp" />
<ClCompile Include="DDraw\IReleaseNotifier.cpp" />
<ClCompile Include="DDraw\RealPrimarySurface.cpp" />
<ClCompile Include="DDraw\Surfaces\TagSurface.cpp" />
<ClCompile Include="DDraw\Surfaces\PrimarySurface.cpp" />
<ClCompile Include="DDraw\Surfaces\PrimarySurfaceImpl.cpp" />
<ClCompile Include="DDraw\Surfaces\Surface.cpp" />

View File

@ -255,9 +255,6 @@
<ClInclude Include="DDraw\Surfaces\PrimarySurfaceImpl.h">
<Filter>Header Files\DDraw\Surfaces</Filter>
</ClInclude>
<ClInclude Include="DDraw\Surfaces\TagSurface.h">
<Filter>Header Files\DDraw\Surfaces</Filter>
</ClInclude>
<ClInclude Include="Direct3d\Visitors\Direct3dViewportVtblVisitor.h">
<Filter>Header Files\Direct3d\Visitors</Filter>
</ClInclude>
@ -449,9 +446,6 @@
<ClCompile Include="DDraw\Surfaces\PrimarySurfaceImpl.cpp">
<Filter>Source Files\DDraw\Surfaces</Filter>
</ClCompile>
<ClCompile Include="DDraw\Surfaces\TagSurface.cpp">
<Filter>Source Files\DDraw\Surfaces</Filter>
</ClCompile>
<ClCompile Include="Direct3d\Direct3dViewport.cpp">
<Filter>Source Files\Direct3d</Filter>
</ClCompile>

View File

@ -84,7 +84,7 @@ namespace
#define LOAD_ORIGINAL_PROC(procName) \
Dll::g_origProcs.procName = Compat::getProcAddress(g_origDDrawModule, #procName);
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/)
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
@ -96,7 +96,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/)
char currentDllPath[MAX_PATH] = {};
GetModuleFileName(hinstDLL, currentDllPath, MAX_PATH);
Compat::Log() << "Loading DDrawCompat from " << currentDllPath;
Compat::Log() << "Loading DDrawCompat " << (lpvReserved ? "statically" : "dynamically")
<< " from " << currentDllPath;
char systemDirectory[MAX_PATH] = {};
GetSystemDirectory(systemDirectory, MAX_PATH);
@ -138,17 +139,24 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/)
}
else if (fdwReason == DLL_PROCESS_DETACH)
{
Compat::Log() << "Detaching DDrawCompat";
DDraw::uninstallHooks();
D3dDdi::uninstallHooks();
Gdi::uninstallHooks();
Compat::unhookAllFunctions();
FreeLibrary(g_origDInputModule);
FreeLibrary(g_origDDrawModule);
Compat::Log() << "Detaching DDrawCompat due to " << (lpvReserved ? "process termination" : "FreeLibrary");
if (!lpvReserved)
{
DDraw::uninstallHooks();
D3dDdi::uninstallHooks();
Gdi::uninstallHooks();
Compat::unhookAllFunctions();
FreeLibrary(g_origDInputModule);
FreeLibrary(g_origDDrawModule);
}
Win32::FontSmoothing::setSystemSettingsForced(Win32::FontSmoothing::g_origSystemSettings);
timeEndPeriod(1);
Compat::Log() << "DDrawCompat detached successfully";
}
else if (fdwReason == DLL_THREAD_DETACH)
{
Gdi::dllThreadDetach();
}
return TRUE;
}

View File

@ -25,7 +25,6 @@ namespace
bool isDrawn;
};
CaretData g_caret = {};
long long g_qpcLastBlink = 0;

View File

@ -18,14 +18,15 @@ namespace
HDC dc;
DWORD refCount;
HDC origDc;
DWORD threadId;
int savedState;
};
typedef std::unique_ptr<HDC__, void(*)(HDC)> OrigDc;
typedef std::unordered_map<HDC, CompatDc> CompatDcMap;
CompatDcMap g_origDcToCompatDc;
thread_local std::vector<OrigDc> g_threadDcs;
void restoreDc(const CompatDc& compatDc);
void copyDcAttributes(const CompatDc& compatDc, HDC origDc, const POINT& origin)
{
@ -79,13 +80,12 @@ namespace
MoveToEx(compatDc.dc, currentPos.x, currentPos.y, nullptr);
}
void deleteDc(HDC origDc)
void restoreDc(const CompatDc& compatDc)
{
DDraw::ScopedThreadLock lock;
auto it = g_origDcToCompatDc.find(origDc);
RestoreDC(it->second.dc, it->second.savedState);
Gdi::DcCache::deleteDc(it->second.dc);
g_origDcToCompatDc.erase(origDc);
// Bitmap may have changed during VirtualScreen::update, do not let RestoreDC restore the old one
HGDIOBJ bitmap = GetCurrentObject(compatDc.dc, OBJ_BITMAP);
RestoreDC(compatDc.dc, compatDc.savedState);
SelectObject(compatDc.dc, bitmap);
}
void setClippingRegion(HDC compatDc, HDC origDc, HWND hwnd, const POINT& origin)
@ -115,6 +115,37 @@ namespace Gdi
{
namespace Dc
{
void dllProcessDetach()
{
DDraw::ScopedThreadLock lock;
for (auto& origDcToCompatDc : g_origDcToCompatDc)
{
restoreDc(origDcToCompatDc.second);
Gdi::DcCache::deleteDc(origDcToCompatDc.second.dc);
}
g_origDcToCompatDc.clear();
}
void dllThreadDetach()
{
DDraw::ScopedThreadLock lock;
const DWORD threadId = GetCurrentThreadId();
auto it = g_origDcToCompatDc.begin();
while (it != g_origDcToCompatDc.end())
{
if (threadId == it->second.threadId)
{
restoreDc(it->second);
Gdi::DcCache::deleteDc(it->second.dc);
it = g_origDcToCompatDc.erase(it);
}
else
{
++it;
}
}
}
HDC getDc(HDC origDc)
{
if (!origDc || OBJ_DC != GetObjectType(origDc) || DT_RASDISPLAY != GetDeviceCaps(origDc, TECHNOLOGY))
@ -161,8 +192,8 @@ namespace Gdi
compatDc.refCount = 1;
compatDc.origDc = origDc;
compatDc.threadId = GetCurrentThreadId();
g_origDcToCompatDc.insert(CompatDcMap::value_type(origDc, compatDc));
g_threadDcs.emplace_back(origDc, &deleteDc);
return compatDc.dc;
}
@ -188,12 +219,7 @@ namespace Gdi
--compatDc.refCount;
if (0 == compatDc.refCount)
{
auto threadDcIter = std::find_if(g_threadDcs.begin(), g_threadDcs.end(),
[origDc](const OrigDc& dc) { return dc.get() == origDc; });
threadDcIter->release();
g_threadDcs.erase(threadDcIter);
RestoreDC(compatDc.dc, compatDc.savedState);
restoreDc(compatDc);
Gdi::DcCache::releaseDc(compatDc.dc);
g_origDcToCompatDc.erase(origDc);
}

View File

@ -8,6 +8,8 @@ namespace Gdi
{
namespace Dc
{
void dllProcessDetach();
void dllThreadDetach();
HDC getDc(HDC origDc);
HDC getOrigDc(HDC dc);
void releaseDc(HDC origDc);

View File

@ -1,14 +1,15 @@
#include <algorithm>
#include <map>
#include <memory>
#include <vector>
#include "DDraw/ScopedThreadLock.h"
#include "Gdi/DcCache.h"
#include "Gdi/VirtualScreen.h"
namespace
{
typedef std::unique_ptr<HDC__, void(*)(HDC)> CachedDc;
thread_local std::vector<CachedDc> g_cache;
std::map<DWORD, std::vector<HDC>> g_threadIdToDcCache;
}
namespace Gdi
@ -17,29 +18,69 @@ namespace Gdi
{
void deleteDc(HDC cachedDc)
{
Gdi::VirtualScreen::deleteDc(cachedDc);
DDraw::ScopedThreadLock lock;
for (auto& threadIdToDcCache : g_threadIdToDcCache)
{
auto& dcCache = threadIdToDcCache.second;
auto it = std::find(dcCache.begin(), dcCache.end(), cachedDc);
if (it != dcCache.end())
{
Gdi::VirtualScreen::deleteDc(*it);
dcCache.erase(it);
return;
}
}
}
void dllProcessDetach()
{
DDraw::ScopedThreadLock lock;
for (auto& threadIdToDcCache : g_threadIdToDcCache)
{
for (HDC dc : threadIdToDcCache.second)
{
Gdi::VirtualScreen::deleteDc(dc);
}
}
g_threadIdToDcCache.clear();
}
void dllThreadDetach()
{
DDraw::ScopedThreadLock lock;
auto it = g_threadIdToDcCache.find(GetCurrentThreadId());
if (it == g_threadIdToDcCache.end())
{
return;
}
for (HDC dc : it->second)
{
Gdi::VirtualScreen::deleteDc(dc);
}
g_threadIdToDcCache.erase(it);
}
HDC getDc()
{
HDC cachedDc = nullptr;
DDraw::ScopedThreadLock lock;
std::vector<HDC>& dcCache = g_threadIdToDcCache[GetCurrentThreadId()];
if (g_cache.empty())
if (dcCache.empty())
{
cachedDc = Gdi::VirtualScreen::createDc();
}
else
{
cachedDc = g_cache.back().release();
g_cache.pop_back();
return Gdi::VirtualScreen::createDc();
}
return cachedDc;
HDC dc = dcCache.back();
dcCache.pop_back();
return dc;
}
void releaseDc(HDC cachedDc)
{
g_cache.emplace_back(CachedDc(cachedDc, &deleteDc));
DDraw::ScopedThreadLock lock;
g_threadIdToDcCache[GetCurrentThreadId()].push_back(cachedDc);
}
}
}

View File

@ -9,6 +9,8 @@ namespace Gdi
namespace DcCache
{
void deleteDc(HDC cachedDc);
void dllProcessDetach();
void dllThreadDetach();
HDC getDc();
void releaseDc(HDC cachedDc);
}

View File

@ -13,6 +13,39 @@
namespace
{
class CompatDc
{
public:
CompatDc(HDC dc) : m_origDc(dc), m_compatDc(Gdi::Dc::getDc(dc))
{
}
CompatDc(const CompatDc&) = delete;
CompatDc(CompatDc&& other) : m_origDc(nullptr), m_compatDc(nullptr)
{
std::swap(m_origDc, other.m_origDc);
std::swap(m_compatDc, other.m_compatDc);
}
~CompatDc()
{
if (m_compatDc)
{
Gdi::Dc::releaseDc(m_origDc);
}
}
operator HDC() const
{
return m_compatDc ? m_compatDc : m_origDc;
}
private:
HDC m_origDc;
HDC m_compatDc;
};
struct ExcludeRgnForOverlappingWindowArgs
{
HRGN rgn;
@ -56,25 +89,9 @@ namespace
return t;
}
HDC replaceDc(HDC dc)
CompatDc replaceDc(HDC dc)
{
HDC compatDc = Gdi::Dc::getDc(dc);
return compatDc ? compatDc : dc;
}
template <typename T>
void releaseDc(T) {}
void releaseDc(HDC dc)
{
Gdi::Dc::releaseDc(dc);
}
template <typename T, typename... Params>
void releaseDc(T t, Params... params)
{
releaseDc(params...);
releaseDc(t);
return CompatDc(dc);
}
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
@ -90,7 +107,6 @@ namespace
const bool isReadOnlyAccess = !hasDisplayDcArg(getDestinationDc<OrigFuncPtr, origFunc>(params...));
Gdi::GdiAccessGuard accessGuard(isReadOnlyAccess ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE);
result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...);
releaseDc(params...);
}
else
{
@ -135,7 +151,6 @@ namespace
{
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
result = CALL_ORIG_FUNC(ExtTextOutW)(replaceDc(hdc), x, y, options, lprect, lpString, c, lpDx);
releaseDc(hdc);
}
}
else
@ -155,7 +170,10 @@ namespace
return FALSE;
}
if (!IsWindowVisible(hwnd) ||
DWORD windowPid = 0;
GetWindowThreadProcessId(hwnd, &windowPid);
if (GetCurrentProcessId() != windowPid ||
!IsWindowVisible(hwnd) ||
(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & (WS_EX_LAYERED | WS_EX_TRANSPARENT)))
{
return TRUE;
@ -248,8 +266,7 @@ namespace
}
ExcludeRgnForOverlappingWindowArgs args = { hrgn, GetAncestor(hwnd, GA_ROOT) };
EnumThreadWindows(Gdi::getGdiThreadId(), excludeRgnForOverlappingWindow,
reinterpret_cast<LPARAM>(&args));
EnumWindows(excludeRgnForOverlappingWindow, reinterpret_cast<LPARAM>(&args));
return 1;
}
@ -282,8 +299,7 @@ namespace Gdi
{
HRGN rgn = getWindowRegion(hwnd);
ExcludeRgnForOverlappingWindowArgs args = { rgn, hwnd };
EnumThreadWindows(Gdi::getGdiThreadId(), excludeRgnForOverlappingWindow,
reinterpret_cast<LPARAM>(&args));
EnumWindows(excludeRgnForOverlappingWindow, reinterpret_cast<LPARAM>(&args));
return rgn;
}

View File

@ -1,5 +1,7 @@
#include "DDraw/Surfaces/PrimarySurface.h"
#include "Gdi/Caret.h"
#include "Gdi/Dc.h"
#include "Gdi/DcCache.h"
#include "Gdi/DcFunctions.h"
#include "Gdi/Gdi.h"
#include "Gdi/PaintHandlers.h"
@ -9,21 +11,27 @@
namespace
{
DWORD g_gdiThreadId = 0;
HDC g_screenDc = nullptr;
BOOL CALLBACK redrawWindowCallback(HWND hwnd, LPARAM lParam)
{
Gdi::redrawWindow(hwnd, reinterpret_cast<HRGN>(lParam));
DWORD windowPid = 0;
GetWindowThreadProcessId(hwnd, &windowPid);
if (GetCurrentProcessId() == windowPid)
{
Gdi::redrawWindow(hwnd, reinterpret_cast<HRGN>(lParam));
}
return TRUE;
}
}
namespace Gdi
{
DWORD getGdiThreadId()
void dllThreadDetach()
{
return g_gdiThreadId;
WinProc::dllThreadDetach();
Dc::dllThreadDetach();
DcCache::dllThreadDetach();
}
HDC getScreenDc()
@ -38,19 +46,18 @@ namespace Gdi
void installHooks()
{
g_gdiThreadId = GetCurrentThreadId();
g_screenDc = GetDC(nullptr);
Gdi::DcFunctions::installHooks();
Gdi::PaintHandlers::installHooks();
Gdi::ScrollFunctions::installHooks();
Gdi::WinProc::installHooks();
Gdi::Caret::installHooks();
DcFunctions::installHooks();
PaintHandlers::installHooks();
ScrollFunctions::installHooks();
WinProc::installHooks();
Caret::installHooks();
}
void redraw(HRGN rgn)
{
EnumThreadWindows(g_gdiThreadId, &redrawWindowCallback, reinterpret_cast<LPARAM>(rgn));
EnumWindows(&redrawWindowCallback, reinterpret_cast<LPARAM>(rgn));
}
void redrawWindow(HWND hwnd, HRGN rgn)
@ -68,7 +75,6 @@ namespace Gdi
}
RedrawWindow(hwnd, nullptr, rgn, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
RedrawWindow(hwnd, nullptr, rgn, RDW_ERASENOW);
if (rgn)
{
@ -85,9 +91,10 @@ namespace Gdi
void uninstallHooks()
{
Gdi::Caret::uninstallHooks();
Gdi::WinProc::uninstallHooks();
Gdi::PaintHandlers::uninstallHooks();
Caret::uninstallHooks();
WinProc::uninstallHooks();
Dc::dllProcessDetach();
DcCache::dllProcessDetach();
ReleaseDC(nullptr, g_screenDc);
}

View File

@ -10,7 +10,7 @@ namespace Gdi
typedef void(*WindowPosChangeNotifyFunc)();
DWORD getGdiThreadId();
void dllThreadDetach();
HDC getScreenDc();
HRGN getVisibleWindowRgn(HWND hwnd);
void installHooks();

View File

@ -41,7 +41,6 @@ namespace
LRESULT onPaint(HWND hwnd, WNDPROC origWndProc);
LRESULT onPrint(HWND hwnd, UINT msg, HDC dc, LONG flags, WNDPROC origWndProc);
HHOOK g_cbtProcHook = nullptr;
int g_menuWndProcIndex = 0;
int g_scrollBarWndProcIndex = 0;
@ -71,52 +70,6 @@ namespace
}
}
LRESULT CALLBACK cbtProc(int nCode, WPARAM wParam, LPARAM lParam)
{
Compat::LogEnter("cbtProc", Compat::hex(nCode), Compat::hex(wParam), Compat::hex(lParam));
LRESULT result = 0;
if (nCode < 0)
{
result = CallNextHookEx(nullptr, nCode, wParam, lParam);
}
else if (HCBT_CREATEWND == nCode)
{
HWND hwnd = reinterpret_cast<HWND>(wParam);
WNDPROC wndProcA = reinterpret_cast<WNDPROC>(GetWindowLongA(hwnd, GWL_WNDPROC));
WNDPROC wndProcW = reinterpret_cast<WNDPROC>(GetWindowLongW(hwnd, GWL_WNDPROC));
int index = -1;
if (wndProcA == g_user32WndProcA[g_menuWndProcIndex].oldWndProc ||
wndProcW == g_user32WndProcW[g_menuWndProcIndex].oldWndProc)
{
index = g_menuWndProcIndex;
}
else if (wndProcA == g_user32WndProcA[g_scrollBarWndProcIndex].oldWndProc ||
wndProcW == g_user32WndProcW[g_scrollBarWndProcIndex].oldWndProc)
{
index = g_scrollBarWndProcIndex;
}
if (-1 != index)
{
if (IsWindowUnicode(hwnd))
{
CALL_ORIG_FUNC(SetWindowLongW)(hwnd, GWL_WNDPROC,
reinterpret_cast<LONG>(g_user32WndProcW[index].newWndProc));
}
else
{
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC,
reinterpret_cast<LONG>(g_user32WndProcA[index].newWndProc));
}
}
}
Compat::LogLeave("cbtProc", Compat::hex(nCode), Compat::hex(wParam), Compat::hex(lParam)) << result;
return result;
}
LRESULT comboBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
{
return defPaintProc(hwnd, msg, wParam, lParam, origWndProc);
@ -481,13 +434,38 @@ namespace Gdi
HOOK_FUNCTION(user32, DefWindowProcW, defWindowProcW);
HOOK_FUNCTION(user32, DefDlgProcA, defDlgProcA);
HOOK_FUNCTION(user32, DefDlgProcW, defDlgProcW);
g_cbtProcHook = SetWindowsHookEx(WH_CBT, cbtProc, nullptr, Gdi::getGdiThreadId());
}
void uninstallHooks()
void onCreateWindow(HWND hwnd)
{
UnhookWindowsHookEx(g_cbtProcHook);
WNDPROC wndProcA = reinterpret_cast<WNDPROC>(GetWindowLongA(hwnd, GWL_WNDPROC));
WNDPROC wndProcW = reinterpret_cast<WNDPROC>(GetWindowLongW(hwnd, GWL_WNDPROC));
int index = -1;
if (wndProcA == g_user32WndProcA[g_menuWndProcIndex].oldWndProc ||
wndProcW == g_user32WndProcW[g_menuWndProcIndex].oldWndProc)
{
index = g_menuWndProcIndex;
}
else if (wndProcA == g_user32WndProcA[g_scrollBarWndProcIndex].oldWndProc ||
wndProcW == g_user32WndProcW[g_scrollBarWndProcIndex].oldWndProc)
{
index = g_scrollBarWndProcIndex;
}
if (-1 != index)
{
if (IsWindowUnicode(hwnd))
{
CALL_ORIG_FUNC(SetWindowLongW)(hwnd, GWL_WNDPROC,
reinterpret_cast<LONG>(g_user32WndProcW[index].newWndProc));
}
else
{
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC,
reinterpret_cast<LONG>(g_user32WndProcA[index].newWndProc));
}
}
}
}
}

View File

@ -5,6 +5,6 @@ namespace Gdi
namespace PaintHandlers
{
void installHooks();
void uninstallHooks();
void onCreateWindow(HWND hwnd);
}
}

View File

@ -1,8 +1,8 @@
#include <set>
#include "Common/ScopedCriticalSection.h"
#include "DDraw/DirectDraw.h"
#include "DDraw/Repository.h"
#include "DDraw/ScopedThreadLock.h"
#include "Gdi/Gdi.h"
#include "Gdi/Region.h"
#include "Gdi/VirtualScreen.h"
@ -10,7 +10,6 @@
namespace
{
CRITICAL_SECTION g_cs = {};
Gdi::Region g_region;
RECT g_bounds = {};
DWORD g_bpp = 0;
@ -71,7 +70,7 @@ namespace Gdi
{
HDC createDc()
{
Compat::ScopedCriticalSection lock(g_cs);
DDraw::ScopedThreadLock lock;
std::unique_ptr<void, decltype(&DeleteObject)> dib(createDib(), DeleteObject);
if (!dib)
{
@ -100,7 +99,7 @@ namespace Gdi
HBITMAP createDib()
{
Compat::ScopedCriticalSection lock(g_cs);
DDraw::ScopedThreadLock lock;
if (!g_surfaceFileMapping)
{
return nullptr;
@ -110,7 +109,7 @@ namespace Gdi
HBITMAP createOffScreenDib(DWORD width, DWORD height)
{
Compat::ScopedCriticalSection lock(g_cs);
DDraw::ScopedThreadLock lock;
return createDibSection(width, height, nullptr);
}
@ -122,7 +121,7 @@ namespace Gdi
return nullptr;
}
Compat::ScopedCriticalSection lock(g_cs);
DDraw::ScopedThreadLock lock;
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH | DDSD_LPSURFACE;
@ -148,7 +147,7 @@ namespace Gdi
return;
}
Compat::ScopedCriticalSection lock(g_cs);
DDraw::ScopedThreadLock lock;
DeleteObject(SelectObject(dc, g_stockBitmap));
DeleteDC(dc);
g_dcs.erase(dc);
@ -156,19 +155,18 @@ namespace Gdi
RECT getBounds()
{
Compat::ScopedCriticalSection lock(g_cs);
DDraw::ScopedThreadLock lock;
return g_bounds;
}
const Region& getRegion()
{
Compat::ScopedCriticalSection lock(g_cs);
DDraw::ScopedThreadLock lock;
return g_region;
}
void init()
{
InitializeCriticalSection(&g_cs);
update();
updatePalette();
}
@ -176,7 +174,7 @@ namespace Gdi
bool update()
{
Compat::LogEnter("VirtualScreen::update");
Compat::ScopedCriticalSection lock(g_cs);
DDraw::ScopedThreadLock lock;
static auto prevDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness() - 1;
const auto currentDisplaySettingsUniqueness = Win32::DisplayMode::queryDisplaySettingsUniqueness();
@ -224,7 +222,7 @@ namespace Gdi
void updatePalette()
{
Compat::ScopedCriticalSection lock(g_cs);
DDraw::ScopedThreadLock lock;
if (8 != g_bpp)
{
return;

View File

@ -1,7 +1,6 @@
#define WIN32_LEAN_AND_MEAN
#include <map>
#include <memory>
#include <set>
#include <dwmapi.h>
@ -11,15 +10,20 @@
#include "Common/ScopedCriticalSection.h"
#include "Gdi/AccessGuard.h"
#include "Gdi/Dc.h"
#include "Gdi/PaintHandlers.h"
#include "Gdi/ScrollBar.h"
#include "Gdi/ScrollFunctions.h"
#include "Gdi/TitleBar.h"
#include "Gdi/Window.h"
#include "Gdi/WinProc.h"
extern "C" IMAGE_DOS_HEADER __ImageBase;
namespace
{
HHOOK g_callWndRetProcHook = nullptr;
std::multimap<DWORD, HHOOK> g_threadIdToHook;
Compat::CriticalSection g_threadIdToHookCs;
HWINEVENTHOOK g_objectCreateEventHook = nullptr;
HWINEVENTHOOK g_objectStateChangeEventHook = nullptr;
std::set<Gdi::WindowPosChangeNotifyFunc> g_windowPosChangeNotifyFuncs;
@ -35,13 +39,9 @@ namespace
auto ret = reinterpret_cast<CWPRETSTRUCT*>(lParam);
Compat::LogEnter("callWndRetProc", Compat::hex(nCode), Compat::hex(wParam), ret);
if (HC_ACTION == nCode)
if (HC_ACTION == nCode && !Gdi::Window::isPresentationWindow(ret->hwnd))
{
if (WM_CREATE == ret->message)
{
onCreateWindow(ret->hwnd);
}
else if (WM_DESTROY == ret->message)
if (WM_DESTROY == ret->message)
{
onDestroyWindow(ret->hwnd);
}
@ -79,8 +79,25 @@ namespace
&disableTransitions, sizeof(disableTransitions));
}
void hookThread(DWORD threadId)
{
Compat::ScopedCriticalSection lock(g_threadIdToHookCs);
if (g_threadIdToHook.end() == g_threadIdToHook.find(threadId))
{
g_threadIdToHook.emplace(threadId,
SetWindowsHookEx(WH_CALLWNDPROCRET, callWndRetProc, nullptr, threadId));
}
}
BOOL CALLBACK initTopLevelWindow(HWND hwnd, LPARAM /*lParam*/)
{
DWORD windowPid = 0;
GetWindowThreadProcessId(hwnd, &windowPid);
if (GetCurrentProcessId() != windowPid)
{
return TRUE;
}
onCreateWindow(hwnd);
if (!(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED))
{
@ -90,6 +107,21 @@ namespace
return TRUE;
}
void CALLBACK objectCreateEvent(
HWINEVENTHOOK /*hWinEventHook*/,
DWORD /*event*/,
HWND hwnd,
LONG idObject,
LONG /*idChild*/,
DWORD /*dwEventThread*/,
DWORD /*dwmsEventTime*/)
{
if (OBJID_WINDOW == idObject && !Gdi::Window::isPresentationWindow(hwnd))
{
onCreateWindow(hwnd);
}
}
void CALLBACK objectStateChangeEvent(
HWINEVENTHOOK /*hWinEventHook*/,
DWORD /*event*/,
@ -149,9 +181,14 @@ namespace
void onCreateWindow(HWND hwnd)
{
hookThread(GetWindowThreadProcessId(hwnd, nullptr));
disableDwmAttributes(hwnd);
removeDropShadow(hwnd);
Gdi::Window::add(hwnd);
Gdi::PaintHandlers::onCreateWindow(hwnd);
if (Gdi::Window::isTopLevelNonLayeredWindow(hwnd))
{
Gdi::Window::add(hwnd);
}
}
void onDestroyWindow(HWND hwnd)
@ -191,14 +228,30 @@ namespace Gdi
{
namespace WinProc
{
void dllThreadDetach()
{
Compat::ScopedCriticalSection lock(g_threadIdToHookCs);
const DWORD threadId = GetCurrentThreadId();
for (auto threadIdToHook : g_threadIdToHook)
{
if (threadId == threadIdToHook.first)
{
UnhookWindowsHookEx(threadIdToHook.second);
}
}
g_threadIdToHook.erase(threadId);
}
void installHooks()
{
const DWORD threadId = Gdi::getGdiThreadId();
g_callWndRetProcHook = SetWindowsHookEx(WH_CALLWNDPROCRET, callWndRetProc, nullptr, threadId);
g_objectCreateEventHook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE,
reinterpret_cast<HMODULE>(&__ImageBase), &objectCreateEvent,
GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
g_objectStateChangeEventHook = SetWinEventHook(EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_STATECHANGE,
nullptr, &objectStateChangeEvent, 0, threadId, WINEVENT_OUTOFCONTEXT);
reinterpret_cast<HMODULE>(&__ImageBase), &objectStateChangeEvent,
GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
EnumThreadWindows(threadId, initTopLevelWindow, 0);
EnumWindows(initTopLevelWindow, 0);
}
void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc)
@ -209,7 +262,16 @@ namespace Gdi
void uninstallHooks()
{
UnhookWinEvent(g_objectStateChangeEventHook);
UnhookWindowsHookEx(g_callWndRetProcHook);
UnhookWinEvent(g_objectCreateEventHook);
{
Compat::ScopedCriticalSection lock(g_threadIdToHookCs);
for (auto threadIdToHook : g_threadIdToHook)
{
UnhookWindowsHookEx(threadIdToHook.second);
}
g_threadIdToHook.clear();
}
}
}
}

View File

@ -6,6 +6,7 @@ namespace Gdi
{
namespace WinProc
{
void dllThreadDetach();
void installHooks();
void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc);
void uninstallHooks();

View File

@ -66,13 +66,9 @@ namespace Gdi
bool Window::add(HWND hwnd)
{
const bool isTopLevelNonLayeredWindow = !(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) &&
(!(GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CHILD) || GetParent(hwnd) == GetDesktopWindow() ||
getComboLBoxAtom() == GetClassLong(hwnd, GCW_ATOM));
if (isTopLevelNonLayeredWindow && !get(hwnd) &&
GetClassLong(hwnd, GCW_ATOM) != getPresentationWindowClassAtom())
if (isTopLevelNonLayeredWindow(hwnd) && !get(hwnd))
{
DDraw::ScopedThreadLock lock;
s_windows.emplace(hwnd, std::make_shared<Window>(hwnd));
return true;
}
@ -143,7 +139,14 @@ namespace Gdi
bool Window::isPresentationWindow(HWND hwnd)
{
return GetClassLong(hwnd, GCW_ATOM) == getPresentationWindowClassAtom();
return IsWindow(hwnd) && GetClassLong(hwnd, GCW_ATOM) == getPresentationWindowClassAtom();
}
bool Window::isTopLevelNonLayeredWindow(HWND hwnd)
{
return !(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) &&
(!(GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CHILD) || GetParent(hwnd) == GetDesktopWindow() ||
getComboLBoxAtom() == GetClassLong(hwnd, GCW_ATOM));
}
void Window::remove(HWND hwnd)
@ -175,14 +178,14 @@ namespace Gdi
newVisibleRegion &= VirtualScreen::getRegion();
}
if (m_presentationWindow)
if (m_presentationWindow && GetCurrentThreadId() == GetWindowThreadProcessId(m_hwnd, nullptr))
{
SetWindowPos(m_presentationWindow, nullptr, newWindowRect.left, newWindowRect.top,
newWindowRect.right - newWindowRect.left, newWindowRect.bottom - newWindowRect.top,
SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW);
}
}
else if (m_presentationWindow)
else if (m_presentationWindow && GetCurrentThreadId() == GetWindowThreadProcessId(m_hwnd, nullptr))
{
ShowWindow(m_presentationWindow, SW_HIDE);
}

View File

@ -29,6 +29,7 @@ namespace Gdi
static std::map<HWND, std::shared_ptr<Window>> getWindows();
static bool isPresentationWindow(HWND hwnd);
static bool isTopLevelNonLayeredWindow(HWND hwnd);
static void updateAll();
private:

View File

@ -4,7 +4,7 @@
#include "Common/CompatPtr.h"
#include "Common/Hook.h"
#include "DDraw/DirectDraw.h"
#include "DDraw/RealPrimarySurface.h"
#include "DDraw/ScopedThreadLock.h"
#include "Win32/DisplayMode.h"
BOOL WINAPI DWM8And16Bit_IsShimApplied_CallOut() { return FALSE; };
@ -48,12 +48,12 @@ namespace
EnumDisplaySettingsExFunc origEnumDisplaySettingsEx,
CStr lpszDeviceName, DevMode* lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam)
{
DDraw::ScopedThreadLock lock;
DevMode prevDevMode = {};
if (!(dwflags & CDS_TEST))
{
prevDevMode.dmSize = sizeof(prevDevMode);
origEnumDisplaySettingsEx(lpszDeviceName, ENUM_CURRENT_SETTINGS, &prevDevMode, 0);
DDraw::RealPrimarySurface::disableUpdates();
}
BOOL result = FALSE;
@ -99,11 +99,6 @@ namespace
}
}
if (!(dwflags & CDS_TEST))
{
DDraw::RealPrimarySurface::enableUpdates();
}
return result;
}