mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Previous method of GDI interworking does not seem feasible anymore as it is leaking GDI resources in more complex scenarios (StarCraft). There does not seem to be a way to prevent all leaks as the ReleaseDC hook does not capture all released DCs. New method redirects the individual GDI drawing methods instead by replacing DCs only temporarily for each operation. Currently only BitBlt is supported (which seems sufficient for Deadlock 2). Also, writing to unlocked video surface memory no longer works on Windows 10. To work around this restriction, the primary surface is temporarily locked for the duration of each GDI rendering operation.
75 lines
1.7 KiB
C++
75 lines
1.7 KiB
C++
#include "CompatGdiDc.h"
|
|
#include "CompatGdiDcCache.h"
|
|
#include "RealPrimarySurface.h"
|
|
|
|
namespace
|
|
{
|
|
struct ExcludeClipRectsData
|
|
{
|
|
HDC compatDc;
|
|
POINT origin;
|
|
HWND rootWnd;
|
|
};
|
|
|
|
BOOL CALLBACK excludeClipRectsForOverlappingWindows(HWND hwnd, LPARAM lParam)
|
|
{
|
|
auto excludeClipRectsData = reinterpret_cast<ExcludeClipRectsData*>(lParam);
|
|
if (hwnd == excludeClipRectsData->rootWnd)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
RECT rect = {};
|
|
GetWindowRect(hwnd, &rect);
|
|
OffsetRect(&rect, -excludeClipRectsData->origin.x, -excludeClipRectsData->origin.y);
|
|
ExcludeClipRect(excludeClipRectsData->compatDc, rect.left, rect.top, rect.right, rect.bottom);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
namespace CompatGdiDc
|
|
{
|
|
CachedDc getDc(HDC origDc)
|
|
{
|
|
CachedDc cachedDc = {};
|
|
if (!origDc || !RealPrimarySurface::isFullScreen() ||
|
|
OBJ_DC != GetObjectType(origDc) ||
|
|
DT_RASDISPLAY != GetDeviceCaps(origDc, TECHNOLOGY))
|
|
{
|
|
return cachedDc;
|
|
}
|
|
|
|
cachedDc = CompatGdiDcCache::getDc();
|
|
if (!cachedDc.dc)
|
|
{
|
|
return cachedDc;
|
|
}
|
|
|
|
HWND hwnd = WindowFromDC(origDc);
|
|
if (hwnd)
|
|
{
|
|
POINT origin = {};
|
|
GetDCOrgEx(origDc, &origin);
|
|
SetWindowOrgEx(cachedDc.dc, -origin.x, -origin.y, nullptr);
|
|
|
|
HRGN clipRgn = CreateRectRgn(0, 0, 0, 0);
|
|
GetRandomRgn(origDc, clipRgn, SYSRGN);
|
|
SelectClipRgn(cachedDc.dc, clipRgn);
|
|
RECT r = {};
|
|
GetRgnBox(clipRgn, &r);
|
|
DeleteObject(clipRgn);
|
|
|
|
ExcludeClipRectsData excludeClipRectsData = { cachedDc.dc, origin, GetAncestor(hwnd, GA_ROOT) };
|
|
EnumThreadWindows(GetCurrentThreadId(), &excludeClipRectsForOverlappingWindows,
|
|
reinterpret_cast<LPARAM>(&excludeClipRectsData));
|
|
}
|
|
|
|
return cachedDc;
|
|
}
|
|
|
|
void releaseDc(const CachedDc& cachedDc)
|
|
{
|
|
CompatGdiDcCache::releaseDc(cachedDc);
|
|
}
|
|
}
|