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

Update original DC's current position after redirection

Fixes incorrectly drawn frames around Mig Alley's controls (issue #12).
This commit is contained in:
narzoul 2020-12-19 20:54:13 +01:00
parent 9b3e900faf
commit 4104540c14

View File

@ -17,7 +17,7 @@ namespace
class CompatDc class CompatDc
{ {
public: public:
CompatDc(HDC dc) : m_origDc(dc), m_compatDc(Gdi::Dc::getDc(dc, false)) CompatDc(HDC dc) : m_origDc(dc), m_compatDc(Gdi::Dc::getDc(dc, false))
{ {
} }
@ -56,11 +56,42 @@ namespace
std::unordered_map<void*, const char*> g_funcNames; std::unordered_map<void*, const char*> g_funcNames;
thread_local bool g_redirectToDib = true; thread_local bool g_redirectToDib = true;
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename... Params>
HDC getDestinationDc(Params... params);
HRGN getWindowRegion(HWND hwnd); HRGN getWindowRegion(HWND hwnd);
#define CREATE_DC_FUNC_ATTRIBUTE(attribute) \
template <typename OrigFuncPtr, OrigFuncPtr origFunc> \
bool attribute() \
{ \
return false; \
}
#define SET_DC_FUNC_ATTRIBUTE(attribute, func) \
template <> \
bool attribute<decltype(&func), &func>() \
{ \
return true; \
}
#define SET_TEXT_DC_FUNC_ATTRIBUTE(attribute, func) \
SET_DC_FUNC_ATTRIBUTE(attribute, func##A) \
SET_DC_FUNC_ATTRIBUTE(attribute, func##W)
CREATE_DC_FUNC_ATTRIBUTE(isPositionUpdated);
SET_DC_FUNC_ATTRIBUTE(isPositionUpdated, AngleArc);
SET_DC_FUNC_ATTRIBUTE(isPositionUpdated, ArcTo);
SET_DC_FUNC_ATTRIBUTE(isPositionUpdated, LineTo);
SET_DC_FUNC_ATTRIBUTE(isPositionUpdated, PolyBezierTo);
SET_DC_FUNC_ATTRIBUTE(isPositionUpdated, PolyDraw);
SET_DC_FUNC_ATTRIBUTE(isPositionUpdated, PolylineTo);
SET_TEXT_DC_FUNC_ATTRIBUTE(isPositionUpdated, ExtTextOut);
SET_TEXT_DC_FUNC_ATTRIBUTE(isPositionUpdated, PolyTextOut);
SET_TEXT_DC_FUNC_ATTRIBUTE(isPositionUpdated, TabbedTextOut);
SET_TEXT_DC_FUNC_ATTRIBUTE(isPositionUpdated, TextOut);
CREATE_DC_FUNC_ATTRIBUTE(isReadOnly);
SET_DC_FUNC_ATTRIBUTE(isReadOnly, GetDIBits);
SET_DC_FUNC_ATTRIBUTE(isReadOnly, GetPixel);
BOOL WINAPI GdiDrawStream(HDC, DWORD, DWORD) { return FALSE; } BOOL WINAPI GdiDrawStream(HDC, DWORD, DWORD) { return FALSE; }
BOOL WINAPI PolyPatBlt(HDC, DWORD, DWORD, DWORD, DWORD) { return FALSE; } BOOL WINAPI PolyPatBlt(HDC, DWORD, DWORD, DWORD, DWORD) { return FALSE; }
@ -106,23 +137,28 @@ namespace
} }
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params> template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
Result WINAPI compatGdiDcFunc(Params... params) Result WINAPI compatGdiDcFunc(HDC hdc, Params... params)
{ {
#ifdef DEBUGLOGS #ifdef DEBUGLOGS
LOG_FUNC(g_funcNames[origFunc], params...); LOG_FUNC(g_funcNames[origFunc], hdc, params...);
#else
LOG_FUNC("", params...);
#endif #endif
if (hasDisplayDcArg(params...)) if (hasDisplayDcArg(hdc, params...))
{ {
D3dDdi::ScopedCriticalSection lock; D3dDdi::ScopedCriticalSection lock;
const bool isReadOnlyAccess = !hasDisplayDcArg(getDestinationDc<OrigFuncPtr, origFunc>(params...)); Gdi::AccessGuard accessGuard(isReadOnly<OrigFuncPtr, origFunc>() ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE);
Gdi::AccessGuard accessGuard(isReadOnlyAccess ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE); CompatDc compatDc(hdc);
return LOG_RESULT(Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...)); Result result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(compatDc, replaceDc(params)...);
if (isPositionUpdated<OrigFuncPtr, origFunc>() && result)
{
POINT currentPos = {};
GetCurrentPositionEx(compatDc, &currentPos);
MoveToEx(hdc, currentPos.x, currentPos.y, nullptr);
}
return LOG_RESULT(result);
} }
return LOG_RESULT(Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(params...)); return LOG_RESULT(Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(hdc, params...));
} }
template <> template <>
@ -155,7 +191,15 @@ namespace
{ {
D3dDdi::ScopedCriticalSection lock; D3dDdi::ScopedCriticalSection lock;
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE); Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
return LOG_RESULT(CALL_ORIG_FUNC(ExtTextOutW)(replaceDc(hdc), x, y, options, lprect, lpString, c, lpDx)); CompatDc compatDc(hdc);
BOOL result = CALL_ORIG_FUNC(ExtTextOutW)(compatDc, x, y, options, lprect, lpString, c, lpDx);
if (result)
{
POINT currentPos = {};
GetCurrentPositionEx(compatDc, &currentPos);
MoveToEx(hdc, currentPos.x, currentPos.y, nullptr);
}
return LOG_RESULT(result);
} }
} }
else else
@ -210,6 +254,18 @@ namespace
return LOG_RESULT(CALL_ORIG_FUNC(createDiscardableBitmap)(hdc, nWidth, nHeight)); return LOG_RESULT(CALL_ORIG_FUNC(createDiscardableBitmap)(hdc, nWidth, nHeight));
} }
BOOL WINAPI drawCaption(HWND hwnd, HDC hdc, const RECT* lprect, UINT flags)
{
LOG_FUNC("DrawCaption", hwnd, hdc, lprect, flags);
if (Gdi::isDisplayDc(hdc))
{
D3dDdi::ScopedCriticalSection lock;
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
return LOG_RESULT(CALL_ORIG_FUNC(DrawCaption)(hwnd, replaceDc(hdc), lprect, flags));
}
return LOG_RESULT(CALL_ORIG_FUNC(DrawCaption)(hwnd, hdc, lprect, flags));
}
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);
@ -235,7 +291,7 @@ namespace
} }
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params> template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
OrigFuncPtr getCompatGdiDcFuncPtr(FuncPtr<Result, Params...>) OrigFuncPtr getCompatGdiDcFuncPtr(FuncPtr<Result, HDC, Params...>)
{ {
return &compatGdiDcFunc<OrigFuncPtr, origFunc, Result, Params...>; return &compatGdiDcFunc<OrigFuncPtr, origFunc, Result, Params...>;
} }
@ -246,42 +302,6 @@ namespace
return &compatGdiTextDcFunc<OrigFuncPtr, origFunc, Result, Params...>; return &compatGdiTextDcFunc<OrigFuncPtr, origFunc, Result, Params...>;
} }
HDC getFirstDc()
{
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>
HDC getDestinationDc(Params... params)
{
return getFirstDc(params...);
}
template <>
HDC getDestinationDc<decltype(&GetDIBits), &GetDIBits>(
HDC, HBITMAP, UINT, UINT, LPVOID, LPBITMAPINFO, UINT)
{
return nullptr;
}
template <>
HDC getDestinationDc<decltype(&GetPixel), &GetPixel>(HDC, int, int)
{
return nullptr;
}
HRGN getWindowRegion(HWND hwnd) HRGN getWindowRegion(HWND hwnd)
{ {
RECT wr = {}; RECT wr = {};
@ -454,8 +474,8 @@ namespace
hookGdiDcFunction<decltype(&func), &func>(#module, #func) hookGdiDcFunction<decltype(&func), &func>(#module, #func)
#define HOOK_GDI_TEXT_DC_FUNCTION(module, func) \ #define HOOK_GDI_TEXT_DC_FUNCTION(module, func) \
hookGdiTextDcFunction<decltype(&func##A), &func##A>(#module, #func "A"); \ HOOK_GDI_DC_FUNCTION(module, func##A); \
hookGdiTextDcFunction<decltype(&func##W), &func##W>(#module, #func "W") HOOK_GDI_DC_FUNCTION(module, func##W)
namespace Gdi namespace Gdi
{ {
@ -541,7 +561,7 @@ namespace Gdi
HOOK_GDI_DC_FUNCTION(gdi32, PolyPolyline); HOOK_GDI_DC_FUNCTION(gdi32, PolyPolyline);
// Painting and drawing functions // Painting and drawing functions
HOOK_GDI_DC_FUNCTION(user32, DrawCaption); HOOK_FUNCTION(user32, DrawCaption, drawCaption);
HOOK_GDI_DC_FUNCTION(user32, DrawEdge); HOOK_GDI_DC_FUNCTION(user32, DrawEdge);
HOOK_GDI_DC_FUNCTION(user32, DrawFocusRect); HOOK_GDI_DC_FUNCTION(user32, DrawFocusRect);
HOOK_GDI_DC_FUNCTION(user32, DrawFrameControl); HOOK_GDI_DC_FUNCTION(user32, DrawFrameControl);