1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00
2022-09-27 21:45:14 +02:00

664 lines
18 KiB
C++

#include <map>
#include <set>
#include <Windows.h>
#include <Common/Hook.h>
#include <Common/Log.h>
#include <Common/ScopedSrwLock.h>
#include <Config/Config.h>
#include <Dll/Dll.h>
#include <DDraw/DirectDraw.h>
#include <DDraw/RealPrimarySurface.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <DDraw/Surfaces/TagSurface.h>
#include <Gdi/CompatDc.h>
#include <Gdi/Cursor.h>
#include <Gdi/Dc.h>
#include <Gdi/Gdi.h>
#include <Gdi/GuiThread.h>
#include <Gdi/PresentationWindow.h>
#include <Gdi/ScrollBar.h>
#include <Gdi/ScrollFunctions.h>
#include <Gdi/TitleBar.h>
#include <Gdi/Window.h>
#include <Gdi/WinProc.h>
#include <Overlay/ConfigWindow.h>
#include <Win32/DisplayMode.h>
namespace
{
struct WindowProc
{
WNDPROC wndProcA;
WNDPROC wndProcW;
};
std::map<HMENU, UINT> g_menuMaxHeight;
std::set<Gdi::WindowPosChangeNotifyFunc> g_windowPosChangeNotifyFuncs;
Compat::SrwLock g_windowProcSrwLock;
std::map<HWND, WindowProc> g_windowProc;
thread_local unsigned g_inCreateDialog = 0;
thread_local unsigned g_inMessageBox = 0;
WindowProc getWindowProc(HWND hwnd);
bool isUser32ScrollBar(HWND hwnd);
void onDestroyWindow(HWND hwnd);
void onGetMinMaxInfo(MINMAXINFO& mmi);
void onInitDialog(HWND hwnd);
void onInitMenuPopup(HMENU menu);
void onUninitMenuPopup(HMENU menu);
void onWindowPosChanged(HWND hwnd, const WINDOWPOS& wp);
void onWindowPosChanging(HWND hwnd, WINDOWPOS& wp);
void setWindowProc(HWND hwnd, WNDPROC wndProcA, WNDPROC wndProcW);
template <auto func, typename Result, typename... Params>
Result WINAPI createDialog(Params... params)
{
LOG_FUNC(Compat::g_origFuncName<func>.c_str(), params...);
++g_inCreateDialog;
Result result = CALL_ORIG_FUNC(func)(params...);
--g_inCreateDialog;
return LOG_RESULT(result);
}
LRESULT CALLBACK ddcWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
decltype(&CallWindowProcA) callWindowProc, WNDPROC wndProc)
{
LOG_FUNC("ddcWindowProc", Compat::WindowMessageStruct(hwnd, uMsg, wParam, lParam));
switch (uMsg)
{
case WM_DISPLAYCHANGE:
if (0 != wParam)
{
return 0;
}
wParam = Win32::DisplayMode::getBpp();
break;
case WM_DWMCOMPOSITIONCHANGED:
Gdi::checkDesktopComposition();
break;
case WM_GETMINMAXINFO:
onGetMinMaxInfo(*reinterpret_cast<MINMAXINFO*>(lParam));
break;
case WM_INITDIALOG:
onInitDialog(hwnd);
break;
case WM_SYNCPAINT:
if (Gdi::Window::isTopLevelWindow(hwnd))
{
Gdi::Window::onSyncPaint(hwnd);
return 0;
}
break;
case WM_UNINITMENUPOPUP:
onUninitMenuPopup(reinterpret_cast<HMENU>(wParam));
break;
case WM_WINDOWPOSCHANGED:
onWindowPosChanged(hwnd, *reinterpret_cast<WINDOWPOS*>(lParam));
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);
}
switch (uMsg)
{
case WM_ACTIVATEAPP:
if (!wParam)
{
Gdi::GuiThread::execute([&]()
{
auto configWindow = Gdi::GuiThread::getConfigWindow();
if (configWindow)
{
configWindow->setVisible(false);
}
CALL_ORIG_FUNC(ClipCursor)(nullptr);
});
}
break;
case WM_CTLCOLORSCROLLBAR:
if (reinterpret_cast<HWND>(lParam) != hwnd &&
isUser32ScrollBar(reinterpret_cast<HWND>(lParam)))
{
Gdi::ScrollBar::onCtlColorScrollBar(hwnd, wParam, lParam, result);
}
break;
case WM_INITMENUPOPUP:
onInitMenuPopup(reinterpret_cast<HMENU>(wParam));
break;
case WM_NCDESTROY:
onDestroyWindow(hwnd);
break;
case WM_STYLECHANGED:
if (Gdi::Window::isTopLevelWindow(hwnd))
{
Gdi::Window::onStyleChanged(hwnd, wParam);
}
break;
case WM_WINDOWPOSCHANGING:
onWindowPosChanging(hwnd, *reinterpret_cast<WINDOWPOS*>(lParam));
break;
}
return LOG_RESULT(result);
}
LRESULT CALLBACK ddcWindowProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return ddcWindowProc(hwnd, uMsg, wParam, lParam, CallWindowProcA, getWindowProc(hwnd).wndProcA);
}
LRESULT CALLBACK ddcWindowProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return ddcWindowProc(hwnd, uMsg, wParam, lParam, CallWindowProcW, getWindowProc(hwnd).wndProcW);
}
BOOL WINAPI getMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
decltype(&GetMessageA) origGetMessage)
{
DDraw::RealPrimarySurface::setUpdateReady();
return origGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
}
BOOL WINAPI getMessageA(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax)
{
return getMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, CALL_ORIG_FUNC(GetMessageA));
}
BOOL WINAPI getMessageW(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax)
{
return getMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, CALL_ORIG_FUNC(GetMessageW));
}
LONG getWindowLong(HWND hWnd, int nIndex,
decltype(&GetWindowLongA) origGetWindowLong, WNDPROC(WindowProc::* wndProc))
{
if (GWL_WNDPROC == nIndex)
{
Compat::ScopedSrwLockExclusive lock(g_windowProcSrwLock);
auto it = g_windowProc.find(hWnd);
if (it != g_windowProc.end())
{
return reinterpret_cast<LONG>(it->second.*wndProc);
}
}
return origGetWindowLong(hWnd, nIndex);
}
LONG WINAPI getWindowLongA(HWND hWnd, int nIndex)
{
LOG_FUNC("GetWindowLongA", hWnd, nIndex);
return LOG_RESULT(getWindowLong(hWnd, nIndex, CALL_ORIG_FUNC(GetWindowLongA), &WindowProc::wndProcA));
}
LONG WINAPI getWindowLongW(HWND hWnd, int nIndex)
{
LOG_FUNC("GetWindowLongW", hWnd, nIndex);
return LOG_RESULT(getWindowLong(hWnd, nIndex, CALL_ORIG_FUNC(GetWindowLongW), &WindowProc::wndProcW));
}
WindowProc getWindowProc(HWND hwnd)
{
Compat::ScopedSrwLockExclusive lock(g_windowProcSrwLock);
return g_windowProc[hwnd];
}
template <auto func, typename... Params>
int WINAPI messageBox(Params... params)
{
LOG_FUNC(Compat::g_origFuncName<func>.c_str(), params...);
++g_inMessageBox;
int result = CALL_ORIG_FUNC(func)(params...);
--g_inMessageBox;
return LOG_RESULT(result);
}
void onInitDialog(HWND hwnd)
{
if (!Gdi::Window::isTopLevelWindow(hwnd) ||
0 == g_inMessageBox &&
(0 == g_inCreateDialog || !(CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_STYLE) & DS_CENTER)))
{
return;
}
HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
MONITORINFO origMi = {};
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 = {};
GetWindowRect(hwnd, &wr);
const LONG width = wr.right - wr.left;
const LONG height = wr.bottom - wr.top;
const RECT& mr = 0 == g_inMessageBox ? mi.rcWork : mi.rcMonitor;
const LONG left = (mr.left + mr.right - width) / 2;
const LONG top = (mr.top + mr.bottom - height) / 2;
CALL_ORIG_FUNC(SetWindowPos)(hwnd, nullptr, left, top, width, height,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING);
}
}
bool isUser32ScrollBar(HWND hwnd)
{
WNDCLASS wc = {};
static const ATOM sbAtom = static_cast<ATOM>(GetClassInfo(nullptr, "ScrollBar", &wc));
if (sbAtom != GetClassLong(hwnd, GCW_ATOM))
{
return false;
}
auto it = g_windowProc.find(hwnd);
if (it == g_windowProc.end())
{
return false;
}
return GetModuleHandle("comctl32") != Compat::getModuleHandleFromAddress(
IsWindowUnicode(hwnd) ? it->second.wndProcW : it->second.wndProcA);
}
void onDestroyWindow(HWND hwnd)
{
if (Gdi::Window::isTopLevelWindow(hwnd))
{
Gdi::Window::updateAll();
Gdi::GuiThread::deleteTaskbarTab(hwnd);
return;
}
Compat::ScopedSrwLockExclusive lock(g_windowProcSrwLock);
auto it = g_windowProc.find(hwnd);
if (it != g_windowProc.end())
{
setWindowProc(hwnd, it->second.wndProcA, it->second.wndProcW);
g_windowProc.erase(it);
}
}
void onGetMinMaxInfo(MINMAXINFO& mmi)
{
MONITORINFOEXA mi = {};
mi.cbSize = sizeof(mi);
GetMonitorInfoA(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi);
mmi.ptMaxSize.x = mi.rcMonitor.right - 2 * mmi.ptMaxPosition.x;
mmi.ptMaxSize.y = mi.rcMonitor.bottom - 2 * mmi.ptMaxPosition.y;
}
void onInitMenuPopup(HMENU menu)
{
if (Gdi::Cursor::isEmulated())
{
MENUINFO mi = {};
mi.cbSize = sizeof(mi);
mi.fMask = MIM_MAXHEIGHT;
GetMenuInfo(menu, &mi);
RECT mr = DDraw::PrimarySurface::getMonitorRect();
UINT maxHeight = mr.bottom - mr.top;
if (0 == mi.cyMax || mi.cyMax > maxHeight)
{
g_menuMaxHeight[menu] = mi.cyMax;
mi.cyMax = maxHeight;
SetMenuInfo(menu, &mi);
}
}
}
void onUninitMenuPopup(HMENU menu)
{
auto it = g_menuMaxHeight.find(menu);
if (it != g_menuMaxHeight.end())
{
MENUINFO mi = {};
mi.cbSize = sizeof(mi);
mi.fMask = MIM_MAXHEIGHT;
mi.cyMax = it->second;
SetMenuInfo(menu, &mi);
g_menuMaxHeight.erase(it);
}
}
void onWindowPosChanged(HWND hwnd, const WINDOWPOS& wp)
{
for (auto notifyFunc : g_windowPosChangeNotifyFuncs)
{
notifyFunc();
}
if (Gdi::Window::isTopLevelWindow(hwnd))
{
Gdi::Window::updateAll();
}
if (wp.flags & SWP_FRAMECHANGED)
{
RECT r = { -1, -1, 0, 0 };
RedrawWindow(hwnd, &r, nullptr, RDW_INVALIDATE | RDW_FRAME);
}
}
void onWindowPosChanging(HWND hwnd, WINDOWPOS& wp)
{
if (Gdi::Window::isTopLevelWindow(hwnd))
{
wp.flags |= SWP_NOREDRAW;
}
else
{
wp.flags |= SWP_NOCOPYBITS;
}
}
BOOL peekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg,
decltype(&PeekMessageA) origPeekMessage)
{
DDraw::RealPrimarySurface::setUpdateReady();
return origPeekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
}
BOOL WINAPI peekMessageA(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
{
return peekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg, CALL_ORIG_FUNC(PeekMessageA));
}
BOOL WINAPI peekMessageW(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
{
return peekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg, CALL_ORIG_FUNC(PeekMessageW));
}
BOOL WINAPI setLayeredWindowAttributes(HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags)
{
LOG_FUNC("SetLayeredWindowAttributes", hwnd, crKey, bAlpha, dwFlags);
BOOL result = CALL_ORIG_FUNC(SetLayeredWindowAttributes)(hwnd, crKey, bAlpha, dwFlags);
if (result && DDraw::RealPrimarySurface::isFullscreen())
{
DDraw::RealPrimarySurface::scheduleUpdate();
}
return LOG_RESULT(result);
}
LONG setWindowLong(HWND hWnd, int nIndex, LONG dwNewLong,
decltype(&SetWindowLongA) origSetWindowLong, WNDPROC(WindowProc::* wndProc))
{
if (GWL_WNDPROC == nIndex)
{
Compat::ScopedSrwLockExclusive lock(g_windowProcSrwLock);
auto it = g_windowProc.find(hWnd);
if (it != g_windowProc.end() && 0 != origSetWindowLong(hWnd, nIndex, dwNewLong))
{
WNDPROC oldWndProc = it->second.*wndProc;
it->second.wndProcA = reinterpret_cast<WNDPROC>(CALL_ORIG_FUNC(GetWindowLongA)(hWnd, GWL_WNDPROC));
it->second.wndProcW = reinterpret_cast<WNDPROC>(CALL_ORIG_FUNC(GetWindowLongW)(hWnd, GWL_WNDPROC));
WindowProc newWindowProc = { ddcWindowProcA, ddcWindowProcW };
origSetWindowLong(hWnd, GWL_WNDPROC, reinterpret_cast<LONG>(newWindowProc.*wndProc));
return reinterpret_cast<LONG>(oldWndProc);
}
}
else if ((GWL_STYLE == nIndex || GWL_EXSTYLE == nIndex) && Config::removeBorders.get())
{
auto tagSurface = DDraw::TagSurface::findFullscreenWindow(hWnd);
if (tagSurface)
{
if (GWL_STYLE == nIndex)
{
return tagSurface->setWindowStyle(dwNewLong);
}
else
{
return tagSurface->setWindowExStyle(dwNewLong);
}
}
}
return origSetWindowLong(hWnd, nIndex, dwNewLong);
}
LONG WINAPI setWindowLongA(HWND hWnd, int nIndex, LONG dwNewLong)
{
LOG_FUNC("SetWindowLongA", hWnd, nIndex, dwNewLong);
return LOG_RESULT(setWindowLong(hWnd, nIndex, dwNewLong, CALL_ORIG_FUNC(SetWindowLongA), &WindowProc::wndProcA));
}
LONG WINAPI setWindowLongW(HWND hWnd, int nIndex, LONG dwNewLong)
{
LOG_FUNC("SetWindowLongW", hWnd, nIndex, dwNewLong);
return LOG_RESULT(setWindowLong(hWnd, nIndex, dwNewLong, CALL_ORIG_FUNC(SetWindowLongW), &WindowProc::wndProcW));
}
BOOL WINAPI setWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags)
{
LOG_FUNC("SetWindowPos", hWnd, hWndInsertAfter, X, Y, cx, cy, Compat::hex(uFlags));
if (uFlags & SWP_NOSENDCHANGING)
{
WINDOWPOS wp = {};
wp.hwnd = hWnd;
wp.hwndInsertAfter = hWndInsertAfter;
wp.x = X;
wp.y = Y;
wp.cx = cx;
wp.cy = cy;
wp.flags = uFlags;
onWindowPosChanging(hWnd, wp);
uFlags = wp.flags;
}
return LOG_RESULT(CALL_ORIG_FUNC(SetWindowPos)(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags));
}
void setWindowProc(HWND hwnd, WNDPROC wndProcA, WNDPROC wndProcW)
{
if (IsWindowUnicode(hwnd))
{
CALL_ORIG_FUNC(SetWindowLongW)(hwnd, GWL_WNDPROC, reinterpret_cast<LONG>(wndProcW));
}
else
{
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC, reinterpret_cast<LONG>(wndProcA));
}
}
void CALLBACK winEventProc(
HWINEVENTHOOK /*hWinEventHook*/,
DWORD event,
HWND hwnd,
LONG idObject,
LONG /*idChild*/,
DWORD /*dwEventThread*/,
DWORD /*dwmsEventTime*/)
{
LOG_FUNC("winEventProc", Compat::hex(event), hwnd, idObject);
switch (event)
{
case EVENT_OBJECT_CREATE:
if (OBJID_WINDOW == idObject)
{
Gdi::WinProc::onCreateWindow(hwnd);
}
break;
case EVENT_OBJECT_NAMECHANGE:
case EVENT_OBJECT_SHOW:
case EVENT_OBJECT_HIDE:
if (OBJID_CURSOR == idObject && Gdi::Cursor::isEmulated())
{
Gdi::Cursor::setCursor(CALL_ORIG_FUNC(GetCursor)());
}
break;
case EVENT_OBJECT_STATECHANGE:
switch (idObject)
{
case OBJID_TITLEBAR:
{
HDC dc = GetWindowDC(hwnd);
Gdi::TitleBar(hwnd).drawButtons(dc);
ReleaseDC(hwnd, dc);
break;
}
case OBJID_CLIENT:
if (!isUser32ScrollBar(hwnd))
{
break;
}
case OBJID_HSCROLL:
case OBJID_VSCROLL:
{
HDC dc = GetWindowDC(hwnd);
if (OBJID_CLIENT == idObject)
{
SendMessage(GetParent(hwnd), WM_CTLCOLORSCROLLBAR,
reinterpret_cast<WPARAM>(dc), reinterpret_cast<LPARAM>(hwnd));
}
else
{
DefWindowProc(hwnd, WM_CTLCOLORSCROLLBAR,
reinterpret_cast<WPARAM>(dc), reinterpret_cast<LPARAM>(hwnd));
}
ReleaseDC(hwnd, dc);
break;
}
}
}
}
}
namespace Gdi
{
namespace WinProc
{
void dllThreadDetach()
{
auto threadId = GetCurrentThreadId();
Compat::ScopedSrwLockExclusive lock(g_windowProcSrwLock);
auto it = g_windowProc.begin();
while (it != g_windowProc.end())
{
if (threadId == GetWindowThreadProcessId(it->first, nullptr))
{
it = g_windowProc.erase(it);
}
else
{
++it;
}
}
}
void installHooks()
{
HOOK_FUNCTION(user32, CreateDialogIndirectParamA, createDialog<CreateDialogIndirectParamA>);
HOOK_FUNCTION(user32, CreateDialogIndirectParamW, createDialog<CreateDialogIndirectParamW>);
HOOK_FUNCTION(user32, CreateDialogParamA, createDialog<CreateDialogParamA>);
HOOK_FUNCTION(user32, CreateDialogParamW, createDialog<CreateDialogParamW>);
HOOK_FUNCTION(user32, DialogBoxParamA, createDialog<DialogBoxParamA>);
HOOK_FUNCTION(user32, DialogBoxParamW, createDialog<DialogBoxParamW>);
HOOK_FUNCTION(user32, DialogBoxIndirectParamA, createDialog<DialogBoxIndirectParamA>);
HOOK_FUNCTION(user32, DialogBoxIndirectParamW, createDialog<DialogBoxIndirectParamW>);
HOOK_FUNCTION(user32, GetMessageA, getMessageA);
HOOK_FUNCTION(user32, GetMessageW, getMessageW);
HOOK_FUNCTION(user32, GetWindowLongA, getWindowLongA);
HOOK_FUNCTION(user32, GetWindowLongW, getWindowLongW);
HOOK_FUNCTION(user32, MessageBoxA, messageBox<MessageBoxA>);
HOOK_FUNCTION(user32, MessageBoxW, messageBox<MessageBoxW>);
HOOK_FUNCTION(user32, MessageBoxExA, messageBox<MessageBoxExA>);
HOOK_FUNCTION(user32, MessageBoxExW, messageBox<MessageBoxExW>);
HOOK_FUNCTION(user32, MessageBoxIndirectA, messageBox<MessageBoxIndirectA>);
HOOK_FUNCTION(user32, MessageBoxIndirectW, messageBox<MessageBoxIndirectW>);
HOOK_FUNCTION(user32, PeekMessageA, peekMessageA);
HOOK_FUNCTION(user32, PeekMessageW, peekMessageW);
HOOK_FUNCTION(user32, SetLayeredWindowAttributes, setLayeredWindowAttributes);
HOOK_FUNCTION(user32, SetWindowLongA, setWindowLongA);
HOOK_FUNCTION(user32, SetWindowLongW, setWindowLongW);
HOOK_FUNCTION(user32, SetWindowPos, setWindowPos);
SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE,
Dll::g_currentModule, &winEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
SetWinEventHook(EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_NAMECHANGE,
Dll::g_currentModule, &winEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
SetWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE,
Dll::g_currentModule, &winEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
SetWinEventHook(EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_STATECHANGE,
Dll::g_currentModule, &winEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
}
void onCreateWindow(HWND hwnd)
{
LOG_FUNC("onCreateWindow", hwnd);
if (!GuiThread::isReady() || GuiThread::isGuiThreadWindow(hwnd))
{
return;
}
{
Compat::ScopedSrwLockExclusive lock(g_windowProcSrwLock);
if (g_windowProc.find(hwnd) != g_windowProc.end())
{
return;
}
auto wndProcA = reinterpret_cast<WNDPROC>(CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_WNDPROC));
auto wndProcW = reinterpret_cast<WNDPROC>(CALL_ORIG_FUNC(GetWindowLongW)(hwnd, GWL_WNDPROC));
g_windowProc[hwnd] = { wndProcA, wndProcW };
setWindowProc(hwnd, ddcWindowProcA, ddcWindowProcW);
}
if (!Gdi::Window::isTopLevelWindow(hwnd))
{
return;
}
char className[64] = {};
GetClassName(hwnd, className, sizeof(className));
if (std::string(className) == "CompatWindowDesktopReplacement")
{
// Disable VirtualizeDesktopPainting shim
SendNotifyMessage(hwnd, WM_CLOSE, 0, 0);
return;
}
Gdi::Window::updateAll();
}
void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc)
{
g_windowPosChangeNotifyFuncs.insert(notifyFunc);
}
}
}