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

Merge helper GUI threads

This commit is contained in:
narzoul 2022-02-06 12:09:46 +01:00
parent fa8dec88c5
commit 229fe449ef
15 changed files with 365 additions and 339 deletions

View File

@ -301,6 +301,7 @@
<ClInclude Include="Gdi\Caret.h" />
<ClInclude Include="Gdi\Dc.h" />
<ClInclude Include="Gdi\DcFunctions.h" />
<ClInclude Include="Gdi\GuiThread.h" />
<ClInclude Include="Gdi\Icon.h" />
<ClInclude Include="Gdi\Metrics.h" />
<ClInclude Include="Gdi\PresentationWindow.h" />
@ -401,6 +402,7 @@
<ClCompile Include="Gdi\Caret.cpp" />
<ClCompile Include="Gdi\Dc.cpp" />
<ClCompile Include="Gdi\DcFunctions.cpp" />
<ClCompile Include="Gdi\GuiThread.cpp" />
<ClCompile Include="Gdi\Icon.cpp" />
<ClCompile Include="Gdi\Metrics.cpp" />
<ClCompile Include="Gdi\PresentationWindow.cpp" />
@ -454,4 +456,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -513,6 +513,9 @@
<ClInclude Include="Common\Rect.h">
<Filter>Header Files\Common</Filter>
</ClInclude>
<ClInclude Include="Gdi\GuiThread.h">
<Filter>Header Files\Gdi</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">
@ -809,6 +812,9 @@
<ClCompile Include="Common\Rect.cpp">
<Filter>Source Files\Common</Filter>
</ClCompile>
<ClCompile Include="Gdi\GuiThread.cpp">
<Filter>Source Files\Gdi</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="DDrawCompat.rc">

View File

@ -17,6 +17,7 @@
#include <Direct3d/Hooks.h>
#include <Dll/Dll.h>
#include <Gdi/Gdi.h>
#include <Gdi/GuiThread.h>
#include <Gdi/PresentationWindow.h>
#include <Gdi/VirtualScreen.h>
#include <Input/Input.h>
@ -113,7 +114,7 @@ namespace
Compat::Log() << "Installing GDI hooks";
Gdi::installHooks();
Compat::closeDbgEng();
Gdi::PresentationWindow::startThread();
Gdi::GuiThread::start();
Compat::Log() << "Finished installing hooks";
isAlreadyInstalled = true;
}

View File

@ -8,6 +8,7 @@
#include <Gdi/DcFunctions.h>
#include <Gdi/Font.h>
#include <Gdi/Gdi.h>
#include <Gdi/GuiThread.h>
#include <Gdi/Icon.h>
#include <Gdi/Metrics.h>
#include <Gdi/Palette.h>
@ -74,6 +75,7 @@ namespace Gdi
Caret::installHooks();
Cursor::installHooks();
Font::installHooks();
WinProc::installHooks();
}
bool isDisplayDc(HDC dc)
@ -90,7 +92,7 @@ namespace Gdi
void redrawWindow(HWND hwnd, HRGN rgn)
{
if (!IsWindowVisible(hwnd) || IsIconic(hwnd) || PresentationWindow::isPresentationWindow(hwnd))
if (!IsWindowVisible(hwnd) || IsIconic(hwnd) || GuiThread::isGuiThreadWindow(hwnd))
{
return;
}

View File

@ -0,0 +1,157 @@
#include <Windows.h>
#include <Common/Log.h>
#include <Common/Hook.h>
#include <D3dDdi/ScopedCriticalSection.h>
#include <Dll/Dll.h>
#include <Gdi/GuiThread.h>
#include <Gdi/Region.h>
#include <Gdi/WinProc.h>
#include <Overlay/ConfigWindow.h>
#include <Win32/DisplayMode.h>
namespace
{
const UINT WM_USER_EXECUTE = WM_USER;
unsigned g_threadId = 0;
Overlay::ConfigWindow* g_configWindow = nullptr;
HWND g_messageWindow = nullptr;
bool g_isReady = false;
BOOL CALLBACK initChildWindow(HWND hwnd, LPARAM /*lParam*/)
{
Gdi::WinProc::onCreateWindow(hwnd);
return TRUE;
}
BOOL CALLBACK initTopLevelWindow(HWND hwnd, LPARAM /*lParam*/)
{
DWORD windowPid = 0;
GetWindowThreadProcessId(hwnd, &windowPid);
if (GetCurrentProcessId() == windowPid)
{
Gdi::WinProc::onCreateWindow(hwnd);
EnumChildWindows(hwnd, &initChildWindow, 0);
if (8 == Win32::DisplayMode::getBpp())
{
PostMessage(hwnd, WM_PALETTECHANGED, reinterpret_cast<WPARAM>(GetDesktopWindow()), 0);
}
}
return TRUE;
}
LRESULT CALLBACK messageWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LOG_FUNC("messageWindowProc", Compat::WindowMessageStruct(hwnd, uMsg, wParam, lParam));
if (WM_USER_EXECUTE == uMsg)
{
auto& func = *reinterpret_cast<const std::function<void()>*>(lParam);
func();
return LOG_RESULT(0);
}
return LOG_RESULT(CALL_ORIG_FUNC(DefWindowProc)(hwnd, uMsg, wParam, lParam));
}
unsigned WINAPI messageWindowThreadProc(LPVOID /*lpParameter*/)
{
WNDCLASS wc = {};
wc.lpfnWndProc = &messageWindowProc;
wc.hInstance = Dll::g_currentModule;
wc.lpszClassName = "DDrawCompatMessageWindow";
CALL_ORIG_FUNC(RegisterClassA)(&wc);
g_messageWindow = CreateWindow(
"DDrawCompatMessageWindow", nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr);
if (!g_messageWindow)
{
Compat::Log() << "ERROR: Failed to create a message-only window";
return 0;
}
Overlay::ConfigWindow configWindow;
g_configWindow = &configWindow;
{
D3dDdi::ScopedCriticalSection lock;
g_isReady = true;
EnumWindows(initTopLevelWindow, 0);
}
MSG msg = {};
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
}
namespace Gdi
{
namespace GuiThread
{
HWND createWindow(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle,
int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
{
// Workaround for ForceSimpleWindow shim
static auto createWindowExA = reinterpret_cast<decltype(&CreateWindowExA)>(
Compat::getProcAddress(GetModuleHandle("user32"), "CreateWindowExA"));
HWND hwnd = nullptr;
execute([&]()
{
hwnd = createWindowExA(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight,
hWndParent, hMenu, hInstance, lpParam);
});
return hwnd;
}
void destroyWindow(HWND hwnd)
{
execute([&]() { DestroyWindow(hwnd); });
}
void executeFunc(const std::function<void()>& func)
{
DWORD_PTR result = 0;
SendMessageTimeout(g_messageWindow, WM_USER_EXECUTE, 0, reinterpret_cast<LPARAM>(&func),
SMTO_BLOCK | SMTO_NOTIMEOUTIFNOTHUNG, 0, &result);
}
Overlay::ConfigWindow* getConfigWindow()
{
return g_configWindow;
}
bool isGuiThreadWindow(HWND hwnd)
{
return GetWindowThreadProcessId(hwnd, nullptr) == g_threadId;
}
bool isReady()
{
return g_isReady;
}
void setWindowRgn(HWND hwnd, Gdi::Region rgn)
{
execute([&]()
{
if (SetWindowRgn(hwnd, rgn, FALSE))
{
rgn.release();
}
});
}
void start()
{
Dll::createThread(messageWindowThreadProc, &g_threadId, THREAD_PRIORITY_TIME_CRITICAL, 0);
}
}
}

View File

@ -0,0 +1,34 @@
#pragma once
#include <functional>
#include <Windows.h>
#include <Gdi/Region.h>
namespace Overlay
{
class ConfigWindow;
}
namespace Gdi
{
namespace GuiThread
{
HWND createWindow(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle,
int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam);
void destroyWindow(HWND hwnd);
void setWindowRgn(HWND hwnd, Gdi::Region rgn);
Overlay::ConfigWindow* getConfigWindow();
template <typename Func>
void execute(const Func& func) { executeFunc(std::cref(func)); }
void executeFunc(const std::function<void()>& func);
bool isGuiThreadWindow(HWND hwnd);
bool isReady();
void start();
}
}

View File

@ -196,7 +196,7 @@ namespace
if (result && !bForceBackground)
{
HWND dcWindow = CALL_ORIG_FUNC(WindowFromDC)(hdc);
if (dcWindow && !(GetWindowLong(dcWindow, GWL_EXSTYLE) & WS_EX_TOOLWINDOW))
if (dcWindow && !(CALL_ORIG_FUNC(GetWindowLongA)(dcWindow, GWL_EXSTYLE) & WS_EX_TOOLWINDOW))
{
HWND activeWindow = GetActiveWindow();
if (activeWindow == dcWindow || IsChild(activeWindow, dcWindow))

View File

@ -1,160 +1,17 @@
#include <Common/Hook.h>
#include <Common/Log.h>
#include <D3dDdi/ScopedCriticalSection.h>
#include <Dll/Dll.h>
#include <Gdi/GuiThread.h>
#include <Gdi/PresentationWindow.h>
#include <Gdi/WinProc.h>
#include <Overlay/ConfigWindow.h>
#include <Win32/DisplayMode.h>
namespace
{
const UINT WM_CREATEPRESENTATIONWINDOW = WM_USER;
const UINT WM_SETPRESENTATIONWINDOWPOS = WM_USER + 1;
const UINT WM_SETPRESENTATIONWINDOWRGN = WM_USER + 2;
HANDLE g_presentationWindowThread = nullptr;
unsigned g_presentationWindowThreadId = 0;
Overlay::ConfigWindow* g_configWindow = nullptr;
HWND g_messageWindow = nullptr;
bool g_isThreadReady = false;
BOOL CALLBACK initChildWindow(HWND hwnd, LPARAM /*lParam*/)
{
Gdi::WinProc::onCreateWindow(hwnd);
return TRUE;
}
BOOL CALLBACK initTopLevelWindow(HWND hwnd, LPARAM /*lParam*/)
{
DWORD windowPid = 0;
GetWindowThreadProcessId(hwnd, &windowPid);
if (GetCurrentProcessId() == windowPid)
{
Gdi::WinProc::onCreateWindow(hwnd);
EnumChildWindows(hwnd, &initChildWindow, 0);
if (8 == Win32::DisplayMode::getBpp())
{
PostMessage(hwnd, WM_PALETTECHANGED, reinterpret_cast<WPARAM>(GetDesktopWindow()), 0);
}
}
return TRUE;
}
LRESULT CALLBACK messageWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LOG_FUNC("messageWindowProc", Compat::WindowMessageStruct(hwnd, uMsg, wParam, lParam));
switch (uMsg)
{
case WM_CREATEPRESENTATIONWINDOW:
{
// Workaround for ForceSimpleWindow shim
static auto origCreateWindowExA = reinterpret_cast<decltype(&CreateWindowExA)>(
Compat::getProcAddress(GetModuleHandle("user32"), "CreateWindowExA"));
HWND owner = reinterpret_cast<HWND>(wParam);
HWND presentationWindow = origCreateWindowExA(
WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOPARENTNOTIFY | WS_EX_TOOLWINDOW,
"DDrawCompatPresentationWindow",
nullptr,
WS_DISABLED | WS_POPUP,
0, 0, 1, 1,
owner,
nullptr,
nullptr,
nullptr);
if (presentationWindow)
{
if (lParam)
{
CALL_ORIG_FUNC(SetWindowLongA)(presentationWindow, GWL_WNDPROC, lParam);
}
CALL_ORIG_FUNC(SetLayeredWindowAttributes)(presentationWindow, 0, 255, LWA_ALPHA);
}
return LOG_RESULT(reinterpret_cast<LRESULT>(presentationWindow));
}
case WM_DESTROY:
PostQuitMessage(0);
return LOG_RESULT(0);
}
return LOG_RESULT(CALL_ORIG_FUNC(DefWindowProc)(hwnd, uMsg, wParam, lParam));
}
ATOM g_classAtom = 0;
LRESULT CALLBACK presentationWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LOG_FUNC("presentationWindowProc", Compat::WindowMessageStruct(hwnd, uMsg, wParam, lParam));
switch (uMsg)
{
case WM_SETPRESENTATIONWINDOWPOS:
{
const auto& wp = *reinterpret_cast<WINDOWPOS*>(lParam);
return SetWindowPos(hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
}
case WM_SETPRESENTATIONWINDOWRGN:
{
HRGN rgn = nullptr;
if (wParam)
{
rgn = CreateRectRgn(0, 0, 0, 0);
CombineRgn(rgn, reinterpret_cast<HRGN>(wParam), nullptr, RGN_COPY);
}
return SetWindowRgn(hwnd, rgn, FALSE);
}
}
return CALL_ORIG_FUNC(DefWindowProc)(hwnd, uMsg, wParam, lParam);
}
unsigned WINAPI presentationWindowThreadProc(LPVOID /*lpParameter*/)
{
WNDCLASS wc = {};
wc.lpfnWndProc = &messageWindowProc;
wc.hInstance = Dll::g_currentModule;
wc.lpszClassName = "DDrawCompatMessageWindow";
CALL_ORIG_FUNC(RegisterClassA)(&wc);
g_messageWindow = CreateWindow(
"DDrawCompatMessageWindow", nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr);
if (!g_messageWindow)
{
Compat::Log() << "ERROR: Failed to create a message-only window";
return 0;
}
{
D3dDdi::ScopedCriticalSection lock;
Gdi::WinProc::installHooks();
g_isThreadReady = true;
EnumWindows(initTopLevelWindow, 0);
}
Compat::closeDbgEng();
Overlay::ConfigWindow configWindow;
g_configWindow = &configWindow;
MSG msg = {};
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT sendMessageBlocking(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
DWORD_PTR result = 0;
SendMessageTimeout(hwnd, msg, wParam, lParam, SMTO_BLOCK | SMTO_NOTIMEOUTIFNOTHUNG, 0, &result);
return result;
return CALL_ORIG_FUNC(DefWindowProcA)(hwnd, uMsg, wParam, lParam);
}
}
@ -162,20 +19,28 @@ namespace Gdi
{
namespace PresentationWindow
{
HWND create(HWND owner, WNDPROC wndProc)
HWND create(HWND owner)
{
return reinterpret_cast<HWND>(sendMessageBlocking(g_messageWindow, WM_CREATEPRESENTATIONWINDOW,
reinterpret_cast<WPARAM>(owner), reinterpret_cast<LPARAM>(wndProc)));
}
HWND presentationWindow = nullptr;
GuiThread::execute([&]()
{
presentationWindow = GuiThread::createWindow(
WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOPARENTNOTIFY | WS_EX_TOOLWINDOW,
reinterpret_cast<const char*>(g_classAtom),
nullptr,
WS_DISABLED | WS_POPUP,
0, 0, 1, 1,
owner,
nullptr,
nullptr,
nullptr);
void destroy(HWND hwnd)
{
PostMessage(hwnd, WM_CLOSE, 0, 0);
}
Overlay::ConfigWindow* getConfigWindow()
{
return g_configWindow;
if (presentationWindow)
{
CALL_ORIG_FUNC(SetLayeredWindowAttributes)(presentationWindow, 0, 255, LWA_ALPHA);
}
});
return presentationWindow;
}
void installHooks()
@ -184,35 +49,7 @@ namespace Gdi
wc.lpfnWndProc = &presentationWindowProc;
wc.hInstance = Dll::g_currentModule;
wc.lpszClassName = "DDrawCompatPresentationWindow";
CALL_ORIG_FUNC(RegisterClassA)(&wc);
g_presentationWindowThread = Dll::createThread(presentationWindowThreadProc, &g_presentationWindowThreadId,
THREAD_PRIORITY_TIME_CRITICAL, CREATE_SUSPENDED);
}
bool isPresentationWindow(HWND hwnd)
{
return GetWindowThreadProcessId(hwnd, nullptr) == g_presentationWindowThreadId;
}
bool isThreadReady()
{
return g_isThreadReady;
}
void setWindowPos(HWND hwnd, const WINDOWPOS& wp)
{
sendMessageBlocking(hwnd, WM_SETPRESENTATIONWINDOWPOS, 0, reinterpret_cast<WPARAM>(&wp));
}
void setWindowRgn(HWND hwnd, HRGN rgn)
{
sendMessageBlocking(hwnd, WM_SETPRESENTATIONWINDOWRGN, reinterpret_cast<WPARAM>(rgn), 0);
}
void startThread()
{
ResumeThread(g_presentationWindowThread);
g_classAtom = CALL_ORIG_FUNC(RegisterClassA)(&wc);
}
}
}

View File

@ -2,23 +2,11 @@
#include <Windows.h>
namespace Overlay
{
class ConfigWindow;
}
namespace Gdi
{
namespace PresentationWindow
{
HWND create(HWND owner, WNDPROC wndProc = nullptr);
void destroy(HWND hwnd);
Overlay::ConfigWindow* getConfigWindow();
bool isPresentationWindow(HWND hwnd);
bool isThreadReady();
void setWindowPos(HWND hwnd, const WINDOWPOS& wp);
void setWindowRgn(HWND hwnd, HRGN rgn);
void startThread();
HWND create(HWND owner);
void installHooks();
}

View File

@ -3,7 +3,7 @@
#include <DDraw/Surfaces/PrimarySurface.h>
#include <Gdi/CompatDc.h>
#include <Gdi/Cursor.h>
#include <Gdi/PresentationWindow.h>
#include <Gdi/GuiThread.h>
#include <Gdi/ScrollBar.h>
#include <Gdi/ScrollFunctions.h>
#include <Gdi/TitleBar.h>
@ -319,7 +319,7 @@ namespace
if (wp.x + wp.cx > mr.right)
{
HWND parent = GetNextWindow(wp.hwnd, GW_HWNDNEXT);
while (Gdi::PresentationWindow::isPresentationWindow(parent))
while (Gdi::GuiThread::isGuiThreadWindow(parent))
{
parent = GetNextWindow(parent, GW_HWNDNEXT);
}

View File

@ -13,6 +13,7 @@
#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>
@ -39,7 +40,6 @@ namespace
WindowProc getWindowProc(HWND hwnd);
bool isTopLevelWindow(HWND hwnd);
bool isUser32ScrollBar(HWND hwnd);
void onCreateWindow(HWND hwnd);
void onDestroyWindow(HWND hwnd);
void onGetMinMaxInfo(MINMAXINFO& mmi);
void onInitMenuPopup(HMENU menu);
@ -95,12 +95,15 @@ namespace
case WM_ACTIVATEAPP:
if (!wParam)
{
auto configWindow = Gdi::PresentationWindow::getConfigWindow();
if (configWindow)
{
configWindow->setVisible(false);
}
CALL_ORIG_FUNC(ClipCursor)(nullptr);
Gdi::GuiThread::execute([&]()
{
auto configWindow = Gdi::GuiThread::getConfigWindow();
if (configWindow)
{
configWindow->setVisible(false);
}
CALL_ORIG_FUNC(ClipCursor)(nullptr);
});
}
break;
@ -202,40 +205,6 @@ namespace
IsWindowUnicode(hwnd) ? it->second.wndProcW : it->second.wndProcA);
}
void onCreateWindow(HWND hwnd)
{
LOG_FUNC("onCreateWindow", hwnd);
{
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 (!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 onDestroyWindow(HWND hwnd)
{
if (isTopLevelWindow(hwnd))
@ -415,9 +384,9 @@ namespace
switch (event)
{
case EVENT_OBJECT_CREATE:
if (OBJID_WINDOW == idObject && !Gdi::PresentationWindow::isPresentationWindow(hwnd))
if (OBJID_WINDOW == idObject)
{
onCreateWindow(hwnd);
Gdi::WinProc::onCreateWindow(hwnd);
}
break;
@ -511,10 +480,40 @@ namespace Gdi
void onCreateWindow(HWND hwnd)
{
if (PresentationWindow::isThreadReady())
LOG_FUNC("onCreateWindow", hwnd);
if (!GuiThread::isReady() || GuiThread::isGuiThreadWindow(hwnd))
{
::onCreateWindow(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 (!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)

View File

@ -9,6 +9,7 @@
#include <D3dDdi/ScopedCriticalSection.h>
#include <DDraw/RealPrimarySurface.h>
#include <Gdi/Gdi.h>
#include <Gdi/GuiThread.h>
#include <Gdi/PresentationWindow.h>
#include <Gdi/VirtualScreen.h>
#include <Gdi/Window.h>
@ -249,7 +250,7 @@ namespace
DWORD processId = 0;
GetWindowThreadProcessId(hwnd, &processId);
if (processId != context.processId ||
Gdi::PresentationWindow::isPresentationWindow(hwnd))
Gdi::GuiThread::isGuiThreadWindow(hwnd))
{
return TRUE;
}
@ -277,7 +278,7 @@ namespace
}
else if (it->second.presentationWindow)
{
Gdi::PresentationWindow::destroy(it->second.presentationWindow);
Gdi::GuiThread::destroyWindow(it->second.presentationWindow);
it->second.presentationWindow = nullptr;
}
}
@ -351,7 +352,7 @@ namespace
{
if (setPresentationWindowRgn)
{
Gdi::PresentationWindow::setWindowRgn(it->second.presentationWindow, it->second.windowRegion);
Gdi::GuiThread::setWindowRgn(it->second.presentationWindow, it->second.windowRegion);
}
WINDOWPOS wp = {};
@ -379,7 +380,11 @@ namespace
wp.flags |= SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
}
Gdi::PresentationWindow::setWindowPos(it->second.presentationWindow, wp);
Gdi::GuiThread::execute([&]()
{
CALL_ORIG_FUNC(SetWindowPos)(it->second.presentationWindow,
wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
});
}
}
return TRUE;
@ -524,7 +529,7 @@ namespace Gdi
}
RECT wr = {};
auto configWindow = PresentationWindow::getConfigWindow();
auto configWindow = GuiThread::getConfigWindow();
if (configWindow && configWindow->isVisible())
{
GetWindowRect(configWindow->getWindow(), &wr);
@ -550,7 +555,7 @@ namespace Gdi
void updateAll()
{
LOG_FUNC("Window::updateAll");
if (!Gdi::PresentationWindow::isThreadReady())
if (!GuiThread::isReady())
{
return;
}
@ -571,7 +576,7 @@ namespace Gdi
{
if (it->second.presentationWindow)
{
Gdi::PresentationWindow::destroy(it->second.presentationWindow);
GuiThread::destroyWindow(it->second.presentationWindow);
}
it = g_windows.erase(it);
}

View File

@ -9,6 +9,7 @@
#include <Common/Log.h>
#include <Dll/Dll.h>
#include <DDraw/RealPrimarySurface.h>
#include <Gdi/GuiThread.h>
#include <Gdi/PresentationWindow.h>
#include <Input/Input.h>
#include <Overlay/Window.h>
@ -21,9 +22,6 @@ namespace
void* context;
};
const UINT WM_USER_HOTKEY = WM_USER;
const UINT WM_USER_RESET_HOOK = WM_USER + 1;
HANDLE g_bmpArrow = nullptr;
SIZE g_bmpArrowSize = {};
Overlay::Window* g_capture = nullptr;
@ -31,7 +29,6 @@ namespace
HWND g_cursorWindow = nullptr;
std::map<Input::HotKey, HotKeyData> g_hotKeys;
RECT g_monitorRect = {};
DWORD g_inputThreadId = 0;
HHOOK g_keyboardHook = nullptr;
HHOOK g_mouseHook = nullptr;
@ -65,72 +62,22 @@ namespace
return CALL_ORIG_FUNC(DefWindowProcA)(hwnd, uMsg, wParam, lParam);
}
unsigned WINAPI inputThreadProc(LPVOID /*lpParameter*/)
{
g_inputThreadId = GetCurrentThreadId();
g_bmpArrow = CALL_ORIG_FUNC(LoadImageA)(Dll::g_currentModule, "BMP_ARROW", IMAGE_BITMAP, 0, 0, 0);
BITMAP bm = {};
GetObject(g_bmpArrow, sizeof(bm), &bm);
g_bmpArrowSize = { bm.bmWidth, bm.bmHeight };
g_keyboardHook = CALL_ORIG_FUNC(SetWindowsHookExA)(WH_KEYBOARD_LL, &lowLevelKeyboardProc, Dll::g_currentModule, 0);
MSG msg = {};
while (GetMessage(&msg, nullptr, 0, 0))
{
if (msg.message == WM_TIMER && !msg.hwnd && msg.lParam)
{
reinterpret_cast<TIMERPROC>(msg.lParam)(nullptr, WM_TIMER, msg.wParam, 0);
}
if (!msg.hwnd)
{
if (WM_USER_HOTKEY == msg.message)
{
DWORD pid = 0;
GetWindowThreadProcessId(GetForegroundWindow(), &pid);
if (GetCurrentProcessId() == pid)
{
auto it = std::find_if(g_hotKeys.begin(), g_hotKeys.end(),
[&](const auto& v) { return v.first.vk == msg.wParam; });
if (it != g_hotKeys.end())
{
it->second.action(it->second.context);
}
}
}
else if (WM_USER_RESET_HOOK == msg.message)
{
if (msg.wParam == WH_KEYBOARD_LL)
{
UnhookWindowsHookEx(g_keyboardHook);
g_keyboardHook = CALL_ORIG_FUNC(SetWindowsHookExA)(
WH_KEYBOARD_LL, &lowLevelKeyboardProc, Dll::g_currentModule, 0);
}
else if (msg.wParam == WH_MOUSE_LL && g_mouseHook)
{
UnhookWindowsHookEx(g_mouseHook);
g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)(
WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_currentModule, 0);
}
}
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (HC_ACTION == nCode && (WM_KEYDOWN == wParam || WM_SYSKEYDOWN == wParam))
{
auto llHook = reinterpret_cast<const KBDLLHOOKSTRUCT*>(lParam);
PostThreadMessage(GetCurrentThreadId(), WM_USER_HOTKEY, llHook->vkCode, llHook->scanCode);
DWORD pid = 0;
GetWindowThreadProcessId(GetForegroundWindow(), &pid);
if (GetCurrentProcessId() == pid)
{
auto llHook = reinterpret_cast<const KBDLLHOOKSTRUCT*>(lParam);
auto it = std::find_if(g_hotKeys.begin(), g_hotKeys.end(),
[&](const auto& v) { return v.first.vk == llHook->vkCode; });
if (it != g_hotKeys.end())
{
it->second.action(it->second.context);
}
}
}
return CallNextHookEx(nullptr, nCode, wParam, lParam);
}
@ -174,6 +121,32 @@ namespace
return CallNextHookEx(nullptr, nCode, wParam, lParam);
}
void resetKeyboardHook()
{
Gdi::GuiThread::execute([]()
{
if (g_keyboardHook)
{
UnhookWindowsHookEx(g_keyboardHook);
}
g_keyboardHook = CALL_ORIG_FUNC(SetWindowsHookExA)(
WH_KEYBOARD_LL, &lowLevelKeyboardProc, Dll::g_currentModule, 0);
});
}
void resetMouseHook()
{
Gdi::GuiThread::execute([]()
{
if (g_mouseHook)
{
UnhookWindowsHookEx(g_mouseHook);
}
g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)(
WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_currentModule, 0);
});
}
void setCursorPos(POINT cp)
{
g_cursorPos = cp;
@ -191,9 +164,16 @@ namespace
}
HHOOK result = origSetWindowsHookEx(idHook, lpfn, hmod, dwThreadId);
if (result && g_inputThreadId && (WH_KEYBOARD_LL == idHook || WH_MOUSE_LL == idHook))
if (result)
{
PostThreadMessage(g_inputThreadId, WM_USER_RESET_HOOK, idHook, 0);
if (WH_KEYBOARD_LL == idHook)
{
resetKeyboardHook();
}
else if (WH_MOUSE_LL == idHook && g_mouseHook)
{
resetMouseHook();
}
}
return result;
}
@ -235,16 +215,22 @@ namespace Input
void installHooks()
{
g_bmpArrow = CALL_ORIG_FUNC(LoadImageA)(Dll::g_currentModule, "BMP_ARROW", IMAGE_BITMAP, 0, 0, 0);
BITMAP bm = {};
GetObject(g_bmpArrow, sizeof(bm), &bm);
g_bmpArrowSize = { bm.bmWidth, bm.bmHeight };
HOOK_FUNCTION(user32, SetWindowsHookExA, setWindowsHookExA);
HOOK_FUNCTION(user32, SetWindowsHookExW, setWindowsHookExW);
}
void registerHotKey(const HotKey& hotKey, std::function<void(void*)> action, void* context)
{
static HANDLE thread = Dll::createThread(&inputThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL);
if (thread)
g_hotKeys[hotKey] = { action, context };
if (!g_keyboardHook)
{
g_hotKeys[hotKey] = { action, context };
resetKeyboardHook();
}
}
@ -255,7 +241,8 @@ namespace Input
{
if (!g_mouseHook)
{
g_cursorWindow = Gdi::PresentationWindow::create(window->getWindow(), &cursorWindowProc);
g_cursorWindow = Gdi::PresentationWindow::create(window->getWindow());
CALL_ORIG_FUNC(SetWindowLongA)(g_cursorWindow, GWL_WNDPROC, reinterpret_cast<LONG>(&cursorWindowProc));
CALL_ORIG_FUNC(SetLayeredWindowAttributes)(g_cursorWindow, RGB(0xFF, 0xFF, 0xFF), 0, LWA_COLORKEY);
MONITORINFO mi = {};
@ -266,17 +253,16 @@ namespace Input
RECT r = window->getRect();
g_cursorPos = { (r.left + r.right) / 2, (r.top + r.bottom) / 2 };
CALL_ORIG_FUNC(SetWindowPos)(g_cursorWindow, HWND_TOPMOST, g_cursorPos.x, g_cursorPos.y,
g_bmpArrowSize.cx, g_bmpArrowSize.cy, SWP_NOACTIVATE | SWP_NOSENDCHANGING);
ShowWindow(g_cursorWindow, SW_SHOW);
g_bmpArrowSize.cx, g_bmpArrowSize.cy, SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)(WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_currentModule, 0);
resetMouseHook();
}
}
else if (g_mouseHook)
{
UnhookWindowsHookEx(g_mouseHook);
g_mouseHook = nullptr;
PostMessage(g_cursorWindow, WM_CLOSE, 0, 0);
Gdi::GuiThread::destroyWindow(g_cursorWindow);
g_cursorWindow = nullptr;
}
}

View File

@ -9,6 +9,7 @@
#include <Dll/Dll.h>
#include <DDraw/RealPrimarySurface.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <Gdi/GuiThread.h>
#include <Gdi/PresentationWindow.h>
#include <Input/Input.h>
#include <Overlay/Control.h>
@ -46,12 +47,14 @@ namespace Overlay
{
Window::Window(Window* parentWindow, const RECT& rect, const Input::HotKey& hotKey)
: Control(nullptr, rect, WS_BORDER)
, m_hwnd(Gdi::PresentationWindow::create(parentWindow ? parentWindow->m_hwnd : nullptr, &staticWindowProc))
, m_hwnd(Gdi::PresentationWindow::create(parentWindow ? parentWindow->m_hwnd : nullptr))
, m_parentWindow(parentWindow)
, m_transparency(25)
{
g_windows.emplace(m_hwnd, *this);
CALL_ORIG_FUNC(SetWindowLongA)(m_hwnd, GWL_WNDPROC, reinterpret_cast<LONG>(&staticWindowProc));
setTransparency(m_transparency);
if (0 != hotKey.vk)
{
Input::registerHotKey(hotKey, &toggleWindow, this);
@ -60,7 +63,7 @@ namespace Overlay
Window::~Window()
{
Gdi::PresentationWindow::destroy(m_hwnd);
Gdi::GuiThread::destroyWindow(m_hwnd);
g_windows.erase(m_hwnd);
}
@ -122,7 +125,7 @@ namespace Overlay
else
{
auto capture = Input::getCapture();
if (capture != this && capture->m_parentWindow == this)
if (capture && capture != this && capture->m_parentWindow == this)
{
capture->setVisible(false);
}
@ -133,7 +136,12 @@ namespace Overlay
LRESULT CALLBACK Window::staticWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return g_windows.find(hwnd)->second.windowProc(uMsg, wParam, lParam);
auto it = g_windows.find(hwnd);
if (it != g_windows.end())
{
return it->second.windowProc(uMsg, wParam, lParam);
}
return CALL_ORIG_FUNC(DefWindowProcA)(hwnd, uMsg, wParam, lParam);
}
void Window::updatePos()

View File

@ -14,6 +14,7 @@
#include <DDraw/DirectDraw.h>
#include <DDraw/ScopedThreadLock.h>
#include <Gdi/Gdi.h>
#include <Gdi/GuiThread.h>
#include <Gdi/VirtualScreen.h>
#include <Win32/DisplayMode.h>
@ -672,7 +673,7 @@ namespace
{
DWORD pid = 0;
GetWindowThreadProcessId(hwnd, &pid);
if (GetCurrentProcessId() == pid)
if (GetCurrentProcessId() == pid && !Gdi::GuiThread::isGuiThreadWindow(hwnd))
{
SendNotifyMessage(hwnd, WM_DISPLAYCHANGE, 0, lParam);
}