mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Fixed display issues with user32 controls
This commit is contained in:
parent
537ef9c595
commit
2f00b74a56
@ -96,10 +96,13 @@ std::ostream& operator<<(std::ostream& os, HRGN__& rgn)
|
|||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, HWND__& hwnd)
|
std::ostream& operator<<(std::ostream& os, HWND__& hwnd)
|
||||||
{
|
{
|
||||||
char name[256] = {};
|
char name[256] = "INVALID";
|
||||||
GetClassName(&hwnd, name, sizeof(name));
|
|
||||||
RECT rect = {};
|
RECT rect = {};
|
||||||
GetWindowRect(&hwnd, &rect);
|
if (IsWindow(&hwnd))
|
||||||
|
{
|
||||||
|
GetClassName(&hwnd, name, sizeof(name));
|
||||||
|
GetWindowRect(&hwnd, &rect);
|
||||||
|
}
|
||||||
return os << "WND(" << static_cast<void*>(&hwnd) << ',' << name << ',' << rect << ')';
|
return os << "WND(" << static_cast<void*>(&hwnd) << ',' << name << ',' << rect << ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,18 +22,6 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct BltToWindowViaGdiArgs
|
|
||||||
{
|
|
||||||
std::unique_ptr<HDC__, void(*)(HDC)> virtualScreenDc;
|
|
||||||
Gdi::Region* primaryRegion;
|
|
||||||
|
|
||||||
BltToWindowViaGdiArgs()
|
|
||||||
: virtualScreenDc(nullptr, &Gdi::VirtualScreen::deleteDc)
|
|
||||||
, primaryRegion(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void onRelease();
|
void onRelease();
|
||||||
DWORD WINAPI updateThreadProc(LPVOID lpParameter);
|
DWORD WINAPI updateThreadProc(LPVOID lpParameter);
|
||||||
|
|
||||||
@ -70,65 +58,61 @@ namespace
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL CALLBACK bltToWindow(HWND hwnd, LPARAM lParam)
|
void bltToWindow(CompatRef<IDirectDrawSurface7> src)
|
||||||
{
|
{
|
||||||
if (!IsWindowVisible(hwnd) || !Gdi::Window::isPresentationWindow(hwnd))
|
for (auto windowPair : Gdi::Window::getWindows())
|
||||||
{
|
{
|
||||||
return TRUE;
|
if (IsWindowVisible(windowPair.first))
|
||||||
|
{
|
||||||
|
g_clipper->SetHWnd(g_clipper, 0, windowPair.second->getPresentationWindow());
|
||||||
|
g_frontBuffer->Blt(g_frontBuffer, nullptr, &src, nullptr, DDBLT_WAIT, nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_clipper->SetHWnd(g_clipper, 0, hwnd);
|
|
||||||
auto src = reinterpret_cast<IDirectDrawSurface7*>(lParam);
|
|
||||||
g_frontBuffer->Blt(g_frontBuffer, nullptr, src, nullptr, DDBLT_WAIT, nullptr);
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL CALLBACK bltToWindowViaGdi(HWND hwnd, LPARAM lParam)
|
void bltToWindowViaGdi(Gdi::Region* primaryRegion)
|
||||||
{
|
{
|
||||||
if (!IsWindowVisible(hwnd) || !Gdi::Window::isPresentationWindow(hwnd))
|
std::unique_ptr<HDC__, void(*)(HDC)> virtualScreenDc(nullptr, &Gdi::VirtualScreen::deleteDc);
|
||||||
{
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto window = Gdi::Window::get(GetParent(hwnd));
|
for (auto windowPair : Gdi::Window::getWindows())
|
||||||
if (!window)
|
|
||||||
{
|
{
|
||||||
return TRUE;
|
if (!IsWindowVisible(windowPair.first))
|
||||||
}
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Gdi::Region visibleRegion = window->getVisibleRegion();
|
Gdi::Region visibleRegion = windowPair.second->getVisibleRegion();
|
||||||
if (visibleRegion.isEmpty())
|
|
||||||
{
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& args = *reinterpret_cast<BltToWindowViaGdiArgs*>(lParam);
|
|
||||||
if (args.primaryRegion)
|
|
||||||
{
|
|
||||||
visibleRegion -= *args.primaryRegion;
|
|
||||||
if (visibleRegion.isEmpty())
|
if (visibleRegion.isEmpty())
|
||||||
{
|
{
|
||||||
return TRUE;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!args.virtualScreenDc)
|
if (primaryRegion)
|
||||||
{
|
|
||||||
args.virtualScreenDc.reset(Gdi::VirtualScreen::createDc());
|
|
||||||
if (!args.virtualScreenDc)
|
|
||||||
{
|
{
|
||||||
return FALSE;
|
visibleRegion -= *primaryRegion;
|
||||||
|
if (visibleRegion.isEmpty())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!virtualScreenDc)
|
||||||
|
{
|
||||||
|
virtualScreenDc.reset(Gdi::VirtualScreen::createDc());
|
||||||
|
if (!virtualScreenDc)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Gdi::GdiAccessGuard gdiAccessGuard(Gdi::ACCESS_READ);
|
||||||
|
HWND presentationWindow = windowPair.second->getPresentationWindow();
|
||||||
|
HDC dc = GetWindowDC(presentationWindow);
|
||||||
|
RECT rect = windowPair.second->getWindowRect();
|
||||||
|
CALL_ORIG_FUNC(BitBlt)(dc, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
|
||||||
|
virtualScreenDc.get(), rect.left, rect.top, SRCCOPY);
|
||||||
|
ReleaseDC(presentationWindow, dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_READ);
|
|
||||||
HDC presentationWindowDc = GetWindowDC(hwnd);
|
|
||||||
RECT rect = window->getWindowRect();
|
|
||||||
CALL_ORIG_FUNC(BitBlt)(presentationWindowDc, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
|
|
||||||
args.virtualScreenDc.get(), rect.left, rect.top, SRCCOPY);
|
|
||||||
ReleaseDC(hwnd, presentationWindowDc);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bltVisibleLayeredWindowsToBackBuffer()
|
void bltVisibleLayeredWindowsToBackBuffer()
|
||||||
@ -174,7 +158,7 @@ namespace
|
|||||||
{
|
{
|
||||||
if (!g_isFullScreen)
|
if (!g_isFullScreen)
|
||||||
{
|
{
|
||||||
EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindow, reinterpret_cast<LPARAM>(&src));
|
bltToWindow(src);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,19 +348,15 @@ namespace
|
|||||||
|
|
||||||
Gdi::VirtualScreen::update();
|
Gdi::VirtualScreen::update();
|
||||||
|
|
||||||
BltToWindowViaGdiArgs bltToWindowViaGdiArgs;
|
|
||||||
if (!g_frontBuffer || !src || DDraw::RealPrimarySurface::isLost())
|
if (!g_frontBuffer || !src || DDraw::RealPrimarySurface::isLost())
|
||||||
{
|
{
|
||||||
EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindowViaGdi,
|
bltToWindowViaGdi(nullptr);
|
||||||
reinterpret_cast<LPARAM>(&bltToWindowViaGdiArgs));
|
|
||||||
Compat::LogLeave("RealPrimarySurface::presentToPrimaryChain", src.get()) << false;
|
Compat::LogLeave("RealPrimarySurface::presentToPrimaryChain", src.get()) << false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Gdi::Region primaryRegion(D3dDdi::KernelModeThunks::getMonitorRect());
|
Gdi::Region primaryRegion(D3dDdi::KernelModeThunks::getMonitorRect());
|
||||||
bltToWindowViaGdiArgs.primaryRegion = &primaryRegion;
|
bltToWindowViaGdi(&primaryRegion);
|
||||||
EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindowViaGdi,
|
|
||||||
reinterpret_cast<LPARAM>(&bltToWindowViaGdiArgs));
|
|
||||||
|
|
||||||
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, DDraw::PrimarySurface::isGdiSurface(src.get()));
|
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, DDraw::PrimarySurface::isGdiSurface(src.get()));
|
||||||
if (DDraw::PrimarySurface::getDesc().ddpfPixelFormat.dwRGBBitCount <= 8)
|
if (DDraw::PrimarySurface::getDesc().ddpfPixelFormat.dwRGBBitCount <= 8)
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include "Common/Hook.h"
|
#include "Common/Hook.h"
|
||||||
#include "Common/Log.h"
|
#include "Common/Log.h"
|
||||||
#include "Common/ScopedCriticalSection.h"
|
#include "DDraw/ScopedThreadLock.h"
|
||||||
#include "Gdi/Dc.h"
|
#include "Gdi/Dc.h"
|
||||||
#include "Gdi/DcCache.h"
|
#include "Gdi/DcCache.h"
|
||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
@ -24,7 +24,6 @@ namespace
|
|||||||
typedef std::unique_ptr<HDC__, void(*)(HDC)> OrigDc;
|
typedef std::unique_ptr<HDC__, void(*)(HDC)> OrigDc;
|
||||||
typedef std::unordered_map<HDC, CompatDc> CompatDcMap;
|
typedef std::unordered_map<HDC, CompatDc> CompatDcMap;
|
||||||
|
|
||||||
CRITICAL_SECTION g_cs;
|
|
||||||
CompatDcMap g_origDcToCompatDc;
|
CompatDcMap g_origDcToCompatDc;
|
||||||
thread_local std::vector<OrigDc> g_threadDcs;
|
thread_local std::vector<OrigDc> g_threadDcs;
|
||||||
|
|
||||||
@ -82,7 +81,7 @@ namespace
|
|||||||
|
|
||||||
void deleteDc(HDC origDc)
|
void deleteDc(HDC origDc)
|
||||||
{
|
{
|
||||||
Compat::ScopedCriticalSection lock(g_cs);
|
DDraw::ScopedThreadLock lock;
|
||||||
auto it = g_origDcToCompatDc.find(origDc);
|
auto it = g_origDcToCompatDc.find(origDc);
|
||||||
RestoreDC(it->second.dc, it->second.savedState);
|
RestoreDC(it->second.dc, it->second.savedState);
|
||||||
Gdi::DcCache::deleteDc(it->second.dc);
|
Gdi::DcCache::deleteDc(it->second.dc);
|
||||||
@ -110,24 +109,6 @@ namespace
|
|||||||
}
|
}
|
||||||
DeleteObject(clipRgn);
|
DeleteObject(clipRgn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateWindow(HWND wnd)
|
|
||||||
{
|
|
||||||
auto window = Gdi::Window::get(wnd);
|
|
||||||
if (!window)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RECT windowRect = {};
|
|
||||||
GetWindowRect(wnd, &windowRect);
|
|
||||||
|
|
||||||
RECT cachedWindowRect = window->getWindowRect();
|
|
||||||
if (!EqualRect(&windowRect, &cachedWindowRect))
|
|
||||||
{
|
|
||||||
Gdi::Window::updateAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Gdi
|
namespace Gdi
|
||||||
@ -141,7 +122,7 @@ namespace Gdi
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Compat::ScopedCriticalSection lock(g_cs);
|
DDraw::ScopedThreadLock lock;
|
||||||
auto it = g_origDcToCompatDc.find(origDc);
|
auto it = g_origDcToCompatDc.find(origDc);
|
||||||
if (it != g_origDcToCompatDc.end())
|
if (it != g_origDcToCompatDc.end())
|
||||||
{
|
{
|
||||||
@ -150,10 +131,15 @@ namespace Gdi
|
|||||||
}
|
}
|
||||||
|
|
||||||
const HWND wnd = CALL_ORIG_FUNC(WindowFromDC)(origDc);
|
const HWND wnd = CALL_ORIG_FUNC(WindowFromDC)(origDc);
|
||||||
const HWND rootWnd = wnd ? GetAncestor(wnd, GA_ROOT) : nullptr;
|
auto rootWnd = wnd ? GetAncestor(wnd, GA_ROOT) : nullptr;
|
||||||
if (rootWnd && GetDesktopWindow() != rootWnd)
|
if (rootWnd && GetDesktopWindow() != rootWnd)
|
||||||
{
|
{
|
||||||
updateWindow(rootWnd);
|
auto rootWindow(Window::get(rootWnd));
|
||||||
|
if (!rootWindow)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
rootWindow->updateWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
CompatDc compatDc;
|
CompatDc compatDc;
|
||||||
@ -183,20 +169,15 @@ namespace Gdi
|
|||||||
|
|
||||||
HDC getOrigDc(HDC dc)
|
HDC getOrigDc(HDC dc)
|
||||||
{
|
{
|
||||||
Compat::ScopedCriticalSection lock(g_cs);
|
DDraw::ScopedThreadLock lock;
|
||||||
const auto it = std::find_if(g_origDcToCompatDc.begin(), g_origDcToCompatDc.end(),
|
const auto it = std::find_if(g_origDcToCompatDc.begin(), g_origDcToCompatDc.end(),
|
||||||
[dc](const CompatDcMap::value_type& compatDc) { return compatDc.second.dc == dc; });
|
[dc](const CompatDcMap::value_type& compatDc) { return compatDc.second.dc == dc; });
|
||||||
return it != g_origDcToCompatDc.end() ? it->first : dc;
|
return it != g_origDcToCompatDc.end() ? it->first : dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init()
|
|
||||||
{
|
|
||||||
InitializeCriticalSection(&g_cs);
|
|
||||||
}
|
|
||||||
|
|
||||||
void releaseDc(HDC origDc)
|
void releaseDc(HDC origDc)
|
||||||
{
|
{
|
||||||
Compat::ScopedCriticalSection lock(g_cs);
|
DDraw::ScopedThreadLock lock;
|
||||||
auto it = g_origDcToCompatDc.find(origDc);
|
auto it = g_origDcToCompatDc.find(origDc);
|
||||||
if (it == g_origDcToCompatDc.end())
|
if (it == g_origDcToCompatDc.end())
|
||||||
{
|
{
|
||||||
|
@ -10,7 +10,6 @@ namespace Gdi
|
|||||||
{
|
{
|
||||||
HDC getDc(HDC origDc);
|
HDC getDc(HDC origDc);
|
||||||
HDC getOrigDc(HDC dc);
|
HDC getOrigDc(HDC dc);
|
||||||
void init();
|
|
||||||
void releaseDc(HDC origDc);
|
void releaseDc(HDC origDc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,9 @@
|
|||||||
#include "Gdi/Dc.h"
|
#include "Gdi/Dc.h"
|
||||||
#include "Gdi/DcFunctions.h"
|
#include "Gdi/DcFunctions.h"
|
||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
|
#include "Gdi/Region.h"
|
||||||
#include "Gdi/VirtualScreen.h"
|
#include "Gdi/VirtualScreen.h"
|
||||||
|
#include "Gdi/Window.h"
|
||||||
#include "Win32/DisplayMode.h"
|
#include "Win32/DisplayMode.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -20,7 +22,7 @@ namespace
|
|||||||
std::unordered_map<void*, const char*> g_funcNames;
|
std::unordered_map<void*, const char*> g_funcNames;
|
||||||
|
|
||||||
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename... Params>
|
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename... Params>
|
||||||
DWORD getDdLockFlags(Params... params);
|
HDC getDestinationDc(Params... params);
|
||||||
|
|
||||||
HRGN getWindowRegion(HWND hwnd);
|
HRGN getWindowRegion(HWND hwnd);
|
||||||
|
|
||||||
@ -85,7 +87,7 @@ namespace
|
|||||||
Result result = 0;
|
Result result = 0;
|
||||||
if (hasDisplayDcArg(params...))
|
if (hasDisplayDcArg(params...))
|
||||||
{
|
{
|
||||||
const bool isReadOnlyAccess = getDdLockFlags<OrigFuncPtr, origFunc>(params...) & DDLOCK_READONLY;
|
const bool isReadOnlyAccess = !hasDisplayDcArg(getDestinationDc<OrigFuncPtr, origFunc>(params...));
|
||||||
Gdi::GdiAccessGuard accessGuard(isReadOnlyAccess ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE);
|
Gdi::GdiAccessGuard accessGuard(isReadOnlyAccess ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE);
|
||||||
result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...);
|
result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...);
|
||||||
releaseDc(params...);
|
releaseDc(params...);
|
||||||
@ -102,6 +104,49 @@ namespace
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
BOOL WINAPI compatGdiDcFunc<decltype(&ExtTextOutW), &ExtTextOutW>(
|
||||||
|
HDC hdc, int x, int y, UINT options, const RECT* lprect, LPCWSTR lpString, UINT c, const INT* lpDx)
|
||||||
|
{
|
||||||
|
Compat::LogEnter("ExtTextOutW", hdc, x, y, options, lprect, lpString, c, lpDx);
|
||||||
|
|
||||||
|
BOOL result = TRUE;
|
||||||
|
if (hasDisplayDcArg(hdc))
|
||||||
|
{
|
||||||
|
HWND hwnd = CALL_ORIG_FUNC(WindowFromDC)(hdc);
|
||||||
|
ATOM atom = static_cast<ATOM>(GetClassLong(hwnd, GCW_ATOM));
|
||||||
|
POINT p = { x, y };
|
||||||
|
if (Gdi::MENU_ATOM == atom)
|
||||||
|
{
|
||||||
|
RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE);
|
||||||
|
}
|
||||||
|
else if (GetCurrentThreadId() == GetWindowThreadProcessId(hwnd, nullptr) &&
|
||||||
|
LPtoDP(hdc, &p, 1) &&
|
||||||
|
HTMENU == SendMessage(hwnd, WM_NCHITTEST, 0, (p.y << 16) | (p.x & 0xFFFF)))
|
||||||
|
{
|
||||||
|
WINDOWINFO wi = {};
|
||||||
|
GetWindowInfo(hwnd, &wi);
|
||||||
|
Gdi::Region ncRegion(wi.rcWindow);
|
||||||
|
ncRegion -= wi.rcClient;
|
||||||
|
ncRegion.offset(-wi.rcClient.left, -wi.rcClient.top);
|
||||||
|
RedrawWindow(hwnd, nullptr, ncRegion, RDW_INVALIDATE | RDW_FRAME);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
||||||
|
result = CALL_ORIG_FUNC(ExtTextOutW)(replaceDc(hdc), x, y, options, lprect, lpString, c, lpDx);
|
||||||
|
releaseDc(hdc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = CALL_ORIG_FUNC(ExtTextOutW)(hdc, x, y, options, lprect, lpString, c, lpDx);
|
||||||
|
}
|
||||||
|
|
||||||
|
Compat::LogLeave("ExtTextOutW", hdc, x, y, options, lprect, lpString, c, lpDx) << result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
BOOL CALLBACK excludeRgnForOverlappingWindow(HWND hwnd, LPARAM lParam)
|
BOOL CALLBACK excludeRgnForOverlappingWindow(HWND hwnd, LPARAM lParam)
|
||||||
{
|
{
|
||||||
auto& args = *reinterpret_cast<ExcludeRgnForOverlappingWindowArgs*>(lParam);
|
auto& args = *reinterpret_cast<ExcludeRgnForOverlappingWindowArgs*>(lParam);
|
||||||
@ -129,84 +174,40 @@ namespace
|
|||||||
return &compatGdiDcFunc<OrigFuncPtr, origFunc, Result, Params...>;
|
return &compatGdiDcFunc<OrigFuncPtr, origFunc, Result, Params...>;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD getDdLockFlagsBlt(HDC hdcDest, HDC hdcSrc)
|
HDC getFirstDc()
|
||||||
{
|
{
|
||||||
return hasDisplayDcArg(hdcSrc) && !hasDisplayDcArg(hdcDest) ? DDLOCK_READONLY : 0;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Params>
|
||||||
|
HDC getFirstDc(HDC dc, Params...)
|
||||||
|
{
|
||||||
|
return dc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FirstParam, typename... Params>
|
||||||
|
HDC getFirstDc(FirstParam, Params... params)
|
||||||
|
{
|
||||||
|
return getFirstDc(params...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename... Params>
|
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename... Params>
|
||||||
DWORD getDdLockFlags(Params...)
|
HDC getDestinationDc(Params... params)
|
||||||
{
|
{
|
||||||
return 0;
|
return getFirstDc(params...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
DWORD getDdLockFlags<decltype(&AlphaBlend), &AlphaBlend>(
|
HDC getDestinationDc<decltype(&GetDIBits), &GetDIBits>(
|
||||||
HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, int, int, BLENDFUNCTION)
|
|
||||||
{
|
|
||||||
return getDdLockFlagsBlt(hdcDest, hdcSrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
DWORD getDdLockFlags<decltype(&BitBlt), &BitBlt>(
|
|
||||||
HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, DWORD)
|
|
||||||
{
|
|
||||||
return getDdLockFlagsBlt(hdcDest, hdcSrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
DWORD getDdLockFlags<decltype(&GdiAlphaBlend), &GdiAlphaBlend>(
|
|
||||||
HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, int, int, BLENDFUNCTION)
|
|
||||||
{
|
|
||||||
return getDdLockFlagsBlt(hdcDest, hdcSrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
DWORD getDdLockFlags<decltype(&GdiTransparentBlt), &GdiTransparentBlt >(
|
|
||||||
HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, int, int, UINT)
|
|
||||||
{
|
|
||||||
return getDdLockFlagsBlt(hdcDest, hdcSrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
DWORD getDdLockFlags<decltype(&GetDIBits), &GetDIBits>(
|
|
||||||
HDC, HBITMAP, UINT, UINT, LPVOID, LPBITMAPINFO, UINT)
|
HDC, HBITMAP, UINT, UINT, LPVOID, LPBITMAPINFO, UINT)
|
||||||
{
|
{
|
||||||
return DDLOCK_READONLY;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
DWORD getDdLockFlags<decltype(&GetPixel), &GetPixel>(HDC, int, int)
|
HDC getDestinationDc<decltype(&GetPixel), &GetPixel>(HDC, int, int)
|
||||||
{
|
{
|
||||||
return DDLOCK_READONLY;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
DWORD getDdLockFlags<decltype(&MaskBlt), &MaskBlt>(
|
|
||||||
HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, HBITMAP, int, int, DWORD)
|
|
||||||
{
|
|
||||||
return getDdLockFlagsBlt(hdcDest, hdcSrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
DWORD getDdLockFlags<decltype(&PlgBlt), &PlgBlt>(
|
|
||||||
HDC hdcDest, const POINT*, HDC hdcSrc, int, int, int, int, HBITMAP, int, int)
|
|
||||||
{
|
|
||||||
return getDdLockFlagsBlt(hdcDest, hdcSrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
DWORD getDdLockFlags<decltype(&StretchBlt), &StretchBlt>(
|
|
||||||
HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, int, int, DWORD)
|
|
||||||
{
|
|
||||||
return getDdLockFlagsBlt(hdcDest, hdcSrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
DWORD getDdLockFlags<decltype(&TransparentBlt), &TransparentBlt>(
|
|
||||||
HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, int, int, UINT)
|
|
||||||
{
|
|
||||||
return getDdLockFlagsBlt(hdcDest, hdcSrc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HRGN getWindowRegion(HWND hwnd)
|
HRGN getWindowRegion(HWND hwnd)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||||
#include "Gdi/Caret.h"
|
#include "Gdi/Caret.h"
|
||||||
#include "Gdi/Dc.h"
|
|
||||||
#include "Gdi/DcFunctions.h"
|
#include "Gdi/DcFunctions.h"
|
||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
#include "Gdi/PaintHandlers.h"
|
#include "Gdi/PaintHandlers.h"
|
||||||
@ -37,20 +36,11 @@ namespace Gdi
|
|||||||
return DcFunctions::getVisibleWindowRgn(hwnd);
|
return DcFunctions::getVisibleWindowRgn(hwnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hookWndProc(LPCSTR className, WNDPROC &oldWndProc, WNDPROC newWndProc)
|
|
||||||
{
|
|
||||||
HWND hwnd = CreateWindow(className, nullptr, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr, 0);
|
|
||||||
oldWndProc = reinterpret_cast<WNDPROC>(
|
|
||||||
SetClassLongPtr(hwnd, GCLP_WNDPROC, reinterpret_cast<LONG>(newWndProc)));
|
|
||||||
DestroyWindow(hwnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void installHooks()
|
void installHooks()
|
||||||
{
|
{
|
||||||
g_gdiThreadId = GetCurrentThreadId();
|
g_gdiThreadId = GetCurrentThreadId();
|
||||||
g_screenDc = GetDC(nullptr);
|
g_screenDc = GetDC(nullptr);
|
||||||
|
|
||||||
Gdi::Dc::init();
|
|
||||||
Gdi::DcFunctions::installHooks();
|
Gdi::DcFunctions::installHooks();
|
||||||
Gdi::PaintHandlers::installHooks();
|
Gdi::PaintHandlers::installHooks();
|
||||||
Gdi::ScrollFunctions::installHooks();
|
Gdi::ScrollFunctions::installHooks();
|
||||||
|
@ -6,12 +6,13 @@
|
|||||||
|
|
||||||
namespace Gdi
|
namespace Gdi
|
||||||
{
|
{
|
||||||
|
const ATOM MENU_ATOM = 0x8000;
|
||||||
|
|
||||||
typedef void(*WindowPosChangeNotifyFunc)();
|
typedef void(*WindowPosChangeNotifyFunc)();
|
||||||
|
|
||||||
DWORD getGdiThreadId();
|
DWORD getGdiThreadId();
|
||||||
HDC getScreenDc();
|
HDC getScreenDc();
|
||||||
HRGN getVisibleWindowRgn(HWND hwnd);
|
HRGN getVisibleWindowRgn(HWND hwnd);
|
||||||
void hookWndProc(LPCSTR className, WNDPROC &oldWndProc, WNDPROC newWndProc);
|
|
||||||
void installHooks();
|
void installHooks();
|
||||||
void redraw(HRGN rgn);
|
void redraw(HRGN rgn);
|
||||||
void redrawWindow(HWND hwnd, HRGN rgn);
|
void redrawWindow(HWND hwnd, HRGN rgn);
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/Hook.h"
|
#include "Common/Hook.h"
|
||||||
#include "Common/Log.h"
|
#include "Common/Log.h"
|
||||||
#include "DDraw/RealPrimarySurface.h"
|
#include "DDraw/RealPrimarySurface.h"
|
||||||
@ -8,56 +10,130 @@
|
|||||||
#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/VirtualScreen.h"
|
||||||
|
#include "Gdi/Window.h"
|
||||||
#include "Win32/Registry.h"
|
#include "Win32/Registry.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
LRESULT WINAPI defPaintProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
|
typedef LRESULT(*WndProcHook)(HWND, UINT, WPARAM, LPARAM, WNDPROC);
|
||||||
WNDPROC origWndProc, const char* origWndProcName);
|
|
||||||
|
struct User32WndProc
|
||||||
|
{
|
||||||
|
WNDPROC oldWndProcTrampoline;
|
||||||
|
WNDPROC oldWndProc;
|
||||||
|
WNDPROC newWndProc;
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
User32WndProc()
|
||||||
|
: 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,
|
||||||
|
const char* origWndProcName);
|
||||||
LRESULT onEraseBackground(HWND hwnd, HDC dc, WNDPROC origWndProc);
|
LRESULT onEraseBackground(HWND hwnd, HDC dc, WNDPROC origWndProc);
|
||||||
LRESULT onMenuPaint(HWND hwnd, WNDPROC origWndProc);
|
|
||||||
LRESULT onNcPaint(HWND hwnd, WPARAM wParam, WNDPROC origWndProc);
|
LRESULT onNcPaint(HWND hwnd, WPARAM wParam, WNDPROC origWndProc);
|
||||||
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);
|
||||||
|
|
||||||
WNDPROC g_origButtonWndProc = nullptr;
|
HHOOK g_cbtProcHook = nullptr;
|
||||||
WNDPROC g_origComboListBoxWndProc = nullptr;
|
int g_menuWndProcIndex = 0;
|
||||||
WNDPROC g_origEditWndProc = nullptr;
|
int g_scrollBarWndProcIndex = 0;
|
||||||
WNDPROC g_origListBoxWndProc = nullptr;
|
|
||||||
WNDPROC g_origMenuWndProc = nullptr;
|
|
||||||
WNDPROC g_origScrollBarWndProc = nullptr;
|
|
||||||
|
|
||||||
LRESULT WINAPI buttonWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
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)
|
||||||
{
|
{
|
||||||
Compat::LogEnter("buttonWndProc", hwnd, msg, wParam, lParam);
|
|
||||||
LRESULT result = 0;
|
|
||||||
|
|
||||||
switch (msg)
|
switch (msg)
|
||||||
{
|
{
|
||||||
case WM_PAINT:
|
case WM_PAINT:
|
||||||
result = onPaint(hwnd, g_origButtonWndProc);
|
return onPaint(hwnd, origWndProc);
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_ENABLE:
|
case WM_ENABLE:
|
||||||
case WM_SETTEXT:
|
case WM_SETTEXT:
|
||||||
case BM_SETCHECK:
|
case BM_SETCHECK:
|
||||||
case BM_SETSTATE:
|
case BM_SETSTATE:
|
||||||
result = CallWindowProc(g_origButtonWndProc, hwnd, msg, wParam, lParam);
|
{
|
||||||
|
LRESULT result = CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
|
||||||
RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW);
|
RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW);
|
||||||
break;
|
return result;
|
||||||
|
|
||||||
default:
|
|
||||||
result = CallWindowProc(g_origButtonWndProc, hwnd, msg, wParam, lParam);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Compat::LogLeave("buttonWndProc", hwnd, msg, wParam, lParam) << result;
|
default:
|
||||||
|
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK cbtProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
Compat::LogEnter("cbtProc", Compat::hex(nCode), Compat::hex(wParam), Compat::hex(lParam));
|
||||||
|
LRESULT result = 0;
|
||||||
|
|
||||||
|
if (nCode < 0)
|
||||||
|
{
|
||||||
|
result = CallNextHookEx(nullptr, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
|
else if (HCBT_CREATEWND == nCode)
|
||||||
|
{
|
||||||
|
HWND hwnd = reinterpret_cast<HWND>(wParam);
|
||||||
|
WNDPROC wndProcA = reinterpret_cast<WNDPROC>(GetWindowLongA(hwnd, GWL_WNDPROC));
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
else if (wndProcA == g_user32WndProcA[g_scrollBarWndProcIndex].oldWndProc ||
|
||||||
|
wndProcW == g_user32WndProcW[g_scrollBarWndProcIndex].oldWndProc)
|
||||||
|
{
|
||||||
|
index = g_scrollBarWndProcIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 != index)
|
||||||
|
{
|
||||||
|
if (IsWindowUnicode(hwnd))
|
||||||
|
{
|
||||||
|
CALL_ORIG_FUNC(SetWindowLongW)(hwnd, GWL_WNDPROC,
|
||||||
|
reinterpret_cast<LONG>(g_user32WndProcW[index].newWndProc));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC,
|
||||||
|
reinterpret_cast<LONG>(g_user32WndProcA[index].newWndProc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Compat::LogLeave("cbtProc", Compat::hex(nCode), Compat::hex(wParam), Compat::hex(lParam)) << result;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT WINAPI comboListBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
LRESULT comboBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
||||||
{
|
{
|
||||||
return defPaintProc(hwnd, msg, wParam, lParam, g_origComboListBoxWndProc, "comboListBoxWndProc");
|
return defPaintProc(hwnd, msg, wParam, lParam, origWndProc);
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT comboListBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
||||||
|
{
|
||||||
|
LRESULT result = defPaintProc(hwnd, msg, wParam, lParam, origWndProc);
|
||||||
|
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WM_NCPAINT:
|
||||||
|
CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT WINAPI defDlgProcA(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
LRESULT WINAPI defDlgProcA(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
@ -70,38 +146,31 @@ namespace
|
|||||||
return defPaintProc(hdlg, msg, wParam, lParam, CALL_ORIG_FUNC(DefDlgProcW), "defDlgProcW");
|
return defPaintProc(hdlg, msg, wParam, lParam, CALL_ORIG_FUNC(DefDlgProcW), "defDlgProcW");
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT WINAPI defPaintProc(
|
LRESULT defPaintProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
||||||
HWND hwnd,
|
|
||||||
UINT msg,
|
|
||||||
WPARAM wParam,
|
|
||||||
LPARAM lParam,
|
|
||||||
WNDPROC origWndProc,
|
|
||||||
const char* origWndProcName)
|
|
||||||
{
|
{
|
||||||
Compat::LogEnter(origWndProcName, hwnd, msg, wParam, lParam);
|
|
||||||
LRESULT result = 0;
|
|
||||||
|
|
||||||
switch (msg)
|
switch (msg)
|
||||||
{
|
{
|
||||||
case WM_ERASEBKGND:
|
case WM_ERASEBKGND:
|
||||||
result = onEraseBackground(hwnd, reinterpret_cast<HDC>(wParam), origWndProc);
|
return onEraseBackground(hwnd, reinterpret_cast<HDC>(wParam), origWndProc);
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_NCPAINT:
|
case WM_NCPAINT:
|
||||||
result = onNcPaint(hwnd, wParam, origWndProc);
|
return onNcPaint(hwnd, wParam, origWndProc);
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_PRINT:
|
case WM_PRINT:
|
||||||
case WM_PRINTCLIENT:
|
case WM_PRINTCLIENT:
|
||||||
result = onPrint(hwnd, msg, reinterpret_cast<HDC>(wParam), lParam, origWndProc);
|
return onPrint(hwnd, msg, reinterpret_cast<HDC>(wParam), lParam, origWndProc);
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
result = CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
|
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Compat::LogLeave(origWndProcName, hwnd, msg, wParam, lParam) << result;
|
LRESULT defPaintProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc,
|
||||||
|
const char* origWndProcName)
|
||||||
|
{
|
||||||
|
Compat::LogEnter(origWndProcName, hwnd, Compat::hex(msg), Compat::hex(wParam), Compat::hex(lParam));
|
||||||
|
LRESULT result = defPaintProc(hwnd, msg, wParam, lParam, origWndProc);
|
||||||
|
Compat::LogLeave(origWndProcName, hwnd, Compat::hex(msg), Compat::hex(wParam), Compat::hex(lParam)) << result;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,9 +210,9 @@ namespace
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT WINAPI editWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
LRESULT editWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
||||||
{
|
{
|
||||||
LRESULT result = defPaintProc(hwnd, msg, wParam, lParam, g_origEditWndProc, "editWndProc");
|
LRESULT result = defPaintProc(hwnd, msg, wParam, lParam, origWndProc);
|
||||||
if (0 == result && (WM_HSCROLL == msg || WM_VSCROLL == msg))
|
if (0 == result && (WM_HSCROLL == msg || WM_VSCROLL == msg))
|
||||||
{
|
{
|
||||||
Gdi::ScrollFunctions::updateScrolledWindow(hwnd);
|
Gdi::ScrollFunctions::updateScrolledWindow(hwnd);
|
||||||
@ -151,37 +220,88 @@ namespace
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT WINAPI listBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
void hookUser32WndProc(const std::string& wndProcName, HWND hwnd, WNDPROC newWndProc,
|
||||||
|
decltype(GetWindowLongPtr)* getWindowLong, std::vector<User32WndProc>& user32WndProc)
|
||||||
{
|
{
|
||||||
return defPaintProc(hwnd, msg, wParam, lParam, g_origListBoxWndProc, "listBoxWndProc");
|
User32WndProc wndProc;
|
||||||
|
wndProc.oldWndProc =
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Compat::hookFunction(
|
||||||
|
reinterpret_cast<void*&>(user32WndProc.back().oldWndProcTrampoline), newWndProc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT WINAPI menuWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
void hookUser32WndProcA(const char* className, WNDPROC newWndProc, const std::string& wndProcName)
|
||||||
{
|
{
|
||||||
Compat::LogEnter("menuWndProc", hwnd, msg, wParam, lParam);
|
CLIENTCREATESTRUCT ccs = {};
|
||||||
LRESULT result = 0;
|
HWND hwnd = CreateWindowA(className, "", 0, 0, 0, 0, 0, 0, 0, 0, &ccs);
|
||||||
|
hookUser32WndProc(wndProcName + 'A', hwnd, newWndProc, CALL_ORIG_FUNC(GetWindowLongA), g_user32WndProcA);
|
||||||
|
DestroyWindow(hwnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hookUser32WndProcW(const char* name, WNDPROC newWndProc, const std::string& wndProcName)
|
||||||
|
{
|
||||||
|
CLIENTCREATESTRUCT ccs = {};
|
||||||
|
HWND hwnd = CreateWindowW(
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT listBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
||||||
|
{
|
||||||
|
return defPaintProc(hwnd, msg, wParam, lParam, origWndProc);
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT mdiClientWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
||||||
|
{
|
||||||
|
return defPaintProc(hwnd, msg, wParam, lParam, origWndProc);
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT menuWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
||||||
|
{
|
||||||
switch (msg)
|
switch (msg)
|
||||||
{
|
{
|
||||||
|
case WM_NCPAINT:
|
||||||
|
CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
|
||||||
|
return onNcPaint(hwnd, wParam, origWndProc);
|
||||||
|
|
||||||
case WM_PAINT:
|
case WM_PAINT:
|
||||||
result = onMenuPaint(hwnd, g_origMenuWndProc);
|
return onPaint(hwnd, origWndProc);
|
||||||
break;
|
|
||||||
|
case WM_PRINTCLIENT:
|
||||||
|
{
|
||||||
|
RECT r = {};
|
||||||
|
GetClientRect(hwnd, &r);
|
||||||
|
HDC dc = CreateCompatibleDC(nullptr);
|
||||||
|
HBITMAP dib = Gdi::VirtualScreen::createOffScreenDib(r.right, r.bottom);
|
||||||
|
HGDIOBJ origBitmap = SelectObject(dc, dib);
|
||||||
|
CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(dc), 0);
|
||||||
|
LRESULT result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(dc), lParam);
|
||||||
|
CALL_ORIG_FUNC(BitBlt)(reinterpret_cast<HDC>(wParam), 0, 0, r.right, r.bottom, dc, 0, 0, SRCCOPY);
|
||||||
|
SelectObject(dc, origBitmap);
|
||||||
|
DeleteObject(dib);
|
||||||
|
DeleteDC(dc);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
case 0x1e5:
|
case 0x1e5:
|
||||||
if (-1 == wParam)
|
if (-1 == wParam)
|
||||||
{
|
{
|
||||||
// Clearing of selection is not caught by WM_MENUSELECT when mouse leaves menu window
|
RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE);
|
||||||
RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE);
|
|
||||||
}
|
}
|
||||||
// fall through to default
|
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
result = CallWindowProc(g_origMenuWndProc, hwnd, msg, wParam, lParam);
|
return defPaintProc(hwnd, msg, wParam, lParam, origWndProc);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Compat::LogLeave("menuWndProc", hwnd, msg, wParam, lParam) << result;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT onEraseBackground(HWND hwnd, HDC dc, WNDPROC origWndProc)
|
LRESULT onEraseBackground(HWND hwnd, HDC dc, WNDPROC origWndProc)
|
||||||
@ -202,32 +322,6 @@ namespace
|
|||||||
return CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(dc), 0);
|
return CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(dc), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT onMenuPaint(HWND hwnd, WNDPROC origWndProc)
|
|
||||||
{
|
|
||||||
if (!hwnd)
|
|
||||||
{
|
|
||||||
return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
HDC dc = GetWindowDC(hwnd);
|
|
||||||
HDC compatDc = Gdi::Dc::getDc(dc);
|
|
||||||
if (compatDc)
|
|
||||||
{
|
|
||||||
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
|
||||||
CallWindowProc(origWndProc, hwnd, WM_PRINT, reinterpret_cast<WPARAM>(compatDc),
|
|
||||||
PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT);
|
|
||||||
ValidateRect(hwnd, nullptr);
|
|
||||||
Gdi::Dc::releaseDc(dc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseDC(hwnd, dc);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
LRESULT onNcPaint(HWND hwnd, WPARAM wParam, WNDPROC origWndProc)
|
LRESULT onNcPaint(HWND hwnd, WPARAM wParam, WNDPROC origWndProc)
|
||||||
{
|
{
|
||||||
if (!hwnd)
|
if (!hwnd)
|
||||||
@ -249,7 +343,7 @@ namespace
|
|||||||
scrollBar.drawAll();
|
scrollBar.drawAll();
|
||||||
scrollBar.excludeFromClipRegion();
|
scrollBar.excludeFromClipRegion();
|
||||||
|
|
||||||
SendMessage(hwnd, WM_PRINT, reinterpret_cast<WPARAM>(compatDc), PRF_NONCLIENT);
|
CallWindowProc(origWndProc, hwnd, WM_PRINT, reinterpret_cast<WPARAM>(compatDc), PRF_NONCLIENT);
|
||||||
|
|
||||||
Gdi::Dc::releaseDc(windowDc);
|
Gdi::Dc::releaseDc(windowDc);
|
||||||
}
|
}
|
||||||
@ -265,6 +359,7 @@ namespace
|
|||||||
return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0);
|
return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
PAINTSTRUCT paint = {};
|
PAINTSTRUCT paint = {};
|
||||||
HDC dc = BeginPaint(hwnd, &paint);
|
HDC dc = BeginPaint(hwnd, &paint);
|
||||||
HDC compatDc = Gdi::Dc::getDc(dc);
|
HDC compatDc = Gdi::Dc::getDc(dc);
|
||||||
@ -303,33 +398,52 @@ namespace
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT WINAPI scrollBarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
LRESULT scrollBarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
||||||
{
|
{
|
||||||
Compat::LogEnter("scrollBarWndProc", hwnd, msg, wParam, lParam);
|
|
||||||
LRESULT result = 0;
|
|
||||||
|
|
||||||
switch (msg)
|
switch (msg)
|
||||||
{
|
{
|
||||||
case WM_PAINT:
|
case WM_PAINT:
|
||||||
result = onPaint(hwnd, g_origScrollBarWndProc);
|
return onPaint(hwnd, origWndProc);
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_SETCURSOR:
|
case WM_SETCURSOR:
|
||||||
if (GetWindowLong(hwnd, GWL_STYLE) & (SBS_SIZEBOX | SBS_SIZEGRIP))
|
if (GetWindowLong(hwnd, GWL_STYLE) & (SBS_SIZEBOX | SBS_SIZEGRIP))
|
||||||
{
|
{
|
||||||
SetCursor(LoadCursor(nullptr, IDC_SIZENWSE));
|
SetCursor(LoadCursor(nullptr, IDC_SIZENWSE));
|
||||||
}
|
}
|
||||||
result = TRUE;
|
return TRUE;
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
result = CallWindowProc(g_origScrollBarWndProc, hwnd, msg, wParam, lParam);
|
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Compat::LogLeave("scrollBarWndProc", hwnd, msg, wParam, lParam) << result;
|
LRESULT staticWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
|
||||||
|
{
|
||||||
|
return defPaintProc(hwnd, msg, wParam, lParam, origWndProc);
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK user32WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
|
||||||
|
const User32WndProc& user32WndProc, WndProcHook wndProcHook)
|
||||||
|
{
|
||||||
|
Compat::LogEnter(user32WndProc.name.c_str(),
|
||||||
|
hwnd, Compat::hex(uMsg), Compat::hex(wParam), Compat::hex(lParam));
|
||||||
|
LRESULT result = wndProcHook(hwnd, uMsg, wParam, lParam, user32WndProc.oldWndProcTrampoline);
|
||||||
|
Compat::LogLeave(user32WndProc.name.c_str(),
|
||||||
|
hwnd, Compat::hex(uMsg), Compat::hex(wParam), Compat::hex(lParam)) << result;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <int index>
|
||||||
|
LRESULT CALLBACK user32WndProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
return user32WndProc(hwnd, uMsg, wParam, lParam, g_user32WndProcA[index], g_user32WndProcHook[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int index>
|
||||||
|
LRESULT CALLBACK user32WndProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
return user32WndProc(hwnd, uMsg, wParam, lParam, g_user32WndProcW[index], g_user32WndProcHook[index]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Gdi
|
namespace Gdi
|
||||||
@ -340,27 +454,40 @@ namespace Gdi
|
|||||||
{
|
{
|
||||||
disableImmersiveContextMenus();
|
disableImmersiveContextMenus();
|
||||||
|
|
||||||
Gdi::hookWndProc("Button", g_origButtonWndProc, &buttonWndProc);
|
#define HOOK_USER32_WNDPROC(index, name, wndProcHook) \
|
||||||
Gdi::hookWndProc("ComboLBox", g_origComboListBoxWndProc, &comboListBoxWndProc);
|
g_user32WndProcHook.push_back(wndProcHook); \
|
||||||
Gdi::hookWndProc("Edit", g_origEditWndProc, &editWndProc);
|
hookUser32WndProcA(name, user32WndProcA<index>, #wndProcHook); \
|
||||||
Gdi::hookWndProc("ListBox", g_origListBoxWndProc, &listBoxWndProc);
|
hookUser32WndProcW(name, user32WndProcW<index>, #wndProcHook)
|
||||||
Gdi::hookWndProc("#32768", g_origMenuWndProc, &menuWndProc);
|
|
||||||
Gdi::hookWndProc("ScrollBar", g_origScrollBarWndProc, &scrollBarWndProc);
|
g_user32WndProcA.reserve(9);
|
||||||
|
g_user32WndProcW.reserve(9);
|
||||||
|
|
||||||
|
HOOK_USER32_WNDPROC(0, "Button", buttonWndProc);
|
||||||
|
HOOK_USER32_WNDPROC(1, "ComboBox", comboBoxWndProc);
|
||||||
|
HOOK_USER32_WNDPROC(2, "Edit", editWndProc);
|
||||||
|
HOOK_USER32_WNDPROC(3, "ListBox", listBoxWndProc);
|
||||||
|
HOOK_USER32_WNDPROC(4, "MDIClient", mdiClientWndProc);
|
||||||
|
HOOK_USER32_WNDPROC(5, "ScrollBar", scrollBarWndProc);
|
||||||
|
HOOK_USER32_WNDPROC(6, "Static", staticWndProc);
|
||||||
|
HOOK_USER32_WNDPROC(7, "ComboLBox", comboListBoxWndProc);
|
||||||
|
HOOK_USER32_WNDPROC(8, "#32768", menuWndProc);
|
||||||
|
|
||||||
|
g_scrollBarWndProcIndex = 5;
|
||||||
|
g_menuWndProcIndex = 8;
|
||||||
|
|
||||||
|
#undef HOOK_USER32_WNDPROC
|
||||||
|
|
||||||
HOOK_FUNCTION(user32, DefWindowProcA, defWindowProcA);
|
HOOK_FUNCTION(user32, DefWindowProcA, defWindowProcA);
|
||||||
HOOK_FUNCTION(user32, DefWindowProcW, defWindowProcW);
|
HOOK_FUNCTION(user32, DefWindowProcW, defWindowProcW);
|
||||||
HOOK_FUNCTION(user32, DefDlgProcA, defDlgProcA);
|
HOOK_FUNCTION(user32, DefDlgProcA, defDlgProcA);
|
||||||
HOOK_FUNCTION(user32, DefDlgProcW, defDlgProcW);
|
HOOK_FUNCTION(user32, DefDlgProcW, defDlgProcW);
|
||||||
|
|
||||||
|
g_cbtProcHook = SetWindowsHookEx(WH_CBT, cbtProc, nullptr, Gdi::getGdiThreadId());
|
||||||
}
|
}
|
||||||
|
|
||||||
void uninstallHooks()
|
void uninstallHooks()
|
||||||
{
|
{
|
||||||
Gdi::unhookWndProc("Button", g_origButtonWndProc);
|
UnhookWindowsHookEx(g_cbtProcHook);
|
||||||
Gdi::unhookWndProc("ComboLBox", g_origComboListBoxWndProc);
|
|
||||||
Gdi::unhookWndProc("Edit", g_origEditWndProc);
|
|
||||||
Gdi::unhookWndProc("ListBox", g_origListBoxWndProc);
|
|
||||||
Gdi::unhookWndProc("#32768", g_origMenuWndProc);
|
|
||||||
Gdi::unhookWndProc("ScrollBar", g_origScrollBarWndProc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
#include "Common/Hook.h"
|
#include "Common/Hook.h"
|
||||||
#include "Common/Log.h"
|
#include "Common/Log.h"
|
||||||
#include "DDraw/RealPrimarySurface.h"
|
#include "DDraw/ScopedThreadLock.h"
|
||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
#include "Gdi/ScrollFunctions.h"
|
#include "Gdi/ScrollFunctions.h"
|
||||||
|
#include "Gdi/Window.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -55,10 +56,14 @@ namespace Gdi
|
|||||||
|
|
||||||
void updateScrolledWindow(HWND hwnd)
|
void updateScrolledWindow(HWND hwnd)
|
||||||
{
|
{
|
||||||
DDraw::RealPrimarySurface::disableUpdates();
|
DDraw::ScopedThreadLock lock;
|
||||||
RedrawWindow(hwnd, nullptr, nullptr,
|
auto window(Gdi::Window::get(hwnd));
|
||||||
RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN | RDW_UPDATENOW);
|
UINT flags = RDW_ERASE | RDW_INVALIDATE | RDW_NOCHILDREN | RDW_UPDATENOW;
|
||||||
DDraw::RealPrimarySurface::enableUpdates();
|
if (!window || window->getPresentationWindow() != hwnd)
|
||||||
|
{
|
||||||
|
flags |= RDW_FRAME;
|
||||||
|
}
|
||||||
|
RedrawWindow(hwnd, nullptr, nullptr, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,37 @@ namespace
|
|||||||
virtualScreenRegion |= monitorRegion;
|
virtualScreenRegion |= monitorRegion;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HBITMAP createDibSection(DWORD width, DWORD height, HANDLE section)
|
||||||
|
{
|
||||||
|
struct BITMAPINFO256 : public BITMAPINFO
|
||||||
|
{
|
||||||
|
RGBQUAD bmiRemainingColors[255];
|
||||||
|
};
|
||||||
|
|
||||||
|
BITMAPINFO256 bmi = {};
|
||||||
|
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
|
||||||
|
bmi.bmiHeader.biWidth = width;
|
||||||
|
bmi.bmiHeader.biHeight = -static_cast<LONG>(height);
|
||||||
|
bmi.bmiHeader.biPlanes = 1;
|
||||||
|
bmi.bmiHeader.biBitCount = static_cast<WORD>(g_bpp);
|
||||||
|
bmi.bmiHeader.biCompression = 8 == g_bpp ? BI_RGB : BI_BITFIELDS;
|
||||||
|
|
||||||
|
if (8 == g_bpp)
|
||||||
|
{
|
||||||
|
memcpy(bmi.bmiColors, g_systemPalette, sizeof(g_systemPalette));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto pf = DDraw::getRgbPixelFormat(g_bpp);
|
||||||
|
reinterpret_cast<DWORD&>(bmi.bmiColors[0]) = pf.dwRBitMask;
|
||||||
|
reinterpret_cast<DWORD&>(bmi.bmiColors[1]) = pf.dwGBitMask;
|
||||||
|
reinterpret_cast<DWORD&>(bmi.bmiColors[2]) = pf.dwBBitMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* bits = nullptr;
|
||||||
|
return CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &bits, section, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Gdi
|
namespace Gdi
|
||||||
@ -74,34 +105,13 @@ namespace Gdi
|
|||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
return createDibSection(g_width, g_height, g_surfaceFileMapping);
|
||||||
|
}
|
||||||
|
|
||||||
struct BITMAPINFO256 : public BITMAPINFO
|
HBITMAP createOffScreenDib(DWORD width, DWORD height)
|
||||||
{
|
{
|
||||||
RGBQUAD bmiRemainingColors[255];
|
Compat::ScopedCriticalSection lock(g_cs);
|
||||||
};
|
return createDibSection(width, height, nullptr);
|
||||||
|
|
||||||
BITMAPINFO256 bmi = {};
|
|
||||||
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
|
|
||||||
bmi.bmiHeader.biWidth = g_width;
|
|
||||||
bmi.bmiHeader.biHeight = -g_height;
|
|
||||||
bmi.bmiHeader.biPlanes = 1;
|
|
||||||
bmi.bmiHeader.biBitCount = static_cast<WORD>(g_bpp);
|
|
||||||
bmi.bmiHeader.biCompression = 8 == g_bpp ? BI_RGB : BI_BITFIELDS;
|
|
||||||
|
|
||||||
if (8 == g_bpp)
|
|
||||||
{
|
|
||||||
memcpy(bmi.bmiColors, g_systemPalette, sizeof(g_systemPalette));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const auto pf = DDraw::getRgbPixelFormat(g_bpp);
|
|
||||||
reinterpret_cast<DWORD&>(bmi.bmiColors[0]) = pf.dwRBitMask;
|
|
||||||
reinterpret_cast<DWORD&>(bmi.bmiColors[1]) = pf.dwGBitMask;
|
|
||||||
reinterpret_cast<DWORD&>(bmi.bmiColors[2]) = pf.dwBBitMask;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* bits = nullptr;
|
|
||||||
return CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &bits, g_surfaceFileMapping, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CompatPtr<IDirectDrawSurface7> createSurface(const RECT& rect)
|
CompatPtr<IDirectDrawSurface7> createSurface(const RECT& rect)
|
||||||
|
@ -14,6 +14,7 @@ namespace Gdi
|
|||||||
{
|
{
|
||||||
HDC createDc();
|
HDC createDc();
|
||||||
HBITMAP createDib();
|
HBITMAP createDib();
|
||||||
|
HBITMAP createOffScreenDib(DWORD width, DWORD height);
|
||||||
CompatPtr<IDirectDrawSurface7> createSurface(const RECT& rect);
|
CompatPtr<IDirectDrawSurface7> createSurface(const RECT& rect);
|
||||||
void deleteDc(HDC dc);
|
void deleteDc(HDC dc);
|
||||||
|
|
||||||
|
@ -27,14 +27,13 @@ namespace
|
|||||||
void onActivate(HWND hwnd);
|
void onActivate(HWND hwnd);
|
||||||
void onCreateWindow(HWND hwnd);
|
void onCreateWindow(HWND hwnd);
|
||||||
void onDestroyWindow(HWND hwnd);
|
void onDestroyWindow(HWND hwnd);
|
||||||
void onMenuSelect();
|
|
||||||
void onWindowPosChanged(HWND hwnd);
|
void onWindowPosChanged(HWND hwnd);
|
||||||
void removeDropShadow(HWND hwnd);
|
void removeDropShadow(HWND hwnd);
|
||||||
|
|
||||||
LRESULT CALLBACK callWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)
|
LRESULT CALLBACK callWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
auto ret = reinterpret_cast<CWPRETSTRUCT*>(lParam);
|
auto ret = reinterpret_cast<CWPRETSTRUCT*>(lParam);
|
||||||
Compat::LogEnter("callWndRetProc", nCode, wParam, ret);
|
Compat::LogEnter("callWndRetProc", Compat::hex(nCode), Compat::hex(wParam), ret);
|
||||||
|
|
||||||
if (HC_ACTION == nCode)
|
if (HC_ACTION == nCode)
|
||||||
{
|
{
|
||||||
@ -62,14 +61,10 @@ namespace
|
|||||||
Gdi::ScrollFunctions::updateScrolledWindow(reinterpret_cast<HWND>(ret->lParam));
|
Gdi::ScrollFunctions::updateScrolledWindow(reinterpret_cast<HWND>(ret->lParam));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (WM_MENUSELECT == ret->message)
|
|
||||||
{
|
|
||||||
onMenuSelect();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT result = CallNextHookEx(nullptr, nCode, wParam, lParam);
|
LRESULT result = CallNextHookEx(nullptr, nCode, wParam, lParam);
|
||||||
Compat::LogLeave("callWndRetProc", nCode, wParam, ret) << result;
|
Compat::LogLeave("callWndRetProc", Compat::hex(nCode), Compat::hex(wParam), ret) << result;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,12 +90,6 @@ namespace
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isTopLevelNonLayeredWindow(HWND hwnd)
|
|
||||||
{
|
|
||||||
return !(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) &&
|
|
||||||
(!(GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CHILD) || GetParent(hwnd) == GetDesktopWindow());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CALLBACK objectStateChangeEvent(
|
void CALLBACK objectStateChangeEvent(
|
||||||
HWINEVENTHOOK /*hWinEventHook*/,
|
HWINEVENTHOOK /*hWinEventHook*/,
|
||||||
DWORD /*event*/,
|
DWORD /*event*/,
|
||||||
@ -160,12 +149,9 @@ namespace
|
|||||||
|
|
||||||
void onCreateWindow(HWND hwnd)
|
void onCreateWindow(HWND hwnd)
|
||||||
{
|
{
|
||||||
if (isTopLevelNonLayeredWindow(hwnd))
|
disableDwmAttributes(hwnd);
|
||||||
{
|
removeDropShadow(hwnd);
|
||||||
disableDwmAttributes(hwnd);
|
Gdi::Window::add(hwnd);
|
||||||
removeDropShadow(hwnd);
|
|
||||||
Gdi::Window::add(hwnd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onDestroyWindow(HWND hwnd)
|
void onDestroyWindow(HWND hwnd)
|
||||||
@ -173,20 +159,9 @@ namespace
|
|||||||
Gdi::Window::remove(hwnd);
|
Gdi::Window::remove(hwnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onMenuSelect()
|
|
||||||
{
|
|
||||||
HWND menuWindow = FindWindow(reinterpret_cast<LPCSTR>(0x8000), nullptr);
|
|
||||||
while (menuWindow)
|
|
||||||
{
|
|
||||||
RedrawWindow(menuWindow, nullptr, nullptr, RDW_INVALIDATE);
|
|
||||||
menuWindow = FindWindowEx(nullptr, menuWindow, reinterpret_cast<LPCSTR>(0x8000), nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void onWindowPosChanged(HWND hwnd)
|
void onWindowPosChanged(HWND hwnd)
|
||||||
{
|
{
|
||||||
const ATOM menuAtom = 0x8000;
|
if (Gdi::MENU_ATOM == GetClassLongPtr(hwnd, GCW_ATOM))
|
||||||
if (menuAtom == GetClassLongPtr(hwnd, GCW_ATOM))
|
|
||||||
{
|
{
|
||||||
SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
|
SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
|
||||||
}
|
}
|
||||||
@ -196,7 +171,7 @@ namespace
|
|||||||
notifyFunc();
|
notifyFunc();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTopLevelNonLayeredWindow(hwnd))
|
if (Gdi::Window::get(hwnd))
|
||||||
{
|
{
|
||||||
Gdi::Window::updateAll();
|
Gdi::Window::updateAll();
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "DDraw/ScopedThreadLock.h"
|
||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
#include "Gdi/VirtualScreen.h"
|
#include "Gdi/VirtualScreen.h"
|
||||||
#include "Gdi/Window.h"
|
#include "Gdi/Window.h"
|
||||||
@ -8,6 +9,13 @@ namespace
|
|||||||
{
|
{
|
||||||
ATOM registerPresentationWindowClass();
|
ATOM registerPresentationWindowClass();
|
||||||
|
|
||||||
|
ATOM getComboLBoxAtom()
|
||||||
|
{
|
||||||
|
WNDCLASS wc = {};
|
||||||
|
static ATOM comboLBoxAtom = static_cast<ATOM>(GetClassInfo(nullptr, "ComboLBox", &wc));
|
||||||
|
return comboLBoxAtom;
|
||||||
|
}
|
||||||
|
|
||||||
ATOM getPresentationWindowClassAtom()
|
ATOM getPresentationWindowClassAtom()
|
||||||
{
|
{
|
||||||
static ATOM atom = registerPresentationWindowClass();
|
static ATOM atom = registerPresentationWindowClass();
|
||||||
@ -33,37 +41,43 @@ namespace Gdi
|
|||||||
{
|
{
|
||||||
Window::Window(HWND hwnd)
|
Window::Window(HWND hwnd)
|
||||||
: m_hwnd(hwnd)
|
: m_hwnd(hwnd)
|
||||||
|
, m_presentationWindow(nullptr)
|
||||||
, m_windowRect{ 0, 0, 0, 0 }
|
, m_windowRect{ 0, 0, 0, 0 }
|
||||||
, m_isUpdating(false)
|
, m_isUpdating(false)
|
||||||
{
|
{
|
||||||
m_presentationWindow = CreateWindowEx(
|
const ATOM atom = static_cast<ATOM>(GetClassLong(hwnd, GCW_ATOM));
|
||||||
WS_EX_LAYERED | WS_EX_TRANSPARENT,
|
if (MENU_ATOM != atom && getComboLBoxAtom() != atom)
|
||||||
reinterpret_cast<const char*>(getPresentationWindowClassAtom()),
|
{
|
||||||
nullptr,
|
m_presentationWindow = CreateWindowEx(
|
||||||
WS_DISABLED | WS_POPUP,
|
WS_EX_LAYERED | WS_EX_TRANSPARENT,
|
||||||
0, 0, 1, 1,
|
reinterpret_cast<const char*>(getPresentationWindowClassAtom()),
|
||||||
m_hwnd,
|
nullptr,
|
||||||
nullptr,
|
WS_DISABLED | WS_POPUP,
|
||||||
nullptr,
|
0, 0, 1, 1,
|
||||||
nullptr);
|
m_hwnd,
|
||||||
SetLayeredWindowAttributes(m_presentationWindow, 0, 255, LWA_ALPHA);
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
nullptr);
|
||||||
|
SetLayeredWindowAttributes(m_presentationWindow, 0, 255, LWA_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
Window* Window::add(HWND hwnd)
|
bool Window::add(HWND hwnd)
|
||||||
{
|
{
|
||||||
auto it = s_windows.find(hwnd);
|
const bool isTopLevelNonLayeredWindow = !(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) &&
|
||||||
if (it != s_windows.end())
|
(!(GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CHILD) || GetParent(hwnd) == GetDesktopWindow() ||
|
||||||
|
getComboLBoxAtom() == GetClassLong(hwnd, GCW_ATOM));
|
||||||
|
|
||||||
|
if (isTopLevelNonLayeredWindow && !get(hwnd) &&
|
||||||
|
GetClassLong(hwnd, GCW_ATOM) != getPresentationWindowClassAtom())
|
||||||
{
|
{
|
||||||
return &it->second;
|
s_windows.emplace(hwnd, std::make_shared<Window>(hwnd));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPresentationWindow(hwnd))
|
return false;
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return &s_windows.emplace(hwnd, hwnd).first->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::calcInvalidatedRegion(const RECT& oldWindowRect, const Region& oldVisibleRegion)
|
void Window::calcInvalidatedRegion(const RECT& oldWindowRect, const Region& oldVisibleRegion)
|
||||||
@ -97,22 +111,36 @@ namespace Gdi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Window* Window::get(HWND hwnd)
|
std::shared_ptr<Window> Window::get(HWND hwnd)
|
||||||
{
|
{
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
auto it = s_windows.find(hwnd);
|
auto it = s_windows.find(hwnd);
|
||||||
return it != s_windows.end() ? &it->second : nullptr;
|
return it != s_windows.end() ? it->second : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND Window::getPresentationWindow() const
|
||||||
|
{
|
||||||
|
return m_presentationWindow ? m_presentationWindow : m_hwnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
Region Window::getVisibleRegion() const
|
Region Window::getVisibleRegion() const
|
||||||
{
|
{
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
return m_visibleRegion;
|
return m_visibleRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
RECT Window::getWindowRect() const
|
RECT Window::getWindowRect() const
|
||||||
{
|
{
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
return m_windowRect;
|
return m_windowRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<HWND, std::shared_ptr<Window>> Window::getWindows()
|
||||||
|
{
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
|
return s_windows;
|
||||||
|
}
|
||||||
|
|
||||||
bool Window::isPresentationWindow(HWND hwnd)
|
bool Window::isPresentationWindow(HWND hwnd)
|
||||||
{
|
{
|
||||||
return GetClassLong(hwnd, GCW_ATOM) == getPresentationWindowClassAtom();
|
return GetClassLong(hwnd, GCW_ATOM) == getPresentationWindowClassAtom();
|
||||||
@ -120,11 +148,13 @@ namespace Gdi
|
|||||||
|
|
||||||
void Window::remove(HWND hwnd)
|
void Window::remove(HWND hwnd)
|
||||||
{
|
{
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
s_windows.erase(hwnd);
|
s_windows.erase(hwnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::update()
|
void Window::update()
|
||||||
{
|
{
|
||||||
|
DDraw::ScopedThreadLock lock;
|
||||||
if (m_isUpdating)
|
if (m_isUpdating)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -145,9 +175,16 @@ namespace Gdi
|
|||||||
newVisibleRegion &= VirtualScreen::getRegion();
|
newVisibleRegion &= VirtualScreen::getRegion();
|
||||||
}
|
}
|
||||||
|
|
||||||
SetWindowPos(m_presentationWindow, nullptr, newWindowRect.left, newWindowRect.top,
|
if (m_presentationWindow)
|
||||||
newWindowRect.right - newWindowRect.left, newWindowRect.bottom - newWindowRect.top,
|
{
|
||||||
SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW);
|
SetWindowPos(m_presentationWindow, nullptr, newWindowRect.left, newWindowRect.top,
|
||||||
|
newWindowRect.right - newWindowRect.left, newWindowRect.bottom - newWindowRect.top,
|
||||||
|
SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_presentationWindow)
|
||||||
|
{
|
||||||
|
ShowWindow(m_presentationWindow, SW_HIDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::swap(m_windowRect, newWindowRect);
|
std::swap(m_windowRect, newWindowRect);
|
||||||
@ -160,23 +197,34 @@ namespace Gdi
|
|||||||
|
|
||||||
void Window::updateAll()
|
void Window::updateAll()
|
||||||
{
|
{
|
||||||
for (auto& windowPair : s_windows)
|
auto windows(getWindows());
|
||||||
|
for (auto& windowPair : windows)
|
||||||
{
|
{
|
||||||
windowPair.second.update();
|
windowPair.second->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& windowPair : s_windows)
|
for (auto& windowPair : windows)
|
||||||
{
|
{
|
||||||
if (!windowPair.second.m_invalidatedRegion.isEmpty())
|
if (!windowPair.second->m_invalidatedRegion.isEmpty())
|
||||||
{
|
{
|
||||||
POINT clientOrigin = {};
|
POINT clientOrigin = {};
|
||||||
ClientToScreen(windowPair.first, &clientOrigin);
|
ClientToScreen(windowPair.first, &clientOrigin);
|
||||||
windowPair.second.m_invalidatedRegion.offset(-clientOrigin.x, -clientOrigin.y);
|
windowPair.second->m_invalidatedRegion.offset(-clientOrigin.x, -clientOrigin.y);
|
||||||
RedrawWindow(windowPair.first, nullptr, windowPair.second.m_invalidatedRegion,
|
RedrawWindow(windowPair.first, nullptr, windowPair.second->m_invalidatedRegion,
|
||||||
RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASENOW);
|
RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASENOW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<HWND, Window> Window::s_windows;
|
void Window::updateWindow()
|
||||||
|
{
|
||||||
|
RECT windowRect = {};
|
||||||
|
GetWindowRect(m_hwnd, &windowRect);
|
||||||
|
if (!EqualRect(&windowRect, &m_windowRect))
|
||||||
|
{
|
||||||
|
updateAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<HWND, std::shared_ptr<Window>> Window::s_windows;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
@ -17,13 +18,16 @@ namespace Gdi
|
|||||||
Window(const Window&) = delete;
|
Window(const Window&) = delete;
|
||||||
Window& operator=(const Window&) = delete;
|
Window& operator=(const Window&) = delete;
|
||||||
|
|
||||||
|
HWND getPresentationWindow() const;
|
||||||
Region getVisibleRegion() const;
|
Region getVisibleRegion() const;
|
||||||
RECT getWindowRect() const;
|
RECT getWindowRect() const;
|
||||||
|
void updateWindow();
|
||||||
|
|
||||||
static Window* add(HWND hwnd);
|
static bool add(HWND hwnd);
|
||||||
static Window* get(HWND hwnd);
|
static std::shared_ptr<Window> get(HWND hwnd);
|
||||||
static void remove(HWND hwnd);
|
static void remove(HWND hwnd);
|
||||||
|
|
||||||
|
static std::map<HWND, std::shared_ptr<Window>> getWindows();
|
||||||
static bool isPresentationWindow(HWND hwnd);
|
static bool isPresentationWindow(HWND hwnd);
|
||||||
static void updateAll();
|
static void updateAll();
|
||||||
|
|
||||||
@ -38,6 +42,6 @@ namespace Gdi
|
|||||||
Region m_invalidatedRegion;
|
Region m_invalidatedRegion;
|
||||||
bool m_isUpdating;
|
bool m_isUpdating;
|
||||||
|
|
||||||
static std::map<HWND, Window> s_windows;
|
static std::map<HWND, std::shared_ptr<Window>> s_windows;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ namespace
|
|||||||
const int subKeyComp = lstrcmpiW(subKey.c_str(), rhs.subKey.c_str());
|
const int subKeyComp = lstrcmpiW(subKey.c_str(), rhs.subKey.c_str());
|
||||||
if (subKeyComp < 0) { return true; }
|
if (subKeyComp < 0) { return true; }
|
||||||
if (subKeyComp > 0) { return false; }
|
if (subKeyComp > 0) { return false; }
|
||||||
return lstrcmpiW(value.c_str(), rhs.value.c_str());
|
return lstrcmpiW(value.c_str(), rhs.value.c_str()) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const RegistryKey& rhs) const
|
bool operator==(const RegistryKey& rhs) const
|
||||||
|
Loading…
x
Reference in New Issue
Block a user