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

Fixed scroll bar control painting and thumb tracking

This commit is contained in:
narzoul 2021-02-13 12:03:00 +01:00
parent 27ae9affb8
commit 205f517845
23 changed files with 493 additions and 496 deletions

View File

@ -187,18 +187,6 @@ namespace D3dDdi
{
}
void Resource::beginGdiAccess(bool isReadOnly)
{
if (m_lockResource)
{
if (!m_lockData[0].isSysMemUpToDate)
{
copyToSysMem(0);
}
m_lockData[0].isVidMemUpToDate &= isReadOnly;
}
}
HRESULT Resource::blt(D3DDDIARG_BLT data)
{
if (!isValidRect(data.DstSubResourceIndex, data.DstRect))
@ -471,14 +459,6 @@ namespace D3dDdi
#endif
}
void Resource::endGdiAccess(bool isReadOnly)
{
if (m_lockResource && !isReadOnly && m_lockData[0].isSysMemUpToDate)
{
m_lockData[0].isVidMemUpToDate = false;
}
}
void* Resource::getLockPtr(UINT subResourceIndex)
{
return m_lockData.empty() ? nullptr : m_lockData[subResourceIndex].data;
@ -517,6 +497,21 @@ namespace D3dDdi
return m_device.getOrigVtable().pfnLock(m_device, &data);
}
void Resource::prepareForGdiRendering(bool isReadOnly)
{
if (!m_lockResource)
{
return;
}
if (!m_lockData[0].isSysMemUpToDate)
{
copyToSysMem(0);
}
m_lockData[0].isVidMemUpToDate &= isReadOnly;
m_lockData[0].qpcLastForcedLock = Time::queryPerformanceCounter();
}
void Resource::prepareForRendering(UINT subResourceIndex, bool isReadOnly)
{
if (m_lockResource && 0 == m_lockData[subResourceIndex].lockCount)

View File

@ -26,12 +26,11 @@ namespace D3dDdi
operator HANDLE() const { return m_handle; }
void beginGdiAccess(bool isReadOnly);
HRESULT blt(D3DDDIARG_BLT data);
HRESULT colorFill(D3DDDIARG_COLORFILL data);
void endGdiAccess(bool isReadOnly);
void* getLockPtr(UINT subResourceIndex);
HRESULT lock(D3DDDIARG_LOCK& data);
void prepareForGdiRendering(bool isReadOnly);
void prepareForRendering(UINT subResourceIndex, bool isReadOnly);
void setAsGdiResource(bool isGdiResource);
HRESULT unlock(const D3DDDIARG_UNLOCK& data);

View File

@ -1,11 +1,10 @@
#include <cstring>
#include <deque>
#include "Common/Time.h"
#include "Config/Config.h"
#include "DDraw/DirectDrawPalette.h"
#include "DDraw/Surfaces/PrimarySurface.h"
#include "Gdi/AccessGuard.h"
#include <Common/Time.h>
#include <Config/Config.h>
#include <DDraw/DirectDrawPalette.h>
#include <DDraw/Surfaces/PrimarySurface.h>
namespace DDraw
{

View File

@ -15,7 +15,6 @@
#include <DDraw/ScopedThreadLock.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <DDraw/Types.h>
#include <Gdi/AccessGuard.h>
#include <Gdi/Caret.h>
#include <Gdi/Gdi.h>
#include <Gdi/VirtualScreen.h>

View File

@ -213,7 +213,7 @@
<ClInclude Include="Direct3d\Visitors\Direct3dViewportVtblVisitor.h" />
<ClInclude Include="Direct3d\Visitors\Direct3dVtblVisitor.h" />
<ClInclude Include="Dll\Dll.h" />
<ClInclude Include="Gdi\AccessGuard.h" />
<ClInclude Include="Gdi\CompatDc.h" />
<ClInclude Include="Gdi\Font.h" />
<ClInclude Include="Gdi\Gdi.h" />
<ClInclude Include="Gdi\Caret.h" />
@ -287,7 +287,7 @@
<ClCompile Include="Direct3d\Log.cpp" />
<ClCompile Include="Dll\DllMain.cpp" />
<ClCompile Include="Dll\Dll.cpp" />
<ClCompile Include="Gdi\AccessGuard.cpp" />
<ClCompile Include="Gdi\CompatDc.cpp" />
<ClCompile Include="Gdi\Font.cpp" />
<ClCompile Include="Gdi\Gdi.cpp" />
<ClCompile Include="Gdi\Caret.cpp" />

View File

@ -297,9 +297,6 @@
<ClInclude Include="Gdi\VirtualScreen.h">
<Filter>Header Files\Gdi</Filter>
</ClInclude>
<ClInclude Include="Gdi\AccessGuard.h">
<Filter>Header Files\Gdi</Filter>
</ClInclude>
<ClInclude Include="Gdi\Palette.h">
<Filter>Header Files\Gdi</Filter>
</ClInclude>
@ -402,6 +399,9 @@
<ClInclude Include="Gdi\Metrics.h">
<Filter>Header Files\Gdi</Filter>
</ClInclude>
<ClInclude Include="Gdi\CompatDc.h">
<Filter>Header Files\Gdi</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">
@ -545,9 +545,6 @@
<ClCompile Include="Gdi\VirtualScreen.cpp">
<Filter>Source Files\Gdi</Filter>
</ClCompile>
<ClCompile Include="Gdi\AccessGuard.cpp">
<Filter>Source Files\Gdi</Filter>
</ClCompile>
<ClCompile Include="Gdi\Palette.cpp">
<Filter>Source Files\Gdi</Filter>
</ClCompile>
@ -620,5 +617,8 @@
<ClCompile Include="Gdi\Metrics.cpp">
<Filter>Source Files\Gdi</Filter>
</ClCompile>
<ClCompile Include="Gdi\CompatDc.cpp">
<Filter>Source Files\Gdi</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,41 +0,0 @@
#include "D3dDdi/Device.h"
#include "D3dDdi/Resource.h"
#include "DDraw/RealPrimarySurface.h"
#include "DDraw/Surfaces/PrimarySurface.h"
#include "Gdi/AccessGuard.h"
namespace Gdi
{
AccessGuard::AccessGuard(Access access, bool condition)
: m_access(access)
, m_condition(condition)
{
if (m_condition)
{
D3dDdi::ScopedCriticalSection lock;
auto gdiResource = D3dDdi::Device::getGdiResource();
if (gdiResource)
{
gdiResource->beginGdiAccess(ACCESS_READ == m_access);
}
}
}
AccessGuard::~AccessGuard()
{
if (m_condition)
{
D3dDdi::ScopedCriticalSection lock;
auto gdiResource = D3dDdi::Device::getGdiResource();
if (gdiResource)
{
gdiResource->endGdiAccess(ACCESS_READ == m_access);
}
if (ACCESS_WRITE == m_access &&
(!gdiResource || DDraw::PrimarySurface::getFrontResource() == *gdiResource))
{
DDraw::RealPrimarySurface::scheduleUpdate();
}
}
}
}

View File

@ -1,21 +0,0 @@
#pragma once
namespace Gdi
{
enum Access
{
ACCESS_READ,
ACCESS_WRITE
};
class AccessGuard
{
public:
AccessGuard(Access access, bool condition = true);
~AccessGuard();
private:
Access m_access;
bool m_condition;
};
}

View File

@ -0,0 +1,44 @@
#include <D3dDdi/Device.h>
#include <D3dDdi/Resource.h>
#include <D3dDdi/ScopedCriticalSection.h>
#include <DDraw/RealPrimarySurface.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <Gdi/CompatDc.h>
#include <Gdi/Dc.h>
namespace Gdi
{
CompatDc::CompatDc(HDC dc, bool isReadOnly)
: m_origDc(dc)
, m_compatDc(Gdi::Dc::getDc(dc))
, m_isReadOnly(isReadOnly)
{
if (m_compatDc)
{
D3dDdi::ScopedCriticalSection lock;
auto gdiResource = D3dDdi::Device::getGdiResource();
if (gdiResource)
{
gdiResource->prepareForGdiRendering(isReadOnly);
}
}
else
{
m_compatDc = m_origDc;
}
}
CompatDc::~CompatDc()
{
if (m_compatDc != m_origDc)
{
D3dDdi::ScopedCriticalSection lock;
auto gdiResource = D3dDdi::Device::getGdiResource();
if (!m_isReadOnly && (!gdiResource || DDraw::PrimarySurface::getFrontResource() == *gdiResource))
{
DDraw::RealPrimarySurface::scheduleUpdate();
}
Gdi::Dc::releaseDc(m_origDc);
}
}
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <Windows.h>
namespace Gdi
{
class CompatDc
{
public:
CompatDc(HDC dc, bool isReadOnly = false);
CompatDc(const CompatDc&) = delete;
CompatDc(CompatDc&& other) = delete;
CompatDc& operator=(const CompatDc&) = delete;
CompatDc& operator=(CompatDc&&) = delete;
~CompatDc();
operator HDC() const
{
return m_compatDc;
}
private:
HDC m_origDc;
HDC m_compatDc;
bool m_isReadOnly;
};
}

View File

@ -22,10 +22,6 @@ namespace
HDC origDc;
DWORD threadId;
int savedState;
HGDIOBJ savedFont;
HGDIOBJ savedBrush;
HGDIOBJ savedPen;
HPALETTE savedPalette;
bool useDefaultPalette;
};
@ -38,11 +34,10 @@ namespace
void copyDcAttributes(CompatDc& compatDc, HDC origDc, const POINT& origin)
{
SelectObject(compatDc.dc, compatDc.savedFont = GetCurrentObject(origDc, OBJ_FONT));
SelectObject(compatDc.dc, compatDc.savedBrush = GetCurrentObject(origDc, OBJ_BRUSH));
SelectObject(compatDc.dc, compatDc.savedPen = GetCurrentObject(origDc, OBJ_PEN));
CALL_ORIG_FUNC(SelectPalette)(
compatDc.dc, compatDc.savedPalette = static_cast<HPALETTE>(GetCurrentObject(origDc, OBJ_PAL)), FALSE);
SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_FONT));
SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_BRUSH));
SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_PEN));
CALL_ORIG_FUNC(SelectPalette)(compatDc.dc, static_cast<HPALETTE>(GetCurrentObject(origDc, OBJ_PAL)), FALSE);
const int graphicsMode = GetGraphicsMode(origDc);
SetGraphicsMode(compatDc.dc, graphicsMode);
@ -98,20 +93,10 @@ namespace
void restoreDc(const CompatDc& compatDc)
{
if (0 != compatDc.savedState)
{
// Bitmap may have changed during VirtualScreen::update, do not let RestoreDC restore the old one
HGDIOBJ bitmap = GetCurrentObject(compatDc.dc, OBJ_BITMAP);
RestoreDC(compatDc.dc, compatDc.savedState);
SelectObject(compatDc.dc, bitmap);
}
else
{
SelectObject(compatDc.dc, compatDc.savedFont);
SelectObject(compatDc.dc, compatDc.savedBrush);
SelectObject(compatDc.dc, compatDc.savedPen);
CALL_ORIG_FUNC(SelectPalette)(compatDc.dc, compatDc.savedPalette, FALSE);
}
// Bitmap may have changed during VirtualScreen::update, do not let RestoreDC restore the old one
HGDIOBJ bitmap = GetCurrentObject(compatDc.dc, OBJ_BITMAP);
RestoreDC(compatDc.dc, compatDc.savedState);
SelectObject(compatDc.dc, bitmap);
}
void setClippingRegion(const CompatDc& compatDc, HWND hwnd, const POINT& origin, const RECT& virtualScreenBounds)
@ -135,10 +120,7 @@ namespace
ExtSelectClipRgn(compatDc.dc, clipRgn, RGN_AND);
}
if (0 != compatDc.savedState)
{
SetMetaRgn(compatDc.dc);
}
SetMetaRgn(compatDc.dc);
}
}
@ -177,7 +159,7 @@ namespace Gdi
}
}
HDC getDc(HDC origDc, bool useMetaRgn)
HDC getDc(HDC origDc)
{
if (!isDisplayDc(origDc))
{
@ -222,7 +204,7 @@ namespace Gdi
compatDc.refCount = 1;
compatDc.origDc = origDc;
compatDc.threadId = GetCurrentThreadId();
compatDc.savedState = useMetaRgn ? SaveDC(compatDc.dc) : 0;
compatDc.savedState = SaveDC(compatDc.dc);
copyDcAttributes(compatDc, origDc, origin);
setClippingRegion(compatDc, hwnd, origin, virtualScreenBounds);

View File

@ -8,7 +8,7 @@ namespace Gdi
{
void dllProcessDetach();
void dllThreadDetach();
HDC getDc(HDC origDc, bool useMetaRgn = true);
HDC getDc(HDC origDc);
HDC getOrigDc(HDC dc);
void releaseDc(HDC origDc);
}

View File

@ -2,7 +2,7 @@
#include <Common/Hook.h>
#include <Common/Log.h>
#include <Gdi/AccessGuard.h>
#include <Gdi/CompatDc.h>
#include <Gdi/Dc.h>
#include <Gdi/DcFunctions.h>
#include <Gdi/Font.h>
@ -14,39 +14,6 @@
namespace
{
class CompatDc
{
public:
CompatDc(HDC dc) : m_origDc(dc), m_compatDc(Gdi::Dc::getDc(dc, false))
{
}
CompatDc(const CompatDc&) = delete;
CompatDc(CompatDc&& other) : m_origDc(nullptr), m_compatDc(nullptr)
{
std::swap(m_origDc, other.m_origDc);
std::swap(m_compatDc, other.m_compatDc);
}
~CompatDc()
{
if (m_compatDc)
{
Gdi::Dc::releaseDc(m_origDc);
}
}
operator HDC() const
{
return m_compatDc ? m_compatDc : m_origDc;
}
private:
HDC m_origDc;
HDC m_compatDc;
};
std::unordered_map<void*, const char*> g_funcNames;
thread_local bool g_redirectToDib = true;
@ -123,9 +90,9 @@ namespace
return t;
}
CompatDc replaceDc(HDC dc)
Gdi::CompatDc replaceDc(HDC dc)
{
return CompatDc(dc);
return Gdi::CompatDc(dc);
}
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
@ -137,9 +104,7 @@ namespace
if (hasDisplayDcArg(hdc, params...))
{
D3dDdi::ScopedCriticalSection lock;
Gdi::AccessGuard accessGuard(isReadOnly<OrigFuncPtr, origFunc>() ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE);
CompatDc compatDc(hdc);
Gdi::CompatDc compatDc(hdc, isReadOnly<OrigFuncPtr, origFunc>());
Result result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(compatDc, replaceDc(params)...);
if (isPositionUpdated<OrigFuncPtr, origFunc>() && result)
{
@ -181,9 +146,7 @@ namespace
}
else
{
D3dDdi::ScopedCriticalSection lock;
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
CompatDc compatDc(hdc);
Gdi::CompatDc compatDc(hdc);
BOOL result = CALL_ORIG_FUNC(ExtTextOutW)(compatDc, x, y, options, lprect, lpString, c, lpDx);
if (result)
{
@ -255,9 +218,7 @@ namespace
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, Gdi::CompatDc(hdc), lprect, flags));
}
return LOG_RESULT(CALL_ORIG_FUNC(DrawCaption)(hwnd, hdc, lprect, flags));
}

View File

@ -1,177 +1,285 @@
#include <Common/Hook.h>
#include <Gdi/Gdi.h>
#include <Gdi/ScrollBar.h>
namespace
{
enum ScrollBarInfoIndex
{
SBII_SCROLLBAR = 0,
SBII_TOP_RIGHT_ARROW = 1,
SBII_PAGEUP_PAGERIGHT_REGION = 2,
SBII_SELF = 0,
SBII_TOP_ARROW = 1,
SBII_PAGEUP_REGION = 2,
SBII_THUMB = 3,
SBII_PAGEDOWN_PAGELEFT_REGION = 4,
SBII_BOTTOM_LEFT_ARROW = 5
SBII_PAGEDOWN_REGION = 4,
SBII_BOTTOM_ARROW = 5
};
bool isVertical(HWND hwnd, int bar)
{
if (SB_CTL == bar)
{
return CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_STYLE) & SBS_VERT;
}
return SB_VERT == bar;
}
thread_local Gdi::ScrollBar* g_trackedScrollBar = nullptr;
}
namespace Gdi
{
ScrollBar::ScrollBar(HWND hwnd, HDC compatDc) :
m_hwnd(hwnd), m_compatDc(compatDc), m_windowRect(),
m_isLeftMouseButtonDown(false), m_cursorPos(),
m_horizontalSbi(), m_verticalSbi()
ScrollBar::ScrollBar(HWND hwnd, int bar)
: m_hwnd(hwnd)
, m_bar(bar)
, m_windowRect{}
, m_sbi{}
, m_isVertical(isVertical(hwnd, bar))
, m_arrowSize(CALL_ORIG_FUNC(GetSystemMetrics)(m_isVertical ? SM_CYVSCROLL : SM_CXHSCROLL))
, m_left(m_isVertical ? &RECT::left : &RECT::top)
, m_top(m_isVertical ? &RECT::top : &RECT::left)
, m_right(m_isVertical ? &RECT::right : &RECT::bottom)
, m_bottom(m_isVertical ? &RECT::bottom : &RECT::right)
, m_trackedChildId(-1)
, m_trackedThumbOffset(0)
{
const LONG windowStyle = CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_STYLE);
m_horizontalSbi.isVisible = 0 != (windowStyle & WS_HSCROLL);
m_verticalSbi.isVisible = 0 != (windowStyle & WS_VSCROLL);
LONG objectId = OBJID_CLIENT;
if (SB_HORZ == bar)
{
objectId = OBJID_HSCROLL;
}
else if (SB_VERT == bar)
{
objectId = OBJID_VSCROLL;
}
m_sbi.cbSize = sizeof(m_sbi);
GetScrollBarInfo(hwnd, objectId, &m_sbi);
GetWindowRect(hwnd, &m_windowRect);
OffsetRect(&m_sbi.rcScrollBar, -m_windowRect.left, -m_windowRect.top);
if (m_horizontalSbi.isVisible || m_verticalSbi.isVisible)
if (g_trackedScrollBar &&
hwnd == g_trackedScrollBar->m_hwnd &&
bar == g_trackedScrollBar->m_bar &&
GetKeyState(GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON) < 0)
{
m_isLeftMouseButtonDown =
hwnd == GetCapture() &&
GetAsyncKeyState(GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON) < 0 &&
GetCursorPos(&m_cursorPos);
DWORD pos = GetMessagePos();
POINTS pt = *reinterpret_cast<POINTS*>(&pos);
POINT p = { pt.x - m_windowRect.left, pt.y - m_windowRect.top };
if (m_isLeftMouseButtonDown)
if (SBII_THUMB == g_trackedScrollBar->m_trackedChildId)
{
m_cursorPos.x -= m_windowRect.left;
m_cursorPos.y -= m_windowRect.top;
RECT trackRect = m_sbi.rcScrollBar;
if (m_isVertical)
{
InflateRect(&trackRect, 8 * (trackRect.right - trackRect.left), 2 * m_arrowSize);
}
else
{
InflateRect(&trackRect, 2 * m_arrowSize, 8 * (trackRect.bottom - trackRect.top));
}
if (PtInRect(&trackRect, p))
{
const LONG thumbSize = m_sbi.xyThumbBottom - m_sbi.xyThumbTop;
const LONG minThumbPos = m_arrowSize;
const LONG maxThumbPos = m_sbi.rcScrollBar.*m_bottom - m_sbi.rcScrollBar.*m_top - thumbSize - m_arrowSize;
LONG thumbPos = (m_isVertical ? p.y : p.x) - m_sbi.rcScrollBar.*m_top -
g_trackedScrollBar->m_trackedThumbOffset;
if (thumbPos < minThumbPos)
{
thumbPos = minThumbPos;
}
if (thumbPos > maxThumbPos)
{
thumbPos = maxThumbPos;
}
m_sbi.xyThumbTop = thumbPos;
m_sbi.xyThumbBottom = thumbPos + thumbSize;
}
}
if (m_horizontalSbi.isVisible)
else
{
m_horizontalSbi = getScrollBarInfo(OBJID_HSCROLL);
}
if (m_verticalSbi.isVisible)
{
m_verticalSbi = getScrollBarInfo(OBJID_VSCROLL);
RECT rect = getChildRect(g_trackedScrollBar->m_trackedChildId);
if (PtInRect(&rect, p))
{
m_sbi.rgstate[g_trackedScrollBar->m_trackedChildId] |= STATE_SYSTEM_PRESSED;
}
}
}
}
void ScrollBar::drawAll() const
ScrollBar::~ScrollBar()
{
drawHorizArrows();
drawVertArrows();
}
void ScrollBar::drawArrow(const ScrollBarChildInfo& sbci, UINT dfcState) const
{
UINT stateFlags = 0;
if (sbci.state & STATE_SYSTEM_UNAVAILABLE)
if (this == g_trackedScrollBar)
{
stateFlags |= DFCS_INACTIVE;
}
else if (sbci.state & STATE_SYSTEM_PRESSED)
{
stateFlags |= DFCS_PUSHED;
}
RECT rect = sbci.rect;
CALL_ORIG_FUNC(DrawFrameControl)(m_compatDc, &rect, DFC_SCROLL, dfcState | stateFlags);
}
void ScrollBar::drawHorizArrows() const
{
if (m_horizontalSbi.isVisible)
{
drawArrow(m_horizontalSbi.topLeftArrow, DFCS_SCROLLLEFT);
drawArrow(m_horizontalSbi.bottomRightArrow, DFCS_SCROLLRIGHT);
g_trackedScrollBar = nullptr;
}
}
void ScrollBar::drawVertArrows() const
void ScrollBar::drawAll(HDC dc, HBRUSH brush)
{
if (m_verticalSbi.isVisible)
if (isVisible())
{
drawArrow(m_verticalSbi.topLeftArrow, DFCS_SCROLLUP);
drawArrow(m_verticalSbi.bottomRightArrow, DFCS_SCROLLDOWN);
drawArrow(dc, SBII_TOP_ARROW);
drawPageRegion(dc, brush, SBII_PAGEUP_REGION);
drawThumb(dc, brush);
drawPageRegion(dc, brush, SBII_PAGEDOWN_REGION);
drawArrow(dc, SBII_BOTTOM_ARROW);
}
}
void ScrollBar::excludeFromClipRegion(const RECT& rect) const
void ScrollBar::drawArrow(HDC dc, LONG childId)
{
ExcludeClipRect(m_compatDc, rect.left, rect.top, rect.right, rect.bottom);
}
void ScrollBar::excludeFromClipRegion(const ScrollBarInfo& sbi) const
{
if (sbi.isVisible)
UINT state = 0;
if (SBII_TOP_ARROW == childId)
{
excludeFromClipRegion(sbi.topLeftArrow.rect);
excludeFromClipRegion(sbi.bottomRightArrow.rect);
}
}
void ScrollBar::excludeFromClipRegion() const
{
excludeFromClipRegion(m_horizontalSbi);
excludeFromClipRegion(m_verticalSbi);
}
ScrollBar::ScrollBarInfo ScrollBar::getScrollBarInfo(LONG objId) const
{
ScrollBarInfo scrollBarInfo = {};
SCROLLBARINFO sbi = {};
sbi.cbSize = sizeof(sbi);
scrollBarInfo.isVisible = GetScrollBarInfo(m_hwnd, objId, &sbi) &&
!(sbi.rgstate[SBII_SCROLLBAR] & (STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_OFFSCREEN));
if (!scrollBarInfo.isVisible)
{
return scrollBarInfo;
}
OffsetRect(&sbi.rcScrollBar, -m_windowRect.left, -m_windowRect.top);
scrollBarInfo.topLeftArrow.rect = sbi.rcScrollBar;
scrollBarInfo.bottomRightArrow.rect = sbi.rcScrollBar;
scrollBarInfo.shaftRect = sbi.rcScrollBar;
if (OBJID_HSCROLL == objId)
{
const int w = GetSystemMetrics(SM_CXHSCROLL);
scrollBarInfo.topLeftArrow.rect.right = scrollBarInfo.topLeftArrow.rect.left + w;
scrollBarInfo.topLeftArrow.state = sbi.rgstate[SBII_BOTTOM_LEFT_ARROW];
scrollBarInfo.bottomRightArrow.rect.left = scrollBarInfo.bottomRightArrow.rect.right - w;
scrollBarInfo.bottomRightArrow.state = sbi.rgstate[SBII_TOP_RIGHT_ARROW];
InflateRect(&scrollBarInfo.shaftRect, -w, 0);
state = m_isVertical ? DFCS_SCROLLUP : DFCS_SCROLLLEFT;
}
else
{
const int h = GetSystemMetrics(SM_CYVSCROLL);
scrollBarInfo.topLeftArrow.rect.bottom = scrollBarInfo.topLeftArrow.rect.top + h;
scrollBarInfo.topLeftArrow.state = sbi.rgstate[SBII_TOP_RIGHT_ARROW];
scrollBarInfo.bottomRightArrow.rect.top = scrollBarInfo.bottomRightArrow.rect.bottom - h;
scrollBarInfo.bottomRightArrow.state = sbi.rgstate[SBII_BOTTOM_LEFT_ARROW];
InflateRect(&scrollBarInfo.shaftRect, 0, -h);
state = m_isVertical ? DFCS_SCROLLDOWN : DFCS_SCROLLRIGHT;
}
if (m_isLeftMouseButtonDown)
if (m_sbi.rgstate[childId] & STATE_SYSTEM_UNAVAILABLE)
{
setPressedState(scrollBarInfo.topLeftArrow);
setPressedState(scrollBarInfo.bottomRightArrow);
state |= DFCS_INACTIVE;
}
else if (m_sbi.rgstate[childId] & STATE_SYSTEM_PRESSED)
{
state |= DFCS_PUSHED;
}
return scrollBarInfo;
RECT rect = getChildRect(childId);
DrawFrameControl(dc, &rect, DFC_SCROLL, state);
}
void ScrollBar::setPressedState(ScrollBarChildInfo& sbci) const
void ScrollBar::drawPageRegion(HDC dc, HBRUSH brush, LONG childId)
{
if (!(sbci.state & STATE_SYSTEM_UNAVAILABLE) && PtInRect(&sbci.rect, m_cursorPos))
RECT rect = getChildRect(childId);
if (IsRectEmpty(&rect))
{
sbci.state |= STATE_SYSTEM_PRESSED;
return;
}
FillRect(dc, &rect, brush);
if (SB_CTL == m_bar)
{
const UINT edges = m_isVertical ? (BF_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM);
DrawEdge(dc, &rect, BDR_SUNKEN, edges | BF_FLAT);
}
if (m_sbi.rgstate[childId] & STATE_SYSTEM_PRESSED)
{
InvertRect(dc, &rect);
}
}
void ScrollBar::drawThumb(HDC dc, HBRUSH brush)
{
if (m_sbi.rgstate[SBII_SELF] & STATE_SYSTEM_UNAVAILABLE)
{
drawPageRegion(dc, brush, SBII_THUMB);
}
else
{
RECT rect = m_sbi.rcScrollBar;
rect.*m_top += m_sbi.xyThumbTop;
rect.*m_bottom = m_sbi.rcScrollBar.*m_top + m_sbi.xyThumbBottom;
DrawFrameControl(dc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH);
}
}
RECT ScrollBar::getChildRect(LONG childId)
{
RECT r = m_sbi.rcScrollBar;
switch (childId)
{
case SBII_TOP_ARROW:
r.*m_bottom = r.*m_top + m_arrowSize;
break;
case SBII_PAGEUP_REGION:
r.*m_bottom = r.*m_top + m_sbi.xyThumbTop;
r.*m_top += m_arrowSize;
break;
case SBII_THUMB:
r.*m_bottom = r.*m_top + m_sbi.xyThumbBottom;
r.*m_top += m_sbi.xyThumbTop;
break;
case SBII_PAGEDOWN_REGION:
r.*m_top += m_sbi.xyThumbBottom;
r.*m_bottom -= m_arrowSize;
break;
case SBII_BOTTOM_ARROW:
r.*m_top = r.*m_bottom - m_arrowSize;
break;
}
return r;
}
LONG ScrollBar::hitTest(POINT p)
{
if (m_sbi.rgstate[SBII_SELF] & STATE_SYSTEM_UNAVAILABLE)
{
return -1;
}
for (UINT i = SBII_TOP_ARROW; i <= SBII_BOTTOM_ARROW; ++i)
{
RECT r = getChildRect(i);
if (PtInRect(&r, p))
{
return (m_sbi.rgstate[i] & STATE_SYSTEM_UNAVAILABLE) ? -1 : i;
}
}
return -1;
}
bool ScrollBar::isVisible()
{
return !(m_sbi.rgstate[SBII_SELF] & (STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_OFFSCREEN));
}
void ScrollBar::onCtlColorScrollBar(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT result)
{
HWND hwndSb = reinterpret_cast<HWND>(lParam);
HBRUSH brush = reinterpret_cast<HBRUSH>(result);
HDC dc = reinterpret_cast<HDC>(wParam);
if (hwnd == hwndSb)
{
ScrollBar(hwnd, SB_HORZ).drawAll(dc, brush);
ScrollBar(hwnd, SB_VERT).drawAll(dc, brush);
}
else
{
ScrollBar(hwndSb, SB_CTL).drawAll(dc, brush);
}
}
void ScrollBar::onLButtonDown(LPARAM lParam)
{
POINTS pt = *reinterpret_cast<POINTS*>(&lParam);
POINT p = { pt.x, pt.y };
if (SB_CTL != m_bar)
{
p.x -= m_windowRect.left;
p.y -= m_windowRect.top;
}
m_trackedChildId = hitTest(p);
if (-1 != m_trackedChildId)
{
g_trackedScrollBar = this;
if (SBII_THUMB == m_trackedChildId)
{
RECT rect = getChildRect(SBII_THUMB);
m_trackedThumbOffset = m_isVertical ? (p.y - rect.top) : (p.x - rect.left);
}
}
}
}

View File

@ -7,42 +7,33 @@ namespace Gdi
class ScrollBar
{
public:
struct ScrollBarChildInfo
{
RECT rect;
LONG state;
};
ScrollBar(HWND hwnd, int bar);
~ScrollBar();
struct ScrollBarInfo
{
ScrollBarChildInfo topLeftArrow;
ScrollBarChildInfo bottomRightArrow;
RECT shaftRect;
bool isVisible;
};
void onLButtonDown(LPARAM lParam);
ScrollBar(HWND hwnd, HDC compatDc);
void drawAll() const;
void drawHorizArrows() const;
void drawVertArrows() const;
void excludeFromClipRegion() const;
const ScrollBarInfo& getHorizontalScrollBarInfo() const { return m_horizontalSbi; }
const ScrollBarInfo& getVerticalScrollBarInfo() const { return m_verticalSbi; }
static void onCtlColorScrollBar(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT result);
private:
void drawArrow(const ScrollBarChildInfo& sbci, UINT dfcState) const;
void excludeFromClipRegion(const RECT& rect) const;
void excludeFromClipRegion(const ScrollBarInfo& sbi) const;
ScrollBarInfo getScrollBarInfo(LONG objId) const;
void setPressedState(ScrollBarChildInfo& sbci) const;
void drawAll(HDC dc, HBRUSH brush);
void drawArrow(HDC dc, LONG childId);
void drawPageRegion(HDC dc, HBRUSH brush, LONG childId);
void drawThumb(HDC dc, HBRUSH brush);
RECT getChildRect(LONG childId);
LONG hitTest(POINT p);
bool isVisible();
HWND m_hwnd;
HDC m_compatDc;
int m_bar;
RECT m_windowRect;
bool m_isLeftMouseButtonDown;
POINT m_cursorPos;
ScrollBarInfo m_horizontalSbi;
ScrollBarInfo m_verticalSbi;
SCROLLBARINFO m_sbi;
bool m_isVertical;
int m_arrowSize;
LONG RECT::* m_left;
LONG RECT::* m_top;
LONG RECT::* m_right;
LONG RECT::* m_bottom;
LONG m_trackedChildId;
LONG m_trackedThumbOffset;
};
}

View File

@ -1,10 +1,8 @@
#include <Common/Hook.h>
#include <Common/Log.h>
#include <Gdi/AccessGuard.h>
#include <Gdi/Dc.h>
#include <Gdi/Gdi.h>
#include <Gdi/Region.h>
#include <Gdi/ScrollBar.h>
#include <Gdi/ScrollFunctions.h>
#include <Gdi/Window.h>
@ -48,31 +46,6 @@ namespace
return LOG_RESULT(result);
}
int WINAPI setScrollInfo(HWND hwnd, int nBar, LPCSCROLLINFO lpsi, BOOL redraw)
{
LOG_FUNC("SetScrollInfo", hwnd, nBar, lpsi, redraw);
int result = CALL_ORIG_FUNC(SetScrollInfo)(hwnd, nBar, lpsi, redraw);
if (redraw && (SB_HORZ == nBar || SB_VERT == nBar))
{
Gdi::ScrollBar sb(hwnd, nullptr);
const auto& sbi = SB_HORZ == nBar ? sb.getHorizontalScrollBarInfo() : sb.getVerticalScrollBarInfo();
if (sbi.isVisible)
{
HDC windowDc = GetWindowDC(hwnd);
SelectClipRgn(windowDc, Gdi::Region(sbi.shaftRect));
HDC compatDc = Gdi::Dc::getDc(windowDc);
if (compatDc)
{
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
CALL_ORIG_FUNC(DefWindowProcA)(hwnd, WM_PRINT, reinterpret_cast<WPARAM>(compatDc), PRF_NONCLIENT);
Gdi::Dc::releaseDc(windowDc);
}
CALL_ORIG_FUNC(ReleaseDC)(hwnd, windowDc);
}
}
return LOG_RESULT(result);
}
}
namespace Gdi
@ -83,7 +56,6 @@ namespace Gdi
{
HOOK_FUNCTION(user32, ScrollWindow, scrollWindow);
HOOK_FUNCTION(user32, ScrollWindowEx, scrollWindowEx);
HOOK_FUNCTION(user32, SetScrollInfo, setScrollInfo);
}
}
}

View File

@ -1,8 +1,6 @@
#include <Common/Hook.h>
#include <Gdi/Gdi.h>
#include <Gdi/Region.h>
#include <Gdi/TitleBar.h>
#include <Gdi/VirtualScreen.h>
#include <Win32/DisplayMode.h>
namespace
@ -19,9 +17,8 @@ namespace
namespace Gdi
{
TitleBar::TitleBar(HWND hwnd, HDC compatDc)
TitleBar::TitleBar(HWND hwnd)
: m_hwnd(hwnd)
, m_compatDc(compatDc)
, m_buttonWidth(0)
, m_buttonHeight(0)
, m_tbi{}
@ -75,26 +72,26 @@ namespace Gdi
}
}
void TitleBar::drawAll() const
void TitleBar::drawAll(HDC dc) const
{
drawCaption();
drawButtons();
drawCaption(dc);
drawButtons(dc);
}
void TitleBar::drawButtons() const
void TitleBar::drawButtons(HDC dc) const
{
if (!m_hasTitleBar)
{
return;
}
drawButton(TBII_MINIMIZE_BUTTON, DFCS_CAPTIONMIN);
drawButton(TBII_MAXIMIZE_BUTTON, IsZoomed(m_hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX);
drawButton(TBII_HELP_BUTTON, DFCS_CAPTIONHELP);
drawButton(TBII_CLOSE_BUTTON, DFCS_CAPTIONCLOSE);
drawButton(dc, TBII_MINIMIZE_BUTTON, DFCS_CAPTIONMIN);
drawButton(dc, TBII_MAXIMIZE_BUTTON, IsZoomed(m_hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX);
drawButton(dc, TBII_HELP_BUTTON, DFCS_CAPTIONHELP);
drawButton(dc, TBII_CLOSE_BUTTON, DFCS_CAPTIONCLOSE);
}
void TitleBar::drawCaption() const
void TitleBar::drawCaption(HDC dc) const
{
if (!m_hasTitleBar)
{
@ -111,20 +108,15 @@ namespace Gdi
flags |= DC_GRADIENT;
}
RECT virtualScreenBounds = VirtualScreen::getBounds();
RECT clipRect = m_tbi.rcTitleBar;
OffsetRect(&clipRect, m_windowRect.left - virtualScreenBounds.left, m_windowRect.top - virtualScreenBounds.top);
Region clipRgn(clipRect);
SelectClipRgn(m_compatDc, clipRgn);
CALL_ORIG_FUNC(DrawCaption)(m_hwnd, m_compatDc, &m_tbi.rcTitleBar, flags);
SelectClipRgn(m_compatDc, nullptr);
SelectClipRgn(dc, Region(m_tbi.rcTitleBar));
DrawCaption(m_hwnd, dc, &m_tbi.rcTitleBar, flags);
SelectClipRgn(dc, nullptr);
if (m_hasIcon)
{
RECT r = m_tbi.rcTitleBar;
r.right = r.left + r.bottom - r.top;
CALL_ORIG_FUNC(FillRect)(m_compatDc, &r,
GetSysColorBrush(m_isActive ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
FillRect(dc, &r, GetSysColorBrush(m_isActive ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
HICON icon = reinterpret_cast<HICON>(SendMessage(m_hwnd, WM_GETICON, ICON_SMALL, 96));
if (!icon)
@ -135,11 +127,11 @@ namespace Gdi
int height = GetSystemMetrics(SM_CYSMICON);
int x = r.left + (r.right - r.left - width) / 2 + 2;
int y = r.top + (r.bottom - r.top - height) / 2;
CALL_ORIG_FUNC(DrawIconEx)(m_compatDc, x, y, icon, width, height, 0, nullptr, DI_NORMAL);
DrawIconEx(dc, x, y, icon, width, height, 0, nullptr, DI_NORMAL);
}
}
void TitleBar::drawButton(std::size_t tbiIndex, UINT dfcState) const
void TitleBar::drawButton(HDC dc, std::size_t tbiIndex, UINT dfcState) const
{
if (!isVisible(tbiIndex))
{
@ -157,16 +149,7 @@ namespace Gdi
}
RECT rect = m_tbi.rgrect[tbiIndex];
CALL_ORIG_FUNC(DrawFrameControl)(m_compatDc, &rect, DFC_CAPTION, dfcState | stateFlags);
}
void TitleBar::excludeFromClipRegion() const
{
if (m_hasTitleBar)
{
const RECT& r = m_tbi.rcTitleBar;
ExcludeClipRect(m_compatDc, r.left, r.top, r.right, r.bottom);
}
DrawFrameControl(dc, &rect, DFC_CAPTION, dfcState | stateFlags);
}
bool TitleBar::isVisible(std::size_t tbiIndex) const

View File

@ -9,19 +9,17 @@ namespace Gdi
class TitleBar
{
public:
TitleBar(HWND hwnd, HDC compatDc);
TitleBar(HWND hwnd);
void drawAll() const;
void drawButtons() const;
void drawCaption() const;
void excludeFromClipRegion() const;
void drawAll(HDC dc) const;
void drawButtons(HDC dc) const;
void drawCaption(HDC dc) const;
private:
void drawButton(std::size_t tbiIndex, UINT dfcState) const;
void drawButton(HDC dc, std::size_t tbiIndex, UINT dfcState) const;
bool isVisible(std::size_t tbiIndex) const;
HWND m_hwnd;
HDC m_compatDc;
int m_buttonWidth;
int m_buttonHeight;
TITLEBARINFOEX m_tbi;

View File

@ -1,7 +1,6 @@
#include <vector>
#include <Gdi/AccessGuard.h>
#include <Gdi/Dc.h>
#include <Gdi/CompatDc.h>
#include <Gdi/ScrollBar.h>
#include <Gdi/ScrollFunctions.h>
#include <Gdi/TitleBar.h>
@ -134,6 +133,15 @@ namespace
{
switch (msg)
{
case WM_CTLCOLORSCROLLBAR:
if (reinterpret_cast<HWND>(lParam) == hwnd)
{
LRESULT result = origDefWindowProc(hwnd, msg, wParam, lParam);
Gdi::ScrollBar::onCtlColorScrollBar(hwnd, wParam, lParam, result);
return result;
}
break;
case WM_NCACTIVATE:
return onNcActivate(hwnd, wParam, lParam);
@ -151,12 +159,13 @@ namespace
case WM_NCLBUTTONDOWN:
{
LRESULT result = origDefWindowProc(hwnd, msg, wParam, lParam);
if (wParam == HTHSCROLL || wParam == HTVSCROLL)
{
onNcPaint(hwnd, origDefWindowProc);
Gdi::ScrollBar sb(hwnd, wParam == HTHSCROLL ? SB_HORZ : SB_VERT);
sb.onLButtonDown(lParam);
return origDefWindowProc(hwnd, msg, wParam, lParam);
}
return result;
return origDefWindowProc(hwnd, msg, wParam, lParam);
}
}
@ -347,20 +356,8 @@ namespace
LRESULT onEraseBackground(HWND hwnd, HDC dc, WNDPROC origWndProc)
{
if (hwnd)
{
LRESULT result = 0;
HDC compatDc = Gdi::Dc::getDc(dc);
if (compatDc)
{
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
result = CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(compatDc), 0);
Gdi::Dc::releaseDc(dc);
return result;
}
}
return CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(dc), 0);
return CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND,
reinterpret_cast<WPARAM>(static_cast<HDC>(Gdi::CompatDc(dc))), 0);
}
LRESULT onNcActivate(HWND hwnd, WPARAM /*wParam*/, LPARAM lParam)
@ -375,73 +372,29 @@ namespace
LRESULT onNcPaint(HWND hwnd, WNDPROC origWndProc)
{
D3dDdi::ScopedCriticalSection lock;
HDC windowDc = GetWindowDC(hwnd);
HDC compatDc = Gdi::Dc::getDc(windowDc);
if (compatDc)
{
D3dDdi::ScopedCriticalSection lock;
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
Gdi::TitleBar titleBar(hwnd, compatDc);
titleBar.drawAll();
titleBar.excludeFromClipRegion();
Gdi::ScrollBar scrollBar(hwnd, compatDc);
scrollBar.drawAll();
scrollBar.excludeFromClipRegion();
CallWindowProc(origWndProc, hwnd, WM_PRINT, reinterpret_cast<WPARAM>(compatDc), PRF_NONCLIENT);
Gdi::Dc::releaseDc(windowDc);
}
CALL_ORIG_FUNC(ReleaseDC)(hwnd, windowDc);
CallWindowProc(origWndProc, hwnd, WM_PRINT,
reinterpret_cast<WPARAM>(static_cast<HDC>(Gdi::CompatDc(windowDc))), PRF_NONCLIENT);
Gdi::TitleBar(hwnd).drawAll(windowDc);
ReleaseDC(hwnd, windowDc);
return 0;
}
LRESULT onPaint(HWND hwnd, WNDPROC origWndProc)
{
if (!hwnd)
{
return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0);
}
PAINTSTRUCT paint = {};
HDC dc = BeginPaint(hwnd, &paint);
HDC compatDc = Gdi::Dc::getDc(dc);
if (compatDc)
{
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
CallWindowProc(origWndProc, hwnd, WM_PRINTCLIENT,
reinterpret_cast<WPARAM>(compatDc), PRF_CLIENT);
Gdi::Dc::releaseDc(dc);
}
else
{
CallWindowProc(origWndProc, hwnd, WM_PRINTCLIENT, reinterpret_cast<WPARAM>(dc), PRF_CLIENT);
}
CallWindowProc(origWndProc, hwnd, WM_PRINTCLIENT,
reinterpret_cast<WPARAM>(static_cast<HDC>(Gdi::CompatDc(dc))), PRF_CLIENT);
EndPaint(hwnd, &paint);
return 0;
}
LRESULT onPrint(HWND hwnd, UINT msg, HDC dc, LONG flags, WNDPROC origWndProc)
{
LRESULT result = 0;
HDC compatDc = Gdi::Dc::getDc(dc);
if (compatDc)
{
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(compatDc), flags);
Gdi::Dc::releaseDc(dc);
}
else
{
result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(dc), flags);
}
return result;
return CallWindowProc(origWndProc, hwnd, msg,
reinterpret_cast<WPARAM>(static_cast<HDC>(Gdi::CompatDc(dc))), flags);
}
LRESULT onSetText(HWND hwnd, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc)
@ -459,6 +412,13 @@ namespace
{
switch (msg)
{
case WM_LBUTTONDOWN:
{
Gdi::ScrollBar sb(hwnd, SB_CTL);
sb.onLButtonDown(lParam);
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
}
case WM_PAINT:
return onPaint(hwnd, origWndProc);
@ -468,10 +428,9 @@ namespace
SetCursor(LoadCursor(nullptr, IDC_SIZENWSE));
}
return TRUE;
default:
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
}
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
}
BOOL WINAPI setMenuItemInfoW(HMENU hmenu, UINT item, BOOL fByPositon, LPCMENUITEMINFOW lpmii)

View File

@ -7,7 +7,7 @@
#include <Common/Log.h>
#include <Common/ScopedSrwLock.h>
#include <Dll/Dll.h>
#include <Gdi/AccessGuard.h>
#include <Gdi/CompatDc.h>
#include <Gdi/Dc.h>
#include <Gdi/PresentationWindow.h>
#include <Gdi/ScrollBar.h>
@ -34,6 +34,7 @@ namespace
WindowProc getWindowProc(HWND hwnd);
bool isTopLevelWindow(HWND hwnd);
bool isUser32ScrollBar(HWND hwnd);
void onCreateWindow(HWND hwnd);
void onDestroyWindow(HWND hwnd);
void onWindowPosChanged(HWND hwnd);
@ -64,6 +65,14 @@ namespace
switch (uMsg)
{
case WM_CTLCOLORSCROLLBAR:
if (reinterpret_cast<HWND>(lParam) != hwnd &&
isUser32ScrollBar(reinterpret_cast<HWND>(lParam)))
{
Gdi::ScrollBar::onCtlColorScrollBar(hwnd, wParam, lParam, result);
}
break;
case WM_NCDESTROY:
onDestroyWindow(hwnd);
break;
@ -153,6 +162,25 @@ namespace
return GetDesktopWindow() == GetAncestor(hwnd, GA_PARENT);
}
bool isUser32ScrollBar(HWND hwnd)
{
WNDCLASS wc = {};
static const ATOM sbAtom = static_cast<ATOM>(GetClassInfo(nullptr, "ScrollBar", &wc));
if (sbAtom != GetClassLong(hwnd, GCW_ATOM))
{
return false;
}
auto it = g_windowProc.find(hwnd);
if (it == g_windowProc.end())
{
return false;
}
return GetModuleHandle("comctl32") != Compat::getModuleHandleFromAddress(
IsWindowUnicode(hwnd) ? it->second.wndProcW : it->second.wndProcA);
}
void CALLBACK objectCreateEvent(
HWINEVENTHOOK /*hWinEventHook*/,
DWORD /*event*/,
@ -177,33 +205,38 @@ namespace
DWORD /*dwEventThread*/,
DWORD /*dwmsEventTime*/)
{
if (OBJID_TITLEBAR == idObject || OBJID_HSCROLL == idObject || OBJID_VSCROLL == idObject)
switch (idObject)
{
if (!hwnd)
{
return;
}
case OBJID_TITLEBAR:
{
HDC dc = GetWindowDC(hwnd);
Gdi::TitleBar(hwnd).drawButtons(dc);
ReleaseDC(hwnd, dc);
break;
}
HDC windowDc = GetWindowDC(hwnd);
HDC compatDc = Gdi::Dc::getDc(windowDc);
if (compatDc)
case OBJID_CLIENT:
if (!isUser32ScrollBar(hwnd))
{
Gdi::AccessGuard accessGuard(Gdi::ACCESS_WRITE);
if (OBJID_TITLEBAR == idObject)
{
Gdi::TitleBar(hwnd, compatDc).drawButtons();
}
else if (OBJID_HSCROLL == idObject)
{
Gdi::ScrollBar(hwnd, compatDc).drawHorizArrows();
}
else if (OBJID_VSCROLL == idObject)
{
Gdi::ScrollBar(hwnd, compatDc).drawVertArrows();
}
Gdi::Dc::releaseDc(windowDc);
break;
}
CALL_ORIG_FUNC(ReleaseDC)(hwnd, windowDc);
case OBJID_HSCROLL:
case OBJID_VSCROLL:
{
HDC dc = GetWindowDC(hwnd);
if (OBJID_CLIENT == idObject)
{
SendMessage(GetParent(hwnd), WM_CTLCOLORSCROLLBAR,
reinterpret_cast<WPARAM>(dc), reinterpret_cast<LPARAM>(hwnd));
}
else
{
DefWindowProc(hwnd, WM_CTLCOLORSCROLLBAR,
reinterpret_cast<WPARAM>(dc), reinterpret_cast<LPARAM>(hwnd));
}
ReleaseDC(hwnd, dc);
break;
}
}
}
@ -421,6 +454,7 @@ namespace Gdi
HOOK_FUNCTION(user32, UpdateLayeredWindow, updateLayeredWindow);
HOOK_FUNCTION(user32, UpdateLayeredWindowIndirect, updateLayeredWindowIndirect);
CoInitialize(nullptr);
g_objectCreateEventHook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE,
Dll::g_currentModule, &objectCreateEvent, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
g_objectStateChangeEventHook = SetWinEventHook(EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_STATECHANGE,

View File

@ -83,7 +83,7 @@ namespace
SelectClipRgn(screenDc, clipRegion);
BitBlt(screenDc, dst.left, dst.top, src.right - src.left, src.bottom - src.top, screenDc, src.left, src.top, SRCCOPY);
SelectClipRgn(screenDc, nullptr);
CALL_ORIG_FUNC(ReleaseDC)(nullptr, screenDc);
ReleaseDC(nullptr, screenDc);
return true;
}

View File

@ -346,6 +346,13 @@ std::ostream& operator<<(std::ostream& os, const POINT& p)
<< p.y;
}
std::ostream& operator<<(std::ostream& os, const POINTS& p)
{
return Compat::LogStruct(os)
<< p.x
<< p.y;
}
std::ostream& operator<<(std::ostream& os, const RECT& rect)
{
return Compat::LogStruct(os)

View File

@ -33,6 +33,7 @@ std::ostream& operator<<(std::ostream& os, const MSG& msg);
std::ostream& operator<<(std::ostream& os, const NCCALCSIZE_PARAMS& nccs);
std::ostream& operator<<(std::ostream& os, const NMHDR& nm);
std::ostream& operator<<(std::ostream& os, const POINT& p);
std::ostream& operator<<(std::ostream& os, const POINTS& p);
std::ostream& operator<<(std::ostream& os, const RECT& rect);
std::ostream& operator<<(std::ostream& os, const SIZE& size);
std::ostream& operator<<(std::ostream& os, const STYLESTRUCT& ss);