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

160 lines
3.7 KiB
C++

#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*/)
{
ImmDisableIME(0);
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);
}
}
}