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

Moved presentation window implementation to separate file

This commit is contained in:
narzoul 2021-01-02 22:31:23 +01:00
parent 481b09f489
commit 13ab654665
8 changed files with 226 additions and 172 deletions

View File

@ -221,6 +221,7 @@
<ClInclude Include="Gdi\Dc.h" />
<ClInclude Include="Gdi\DcCache.h" />
<ClInclude Include="Gdi\DcFunctions.h" />
<ClInclude Include="Gdi\PresentationWindow.h" />
<ClInclude Include="Gdi\User32WndProcs.h" />
<ClInclude Include="Gdi\Palette.h" />
<ClInclude Include="Gdi\Region.h" />
@ -294,6 +295,7 @@
<ClCompile Include="Gdi\Dc.cpp" />
<ClCompile Include="Gdi\DcCache.cpp" />
<ClCompile Include="Gdi\DcFunctions.cpp" />
<ClCompile Include="Gdi\PresentationWindow.cpp" />
<ClCompile Include="Gdi\User32WndProcs.cpp" />
<ClCompile Include="Gdi\Palette.cpp" />
<ClCompile Include="Gdi\Region.cpp" />

View File

@ -399,6 +399,9 @@
<ClInclude Include="Gdi\User32WndProcs.h">
<Filter>Header Files\Gdi</Filter>
</ClInclude>
<ClInclude Include="Gdi\PresentationWindow.h">
<Filter>Header Files\Gdi</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">
@ -614,5 +617,8 @@
<ClCompile Include="Gdi\User32WndProcs.cpp">
<Filter>Source Files\Gdi</Filter>
</ClCompile>
<ClCompile Include="Gdi\PresentationWindow.cpp">
<Filter>Source Files\Gdi</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -6,9 +6,9 @@
#include <Gdi/Font.h>
#include <Gdi/Gdi.h>
#include <Gdi/Palette.h>
#include <Gdi/PresentationWindow.h>
#include <Gdi/ScrollFunctions.h>
#include <Gdi/User32WndProcs.h>
#include <Gdi/Window.h>
#include <Gdi/WinProc.h>
namespace
@ -38,9 +38,9 @@ namespace Gdi
{
DcFunctions::installHooks();
Palette::installHooks();
PresentationWindow::installHooks();
ScrollFunctions::installHooks();
User32WndProcs::installHooks();
Window::installHooks();
WinProc::installHooks();
Caret::installHooks();
Font::installHooks();
@ -59,7 +59,7 @@ namespace Gdi
void redrawWindow(HWND hwnd, HRGN rgn)
{
if (!IsWindowVisible(hwnd) || IsIconic(hwnd) || Window::isPresentationWindow(hwnd))
if (!IsWindowVisible(hwnd) || IsIconic(hwnd) || PresentationWindow::isPresentationWindow(hwnd))
{
return;
}
@ -89,8 +89,8 @@ namespace Gdi
void uninstallHooks()
{
Caret::uninstallHooks();
PresentationWindow::uninstallHooks();
WinProc::uninstallHooks();
Window::uninstallHooks();
Dc::dllProcessDetach();
DcCache::dllProcessDetach();
}

View File

@ -0,0 +1,185 @@
#include <Common/Hook.h>
#include <Common/Log.h>
#include <Dll/Dll.h>
#include <Gdi/PresentationWindow.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;
DWORD g_presentationWindowThreadId = 0;
HWND g_messageWindow = nullptr;
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)
{
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));
}
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);
}
DWORD WINAPI presentationWindowThreadProc(LPVOID /*lpParameter*/)
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
WNDCLASS wc = {};
wc.lpfnWndProc = &messageWindowProc;
wc.hInstance = Dll::g_currentModule;
wc.lpszClassName = "DDrawCompatMessageWindow";
RegisterClass(&wc);
g_messageWindow = CreateWindow(
"DDrawCompatMessageWindow", nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr);
if (!g_messageWindow)
{
return 0;
}
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;
}
}
namespace Gdi
{
namespace PresentationWindow
{
HWND create(HWND owner)
{
return reinterpret_cast<HWND>(sendMessageBlocking(
g_messageWindow, WM_CREATEPRESENTATIONWINDOW, reinterpret_cast<WPARAM>(owner), 0));
}
void destroy(HWND hwnd)
{
sendMessageBlocking(hwnd, WM_CLOSE, 0, 0);
}
void installHooks()
{
WNDCLASS wc = {};
wc.lpfnWndProc = &presentationWindowProc;
wc.hInstance = Dll::g_currentModule;
wc.lpszClassName = "DDrawCompatPresentationWindow";
RegisterClass(&wc);
g_presentationWindowThread = CreateThread(
nullptr, 0, &presentationWindowThreadProc, nullptr, 0, &g_presentationWindowThreadId);
int i = 0;
while (!g_messageWindow && i < 1000)
{
Sleep(1);
++i;
}
if (!g_messageWindow)
{
Compat::Log() << "ERROR: Failed to create a message-only window";
}
}
bool isPresentationWindow(HWND hwnd)
{
return GetWindowThreadProcessId(hwnd, nullptr) == g_presentationWindowThreadId;
}
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 uninstallHooks()
{
if (g_presentationWindowThread)
{
sendMessageBlocking(g_messageWindow, WM_CLOSE, 0, 0);
if (WAIT_OBJECT_0 != WaitForSingleObject(g_presentationWindowThread, 1000))
{
TerminateThread(g_presentationWindowThread, 0);
Compat::Log() << "The presentation window thread was terminated forcefully";
}
}
}
}
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <Windows.h>
namespace Gdi
{
namespace PresentationWindow
{
HWND create(HWND owner);
void destroy(HWND hwnd);
bool isPresentationWindow(HWND hwnd);
void setWindowPos(HWND hwnd, const WINDOWPOS& wp);
void setWindowRgn(HWND hwnd, HRGN rgn);
void installHooks();
void uninstallHooks();
}
}

View File

@ -9,12 +9,13 @@
#include <Dll/Dll.h>
#include <Gdi/AccessGuard.h>
#include <Gdi/Dc.h>
#include <Win32/DisplayMode.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 <Win32/DisplayMode.h>
namespace
{
@ -171,7 +172,7 @@ namespace
DWORD /*dwEventThread*/,
DWORD /*dwmsEventTime*/)
{
if (OBJID_WINDOW == idObject && !Gdi::Window::isPresentationWindow(hwnd))
if (OBJID_WINDOW == idObject && !Gdi::PresentationWindow::isPresentationWindow(hwnd))
{
onCreateWindow(hwnd);
}

View File

@ -4,12 +4,11 @@
#include <dwmapi.h>
#include <Common/Hook.h>
#include <Common/Log.h>
#include <D3dDdi/KernelModeThunks.h>
#include <D3dDdi/ScopedCriticalSection.h>
#include <DDraw/RealPrimarySurface.h>
#include <Gdi/Gdi.h>
#include <Gdi/PresentationWindow.h>
#include <Gdi/VirtualScreen.h>
#include <Gdi/Window.h>
@ -50,14 +49,8 @@ namespace
}
};
const UINT WM_CREATEPRESENTATIONWINDOW = WM_USER;
const UINT WM_SETPRESENTATIONWINDOWPOS = WM_USER + 1;
const UINT WM_SETPRESENTATIONWINDOWRGN = WM_USER + 2;
const RECT REGION_OVERRIDE_MARKER_RECT = { 32000, 32000, 32001, 32001 };
HANDLE g_presentationWindowThread = nullptr;
DWORD g_presentationWindowThreadId = 0;
HWND g_messageWindow = nullptr;
std::map<HWND, Window> g_windows;
std::vector<Window*> g_windowZOrder;
@ -102,107 +95,6 @@ namespace
return rgn;
}
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)
{
CALL_ORIG_FUNC(SetLayeredWindowAttributes)(presentationWindow, 0, 255, LWA_ALPHA);
}
return reinterpret_cast<LRESULT>(presentationWindow);
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return CALL_ORIG_FUNC(DefWindowProc)(hwnd, uMsg, wParam, lParam);
}
}
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);
}
DWORD WINAPI presentationWindowThreadProc(LPVOID /*lpParameter*/)
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
WNDCLASS wc = {};
wc.lpfnWndProc = &messageWindowProc;
wc.hInstance = Dll::g_currentModule;
wc.lpszClassName = "DDrawCompatMessageWindow";
RegisterClass(&wc);
g_messageWindow = CreateWindow(
"DDrawCompatMessageWindow", nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr);
if (!g_messageWindow)
{
return 0;
}
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;
}
void updatePosition(Window& window, const RECT& oldWindowRect, const RECT& oldClientRect,
const Gdi::Region& oldVisibleRegion)
{
@ -286,8 +178,8 @@ namespace
DWORD processId = 0;
GetWindowThreadProcessId(hwnd, &processId);
if (GetWindowThreadProcessId(hwnd, &processId) == g_presentationWindowThreadId ||
processId != context.processId)
if (processId != context.processId ||
Gdi::PresentationWindow::isPresentationWindow(hwnd))
{
return TRUE;
}
@ -310,13 +202,12 @@ namespace
it->second.isVisibleRegionChanged = isVisible;
if (!isLayered)
{
it->second.presentationWindow = reinterpret_cast<HWND>(
sendMessageBlocking(g_messageWindow, WM_CREATEPRESENTATIONWINDOW, reinterpret_cast<WPARAM>(hwnd), 0));
it->second.presentationWindow = Gdi::PresentationWindow::create(hwnd);
setPresentationWindowRgn = true;
}
else if (it->second.presentationWindow)
{
sendMessageBlocking(it->second.presentationWindow, WM_CLOSE, 0, 0);
Gdi::PresentationWindow::destroy(it->second.presentationWindow);
it->second.presentationWindow = nullptr;
}
}
@ -382,9 +273,7 @@ namespace
{
if (setPresentationWindowRgn)
{
HRGN rgn = it->second.windowRegion;
sendMessageBlocking(it->second.presentationWindow, WM_SETPRESENTATIONWINDOWRGN,
reinterpret_cast<WPARAM>(rgn), 0);
Gdi::PresentationWindow::setWindowRgn(it->second.presentationWindow, it->second.windowRegion);
}
WINDOWPOS wp = {};
@ -412,8 +301,7 @@ namespace
wp.flags |= SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
}
sendMessageBlocking(it->second.presentationWindow, WM_SETPRESENTATIONWINDOWPOS,
0, reinterpret_cast<LPARAM>(&wp));
Gdi::PresentationWindow::setWindowPos(it->second.presentationWindow, wp);
}
}
return TRUE;
@ -424,35 +312,6 @@ namespace Gdi
{
namespace Window
{
void installHooks()
{
WNDCLASS wc = {};
wc.lpfnWndProc = &presentationWindowProc;
wc.hInstance = Dll::g_currentModule;
wc.lpszClassName = "DDrawCompatPresentationWindow";
RegisterClass(&wc);
g_presentationWindowThread = CreateThread(
nullptr, 0, &presentationWindowThreadProc, nullptr, 0, &g_presentationWindowThreadId);
int i = 0;
while (!g_messageWindow && i < 1000)
{
Sleep(1);
++i;
}
if (!g_messageWindow)
{
Compat::Log() << "ERROR: Failed to create a message-only window";
}
}
bool isPresentationWindow(HWND hwnd)
{
return g_presentationWindowThreadId == GetWindowThreadProcessId(hwnd, nullptr);
}
void onStyleChanged(HWND hwnd, WPARAM wParam)
{
if (GWL_EXSTYLE == wParam)
@ -655,7 +514,7 @@ namespace Gdi
{
if (it->second.presentationWindow)
{
sendMessageBlocking(it->second.presentationWindow, WM_CLOSE, 0, 0);
Gdi::PresentationWindow::destroy(it->second.presentationWindow);
}
it = g_windows.erase(it);
}
@ -695,18 +554,5 @@ namespace Gdi
}
}
}
void uninstallHooks()
{
if (g_presentationWindowThread)
{
sendMessageBlocking(g_messageWindow, WM_CLOSE, 0, 0);
if (WAIT_OBJECT_0 != WaitForSingleObject(g_presentationWindowThread, 1000))
{
TerminateThread(g_presentationWindowThread, 0);
Compat::Log() << "The presentation window thread was terminated forcefully";
}
}
}
}
}

View File

@ -9,7 +9,6 @@ namespace Gdi
{
namespace Window
{
bool isPresentationWindow(HWND hwnd);
void onStyleChanged(HWND hwnd, WPARAM wParam);
void onSyncPaint(HWND hwnd);
void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
@ -18,8 +17,5 @@ namespace Gdi
void presentLayered(CompatRef<IDirectDrawSurface7> dst, POINT offset);
void updateAll();
void updateLayeredWindowInfo(HWND hwnd, COLORREF colorKey, BYTE alpha);
void installHooks();
void uninstallHooks();
}
}