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

View File

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

View File

@ -6,9 +6,9 @@
#include <Gdi/Font.h> #include <Gdi/Font.h>
#include <Gdi/Gdi.h> #include <Gdi/Gdi.h>
#include <Gdi/Palette.h> #include <Gdi/Palette.h>
#include <Gdi/PresentationWindow.h>
#include <Gdi/ScrollFunctions.h> #include <Gdi/ScrollFunctions.h>
#include <Gdi/User32WndProcs.h> #include <Gdi/User32WndProcs.h>
#include <Gdi/Window.h>
#include <Gdi/WinProc.h> #include <Gdi/WinProc.h>
namespace namespace
@ -38,9 +38,9 @@ namespace Gdi
{ {
DcFunctions::installHooks(); DcFunctions::installHooks();
Palette::installHooks(); Palette::installHooks();
PresentationWindow::installHooks();
ScrollFunctions::installHooks(); ScrollFunctions::installHooks();
User32WndProcs::installHooks(); User32WndProcs::installHooks();
Window::installHooks();
WinProc::installHooks(); WinProc::installHooks();
Caret::installHooks(); Caret::installHooks();
Font::installHooks(); Font::installHooks();
@ -59,7 +59,7 @@ namespace Gdi
void redrawWindow(HWND hwnd, HRGN rgn) void redrawWindow(HWND hwnd, HRGN rgn)
{ {
if (!IsWindowVisible(hwnd) || IsIconic(hwnd) || Window::isPresentationWindow(hwnd)) if (!IsWindowVisible(hwnd) || IsIconic(hwnd) || PresentationWindow::isPresentationWindow(hwnd))
{ {
return; return;
} }
@ -89,8 +89,8 @@ namespace Gdi
void uninstallHooks() void uninstallHooks()
{ {
Caret::uninstallHooks(); Caret::uninstallHooks();
PresentationWindow::uninstallHooks();
WinProc::uninstallHooks(); WinProc::uninstallHooks();
Window::uninstallHooks();
Dc::dllProcessDetach(); Dc::dllProcessDetach();
DcCache::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 <Dll/Dll.h>
#include <Gdi/AccessGuard.h> #include <Gdi/AccessGuard.h>
#include <Gdi/Dc.h> #include <Gdi/Dc.h>
#include <Win32/DisplayMode.h> #include <Gdi/PresentationWindow.h>
#include <Gdi/ScrollBar.h> #include <Gdi/ScrollBar.h>
#include <Gdi/ScrollFunctions.h> #include <Gdi/ScrollFunctions.h>
#include <Gdi/TitleBar.h> #include <Gdi/TitleBar.h>
#include <Gdi/Window.h> #include <Gdi/Window.h>
#include <Gdi/WinProc.h> #include <Gdi/WinProc.h>
#include <Win32/DisplayMode.h>
namespace namespace
{ {
@ -171,7 +172,7 @@ namespace
DWORD /*dwEventThread*/, DWORD /*dwEventThread*/,
DWORD /*dwmsEventTime*/) DWORD /*dwmsEventTime*/)
{ {
if (OBJID_WINDOW == idObject && !Gdi::Window::isPresentationWindow(hwnd)) if (OBJID_WINDOW == idObject && !Gdi::PresentationWindow::isPresentationWindow(hwnd))
{ {
onCreateWindow(hwnd); onCreateWindow(hwnd);
} }

View File

@ -4,12 +4,11 @@
#include <dwmapi.h> #include <dwmapi.h>
#include <Common/Hook.h>
#include <Common/Log.h> #include <Common/Log.h>
#include <D3dDdi/KernelModeThunks.h> #include <D3dDdi/KernelModeThunks.h>
#include <D3dDdi/ScopedCriticalSection.h> #include <D3dDdi/ScopedCriticalSection.h>
#include <DDraw/RealPrimarySurface.h> #include <DDraw/RealPrimarySurface.h>
#include <Gdi/Gdi.h> #include <Gdi/PresentationWindow.h>
#include <Gdi/VirtualScreen.h> #include <Gdi/VirtualScreen.h>
#include <Gdi/Window.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 }; 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::map<HWND, Window> g_windows;
std::vector<Window*> g_windowZOrder; std::vector<Window*> g_windowZOrder;
@ -102,107 +95,6 @@ namespace
return rgn; 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, void updatePosition(Window& window, const RECT& oldWindowRect, const RECT& oldClientRect,
const Gdi::Region& oldVisibleRegion) const Gdi::Region& oldVisibleRegion)
{ {
@ -286,8 +178,8 @@ namespace
DWORD processId = 0; DWORD processId = 0;
GetWindowThreadProcessId(hwnd, &processId); GetWindowThreadProcessId(hwnd, &processId);
if (GetWindowThreadProcessId(hwnd, &processId) == g_presentationWindowThreadId || if (processId != context.processId ||
processId != context.processId) Gdi::PresentationWindow::isPresentationWindow(hwnd))
{ {
return TRUE; return TRUE;
} }
@ -310,13 +202,12 @@ namespace
it->second.isVisibleRegionChanged = isVisible; it->second.isVisibleRegionChanged = isVisible;
if (!isLayered) if (!isLayered)
{ {
it->second.presentationWindow = reinterpret_cast<HWND>( it->second.presentationWindow = Gdi::PresentationWindow::create(hwnd);
sendMessageBlocking(g_messageWindow, WM_CREATEPRESENTATIONWINDOW, reinterpret_cast<WPARAM>(hwnd), 0));
setPresentationWindowRgn = true; setPresentationWindowRgn = true;
} }
else if (it->second.presentationWindow) else if (it->second.presentationWindow)
{ {
sendMessageBlocking(it->second.presentationWindow, WM_CLOSE, 0, 0); Gdi::PresentationWindow::destroy(it->second.presentationWindow);
it->second.presentationWindow = nullptr; it->second.presentationWindow = nullptr;
} }
} }
@ -382,9 +273,7 @@ namespace
{ {
if (setPresentationWindowRgn) if (setPresentationWindowRgn)
{ {
HRGN rgn = it->second.windowRegion; Gdi::PresentationWindow::setWindowRgn(it->second.presentationWindow, it->second.windowRegion);
sendMessageBlocking(it->second.presentationWindow, WM_SETPRESENTATIONWINDOWRGN,
reinterpret_cast<WPARAM>(rgn), 0);
} }
WINDOWPOS wp = {}; WINDOWPOS wp = {};
@ -412,8 +301,7 @@ namespace
wp.flags |= SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER; wp.flags |= SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
} }
sendMessageBlocking(it->second.presentationWindow, WM_SETPRESENTATIONWINDOWPOS, Gdi::PresentationWindow::setWindowPos(it->second.presentationWindow, wp);
0, reinterpret_cast<LPARAM>(&wp));
} }
} }
return TRUE; return TRUE;
@ -424,35 +312,6 @@ namespace Gdi
{ {
namespace Window 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) void onStyleChanged(HWND hwnd, WPARAM wParam)
{ {
if (GWL_EXSTYLE == wParam) if (GWL_EXSTYLE == wParam)
@ -655,7 +514,7 @@ namespace Gdi
{ {
if (it->second.presentationWindow) if (it->second.presentationWindow)
{ {
sendMessageBlocking(it->second.presentationWindow, WM_CLOSE, 0, 0); Gdi::PresentationWindow::destroy(it->second.presentationWindow);
} }
it = g_windows.erase(it); 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 namespace Window
{ {
bool isPresentationWindow(HWND hwnd);
void onStyleChanged(HWND hwnd, WPARAM wParam); void onStyleChanged(HWND hwnd, WPARAM wParam);
void onSyncPaint(HWND hwnd); void onSyncPaint(HWND hwnd);
void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src, void present(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
@ -18,8 +17,5 @@ namespace Gdi
void presentLayered(CompatRef<IDirectDrawSurface7> dst, POINT offset); void presentLayered(CompatRef<IDirectDrawSurface7> dst, POINT offset);
void updateAll(); void updateAll();
void updateLayeredWindowInfo(HWND hwnd, COLORREF colorKey, BYTE alpha); void updateLayeredWindowInfo(HWND hwnd, COLORREF colorKey, BYTE alpha);
void installHooks();
void uninstallHooks();
} }
} }