mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Revamping GDI interworking - Part 2
Extended GDI redirection to most of the GDI rendering methods. Readded handling of window messages and extended it to support scrolling. Readded manual drawing of the caret. Simplified the DC cache.
This commit is contained in:
parent
5a30b072ba
commit
1999d1c56e
@ -66,10 +66,6 @@ HRESULT STDMETHODCALLTYPE CompatDirectDraw<TDirectDraw>::CreateSurface(
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
CompatDirectDrawSurface<TSurface>::fixSurfacePtrs(**lplpDDSurface);
|
||||
if (isPrimary)
|
||||
{
|
||||
CompatDirectDrawSurface<TSurface>::updateSurfaceParams();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -477,7 +477,6 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Flip(
|
||||
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||
{
|
||||
result = RealPrimarySurface::flip(dwFlags);
|
||||
updateSurfaceParams();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -603,8 +602,7 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Restore(TSurface* T
|
||||
result = RealPrimarySurface::restore();
|
||||
if (wasLost)
|
||||
{
|
||||
CompatGdi::releaseSurfaceMemory();
|
||||
updateSurfaceParams();
|
||||
CompatGdi::invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -682,20 +680,6 @@ void CompatDirectDrawSurface<TSurface>::restorePrimaryCaps(TDdsCaps& caps)
|
||||
caps.dwCaps |= DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
void CompatDirectDrawSurface<TSurface>::updateSurfaceParams()
|
||||
{
|
||||
TSurfaceDesc desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
g_lockingPrimary = true;
|
||||
if (SUCCEEDED(s_origVtable.Lock(s_compatPrimarySurface, nullptr, &desc, DDLOCK_WAIT, nullptr)))
|
||||
{
|
||||
s_origVtable.Unlock(s_compatPrimarySurface, nullptr);
|
||||
CompatGdi::setSurfaceMemory(desc.lpSurface, desc.lPitch);
|
||||
}
|
||||
g_lockingPrimary = false;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
TSurface* CompatDirectDrawSurface<TSurface>::s_compatPrimarySurface = nullptr;
|
||||
|
||||
|
@ -23,7 +23,6 @@ public:
|
||||
static void fixSurfacePtrs(TSurface& surface);
|
||||
static void initPrimarySurfacePtr(const GUID& guid, IUnknown& surface);
|
||||
static void resetPrimarySurfacePtr();
|
||||
static void updateSurfaceParams();
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE Blt(
|
||||
TSurface* This,
|
||||
|
@ -1,14 +1,72 @@
|
||||
#include "CompatDirectDrawSurface.h"
|
||||
#include "CompatGdi.h"
|
||||
#include "CompatGdiCaret.h"
|
||||
#include "CompatGdiDcCache.h"
|
||||
#include "CompatGdiFunctions.h"
|
||||
#include "CompatGdiWinProc.h"
|
||||
#include "CompatPrimarySurface.h"
|
||||
#include "DDrawProcs.h"
|
||||
#include "RealPrimarySurface.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
CRITICAL_SECTION g_gdiCriticalSection;
|
||||
DWORD g_renderingDepth = 0;
|
||||
|
||||
FARPROC getProcAddress(HMODULE module, const char* procName)
|
||||
{
|
||||
if (!module || !procName)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PIMAGE_DOS_HEADER dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(module);
|
||||
if (IMAGE_DOS_SIGNATURE != dosHeader->e_magic) {
|
||||
return nullptr;
|
||||
}
|
||||
char* moduleBase = reinterpret_cast<char*>(module);
|
||||
|
||||
PIMAGE_NT_HEADERS ntHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(
|
||||
reinterpret_cast<char*>(dosHeader) + dosHeader->e_lfanew);
|
||||
if (IMAGE_NT_SIGNATURE != ntHeader->Signature)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PIMAGE_EXPORT_DIRECTORY exportDir = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
|
||||
moduleBase + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
|
||||
|
||||
DWORD* rvaOfNames = reinterpret_cast<DWORD*>(moduleBase + exportDir->AddressOfNames);
|
||||
|
||||
for (DWORD i = 0; i < exportDir->NumberOfNames; ++i)
|
||||
{
|
||||
if (0 == strcmp(procName, moduleBase + rvaOfNames[i]))
|
||||
{
|
||||
WORD* nameOrds = reinterpret_cast<WORD*>(moduleBase + exportDir->AddressOfNameOrdinals);
|
||||
DWORD* rvaOfFunctions = reinterpret_cast<DWORD*>(moduleBase + exportDir->AddressOfFunctions);
|
||||
return reinterpret_cast<FARPROC>(moduleBase + rvaOfFunctions[nameOrds[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BOOL CALLBACK invalidateWindow(HWND hwnd, LPARAM /*lParam*/)
|
||||
{
|
||||
DWORD processId = 0;
|
||||
GetWindowThreadProcessId(hwnd, &processId);
|
||||
if (processId == GetCurrentProcessId())
|
||||
{
|
||||
RedrawWindow(hwnd, nullptr, nullptr, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
namespace CompatGdi
|
||||
{
|
||||
CRITICAL_SECTION g_gdiCriticalSection;
|
||||
std::unordered_map<void*, const char*> g_funcNames;
|
||||
|
||||
GdiScopedThreadLock::GdiScopedThreadLock()
|
||||
{
|
||||
EnterCriticalSection(&g_gdiCriticalSection);
|
||||
@ -19,29 +77,89 @@ namespace CompatGdi
|
||||
LeaveCriticalSection(&g_gdiCriticalSection);
|
||||
}
|
||||
|
||||
bool beginGdiRendering()
|
||||
{
|
||||
if (!RealPrimarySurface::isFullScreen())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
EnterCriticalSection(&g_gdiCriticalSection);
|
||||
|
||||
if (0 == g_renderingDepth)
|
||||
{
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
if (FAILED(CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Lock(
|
||||
CompatPrimarySurface::surface, nullptr, &desc, DDLOCK_WAIT, nullptr)))
|
||||
{
|
||||
LeaveCriticalSection(&g_gdiCriticalSection);
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
return false;
|
||||
}
|
||||
CompatGdiDcCache::setSurfaceMemory(desc.lpSurface, desc.lPitch);
|
||||
}
|
||||
|
||||
++g_renderingDepth;
|
||||
return true;
|
||||
}
|
||||
|
||||
void endGdiRendering()
|
||||
{
|
||||
--g_renderingDepth;
|
||||
if (0 == g_renderingDepth)
|
||||
{
|
||||
GdiFlush();
|
||||
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Unlock(
|
||||
CompatPrimarySurface::surface, nullptr);
|
||||
RealPrimarySurface::update();
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&g_gdiCriticalSection);
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
}
|
||||
|
||||
void hookGdiFunction(const char* moduleName, const char* funcName, void*& origFuncPtr, void* newFuncPtr)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
g_funcNames[origFuncPtr] = funcName;
|
||||
#endif
|
||||
|
||||
FARPROC procAddr = getProcAddress(GetModuleHandle(moduleName), funcName);
|
||||
if (!procAddr)
|
||||
{
|
||||
Compat::Log() << "Failed to load the address of a GDI function: " << funcName;
|
||||
return;
|
||||
}
|
||||
|
||||
origFuncPtr = procAddr;
|
||||
if (NO_ERROR != DetourAttach(&origFuncPtr, newFuncPtr))
|
||||
{
|
||||
Compat::Log() << "Failed to hook a GDI function: " << funcName;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void installHooks()
|
||||
{
|
||||
InitializeCriticalSection(&g_gdiCriticalSection);
|
||||
if (CompatGdiDcCache::init())
|
||||
{
|
||||
CompatGdiFunctions::hookGdiFunctions();
|
||||
CompatGdiFunctions::installHooks();
|
||||
CompatGdiWinProc::installHooks();
|
||||
CompatGdiCaret::installHooks();
|
||||
}
|
||||
}
|
||||
|
||||
void releaseSurfaceMemory()
|
||||
void invalidate()
|
||||
{
|
||||
GdiScopedThreadLock gdiLock;
|
||||
CompatGdiDcCache::release();
|
||||
EnumWindows(&invalidateWindow, 0);
|
||||
}
|
||||
|
||||
void setSurfaceMemory(void* surfaceMemory, int pitch)
|
||||
void updatePalette()
|
||||
{
|
||||
GdiScopedThreadLock gdiLock;
|
||||
const bool wasReleased = CompatGdiDcCache::isReleased();
|
||||
CompatGdiDcCache::setSurfaceMemory(surfaceMemory, pitch);
|
||||
if (wasReleased)
|
||||
{
|
||||
InvalidateRect(nullptr, nullptr, TRUE);
|
||||
}
|
||||
CompatGdiDcCache::clear();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "DDrawLog.h"
|
||||
|
||||
#define CALL_ORIG_GDI(func) CompatGdi::getOrigFuncPtr<decltype(&func), &func>()
|
||||
|
||||
namespace CompatGdi
|
||||
{
|
||||
class GdiScopedThreadLock
|
||||
@ -9,7 +19,29 @@ namespace CompatGdi
|
||||
~GdiScopedThreadLock();
|
||||
};
|
||||
|
||||
extern CRITICAL_SECTION g_gdiCriticalSection;
|
||||
extern std::unordered_map<void*, const char*> g_funcNames;
|
||||
|
||||
bool beginGdiRendering();
|
||||
void endGdiRendering();
|
||||
|
||||
template <typename OrigFuncPtr, OrigFuncPtr origFunc>
|
||||
OrigFuncPtr& getOrigFuncPtr()
|
||||
{
|
||||
static OrigFuncPtr origFuncPtr = origFunc;
|
||||
return origFuncPtr;
|
||||
}
|
||||
|
||||
void hookGdiFunction(const char* moduleName, const char* funcName, void*& origFuncPtr, void* newFuncPtr);
|
||||
|
||||
template <typename OrigFuncPtr, OrigFuncPtr origFunc>
|
||||
void hookGdiFunction(const char* moduleName, const char* funcName, OrigFuncPtr newFuncPtr)
|
||||
{
|
||||
hookGdiFunction(moduleName, funcName,
|
||||
reinterpret_cast<void*&>(getOrigFuncPtr<OrigFuncPtr, origFunc>()), newFuncPtr);
|
||||
}
|
||||
|
||||
void installHooks();
|
||||
void releaseSurfaceMemory();
|
||||
void setSurfaceMemory(void* surfaceMemory, int pitch);
|
||||
void invalidate();
|
||||
void updatePalette();
|
||||
};
|
||||
|
160
DDrawCompat/CompatGdiCaret.cpp
Normal file
160
DDrawCompat/CompatGdiCaret.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
#define CINTERFACE
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <oleacc.h>
|
||||
#include <Windows.h>
|
||||
#include <detours.h>
|
||||
|
||||
#include "CompatGdi.h"
|
||||
#include "CompatGdiCaret.h"
|
||||
#include "CompatGdiDc.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct CaretData
|
||||
{
|
||||
HWND hwnd;
|
||||
long left;
|
||||
long top;
|
||||
long width;
|
||||
long height;
|
||||
bool isDrawn;
|
||||
};
|
||||
|
||||
CaretData g_caret = {};
|
||||
|
||||
void drawCaret()
|
||||
{
|
||||
if (CompatGdi::beginGdiRendering())
|
||||
{
|
||||
HDC dc = GetDC(g_caret.hwnd);
|
||||
HDC compatDc = CompatGdiDc::getDc(dc);
|
||||
PatBlt(compatDc, g_caret.left, g_caret.top, g_caret.width, g_caret.height, PATINVERT);
|
||||
CompatGdiDc::releaseDc(dc);
|
||||
ReleaseDC(g_caret.hwnd, dc);
|
||||
CompatGdi::endGdiRendering();
|
||||
}
|
||||
}
|
||||
|
||||
LONG getCaretState(IAccessible* accessible)
|
||||
{
|
||||
VARIANT varChild = {};
|
||||
varChild.vt = VT_I4;
|
||||
varChild.lVal = CHILDID_SELF;
|
||||
VARIANT varState = {};
|
||||
accessible->lpVtbl->get_accState(accessible, varChild, &varState);
|
||||
return varState.lVal;
|
||||
}
|
||||
|
||||
void CALLBACK caretDestroyEvent(
|
||||
HWINEVENTHOOK /*hWinEventHook*/,
|
||||
DWORD /*event*/,
|
||||
HWND hwnd,
|
||||
LONG idObject,
|
||||
LONG idChild,
|
||||
DWORD /*dwEventThread*/,
|
||||
DWORD /*dwmsEventTime*/)
|
||||
{
|
||||
CompatGdi::GdiScopedThreadLock gdiLock;
|
||||
if (OBJID_CARET != idObject || !g_caret.isDrawn || g_caret.hwnd != hwnd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IAccessible* accessible = nullptr;
|
||||
VARIANT varChild = {};
|
||||
AccessibleObjectFromEvent(hwnd, idObject, idChild, &accessible, &varChild);
|
||||
if (accessible)
|
||||
{
|
||||
if (STATE_SYSTEM_INVISIBLE == getCaretState(accessible))
|
||||
{
|
||||
drawCaret();
|
||||
g_caret.isDrawn = false;
|
||||
}
|
||||
accessible->lpVtbl->Release(accessible);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL WINAPI createCaret(HWND hWnd, HBITMAP hBitmap, int nWidth, int nHeight)
|
||||
{
|
||||
BOOL result = CALL_ORIG_GDI(CreateCaret)(hWnd, hBitmap, nWidth, nHeight);
|
||||
if (result)
|
||||
{
|
||||
CompatGdi::GdiScopedThreadLock gdiLock;
|
||||
if (g_caret.isDrawn)
|
||||
{
|
||||
drawCaret();
|
||||
g_caret.isDrawn = false;
|
||||
}
|
||||
g_caret.width = nWidth ? nWidth : GetSystemMetrics(SM_CXBORDER);
|
||||
g_caret.height = nHeight ? nHeight : GetSystemMetrics(SM_CYBORDER);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL WINAPI showCaret(HWND hWnd)
|
||||
{
|
||||
if (!CALL_ORIG_GDI(ShowCaret)(hWnd))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CompatGdi::GdiScopedThreadLock gdiLock;
|
||||
if (!g_caret.isDrawn)
|
||||
{
|
||||
IAccessible* accessible = nullptr;
|
||||
AccessibleObjectFromWindow(hWnd, static_cast<DWORD>(OBJID_CARET), IID_IAccessible,
|
||||
reinterpret_cast<void**>(&accessible));
|
||||
if (accessible)
|
||||
{
|
||||
if (0 == getCaretState(accessible))
|
||||
{
|
||||
POINT caretPos = {};
|
||||
GetCaretPos(&caretPos);
|
||||
g_caret.left = caretPos.x;
|
||||
g_caret.top = caretPos.y;
|
||||
g_caret.hwnd = hWnd;
|
||||
drawCaret();
|
||||
g_caret.isDrawn = true;
|
||||
}
|
||||
accessible->lpVtbl->Release(accessible);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WINAPI hideCaret(HWND hWnd)
|
||||
{
|
||||
BOOL result = CALL_ORIG_GDI(HideCaret)(hWnd);
|
||||
if (result)
|
||||
{
|
||||
CompatGdi::GdiScopedThreadLock gdiLock;
|
||||
if (g_caret.isDrawn)
|
||||
{
|
||||
drawCaret();
|
||||
g_caret.isDrawn = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
#define HOOK_GDI_FUNCTION(module, func, newFunc) \
|
||||
CompatGdi::hookGdiFunction<decltype(&func), &func>(#module, #func, &newFunc);
|
||||
|
||||
namespace CompatGdiCaret
|
||||
{
|
||||
void installHooks()
|
||||
{
|
||||
DetourTransactionBegin();
|
||||
HOOK_GDI_FUNCTION(user32, CreateCaret, createCaret);
|
||||
HOOK_GDI_FUNCTION(user32, ShowCaret, showCaret);
|
||||
HOOK_GDI_FUNCTION(user32, HideCaret, hideCaret);
|
||||
DetourTransactionCommit();
|
||||
|
||||
const DWORD threadId = GetCurrentThreadId();
|
||||
SetWinEventHook(EVENT_OBJECT_DESTROY, EVENT_OBJECT_DESTROY,
|
||||
nullptr, &caretDestroyEvent, 0, threadId, WINEVENT_OUTOFCONTEXT);
|
||||
}
|
||||
}
|
@ -1,9 +1,27 @@
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "CompatGdiDc.h"
|
||||
#include "CompatGdiDcCache.h"
|
||||
#include "RealPrimarySurface.h"
|
||||
#include "DDrawLog.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
using CompatGdiDcCache::CachedDc;
|
||||
|
||||
struct CompatDc : CachedDc
|
||||
{
|
||||
CompatDc(const CachedDc& cachedDc = {}) : CachedDc(cachedDc) {}
|
||||
DWORD refCount;
|
||||
HDC origDc;
|
||||
HGDIOBJ origFont;
|
||||
HGDIOBJ origBrush;
|
||||
HGDIOBJ origPen;
|
||||
};
|
||||
|
||||
typedef std::unordered_map<HDC, CompatDc> CompatDcMap;
|
||||
CompatDcMap g_origDcToCompatDc;
|
||||
|
||||
struct ExcludeClipRectsData
|
||||
{
|
||||
HDC compatDc;
|
||||
@ -11,6 +29,35 @@ namespace
|
||||
HWND rootWnd;
|
||||
};
|
||||
|
||||
void copyDcAttributes(CompatDc& compatDc, HDC origDc, POINT& origin)
|
||||
{
|
||||
compatDc.origFont = SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_FONT));
|
||||
compatDc.origBrush = SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_BRUSH));
|
||||
compatDc.origPen = SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_PEN));
|
||||
|
||||
SetArcDirection(compatDc.dc, GetArcDirection(origDc));
|
||||
SetBkColor(compatDc.dc, GetBkColor(origDc));
|
||||
SetBkMode(compatDc.dc, GetBkMode(origDc));
|
||||
SetDCBrushColor(compatDc.dc, GetDCBrushColor(origDc));
|
||||
SetDCPenColor(compatDc.dc, GetDCPenColor(origDc));
|
||||
SetPolyFillMode(compatDc.dc, GetPolyFillMode(origDc));
|
||||
SetROP2(compatDc.dc, GetROP2(origDc));
|
||||
SetStretchBltMode(compatDc.dc, GetStretchBltMode(origDc));
|
||||
SetTextAlign(compatDc.dc, GetTextAlign(origDc));
|
||||
SetTextCharacterExtra(compatDc.dc, GetTextCharacterExtra(origDc));
|
||||
SetTextColor(compatDc.dc, GetTextColor(origDc));
|
||||
SetWindowOrgEx(compatDc.dc, -origin.x, -origin.y, nullptr);
|
||||
|
||||
POINT brushOrg = {};
|
||||
GetBrushOrgEx(origDc, &brushOrg);
|
||||
SetBrushOrgEx(compatDc.dc, brushOrg.x, brushOrg.y, nullptr);
|
||||
|
||||
POINT currentPos = {};
|
||||
MoveToEx(origDc, 0, 0, ¤tPos);
|
||||
MoveToEx(origDc, currentPos.x, currentPos.y, nullptr);
|
||||
MoveToEx(compatDc.dc, currentPos.x, currentPos.y, nullptr);
|
||||
}
|
||||
|
||||
BOOL CALLBACK excludeClipRectsForOverlappingWindows(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
auto excludeClipRectsData = reinterpret_cast<ExcludeClipRectsData*>(lParam);
|
||||
@ -19,56 +66,102 @@ namespace
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!IsWindowVisible(hwnd))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void setClippingRegion(HDC compatDc, HDC origDc, POINT& origin)
|
||||
{
|
||||
HRGN clipRgn = CreateRectRgn(0, 0, 0, 0);
|
||||
const bool isEmptyClipRgn = 1 != GetRandomRgn(origDc, clipRgn, SYSRGN);
|
||||
SelectClipRgn(compatDc, isEmptyClipRgn ? nullptr : clipRgn);
|
||||
DeleteObject(clipRgn);
|
||||
|
||||
HRGN origClipRgn = CreateRectRgn(0, 0, 0, 0);
|
||||
if (1 == GetClipRgn(origDc, origClipRgn))
|
||||
{
|
||||
OffsetRgn(origClipRgn, origin.x, origin.y);
|
||||
ExtSelectClipRgn(compatDc, origClipRgn, RGN_AND);
|
||||
}
|
||||
DeleteObject(origClipRgn);
|
||||
|
||||
if (!isEmptyClipRgn)
|
||||
{
|
||||
HWND hwnd = WindowFromDC(origDc);
|
||||
if (hwnd)
|
||||
{
|
||||
ExcludeClipRectsData excludeClipRectsData = { compatDc, origin, GetAncestor(hwnd, GA_ROOT) };
|
||||
EnumThreadWindows(GetCurrentThreadId(), &excludeClipRectsForOverlappingWindows,
|
||||
reinterpret_cast<LPARAM>(&excludeClipRectsData));
|
||||
RECT windowRect = {};
|
||||
GetWindowRect(hwnd, &windowRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace CompatGdiDc
|
||||
{
|
||||
CachedDc getDc(HDC origDc)
|
||||
HDC getDc(HDC origDc)
|
||||
{
|
||||
CachedDc cachedDc = {};
|
||||
if (!origDc || !RealPrimarySurface::isFullScreen() ||
|
||||
OBJ_DC != GetObjectType(origDc) ||
|
||||
DT_RASDISPLAY != GetDeviceCaps(origDc, TECHNOLOGY))
|
||||
if (!origDc || OBJ_DC != GetObjectType(origDc) || DT_RASDISPLAY != GetDeviceCaps(origDc, TECHNOLOGY) ||
|
||||
g_origDcToCompatDc.end() != std::find_if(g_origDcToCompatDc.begin(), g_origDcToCompatDc.end(),
|
||||
[=](const CompatDcMap::value_type& compatDc) { return compatDc.second.dc == origDc; }))
|
||||
{
|
||||
return cachedDc;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cachedDc = CompatGdiDcCache::getDc();
|
||||
if (!cachedDc.dc)
|
||||
auto it = g_origDcToCompatDc.find(origDc);
|
||||
if (it != g_origDcToCompatDc.end())
|
||||
{
|
||||
return cachedDc;
|
||||
++it->second.refCount;
|
||||
return it->second.dc;
|
||||
}
|
||||
|
||||
HWND hwnd = WindowFromDC(origDc);
|
||||
if (hwnd)
|
||||
CompatDc compatDc(CompatGdiDcCache::getDc());
|
||||
if (!compatDc.dc)
|
||||
{
|
||||
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 nullptr;
|
||||
}
|
||||
|
||||
return cachedDc;
|
||||
POINT origin = {};
|
||||
GetDCOrgEx(origDc, &origin);
|
||||
|
||||
copyDcAttributes(compatDc, origDc, origin);
|
||||
setClippingRegion(compatDc.dc, origDc, origin);
|
||||
|
||||
compatDc.refCount = 1;
|
||||
compatDc.origDc = origDc;
|
||||
g_origDcToCompatDc.insert(CompatDcMap::value_type(origDc, compatDc));
|
||||
|
||||
return compatDc.dc;
|
||||
}
|
||||
|
||||
void releaseDc(const CachedDc& cachedDc)
|
||||
void releaseDc(HDC origDc)
|
||||
{
|
||||
CompatGdiDcCache::releaseDc(cachedDc);
|
||||
auto it = g_origDcToCompatDc.find(origDc);
|
||||
if (it == g_origDcToCompatDc.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CompatDc& compatDc = it->second;
|
||||
--compatDc.refCount;
|
||||
if (0 == compatDc.refCount)
|
||||
{
|
||||
SelectObject(compatDc.dc, compatDc.origFont);
|
||||
SelectObject(compatDc.dc, compatDc.origBrush);
|
||||
SelectObject(compatDc.dc, compatDc.origPen);
|
||||
CompatGdiDcCache::releaseDc(compatDc);
|
||||
g_origDcToCompatDc.erase(origDc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,8 @@
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "CompatGdiDcCache.h"
|
||||
|
||||
namespace CompatGdiDc
|
||||
{
|
||||
using CompatGdiDcCache::CachedDc;
|
||||
|
||||
CachedDc getDc(HDC origDc);
|
||||
void releaseDc(const CachedDc& cachedDc);
|
||||
HDC getDc(HDC origDc);
|
||||
void releaseDc(HDC origDc);
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "CompatDirectDraw.h"
|
||||
@ -8,41 +7,18 @@
|
||||
#include "Config.h"
|
||||
#include "DDrawLog.h"
|
||||
#include "DDrawProcs.h"
|
||||
#include "DDrawScopedThreadLock.h"
|
||||
|
||||
namespace CompatGdiDcCache
|
||||
{
|
||||
bool operator<(const SurfaceMemoryDesc& desc1, const SurfaceMemoryDesc& desc2)
|
||||
{
|
||||
return desc1.surfaceMemory < desc2.surfaceMemory ||
|
||||
(desc1.surfaceMemory == desc2.surfaceMemory && desc1.pitch < desc2.pitch);
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
using CompatGdiDcCache::SurfaceMemoryDesc;
|
||||
using CompatGdiDcCache::CachedDc;
|
||||
|
||||
std::map<SurfaceMemoryDesc, std::vector<CachedDc>> g_caches;
|
||||
std::vector<CachedDc>* g_currentCache = nullptr;
|
||||
std::vector<CachedDc> g_cache;
|
||||
|
||||
IDirectDraw7* g_directDraw = nullptr;
|
||||
void* g_surfaceMemory = nullptr;
|
||||
LONG g_pitch = 0;
|
||||
|
||||
IDirectDrawSurface7* createGdiSurface();
|
||||
void releaseCachedDc(CachedDc cachedDc);
|
||||
void releaseCache(std::vector<CachedDc>& cache);
|
||||
|
||||
void clearAllCaches()
|
||||
{
|
||||
for (auto& cache : g_caches)
|
||||
{
|
||||
releaseCache(cache.second);
|
||||
}
|
||||
g_caches.clear();
|
||||
}
|
||||
|
||||
IDirectDraw7* createDirectDraw()
|
||||
{
|
||||
@ -86,17 +62,13 @@ namespace
|
||||
// Release DD critical section acquired by IDirectDrawSurface7::GetDC to avoid deadlocks
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
|
||||
cachedDc.surfaceMemoryDesc.surfaceMemory = g_surfaceMemory;
|
||||
cachedDc.surfaceMemoryDesc.pitch = g_pitch;
|
||||
cachedDc.dc = dc;
|
||||
cachedDc.surface = surface;
|
||||
cachedDc.dc = dc;
|
||||
return cachedDc;
|
||||
}
|
||||
|
||||
IDirectDrawSurface7* createGdiSurface()
|
||||
{
|
||||
Compat::DDrawScopedThreadLock ddLock;
|
||||
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH | DDSD_LPSURFACE;
|
||||
@ -125,66 +97,49 @@ namespace
|
||||
return surface;
|
||||
}
|
||||
|
||||
void fillCurrentCache()
|
||||
{
|
||||
for (DWORD i = 0; i < Config::gdiDcCacheSize; ++i)
|
||||
{
|
||||
CachedDc cachedDc = createCachedDc();
|
||||
if (!cachedDc.dc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
g_currentCache->push_back(cachedDc);
|
||||
}
|
||||
}
|
||||
|
||||
void releaseCachedDc(CachedDc cachedDc)
|
||||
{
|
||||
// Reacquire DD critical section that was temporarily released after IDirectDrawSurface7::GetDC
|
||||
Compat::origProcs.AcquireDDThreadLock();
|
||||
|
||||
if (FAILED(CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.ReleaseDC(
|
||||
cachedDc.surface, cachedDc.dc)))
|
||||
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.ReleaseDC(
|
||||
cachedDc.surface, cachedDc.dc);
|
||||
if (FAILED(result))
|
||||
{
|
||||
LOG_ONCE("Failed to release a cached DC");
|
||||
Compat::origProcs.ReleaseDDThreadLock();
|
||||
LOG_ONCE("Failed to release a cached DC: " << result);
|
||||
}
|
||||
|
||||
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Release(cachedDc.surface);
|
||||
}
|
||||
|
||||
void releaseCache(std::vector<CachedDc>& cache)
|
||||
{
|
||||
for (auto& cachedDc : cache)
|
||||
{
|
||||
releaseCachedDc(cachedDc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace CompatGdiDcCache
|
||||
{
|
||||
void clear()
|
||||
{
|
||||
for (auto& cachedDc : g_cache)
|
||||
{
|
||||
releaseCachedDc(cachedDc);
|
||||
}
|
||||
g_cache.clear();
|
||||
}
|
||||
|
||||
CachedDc getDc()
|
||||
{
|
||||
CachedDc cachedDc = {};
|
||||
if (!g_currentCache)
|
||||
if (!g_surfaceMemory)
|
||||
{
|
||||
return cachedDc;
|
||||
}
|
||||
|
||||
if (g_currentCache->empty())
|
||||
if (g_cache.empty())
|
||||
{
|
||||
LOG_ONCE("Warning: GDI DC cache size is insufficient");
|
||||
cachedDc = createCachedDc();
|
||||
if (!cachedDc.dc)
|
||||
{
|
||||
return cachedDc;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cachedDc = g_currentCache->back();
|
||||
g_currentCache->pop_back();
|
||||
cachedDc = g_cache.back();
|
||||
g_cache.pop_back();
|
||||
}
|
||||
|
||||
return cachedDc;
|
||||
@ -196,46 +151,20 @@ namespace CompatGdiDcCache
|
||||
return nullptr != g_directDraw;
|
||||
}
|
||||
|
||||
bool isReleased()
|
||||
{
|
||||
return g_caches.empty();
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
if (g_currentCache)
|
||||
{
|
||||
g_currentCache = nullptr;
|
||||
clearAllCaches();
|
||||
}
|
||||
}
|
||||
|
||||
void releaseDc(const CachedDc& cachedDc)
|
||||
{
|
||||
g_caches[cachedDc.surfaceMemoryDesc].push_back(cachedDc);
|
||||
g_cache.push_back(cachedDc);
|
||||
}
|
||||
|
||||
void setSurfaceMemory(void* surfaceMemory, LONG pitch)
|
||||
{
|
||||
g_surfaceMemory = surfaceMemory;
|
||||
g_pitch = pitch;
|
||||
|
||||
if (!surfaceMemory)
|
||||
if (g_surfaceMemory == surfaceMemory && g_pitch == pitch)
|
||||
{
|
||||
g_currentCache = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
SurfaceMemoryDesc surfaceMemoryDesc = { surfaceMemory, pitch };
|
||||
auto it = g_caches.find(surfaceMemoryDesc);
|
||||
if (it == g_caches.end())
|
||||
{
|
||||
g_currentCache = &g_caches[surfaceMemoryDesc];
|
||||
fillCurrentCache();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_currentCache = &it->second;
|
||||
}
|
||||
g_surfaceMemory = surfaceMemory;
|
||||
g_pitch = pitch;
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
@ -8,23 +8,15 @@
|
||||
|
||||
namespace CompatGdiDcCache
|
||||
{
|
||||
struct SurfaceMemoryDesc
|
||||
{
|
||||
void* surfaceMemory;
|
||||
LONG pitch;
|
||||
};
|
||||
|
||||
struct CachedDc
|
||||
{
|
||||
SurfaceMemoryDesc surfaceMemoryDesc;
|
||||
IDirectDrawSurface7* surface;
|
||||
HDC dc;
|
||||
};
|
||||
|
||||
void clear();
|
||||
CachedDc getDc();
|
||||
bool init();
|
||||
bool isReleased();
|
||||
void release();
|
||||
void releaseDc(const CachedDc& cachedDc);
|
||||
void setSurfaceMemory(void* surfaceMemory, LONG pitch);
|
||||
}
|
||||
|
@ -1,42 +1,30 @@
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "CompatDirectDrawSurface.h"
|
||||
#include "CompatGdi.h"
|
||||
#include "CompatGdiDc.h"
|
||||
#include "CompatGdiFunctions.h"
|
||||
#include "CompatPrimarySurface.h"
|
||||
#include "DDrawLog.h"
|
||||
#include "DDrawScopedThreadLock.h"
|
||||
#include "RealPrimarySurface.h"
|
||||
|
||||
#include <detours.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
using CompatGdiDc::CachedDc;
|
||||
|
||||
struct CompatDc : CachedDc
|
||||
{
|
||||
CompatDc(const CachedDc& cachedDc) : CachedDc(cachedDc) {}
|
||||
HGDIOBJ origFont;
|
||||
HGDIOBJ origBrush;
|
||||
HGDIOBJ origPen;
|
||||
};
|
||||
|
||||
std::unordered_map<void*, const char*> g_funcNames;
|
||||
std::vector<CompatDc> g_usedCompatDcs;
|
||||
DWORD* g_usedCompatDcCount = nullptr;
|
||||
|
||||
template <typename Result, typename... Params>
|
||||
using FuncPtr = Result(WINAPI *)(Params...);
|
||||
|
||||
template <typename OrigFuncPtr, OrigFuncPtr origFunc>
|
||||
OrigFuncPtr& getOrigFuncPtr()
|
||||
bool hasDisplayDcArg(HDC dc)
|
||||
{
|
||||
static OrigFuncPtr origFuncPtr = origFunc;
|
||||
return origFuncPtr;
|
||||
return dc && OBJ_DC == GetObjectType(dc) && DT_RASDISPLAY == GetDeviceCaps(dc, TECHNOLOGY);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool hasDisplayDcArg(T)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T, typename... Params>
|
||||
bool hasDisplayDcArg(T t, Params... params)
|
||||
{
|
||||
return hasDisplayDcArg(t) || hasDisplayDcArg(params...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -47,140 +35,147 @@ namespace
|
||||
|
||||
HDC replaceDc(HDC dc)
|
||||
{
|
||||
auto it = std::find_if(g_usedCompatDcs.begin(), g_usedCompatDcs.end(),
|
||||
[dc](const CompatDc& compatDc) { return compatDc.dc == dc; });
|
||||
if (it != g_usedCompatDcs.end())
|
||||
{
|
||||
return it->dc;
|
||||
}
|
||||
HDC compatDc = CompatGdiDc::getDc(dc);
|
||||
return compatDc ? compatDc : dc;
|
||||
}
|
||||
|
||||
CompatDc compatDc = CompatGdiDc::getDc(dc);
|
||||
if (!compatDc.dc)
|
||||
{
|
||||
return dc;
|
||||
}
|
||||
template <typename T>
|
||||
void releaseDc(T) {}
|
||||
|
||||
compatDc.origFont = SelectObject(compatDc.dc, GetCurrentObject(dc, OBJ_FONT));
|
||||
compatDc.origBrush = SelectObject(compatDc.dc, GetCurrentObject(dc, OBJ_BRUSH));
|
||||
compatDc.origPen = SelectObject(compatDc.dc, GetCurrentObject(dc, OBJ_PEN));
|
||||
SetTextColor(compatDc.dc, GetTextColor(dc));
|
||||
SetBkColor(compatDc.dc, GetBkColor(dc));
|
||||
SetBkMode(compatDc.dc, GetBkMode(dc));
|
||||
void releaseDc(HDC dc)
|
||||
{
|
||||
CompatGdiDc::releaseDc(dc);
|
||||
}
|
||||
|
||||
g_usedCompatDcs.push_back(compatDc);
|
||||
++*g_usedCompatDcCount;
|
||||
return compatDc.dc;
|
||||
template <typename T, typename... Params>
|
||||
void releaseDc(T t, Params... params)
|
||||
{
|
||||
releaseDc(params...);
|
||||
releaseDc(t);
|
||||
}
|
||||
|
||||
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
|
||||
Result WINAPI compatGdiFunc(Params... params)
|
||||
{
|
||||
CompatGdi::GdiScopedThreadLock gdiLock;
|
||||
Compat::DDrawScopedThreadLock ddLock;
|
||||
|
||||
DWORD usedCompatDcCount = 0;
|
||||
g_usedCompatDcCount = &usedCompatDcCount;
|
||||
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
if (FAILED(CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Lock(
|
||||
CompatPrimarySurface::surface, nullptr, &desc, DDLOCK_WAIT, nullptr)))
|
||||
if (!hasDisplayDcArg(params...) || !CompatGdi::beginGdiRendering())
|
||||
{
|
||||
return getOrigFuncPtr<OrigFuncPtr, origFunc>()(params...);
|
||||
return CompatGdi::getOrigFuncPtr<OrigFuncPtr, origFunc>()(params...);
|
||||
}
|
||||
|
||||
Result result = getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...);
|
||||
GdiFlush();
|
||||
#ifdef _DEBUG
|
||||
Compat::LogEnter(CompatGdi::g_funcNames[origFunc], params...);
|
||||
#endif
|
||||
|
||||
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Unlock(
|
||||
CompatPrimarySurface::surface, nullptr);
|
||||
Result result = CompatGdi::getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...);
|
||||
releaseDc(params...);
|
||||
CompatGdi::endGdiRendering();
|
||||
|
||||
if (0 != usedCompatDcCount)
|
||||
{
|
||||
RealPrimarySurface::update();
|
||||
}
|
||||
|
||||
for (DWORD i = 0; i < usedCompatDcCount; ++i)
|
||||
{
|
||||
CompatDc& compatDc = g_usedCompatDcs.back();
|
||||
SelectObject(compatDc.dc, compatDc.origFont);
|
||||
SelectObject(compatDc.dc, compatDc.origBrush);
|
||||
SelectObject(compatDc.dc, compatDc.origPen);
|
||||
|
||||
CompatGdiDc::releaseDc(compatDc);
|
||||
g_usedCompatDcs.pop_back();
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
Compat::LogLeave(CompatGdi::g_funcNames[origFunc], params...) << result;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
|
||||
OrigFuncPtr getCompatGdiFuncPtr(FuncPtr<Result, Params...>&)
|
||||
OrigFuncPtr getCompatGdiFuncPtr(FuncPtr<Result, Params...>)
|
||||
{
|
||||
return &compatGdiFunc<OrigFuncPtr, origFunc, Result, Params...>;
|
||||
}
|
||||
|
||||
FARPROC getProcAddress(HMODULE module, const char* procName)
|
||||
{
|
||||
if (!module || !procName)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PIMAGE_DOS_HEADER dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(module);
|
||||
if (IMAGE_DOS_SIGNATURE != dosHeader->e_magic) {
|
||||
return nullptr;
|
||||
}
|
||||
char* moduleBase = reinterpret_cast<char*>(module);
|
||||
|
||||
PIMAGE_NT_HEADERS ntHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(
|
||||
reinterpret_cast<char*>(dosHeader) + dosHeader->e_lfanew);
|
||||
if (IMAGE_NT_SIGNATURE != ntHeader->Signature)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PIMAGE_EXPORT_DIRECTORY exportDir = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
|
||||
moduleBase + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
|
||||
|
||||
DWORD* rvaOfNames = reinterpret_cast<DWORD*>(moduleBase + exportDir->AddressOfNames);
|
||||
|
||||
for (DWORD i = 0; i < exportDir->NumberOfNames; ++i)
|
||||
{
|
||||
if (0 == strcmp(procName, moduleBase + rvaOfNames[i]))
|
||||
{
|
||||
WORD* nameOrds = reinterpret_cast<WORD*>(moduleBase + exportDir->AddressOfNameOrdinals);
|
||||
DWORD* rvaOfFunctions = reinterpret_cast<DWORD*>(moduleBase + exportDir->AddressOfFunctions);
|
||||
return reinterpret_cast<FARPROC>(moduleBase + rvaOfFunctions[nameOrds[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename OrigFuncPtr, OrigFuncPtr origFunc>
|
||||
void hookGdiFunction(const char* moduleName, const char* funcName)
|
||||
{
|
||||
OrigFuncPtr& origFuncPtr = getOrigFuncPtr<OrigFuncPtr, origFunc>();
|
||||
origFuncPtr = reinterpret_cast<OrigFuncPtr>(getProcAddress(GetModuleHandle(moduleName), funcName));
|
||||
OrigFuncPtr newFuncPtr = getCompatGdiFuncPtr<OrigFuncPtr, origFunc>(origFuncPtr);
|
||||
DetourAttach(reinterpret_cast<void**>(&origFuncPtr), newFuncPtr);
|
||||
g_funcNames[origFunc] = funcName;
|
||||
}
|
||||
}
|
||||
|
||||
void CompatGdiFunctions::hookGdiFunctions()
|
||||
{
|
||||
#define HOOK_GDI_FUNCTION(module, func) hookGdiFunction<decltype(&func), &func>(#module, #func);
|
||||
#define HOOK_GDI_FUNCTION(module, func) \
|
||||
CompatGdi::hookGdiFunction<decltype(&func), &func>( \
|
||||
#module, #func, getCompatGdiFuncPtr<decltype(&func), &func>(&func));
|
||||
|
||||
#define HOOK_GDI_TEXT_FUNCTION(module, func) \
|
||||
HOOK_GDI_FUNCTION(module, func##A); \
|
||||
HOOK_GDI_FUNCTION(module, func##W)
|
||||
|
||||
DetourTransactionBegin();
|
||||
HOOK_GDI_FUNCTION(gdi32, BitBlt);
|
||||
DetourTransactionCommit();
|
||||
namespace CompatGdiFunctions
|
||||
{
|
||||
void installHooks()
|
||||
{
|
||||
DetourTransactionBegin();
|
||||
|
||||
#undef HOOK_GDI_TEXT_FUNCTION
|
||||
#undef HOOK_GDI_FUNCTION
|
||||
// Bitmap functions
|
||||
HOOK_GDI_FUNCTION(msimg32, AlphaBlend);
|
||||
HOOK_GDI_FUNCTION(gdi32, BitBlt);
|
||||
HOOK_GDI_FUNCTION(gdi32, CreateCompatibleBitmap);
|
||||
HOOK_GDI_FUNCTION(gdi32, CreateDIBitmap);
|
||||
HOOK_GDI_FUNCTION(gdi32, CreateDIBSection);
|
||||
HOOK_GDI_FUNCTION(gdi32, CreateDiscardableBitmap);
|
||||
HOOK_GDI_FUNCTION(gdi32, ExtFloodFill);
|
||||
HOOK_GDI_FUNCTION(gdi32, GetDIBits);
|
||||
HOOK_GDI_FUNCTION(gdi32, GetPixel);
|
||||
HOOK_GDI_FUNCTION(msimg32, GradientFill);
|
||||
HOOK_GDI_FUNCTION(gdi32, MaskBlt);
|
||||
HOOK_GDI_FUNCTION(gdi32, PlgBlt);
|
||||
HOOK_GDI_FUNCTION(gdi32, SetDIBits);
|
||||
HOOK_GDI_FUNCTION(gdi32, SetDIBitsToDevice);
|
||||
HOOK_GDI_FUNCTION(gdi32, SetPixel);
|
||||
HOOK_GDI_FUNCTION(gdi32, SetPixelV);
|
||||
HOOK_GDI_FUNCTION(gdi32, StretchBlt);
|
||||
HOOK_GDI_FUNCTION(gdi32, StretchDIBits);
|
||||
HOOK_GDI_FUNCTION(msimg32, TransparentBlt);
|
||||
|
||||
// Brush functions
|
||||
HOOK_GDI_FUNCTION(gdi32, PatBlt);
|
||||
|
||||
// Device context functions
|
||||
HOOK_GDI_FUNCTION(gdi32, CreateCompatibleDC);
|
||||
HOOK_GDI_FUNCTION(gdi32, DrawEscape);
|
||||
|
||||
// Filled shape functions
|
||||
HOOK_GDI_FUNCTION(gdi32, Chord);
|
||||
HOOK_GDI_FUNCTION(gdi32, Ellipse);
|
||||
HOOK_GDI_FUNCTION(user32, FillRect);
|
||||
HOOK_GDI_FUNCTION(user32, FrameRect);
|
||||
HOOK_GDI_FUNCTION(user32, InvertRect);
|
||||
HOOK_GDI_FUNCTION(gdi32, Pie);
|
||||
HOOK_GDI_FUNCTION(gdi32, Polygon);
|
||||
HOOK_GDI_FUNCTION(gdi32, PolyPolygon);
|
||||
HOOK_GDI_FUNCTION(gdi32, Rectangle);
|
||||
HOOK_GDI_FUNCTION(gdi32, RoundRect);
|
||||
|
||||
// Font and text functions
|
||||
HOOK_GDI_TEXT_FUNCTION(user32, DrawText);
|
||||
HOOK_GDI_TEXT_FUNCTION(user32, DrawTextEx);
|
||||
HOOK_GDI_TEXT_FUNCTION(gdi32, ExtTextOut);
|
||||
HOOK_GDI_TEXT_FUNCTION(gdi32, PolyTextOut);
|
||||
HOOK_GDI_TEXT_FUNCTION(user32, TabbedTextOut);
|
||||
HOOK_GDI_TEXT_FUNCTION(gdi32, TextOut);
|
||||
|
||||
// Line and curve functions
|
||||
HOOK_GDI_FUNCTION(gdi32, AngleArc);
|
||||
HOOK_GDI_FUNCTION(gdi32, Arc);
|
||||
HOOK_GDI_FUNCTION(gdi32, ArcTo);
|
||||
HOOK_GDI_FUNCTION(gdi32, LineTo);
|
||||
HOOK_GDI_FUNCTION(gdi32, PolyBezier);
|
||||
HOOK_GDI_FUNCTION(gdi32, PolyBezierTo);
|
||||
HOOK_GDI_FUNCTION(gdi32, PolyDraw);
|
||||
HOOK_GDI_FUNCTION(gdi32, Polyline);
|
||||
HOOK_GDI_FUNCTION(gdi32, PolylineTo);
|
||||
HOOK_GDI_FUNCTION(gdi32, PolyPolyline);
|
||||
|
||||
// Painting and drawing functions
|
||||
HOOK_GDI_FUNCTION(user32, DrawCaption);
|
||||
HOOK_GDI_FUNCTION(user32, DrawEdge);
|
||||
HOOK_GDI_FUNCTION(user32, DrawFocusRect);
|
||||
HOOK_GDI_FUNCTION(user32, DrawFrameControl);
|
||||
HOOK_GDI_TEXT_FUNCTION(user32, DrawState);
|
||||
HOOK_GDI_TEXT_FUNCTION(user32, GrayString);
|
||||
HOOK_GDI_FUNCTION(user32, PaintDesktop);
|
||||
|
||||
// Region functions
|
||||
HOOK_GDI_FUNCTION(gdi32, FillRgn);
|
||||
HOOK_GDI_FUNCTION(gdi32, FrameRgn);
|
||||
HOOK_GDI_FUNCTION(gdi32, InvertRgn);
|
||||
HOOK_GDI_FUNCTION(gdi32, PaintRgn);
|
||||
|
||||
// Scroll bar functions
|
||||
HOOK_GDI_FUNCTION(user32, ScrollDC);
|
||||
|
||||
DetourTransactionCommit();
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
class CompatGdiFunctions
|
||||
namespace CompatGdiFunctions
|
||||
{
|
||||
public:
|
||||
static void hookGdiFunctions();
|
||||
void installHooks();
|
||||
};
|
||||
|
@ -4,7 +4,6 @@ typedef unsigned long DWORD;
|
||||
|
||||
namespace Config
|
||||
{
|
||||
const DWORD gdiDcCacheSize = 10;
|
||||
const DWORD minRefreshInterval = 1000 / 60;
|
||||
const DWORD minRefreshIntervalAfterFlip = 1000 / 10;
|
||||
const DWORD minPaletteUpdateInterval = 1000 / 60;
|
||||
|
@ -94,7 +94,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>dxguid.lib;detours.lib;oleacc.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>dxguid.lib;detours.lib;msimg32.lib;oleacc.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@ -121,7 +121,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>dxguid.lib;detours.lib;oleacc.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>dxguid.lib;detours.lib;msimg32.lib;oleacc.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>No</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@ -146,9 +146,11 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CompatDirectDrawPalette.h" />
|
||||
<ClInclude Include="CompatGdi.h" />
|
||||
<ClInclude Include="CompatGdiCaret.h" />
|
||||
<ClInclude Include="CompatGdiDc.h" />
|
||||
<ClInclude Include="CompatGdiDcCache.h" />
|
||||
<ClInclude Include="CompatGdiFunctions.h" />
|
||||
<ClInclude Include="CompatGdiWinProc.h" />
|
||||
<ClInclude Include="Config.h" />
|
||||
<ClInclude Include="DDrawProcs.h" />
|
||||
<ClInclude Include="CompatDirectDraw.h" />
|
||||
@ -170,8 +172,10 @@
|
||||
<ClCompile Include="CompatDirectDrawPalette.cpp" />
|
||||
<ClCompile Include="CompatDirectDrawSurface.cpp" />
|
||||
<ClCompile Include="CompatGdi.cpp" />
|
||||
<ClCompile Include="CompatGdiCaret.cpp" />
|
||||
<ClCompile Include="CompatGdiDcCache.cpp" />
|
||||
<ClCompile Include="CompatGdiFunctions.cpp" />
|
||||
<ClCompile Include="CompatGdiWinProc.cpp" />
|
||||
<ClCompile Include="CompatVtable.cpp" />
|
||||
<ClCompile Include="DDrawLog.cpp" />
|
||||
<ClCompile Include="DllMain.cpp" />
|
||||
|
@ -75,6 +75,12 @@
|
||||
<ClInclude Include="CompatGdi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CompatGdiWinProc.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CompatGdiCaret.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="DllMain.cpp">
|
||||
@ -122,6 +128,12 @@
|
||||
<ClCompile Include="CompatGdi.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CompatGdiWinProc.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CompatGdiCaret.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="DDrawCompat.def">
|
||||
|
@ -302,13 +302,8 @@ bool RealPrimarySurface::isFullScreen()
|
||||
|
||||
bool RealPrimarySurface::isLost()
|
||||
{
|
||||
const bool isLost = g_frontBuffer &&
|
||||
return g_frontBuffer &&
|
||||
DDERR_SURFACELOST == CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.IsLost(g_frontBuffer);
|
||||
if (isLost)
|
||||
{
|
||||
CompatGdi::releaseSurfaceMemory();
|
||||
}
|
||||
return isLost;
|
||||
}
|
||||
|
||||
void RealPrimarySurface::release()
|
||||
@ -380,6 +375,8 @@ void RealPrimarySurface::update()
|
||||
|
||||
void RealPrimarySurface::updatePalette()
|
||||
{
|
||||
CompatGdi::updatePalette();
|
||||
|
||||
if (isFullScreen())
|
||||
{
|
||||
flip(DDFLIP_WAIT);
|
||||
|
Loading…
x
Reference in New Issue
Block a user