mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Improved hooking of user32 window procedures
This commit is contained in:
parent
c7b94700d3
commit
81c2748027
@ -21,17 +21,12 @@ namespace
|
|||||||
|
|
||||||
struct User32WndProc
|
struct User32WndProc
|
||||||
{
|
{
|
||||||
WNDPROC oldWndProcTrampoline;
|
|
||||||
WNDPROC oldWndProc;
|
WNDPROC oldWndProc;
|
||||||
|
WNDPROC oldWndProcTrampoline;
|
||||||
WNDPROC newWndProc;
|
WNDPROC newWndProc;
|
||||||
std::string name;
|
std::string procName;
|
||||||
|
std::string className;
|
||||||
User32WndProc()
|
bool isUnicode;
|
||||||
: oldWndProcTrampoline(nullptr)
|
|
||||||
, oldWndProc(nullptr)
|
|
||||||
, newWndProc(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
LRESULT defPaintProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc);
|
LRESULT defPaintProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc);
|
||||||
@ -42,12 +37,8 @@ namespace
|
|||||||
LRESULT onPaint(HWND hwnd, WNDPROC origWndProc);
|
LRESULT onPaint(HWND hwnd, WNDPROC origWndProc);
|
||||||
LRESULT onPrint(HWND hwnd, UINT msg, HDC dc, LONG flags, WNDPROC origWndProc);
|
LRESULT onPrint(HWND hwnd, UINT msg, HDC dc, LONG flags, WNDPROC origWndProc);
|
||||||
|
|
||||||
int g_menuWndProcIndex = 0;
|
User32WndProc* g_currentUser32WndProc = nullptr;
|
||||||
int g_scrollBarWndProcIndex = 0;
|
std::vector<std::string> g_failedHooks;
|
||||||
|
|
||||||
std::vector<User32WndProc> g_user32WndProcA;
|
|
||||||
std::vector<User32WndProc> g_user32WndProcW;
|
|
||||||
std::vector<WndProcHook> g_user32WndProcHook;
|
|
||||||
|
|
||||||
LRESULT buttonWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
LRESULT buttonWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
||||||
{
|
{
|
||||||
@ -71,6 +62,38 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK cbtProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
if (HCBT_CREATEWND == nCode && g_currentUser32WndProc)
|
||||||
|
{
|
||||||
|
const auto hwnd = reinterpret_cast<HWND>(wParam);
|
||||||
|
const bool isUnicode = IsWindowUnicode(hwnd);
|
||||||
|
char className[32] = {};
|
||||||
|
GetClassName(hwnd, className, sizeof(className));
|
||||||
|
|
||||||
|
if (0 == _stricmp(className, g_currentUser32WndProc->className.c_str()) &&
|
||||||
|
isUnicode == g_currentUser32WndProc->isUnicode &&
|
||||||
|
!g_currentUser32WndProc->oldWndProc)
|
||||||
|
{
|
||||||
|
decltype(&GetWindowLong) getWindowLong = isUnicode ? GetWindowLongW : GetWindowLongA;
|
||||||
|
auto wndProc = reinterpret_cast<WNDPROC>(getWindowLong(hwnd, GWL_WNDPROC));
|
||||||
|
HMODULE wndProcModule = nullptr;
|
||||||
|
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||||
|
reinterpret_cast<const char*>(wndProc), &wndProcModule);
|
||||||
|
|
||||||
|
if (wndProcModule && wndProcModule == GetModuleHandle("user32"))
|
||||||
|
{
|
||||||
|
g_currentUser32WndProc->oldWndProc = wndProc;
|
||||||
|
g_currentUser32WndProc->oldWndProcTrampoline = wndProc;
|
||||||
|
Compat::hookFunction(reinterpret_cast<void*&>(g_currentUser32WndProc->oldWndProcTrampoline),
|
||||||
|
g_currentUser32WndProc->newWndProc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CallNextHookEx(nullptr, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
LRESULT comboBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
LRESULT comboBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
||||||
{
|
{
|
||||||
return defPaintProc(hwnd, msg, wParam, lParam, origWndProc);
|
return defPaintProc(hwnd, msg, wParam, lParam, origWndProc);
|
||||||
@ -163,39 +186,66 @@ namespace
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hookUser32WndProc(const std::string& wndProcName, HWND hwnd, WNDPROC newWndProc,
|
template <WndProcHook>
|
||||||
decltype(GetWindowLongPtr)* getWindowLong, std::vector<User32WndProc>& user32WndProc)
|
User32WndProc& getUser32WndProcA()
|
||||||
{
|
{
|
||||||
User32WndProc wndProc;
|
static User32WndProc user32WndProcA = {};
|
||||||
wndProc.oldWndProc =
|
return user32WndProcA;
|
||||||
reinterpret_cast<WNDPROC>(getWindowLong(hwnd, GWL_WNDPROC));
|
}
|
||||||
wndProc.oldWndProcTrampoline = wndProc.oldWndProc;
|
|
||||||
wndProc.newWndProc = newWndProc;
|
|
||||||
wndProc.name = wndProcName;
|
|
||||||
user32WndProc.push_back(wndProc);
|
|
||||||
|
|
||||||
if (reinterpret_cast<DWORD>(wndProc.oldWndProcTrampoline) < 0xFFFF0000)
|
template <WndProcHook>
|
||||||
|
User32WndProc& getUser32WndProcW()
|
||||||
|
{
|
||||||
|
static User32WndProc user32WndProcW = {};
|
||||||
|
return user32WndProcW;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hookUser32WndProc(User32WndProc& user32WndProc, WNDPROC newWndProc,
|
||||||
|
const std::string& procName, const std::string& className, bool isUnicode)
|
||||||
|
{
|
||||||
|
CLIENTCREATESTRUCT ccs = {};
|
||||||
|
user32WndProc.newWndProc = newWndProc;
|
||||||
|
user32WndProc.procName = procName;
|
||||||
|
user32WndProc.className = className;
|
||||||
|
user32WndProc.isUnicode = isUnicode;
|
||||||
|
|
||||||
|
g_currentUser32WndProc = &user32WndProc;
|
||||||
|
if (isUnicode)
|
||||||
{
|
{
|
||||||
Compat::hookFunction(
|
DestroyWindow(CreateWindowW(std::wstring(className.begin(), className.end()).c_str(), L"", 0, 0, 0, 0, 0,
|
||||||
reinterpret_cast<void*&>(user32WndProc.back().oldWndProcTrampoline), newWndProc);
|
nullptr, nullptr, nullptr, &ccs));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DestroyWindow(CreateWindowA(className.c_str(), "", 0, 0, 0, 0, 0, nullptr, nullptr, nullptr, &ccs));
|
||||||
|
}
|
||||||
|
g_currentUser32WndProc = nullptr;
|
||||||
|
|
||||||
|
if (user32WndProc.oldWndProc == user32WndProc.oldWndProcTrampoline)
|
||||||
|
{
|
||||||
|
g_failedHooks.push_back(user32WndProc.procName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hookUser32WndProcA(const char* className, WNDPROC newWndProc, const std::string& wndProcName)
|
template <WndProcHook wndProcHook>
|
||||||
|
void hookUser32WndProcA(const std::string& className, const std::string& procName)
|
||||||
{
|
{
|
||||||
CLIENTCREATESTRUCT ccs = {};
|
hookUser32WndProc(getUser32WndProcA<wndProcHook>(), user32WndProcA<wndProcHook>,
|
||||||
HWND hwnd = CreateWindowA(className, "", 0, 0, 0, 0, 0, 0, 0, 0, &ccs);
|
procName + 'A', className, false);
|
||||||
hookUser32WndProc(wndProcName + 'A', hwnd, newWndProc, CALL_ORIG_FUNC(GetWindowLongA), g_user32WndProcA);
|
|
||||||
DestroyWindow(hwnd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void hookUser32WndProcW(const char* name, WNDPROC newWndProc, const std::string& wndProcName)
|
template <WndProcHook wndProcHook>
|
||||||
|
void hookUser32WndProcW(const std::string& className, const std::string& procName)
|
||||||
{
|
{
|
||||||
CLIENTCREATESTRUCT ccs = {};
|
hookUser32WndProc(getUser32WndProcW<wndProcHook>(), user32WndProcW<wndProcHook>,
|
||||||
HWND hwnd = CreateWindowW(
|
procName + 'W', className, true);
|
||||||
std::wstring(name, name + std::strlen(name)).c_str(), L"", 0, 0, 0, 0, 0, 0, 0, 0, &ccs);
|
}
|
||||||
hookUser32WndProc(wndProcName + 'W', hwnd, newWndProc, CALL_ORIG_FUNC(GetWindowLongW), g_user32WndProcW);
|
|
||||||
DestroyWindow(hwnd);
|
template <WndProcHook wndProcHook>
|
||||||
|
void hookUser32WndProc(const std::string& className, const std::string& procName)
|
||||||
|
{
|
||||||
|
hookUser32WndProcA<wndProcHook>(className, procName);
|
||||||
|
hookUser32WndProcW<wndProcHook>(className, procName);
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT listBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
LRESULT listBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
||||||
@ -369,22 +419,24 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
LRESULT CALLBACK user32WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
|
LRESULT CALLBACK user32WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
|
||||||
const User32WndProc& user32WndProc, WndProcHook wndProcHook)
|
const std::string& procName, WndProcHook wndProcHook, WNDPROC oldWndProcTrampoline)
|
||||||
{
|
{
|
||||||
LOG_FUNC(user32WndProc.name.c_str(), hwnd, Compat::hex(uMsg), Compat::hex(wParam), Compat::hex(lParam));
|
LOG_FUNC(procName.c_str(), hwnd, Compat::hex(uMsg), Compat::hex(wParam), Compat::hex(lParam));
|
||||||
return LOG_RESULT(wndProcHook(hwnd, uMsg, wParam, lParam, user32WndProc.oldWndProcTrampoline));
|
return LOG_RESULT(wndProcHook(hwnd, uMsg, wParam, lParam, oldWndProcTrampoline));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int index>
|
template <WndProcHook wndProcHook>
|
||||||
LRESULT CALLBACK user32WndProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
LRESULT CALLBACK user32WndProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
return user32WndProc(hwnd, uMsg, wParam, lParam, g_user32WndProcA[index], g_user32WndProcHook[index]);
|
auto& wp = getUser32WndProcA<wndProcHook>();
|
||||||
|
return user32WndProc(hwnd, uMsg, wParam, lParam, wp.procName, wndProcHook, wp.oldWndProcTrampoline);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int index>
|
template <WndProcHook wndProcHook>
|
||||||
LRESULT CALLBACK user32WndProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
LRESULT CALLBACK user32WndProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
return user32WndProc(hwnd, uMsg, wParam, lParam, g_user32WndProcW[index], g_user32WndProcHook[index]);
|
auto& wp = getUser32WndProcW<wndProcHook>();
|
||||||
|
return user32WndProc(hwnd, uMsg, wParam, lParam, wp.procName, wndProcHook, wp.oldWndProcTrampoline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,28 +448,33 @@ namespace Gdi
|
|||||||
{
|
{
|
||||||
disableImmersiveContextMenus();
|
disableImmersiveContextMenus();
|
||||||
|
|
||||||
#define HOOK_USER32_WNDPROC(index, name, wndProcHook) \
|
#define HOOK_USER32_WNDPROC(className, wndProcHook) hookUser32WndProc<wndProcHook>(className, #wndProcHook)
|
||||||
g_user32WndProcHook.push_back(wndProcHook); \
|
#define HOOK_USER32_WNDPROCW(className, wndProcHook) hookUser32WndProcW<wndProcHook>(className, #wndProcHook)
|
||||||
hookUser32WndProcA(name, user32WndProcA<index>, #wndProcHook); \
|
|
||||||
hookUser32WndProcW(name, user32WndProcW<index>, #wndProcHook)
|
|
||||||
|
|
||||||
g_user32WndProcA.reserve(9);
|
auto hook = SetWindowsHookEx(WH_CBT, cbtProc, nullptr, GetCurrentThreadId());
|
||||||
g_user32WndProcW.reserve(9);
|
|
||||||
|
|
||||||
HOOK_USER32_WNDPROC(0, "Button", buttonWndProc);
|
HOOK_USER32_WNDPROC("Button", buttonWndProc);
|
||||||
HOOK_USER32_WNDPROC(1, "ComboBox", comboBoxWndProc);
|
HOOK_USER32_WNDPROC("ComboBox", comboBoxWndProc);
|
||||||
HOOK_USER32_WNDPROC(2, "Edit", editWndProc);
|
HOOK_USER32_WNDPROC("Edit", editWndProc);
|
||||||
HOOK_USER32_WNDPROC(3, "ListBox", listBoxWndProc);
|
HOOK_USER32_WNDPROC("ListBox", listBoxWndProc);
|
||||||
HOOK_USER32_WNDPROC(4, "MDIClient", mdiClientWndProc);
|
HOOK_USER32_WNDPROC("MDIClient", mdiClientWndProc);
|
||||||
HOOK_USER32_WNDPROC(5, "ScrollBar", scrollBarWndProc);
|
HOOK_USER32_WNDPROC("Static", staticWndProc);
|
||||||
HOOK_USER32_WNDPROC(6, "Static", staticWndProc);
|
HOOK_USER32_WNDPROC("ComboLBox", comboListBoxWndProc);
|
||||||
HOOK_USER32_WNDPROC(7, "ComboLBox", comboListBoxWndProc);
|
|
||||||
HOOK_USER32_WNDPROC(8, "#32768", menuWndProc);
|
|
||||||
|
|
||||||
g_scrollBarWndProcIndex = 5;
|
HOOK_USER32_WNDPROCW("ScrollBar", scrollBarWndProc);
|
||||||
g_menuWndProcIndex = 8;
|
HOOK_USER32_WNDPROCW("#32768", menuWndProc);
|
||||||
|
|
||||||
|
UnhookWindowsHookEx(hook);
|
||||||
|
|
||||||
#undef HOOK_USER32_WNDPROC
|
#undef HOOK_USER32_WNDPROC
|
||||||
|
#undef HOOK_USER32_WNDPROCW
|
||||||
|
|
||||||
|
if (!g_failedHooks.empty())
|
||||||
|
{
|
||||||
|
Compat::Log() << "Warning: Failed to hook the following user32 window procedures: " <<
|
||||||
|
Compat::array(g_failedHooks.data(), g_failedHooks.size());
|
||||||
|
g_failedHooks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
HOOK_FUNCTION(user32, DefWindowProcA, defWindowProcA);
|
HOOK_FUNCTION(user32, DefWindowProcA, defWindowProcA);
|
||||||
HOOK_FUNCTION(user32, DefWindowProcW, defWindowProcW);
|
HOOK_FUNCTION(user32, DefWindowProcW, defWindowProcW);
|
||||||
@ -427,33 +484,25 @@ namespace Gdi
|
|||||||
|
|
||||||
void onCreateWindow(HWND hwnd)
|
void onCreateWindow(HWND hwnd)
|
||||||
{
|
{
|
||||||
WNDPROC wndProcA = reinterpret_cast<WNDPROC>(GetWindowLongA(hwnd, GWL_WNDPROC));
|
if (!IsWindowUnicode(hwnd))
|
||||||
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;
|
return;
|
||||||
}
|
|
||||||
else if (wndProcA == g_user32WndProcA[g_scrollBarWndProcIndex].oldWndProc ||
|
|
||||||
wndProcW == g_user32WndProcW[g_scrollBarWndProcIndex].oldWndProc)
|
|
||||||
{
|
|
||||||
index = g_scrollBarWndProcIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-1 != index)
|
const auto wndProc = reinterpret_cast<WNDPROC>(GetWindowLongW(hwnd, GWL_WNDPROC));
|
||||||
|
User32WndProc* user32WndProc = nullptr;
|
||||||
|
if (getUser32WndProcW<menuWndProc>().oldWndProc == wndProc)
|
||||||
{
|
{
|
||||||
if (IsWindowUnicode(hwnd))
|
user32WndProc = &getUser32WndProcW<menuWndProc>();
|
||||||
{
|
}
|
||||||
CALL_ORIG_FUNC(SetWindowLongW)(hwnd, GWL_WNDPROC,
|
else if (getUser32WndProcW<scrollBarWndProc>().oldWndProc == wndProc)
|
||||||
reinterpret_cast<LONG>(g_user32WndProcW[index].newWndProc));
|
{
|
||||||
}
|
user32WndProc = &getUser32WndProcW<scrollBarWndProc>();
|
||||||
else
|
}
|
||||||
{
|
|
||||||
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC,
|
if (user32WndProc)
|
||||||
reinterpret_cast<LONG>(g_user32WndProcA[index].newWndProc));
|
{
|
||||||
}
|
SetWindowLongW(hwnd, GWL_WNDPROC, reinterpret_cast<LONG>(user32WndProc->newWndProc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user