1
0
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:
narzoul 2018-10-20 17:49:00 +02:00
parent 537ef9c595
commit 2f00b74a56
15 changed files with 510 additions and 385 deletions

View File

@ -96,10 +96,13 @@ std::ostream& operator<<(std::ostream& os, HRGN__& rgn)
std::ostream& operator<<(std::ostream& os, HWND__& hwnd)
{
char name[256] = {};
GetClassName(&hwnd, name, sizeof(name));
char name[256] = "INVALID";
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 << ')';
}

View File

@ -22,18 +22,6 @@
namespace
{
struct BltToWindowViaGdiArgs
{
std::unique_ptr<HDC__, void(*)(HDC)> virtualScreenDc;
Gdi::Region* primaryRegion;
BltToWindowViaGdiArgs()
: virtualScreenDc(nullptr, &Gdi::VirtualScreen::deleteDc)
, primaryRegion(nullptr)
{
}
};
void onRelease();
DWORD WINAPI updateThreadProc(LPVOID lpParameter);
@ -70,65 +58,61 @@ namespace
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))
{
return TRUE;
}
std::unique_ptr<HDC__, void(*)(HDC)> virtualScreenDc(nullptr, &Gdi::VirtualScreen::deleteDc);
auto window = Gdi::Window::get(GetParent(hwnd));
if (!window)
for (auto windowPair : Gdi::Window::getWindows())
{
return TRUE;
}
if (!IsWindowVisible(windowPair.first))
{
continue;
}
Gdi::Region visibleRegion = window->getVisibleRegion();
if (visibleRegion.isEmpty())
{
return TRUE;
}
auto& args = *reinterpret_cast<BltToWindowViaGdiArgs*>(lParam);
if (args.primaryRegion)
{
visibleRegion -= *args.primaryRegion;
Gdi::Region visibleRegion = windowPair.second->getVisibleRegion();
if (visibleRegion.isEmpty())
{
return TRUE;
continue;
}
}
if (!args.virtualScreenDc)
{
args.virtualScreenDc.reset(Gdi::VirtualScreen::createDc());
if (!args.virtualScreenDc)
if (primaryRegion)
{
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()
@ -174,7 +158,7 @@ namespace
{
if (!g_isFullScreen)
{
EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindow, reinterpret_cast<LPARAM>(&src));
bltToWindow(src);
return;
}
@ -364,19 +348,15 @@ namespace
Gdi::VirtualScreen::update();
BltToWindowViaGdiArgs bltToWindowViaGdiArgs;
if (!g_frontBuffer || !src || DDraw::RealPrimarySurface::isLost())
{
EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindowViaGdi,
reinterpret_cast<LPARAM>(&bltToWindowViaGdiArgs));
bltToWindowViaGdi(nullptr);
Compat::LogLeave("RealPrimarySurface::presentToPrimaryChain", src.get()) << false;
return;
}
Gdi::Region primaryRegion(D3dDdi::KernelModeThunks::getMonitorRect());
bltToWindowViaGdiArgs.primaryRegion = &primaryRegion;
EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindowViaGdi,
reinterpret_cast<LPARAM>(&bltToWindowViaGdiArgs));
bltToWindowViaGdi(&primaryRegion);
Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, DDraw::PrimarySurface::isGdiSurface(src.get()));
if (DDraw::PrimarySurface::getDesc().ddpfPixelFormat.dwRGBBitCount <= 8)

View File

@ -4,7 +4,7 @@
#include "Common/Hook.h"
#include "Common/Log.h"
#include "Common/ScopedCriticalSection.h"
#include "DDraw/ScopedThreadLock.h"
#include "Gdi/Dc.h"
#include "Gdi/DcCache.h"
#include "Gdi/Gdi.h"
@ -24,7 +24,6 @@ namespace
typedef std::unique_ptr<HDC__, void(*)(HDC)> OrigDc;
typedef std::unordered_map<HDC, CompatDc> CompatDcMap;
CRITICAL_SECTION g_cs;
CompatDcMap g_origDcToCompatDc;
thread_local std::vector<OrigDc> g_threadDcs;
@ -82,7 +81,7 @@ namespace
void deleteDc(HDC origDc)
{
Compat::ScopedCriticalSection lock(g_cs);
DDraw::ScopedThreadLock lock;
auto it = g_origDcToCompatDc.find(origDc);
RestoreDC(it->second.dc, it->second.savedState);
Gdi::DcCache::deleteDc(it->second.dc);
@ -110,24 +109,6 @@ namespace
}
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
@ -141,7 +122,7 @@ namespace Gdi
return nullptr;
}
Compat::ScopedCriticalSection lock(g_cs);
DDraw::ScopedThreadLock lock;
auto it = g_origDcToCompatDc.find(origDc);
if (it != g_origDcToCompatDc.end())
{
@ -150,10 +131,15 @@ namespace Gdi
}
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)
{
updateWindow(rootWnd);
auto rootWindow(Window::get(rootWnd));
if (!rootWindow)
{
return nullptr;
}
rootWindow->updateWindow();
}
CompatDc compatDc;
@ -183,20 +169,15 @@ namespace Gdi
HDC getOrigDc(HDC dc)
{
Compat::ScopedCriticalSection lock(g_cs);
DDraw::ScopedThreadLock lock;
const auto it = std::find_if(g_origDcToCompatDc.begin(), g_origDcToCompatDc.end(),
[dc](const CompatDcMap::value_type& compatDc) { return compatDc.second.dc == dc; });
return it != g_origDcToCompatDc.end() ? it->first : dc;
}
void init()
{
InitializeCriticalSection(&g_cs);
}
void releaseDc(HDC origDc)
{
Compat::ScopedCriticalSection lock(g_cs);
DDraw::ScopedThreadLock lock;
auto it = g_origDcToCompatDc.find(origDc);
if (it == g_origDcToCompatDc.end())
{

View File

@ -10,7 +10,6 @@ namespace Gdi
{
HDC getDc(HDC origDc);
HDC getOrigDc(HDC dc);
void init();
void releaseDc(HDC origDc);
}
}

View File

@ -6,7 +6,9 @@
#include "Gdi/Dc.h"
#include "Gdi/DcFunctions.h"
#include "Gdi/Gdi.h"
#include "Gdi/Region.h"
#include "Gdi/VirtualScreen.h"
#include "Gdi/Window.h"
#include "Win32/DisplayMode.h"
namespace
@ -20,7 +22,7 @@ namespace
std::unordered_map<void*, const char*> g_funcNames;
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename... Params>
DWORD getDdLockFlags(Params... params);
HDC getDestinationDc(Params... params);
HRGN getWindowRegion(HWND hwnd);
@ -85,7 +87,7 @@ namespace
Result result = 0;
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);
result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...);
releaseDc(params...);
@ -102,6 +104,49 @@ namespace
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)
{
auto& args = *reinterpret_cast<ExcludeRgnForOverlappingWindowArgs*>(lParam);
@ -129,84 +174,40 @@ namespace
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>
DWORD getDdLockFlags(Params...)
HDC getDestinationDc(Params... params)
{
return 0;
return getFirstDc(params...);
}
template <>
DWORD getDdLockFlags<decltype(&AlphaBlend), &AlphaBlend>(
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 getDestinationDc<decltype(&GetDIBits), &GetDIBits>(
HDC, HBITMAP, UINT, UINT, LPVOID, LPBITMAPINFO, UINT)
{
return DDLOCK_READONLY;
return nullptr;
}
template <>
DWORD getDdLockFlags<decltype(&GetPixel), &GetPixel>(HDC, int, int)
HDC getDestinationDc<decltype(&GetPixel), &GetPixel>(HDC, int, int)
{
return DDLOCK_READONLY;
}
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);
return nullptr;
}
HRGN getWindowRegion(HWND hwnd)

View File

@ -1,6 +1,5 @@
#include "DDraw/Surfaces/PrimarySurface.h"
#include "Gdi/Caret.h"
#include "Gdi/Dc.h"
#include "Gdi/DcFunctions.h"
#include "Gdi/Gdi.h"
#include "Gdi/PaintHandlers.h"
@ -37,20 +36,11 @@ namespace Gdi
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()
{
g_gdiThreadId = GetCurrentThreadId();
g_screenDc = GetDC(nullptr);
Gdi::Dc::init();
Gdi::DcFunctions::installHooks();
Gdi::PaintHandlers::installHooks();
Gdi::ScrollFunctions::installHooks();

View File

@ -6,12 +6,13 @@
namespace Gdi
{
const ATOM MENU_ATOM = 0x8000;
typedef void(*WindowPosChangeNotifyFunc)();
DWORD getGdiThreadId();
HDC getScreenDc();
HRGN getVisibleWindowRgn(HWND hwnd);
void hookWndProc(LPCSTR className, WNDPROC &oldWndProc, WNDPROC newWndProc);
void installHooks();
void redraw(HRGN rgn);
void redrawWindow(HWND hwnd, HRGN rgn);

View File

@ -1,3 +1,5 @@
#include <vector>
#include "Common/Hook.h"
#include "Common/Log.h"
#include "DDraw/RealPrimarySurface.h"
@ -8,56 +10,130 @@
#include "Gdi/ScrollBar.h"
#include "Gdi/ScrollFunctions.h"
#include "Gdi/TitleBar.h"
#include "Gdi/VirtualScreen.h"
#include "Gdi/Window.h"
#include "Win32/Registry.h"
namespace
{
LRESULT WINAPI defPaintProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
WNDPROC origWndProc, const char* origWndProcName);
typedef LRESULT(*WndProcHook)(HWND, UINT, WPARAM, LPARAM, WNDPROC);
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 onMenuPaint(HWND hwnd, WNDPROC origWndProc);
LRESULT onNcPaint(HWND hwnd, WPARAM wParam, WNDPROC origWndProc);
LRESULT onPaint(HWND hwnd, WNDPROC origWndProc);
LRESULT onPrint(HWND hwnd, UINT msg, HDC dc, LONG flags, WNDPROC origWndProc);
WNDPROC g_origButtonWndProc = nullptr;
WNDPROC g_origComboListBoxWndProc = nullptr;
WNDPROC g_origEditWndProc = nullptr;
WNDPROC g_origListBoxWndProc = nullptr;
WNDPROC g_origMenuWndProc = nullptr;
WNDPROC g_origScrollBarWndProc = nullptr;
HHOOK g_cbtProcHook = nullptr;
int g_menuWndProcIndex = 0;
int g_scrollBarWndProcIndex = 0;
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)
{
case WM_PAINT:
result = onPaint(hwnd, g_origButtonWndProc);
break;
return onPaint(hwnd, origWndProc);
case WM_ENABLE:
case WM_SETTEXT:
case BM_SETCHECK:
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);
break;
default:
result = CallWindowProc(g_origButtonWndProc, hwnd, msg, wParam, lParam);
break;
return result;
}
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;
}
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)
@ -70,38 +146,31 @@ namespace
return defPaintProc(hdlg, msg, wParam, lParam, CALL_ORIG_FUNC(DefDlgProcW), "defDlgProcW");
}
LRESULT WINAPI defPaintProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam,
WNDPROC origWndProc,
const char* origWndProcName)
LRESULT defPaintProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
{
Compat::LogEnter(origWndProcName, hwnd, msg, wParam, lParam);
LRESULT result = 0;
switch (msg)
{
case WM_ERASEBKGND:
result = onEraseBackground(hwnd, reinterpret_cast<HDC>(wParam), origWndProc);
break;
return onEraseBackground(hwnd, reinterpret_cast<HDC>(wParam), origWndProc);
case WM_NCPAINT:
result = onNcPaint(hwnd, wParam, origWndProc);
break;
return onNcPaint(hwnd, wParam, origWndProc);
case WM_PRINT:
case WM_PRINTCLIENT:
result = onPrint(hwnd, msg, reinterpret_cast<HDC>(wParam), lParam, origWndProc);
break;
return onPrint(hwnd, msg, reinterpret_cast<HDC>(wParam), lParam, origWndProc);
default:
result = CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
break;
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
}
}
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;
}
@ -141,9 +210,9 @@ namespace
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))
{
Gdi::ScrollFunctions::updateScrolledWindow(hwnd);
@ -151,37 +220,88 @@ namespace
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);
LRESULT result = 0;
CLIENTCREATESTRUCT ccs = {};
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)
{
case WM_NCPAINT:
CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
return onNcPaint(hwnd, wParam, origWndProc);
case WM_PAINT:
result = onMenuPaint(hwnd, g_origMenuWndProc);
break;
return onPaint(hwnd, origWndProc);
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:
if (-1 == wParam)
{
// Clearing of selection is not caught by WM_MENUSELECT when mouse leaves menu window
RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE);
RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE);
}
// fall through to default
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
default:
result = CallWindowProc(g_origMenuWndProc, hwnd, msg, wParam, lParam);
break;
return defPaintProc(hwnd, msg, wParam, lParam, origWndProc);
}
Compat::LogLeave("menuWndProc", hwnd, msg, wParam, lParam) << result;
return result;
}
LRESULT onEraseBackground(HWND hwnd, HDC dc, WNDPROC origWndProc)
@ -202,32 +322,6 @@ namespace
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)
{
if (!hwnd)
@ -249,7 +343,7 @@ namespace
scrollBar.drawAll();
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);
}
@ -265,6 +359,7 @@ namespace
return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0);
}
DDraw::ScopedThreadLock lock;
PAINTSTRUCT paint = {};
HDC dc = BeginPaint(hwnd, &paint);
HDC compatDc = Gdi::Dc::getDc(dc);
@ -303,33 +398,52 @@ namespace
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)
{
case WM_PAINT:
result = onPaint(hwnd, g_origScrollBarWndProc);
break;
return onPaint(hwnd, origWndProc);
case WM_SETCURSOR:
if (GetWindowLong(hwnd, GWL_STYLE) & (SBS_SIZEBOX | SBS_SIZEGRIP))
{
SetCursor(LoadCursor(nullptr, IDC_SIZENWSE));
}
result = TRUE;
break;
return TRUE;
default:
result = CallWindowProc(g_origScrollBarWndProc, hwnd, msg, wParam, lParam);
break;
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
}
}
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;
}
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
@ -340,27 +454,40 @@ namespace Gdi
{
disableImmersiveContextMenus();
Gdi::hookWndProc("Button", g_origButtonWndProc, &buttonWndProc);
Gdi::hookWndProc("ComboLBox", g_origComboListBoxWndProc, &comboListBoxWndProc);
Gdi::hookWndProc("Edit", g_origEditWndProc, &editWndProc);
Gdi::hookWndProc("ListBox", g_origListBoxWndProc, &listBoxWndProc);
Gdi::hookWndProc("#32768", g_origMenuWndProc, &menuWndProc);
Gdi::hookWndProc("ScrollBar", g_origScrollBarWndProc, &scrollBarWndProc);
#define HOOK_USER32_WNDPROC(index, name, wndProcHook) \
g_user32WndProcHook.push_back(wndProcHook); \
hookUser32WndProcA(name, user32WndProcA<index>, #wndProcHook); \
hookUser32WndProcW(name, user32WndProcW<index>, #wndProcHook)
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, DefWindowProcW, defWindowProcW);
HOOK_FUNCTION(user32, DefDlgProcA, defDlgProcA);
HOOK_FUNCTION(user32, DefDlgProcW, defDlgProcW);
g_cbtProcHook = SetWindowsHookEx(WH_CBT, cbtProc, nullptr, Gdi::getGdiThreadId());
}
void uninstallHooks()
{
Gdi::unhookWndProc("Button", g_origButtonWndProc);
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);
UnhookWindowsHookEx(g_cbtProcHook);
}
}
}

View File

@ -1,8 +1,9 @@
#include "Common/Hook.h"
#include "Common/Log.h"
#include "DDraw/RealPrimarySurface.h"
#include "DDraw/ScopedThreadLock.h"
#include "Gdi/Gdi.h"
#include "Gdi/ScrollFunctions.h"
#include "Gdi/Window.h"
namespace
{
@ -55,10 +56,14 @@ namespace Gdi
void updateScrolledWindow(HWND hwnd)
{
DDraw::RealPrimarySurface::disableUpdates();
RedrawWindow(hwnd, nullptr, nullptr,
RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN | RDW_UPDATENOW);
DDraw::RealPrimarySurface::enableUpdates();
DDraw::ScopedThreadLock lock;
auto window(Gdi::Window::get(hwnd));
UINT flags = RDW_ERASE | RDW_INVALIDATE | RDW_NOCHILDREN | RDW_UPDATENOW;
if (!window || window->getPresentationWindow() != hwnd)
{
flags |= RDW_FRAME;
}
RedrawWindow(hwnd, nullptr, nullptr, flags);
}
}
}

View File

@ -32,6 +32,37 @@ namespace
virtualScreenRegion |= monitorRegion;
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
@ -74,34 +105,13 @@ namespace Gdi
{
return nullptr;
}
return createDibSection(g_width, g_height, g_surfaceFileMapping);
}
struct BITMAPINFO256 : public BITMAPINFO
{
RGBQUAD bmiRemainingColors[255];
};
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);
HBITMAP createOffScreenDib(DWORD width, DWORD height)
{
Compat::ScopedCriticalSection lock(g_cs);
return createDibSection(width, height, nullptr);
}
CompatPtr<IDirectDrawSurface7> createSurface(const RECT& rect)

View File

@ -14,6 +14,7 @@ namespace Gdi
{
HDC createDc();
HBITMAP createDib();
HBITMAP createOffScreenDib(DWORD width, DWORD height);
CompatPtr<IDirectDrawSurface7> createSurface(const RECT& rect);
void deleteDc(HDC dc);

View File

@ -27,14 +27,13 @@ namespace
void onActivate(HWND hwnd);
void onCreateWindow(HWND hwnd);
void onDestroyWindow(HWND hwnd);
void onMenuSelect();
void onWindowPosChanged(HWND hwnd);
void removeDropShadow(HWND hwnd);
LRESULT CALLBACK callWndRetProc(int nCode, WPARAM wParam, LPARAM 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)
{
@ -62,14 +61,10 @@ namespace
Gdi::ScrollFunctions::updateScrolledWindow(reinterpret_cast<HWND>(ret->lParam));
}
}
else if (WM_MENUSELECT == ret->message)
{
onMenuSelect();
}
}
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;
}
@ -95,12 +90,6 @@ namespace
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(
HWINEVENTHOOK /*hWinEventHook*/,
DWORD /*event*/,
@ -160,12 +149,9 @@ namespace
void onCreateWindow(HWND hwnd)
{
if (isTopLevelNonLayeredWindow(hwnd))
{
disableDwmAttributes(hwnd);
removeDropShadow(hwnd);
Gdi::Window::add(hwnd);
}
disableDwmAttributes(hwnd);
removeDropShadow(hwnd);
Gdi::Window::add(hwnd);
}
void onDestroyWindow(HWND hwnd)
@ -173,20 +159,9 @@ namespace
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)
{
const ATOM menuAtom = 0x8000;
if (menuAtom == GetClassLongPtr(hwnd, GCW_ATOM))
if (Gdi::MENU_ATOM == GetClassLongPtr(hwnd, GCW_ATOM))
{
SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
}
@ -196,7 +171,7 @@ namespace
notifyFunc();
}
if (isTopLevelNonLayeredWindow(hwnd))
if (Gdi::Window::get(hwnd))
{
Gdi::Window::updateAll();
}

View File

@ -1,3 +1,4 @@
#include "DDraw/ScopedThreadLock.h"
#include "Gdi/Gdi.h"
#include "Gdi/VirtualScreen.h"
#include "Gdi/Window.h"
@ -8,6 +9,13 @@ namespace
{
ATOM registerPresentationWindowClass();
ATOM getComboLBoxAtom()
{
WNDCLASS wc = {};
static ATOM comboLBoxAtom = static_cast<ATOM>(GetClassInfo(nullptr, "ComboLBox", &wc));
return comboLBoxAtom;
}
ATOM getPresentationWindowClassAtom()
{
static ATOM atom = registerPresentationWindowClass();
@ -33,37 +41,43 @@ namespace Gdi
{
Window::Window(HWND hwnd)
: m_hwnd(hwnd)
, m_presentationWindow(nullptr)
, m_windowRect{ 0, 0, 0, 0 }
, m_isUpdating(false)
{
m_presentationWindow = CreateWindowEx(
WS_EX_LAYERED | WS_EX_TRANSPARENT,
reinterpret_cast<const char*>(getPresentationWindowClassAtom()),
nullptr,
WS_DISABLED | WS_POPUP,
0, 0, 1, 1,
m_hwnd,
nullptr,
nullptr,
nullptr);
SetLayeredWindowAttributes(m_presentationWindow, 0, 255, LWA_ALPHA);
const ATOM atom = static_cast<ATOM>(GetClassLong(hwnd, GCW_ATOM));
if (MENU_ATOM != atom && getComboLBoxAtom() != atom)
{
m_presentationWindow = CreateWindowEx(
WS_EX_LAYERED | WS_EX_TRANSPARENT,
reinterpret_cast<const char*>(getPresentationWindowClassAtom()),
nullptr,
WS_DISABLED | WS_POPUP,
0, 0, 1, 1,
m_hwnd,
nullptr,
nullptr,
nullptr);
SetLayeredWindowAttributes(m_presentationWindow, 0, 255, LWA_ALPHA);
}
update();
}
Window* Window::add(HWND hwnd)
bool Window::add(HWND hwnd)
{
auto it = s_windows.find(hwnd);
if (it != s_windows.end())
const bool isTopLevelNonLayeredWindow = !(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) &&
(!(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 nullptr;
}
return &s_windows.emplace(hwnd, hwnd).first->second;
return false;
}
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);
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
{
DDraw::ScopedThreadLock lock;
return m_visibleRegion;
}
RECT Window::getWindowRect() const
{
DDraw::ScopedThreadLock lock;
return m_windowRect;
}
std::map<HWND, std::shared_ptr<Window>> Window::getWindows()
{
DDraw::ScopedThreadLock lock;
return s_windows;
}
bool Window::isPresentationWindow(HWND hwnd)
{
return GetClassLong(hwnd, GCW_ATOM) == getPresentationWindowClassAtom();
@ -120,11 +148,13 @@ namespace Gdi
void Window::remove(HWND hwnd)
{
DDraw::ScopedThreadLock lock;
s_windows.erase(hwnd);
}
void Window::update()
{
DDraw::ScopedThreadLock lock;
if (m_isUpdating)
{
return;
@ -145,9 +175,16 @@ namespace Gdi
newVisibleRegion &= VirtualScreen::getRegion();
}
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);
if (m_presentationWindow)
{
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);
@ -160,23 +197,34 @@ namespace Gdi
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 = {};
ClientToScreen(windowPair.first, &clientOrigin);
windowPair.second.m_invalidatedRegion.offset(-clientOrigin.x, -clientOrigin.y);
RedrawWindow(windowPair.first, nullptr, windowPair.second.m_invalidatedRegion,
windowPair.second->m_invalidatedRegion.offset(-clientOrigin.x, -clientOrigin.y);
RedrawWindow(windowPair.first, nullptr, windowPair.second->m_invalidatedRegion,
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;
}

View File

@ -3,6 +3,7 @@
#define WIN32_LEAN_AND_MEAN
#include <map>
#include <memory>
#include <Windows.h>
@ -17,13 +18,16 @@ namespace Gdi
Window(const Window&) = delete;
Window& operator=(const Window&) = delete;
HWND getPresentationWindow() const;
Region getVisibleRegion() const;
RECT getWindowRect() const;
void updateWindow();
static Window* add(HWND hwnd);
static Window* get(HWND hwnd);
static bool add(HWND hwnd);
static std::shared_ptr<Window> get(HWND hwnd);
static void remove(HWND hwnd);
static std::map<HWND, std::shared_ptr<Window>> getWindows();
static bool isPresentationWindow(HWND hwnd);
static void updateAll();
@ -38,6 +42,6 @@ namespace Gdi
Region m_invalidatedRegion;
bool m_isUpdating;
static std::map<HWND, Window> s_windows;
static std::map<HWND, std::shared_ptr<Window>> s_windows;
};
}

View File

@ -30,7 +30,7 @@ namespace
const int subKeyComp = lstrcmpiW(subKey.c_str(), rhs.subKey.c_str());
if (subKeyComp < 0) { return true; }
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