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))
|
if (SUCCEEDED(result))
|
||||||
{
|
{
|
||||||
CompatDirectDrawSurface<TSurface>::fixSurfacePtrs(**lplpDDSurface);
|
CompatDirectDrawSurface<TSurface>::fixSurfacePtrs(**lplpDDSurface);
|
||||||
if (isPrimary)
|
|
||||||
{
|
|
||||||
CompatDirectDrawSurface<TSurface>::updateSurfaceParams();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -477,7 +477,6 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Flip(
|
|||||||
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||||
{
|
{
|
||||||
result = RealPrimarySurface::flip(dwFlags);
|
result = RealPrimarySurface::flip(dwFlags);
|
||||||
updateSurfaceParams();
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -603,8 +602,7 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Restore(TSurface* T
|
|||||||
result = RealPrimarySurface::restore();
|
result = RealPrimarySurface::restore();
|
||||||
if (wasLost)
|
if (wasLost)
|
||||||
{
|
{
|
||||||
CompatGdi::releaseSurfaceMemory();
|
CompatGdi::invalidate();
|
||||||
updateSurfaceParams();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -682,20 +680,6 @@ void CompatDirectDrawSurface<TSurface>::restorePrimaryCaps(TDdsCaps& caps)
|
|||||||
caps.dwCaps |= DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE;
|
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>
|
template <typename TSurface>
|
||||||
TSurface* CompatDirectDrawSurface<TSurface>::s_compatPrimarySurface = nullptr;
|
TSurface* CompatDirectDrawSurface<TSurface>::s_compatPrimarySurface = nullptr;
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@ public:
|
|||||||
static void fixSurfacePtrs(TSurface& surface);
|
static void fixSurfacePtrs(TSurface& surface);
|
||||||
static void initPrimarySurfacePtr(const GUID& guid, IUnknown& surface);
|
static void initPrimarySurfacePtr(const GUID& guid, IUnknown& surface);
|
||||||
static void resetPrimarySurfacePtr();
|
static void resetPrimarySurfacePtr();
|
||||||
static void updateSurfaceParams();
|
|
||||||
|
|
||||||
static HRESULT STDMETHODCALLTYPE Blt(
|
static HRESULT STDMETHODCALLTYPE Blt(
|
||||||
TSurface* This,
|
TSurface* This,
|
||||||
|
@ -1,14 +1,72 @@
|
|||||||
|
#include "CompatDirectDrawSurface.h"
|
||||||
#include "CompatGdi.h"
|
#include "CompatGdi.h"
|
||||||
|
#include "CompatGdiCaret.h"
|
||||||
#include "CompatGdiDcCache.h"
|
#include "CompatGdiDcCache.h"
|
||||||
#include "CompatGdiFunctions.h"
|
#include "CompatGdiFunctions.h"
|
||||||
|
#include "CompatGdiWinProc.h"
|
||||||
|
#include "CompatPrimarySurface.h"
|
||||||
|
#include "DDrawProcs.h"
|
||||||
|
#include "RealPrimarySurface.h"
|
||||||
|
|
||||||
namespace
|
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
|
namespace CompatGdi
|
||||||
{
|
{
|
||||||
|
CRITICAL_SECTION g_gdiCriticalSection;
|
||||||
|
std::unordered_map<void*, const char*> g_funcNames;
|
||||||
|
|
||||||
GdiScopedThreadLock::GdiScopedThreadLock()
|
GdiScopedThreadLock::GdiScopedThreadLock()
|
||||||
{
|
{
|
||||||
EnterCriticalSection(&g_gdiCriticalSection);
|
EnterCriticalSection(&g_gdiCriticalSection);
|
||||||
@ -19,29 +77,89 @@ namespace CompatGdi
|
|||||||
LeaveCriticalSection(&g_gdiCriticalSection);
|
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()
|
void installHooks()
|
||||||
{
|
{
|
||||||
InitializeCriticalSection(&g_gdiCriticalSection);
|
InitializeCriticalSection(&g_gdiCriticalSection);
|
||||||
if (CompatGdiDcCache::init())
|
if (CompatGdiDcCache::init())
|
||||||
{
|
{
|
||||||
CompatGdiFunctions::hookGdiFunctions();
|
CompatGdiFunctions::installHooks();
|
||||||
|
CompatGdiWinProc::installHooks();
|
||||||
|
CompatGdiCaret::installHooks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void releaseSurfaceMemory()
|
void invalidate()
|
||||||
{
|
{
|
||||||
GdiScopedThreadLock gdiLock;
|
EnumWindows(&invalidateWindow, 0);
|
||||||
CompatGdiDcCache::release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSurfaceMemory(void* surfaceMemory, int pitch)
|
void updatePalette()
|
||||||
{
|
{
|
||||||
GdiScopedThreadLock gdiLock;
|
GdiScopedThreadLock gdiLock;
|
||||||
const bool wasReleased = CompatGdiDcCache::isReleased();
|
CompatGdiDcCache::clear();
|
||||||
CompatGdiDcCache::setSurfaceMemory(surfaceMemory, pitch);
|
|
||||||
if (wasReleased)
|
|
||||||
{
|
|
||||||
InvalidateRect(nullptr, nullptr, TRUE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
#pragma once
|
#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
|
namespace CompatGdi
|
||||||
{
|
{
|
||||||
class GdiScopedThreadLock
|
class GdiScopedThreadLock
|
||||||
@ -9,7 +19,29 @@ namespace CompatGdi
|
|||||||
~GdiScopedThreadLock();
|
~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 installHooks();
|
||||||
void releaseSurfaceMemory();
|
void invalidate();
|
||||||
void setSurfaceMemory(void* surfaceMemory, int pitch);
|
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 "CompatGdiDc.h"
|
||||||
#include "CompatGdiDcCache.h"
|
#include "CompatGdiDcCache.h"
|
||||||
#include "RealPrimarySurface.h"
|
#include "DDrawLog.h"
|
||||||
|
|
||||||
namespace
|
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
|
struct ExcludeClipRectsData
|
||||||
{
|
{
|
||||||
HDC compatDc;
|
HDC compatDc;
|
||||||
@ -11,6 +29,35 @@ namespace
|
|||||||
HWND rootWnd;
|
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)
|
BOOL CALLBACK excludeClipRectsForOverlappingWindows(HWND hwnd, LPARAM lParam)
|
||||||
{
|
{
|
||||||
auto excludeClipRectsData = reinterpret_cast<ExcludeClipRectsData*>(lParam);
|
auto excludeClipRectsData = reinterpret_cast<ExcludeClipRectsData*>(lParam);
|
||||||
@ -19,56 +66,102 @@ namespace
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!IsWindowVisible(hwnd))
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
RECT rect = {};
|
RECT rect = {};
|
||||||
GetWindowRect(hwnd, &rect);
|
GetWindowRect(hwnd, &rect);
|
||||||
OffsetRect(&rect, -excludeClipRectsData->origin.x, -excludeClipRectsData->origin.y);
|
OffsetRect(&rect, -excludeClipRectsData->origin.x, -excludeClipRectsData->origin.y);
|
||||||
ExcludeClipRect(excludeClipRectsData->compatDc, rect.left, rect.top, rect.right, rect.bottom);
|
ExcludeClipRect(excludeClipRectsData->compatDc, rect.left, rect.top, rect.right, rect.bottom);
|
||||||
return TRUE;
|
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
|
namespace CompatGdiDc
|
||||||
{
|
{
|
||||||
CachedDc getDc(HDC origDc)
|
HDC getDc(HDC origDc)
|
||||||
{
|
{
|
||||||
CachedDc cachedDc = {};
|
if (!origDc || OBJ_DC != GetObjectType(origDc) || DT_RASDISPLAY != GetDeviceCaps(origDc, TECHNOLOGY) ||
|
||||||
if (!origDc || !RealPrimarySurface::isFullScreen() ||
|
g_origDcToCompatDc.end() != std::find_if(g_origDcToCompatDc.begin(), g_origDcToCompatDc.end(),
|
||||||
OBJ_DC != GetObjectType(origDc) ||
|
[=](const CompatDcMap::value_type& compatDc) { return compatDc.second.dc == origDc; }))
|
||||||
DT_RASDISPLAY != GetDeviceCaps(origDc, TECHNOLOGY))
|
|
||||||
{
|
{
|
||||||
return cachedDc;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
cachedDc = CompatGdiDcCache::getDc();
|
auto it = g_origDcToCompatDc.find(origDc);
|
||||||
if (!cachedDc.dc)
|
if (it != g_origDcToCompatDc.end())
|
||||||
{
|
{
|
||||||
return cachedDc;
|
++it->second.refCount;
|
||||||
|
return it->second.dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
HWND hwnd = WindowFromDC(origDc);
|
CompatDc compatDc(CompatGdiDcCache::getDc());
|
||||||
if (hwnd)
|
if (!compatDc.dc)
|
||||||
{
|
{
|
||||||
POINT origin = {};
|
return nullptr;
|
||||||
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;
|
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 <Windows.h>
|
||||||
|
|
||||||
#include "CompatGdiDcCache.h"
|
|
||||||
|
|
||||||
namespace CompatGdiDc
|
namespace CompatGdiDc
|
||||||
{
|
{
|
||||||
using CompatGdiDcCache::CachedDc;
|
HDC getDc(HDC origDc);
|
||||||
|
void releaseDc(HDC origDc);
|
||||||
CachedDc getDc(HDC origDc);
|
|
||||||
void releaseDc(const CachedDc& cachedDc);
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#include <map>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "CompatDirectDraw.h"
|
#include "CompatDirectDraw.h"
|
||||||
@ -8,41 +7,18 @@
|
|||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "DDrawLog.h"
|
#include "DDrawLog.h"
|
||||||
#include "DDrawProcs.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
|
namespace
|
||||||
{
|
{
|
||||||
using CompatGdiDcCache::SurfaceMemoryDesc;
|
|
||||||
using CompatGdiDcCache::CachedDc;
|
using CompatGdiDcCache::CachedDc;
|
||||||
|
|
||||||
std::map<SurfaceMemoryDesc, std::vector<CachedDc>> g_caches;
|
std::vector<CachedDc> g_cache;
|
||||||
std::vector<CachedDc>* g_currentCache = nullptr;
|
|
||||||
|
|
||||||
IDirectDraw7* g_directDraw = nullptr;
|
IDirectDraw7* g_directDraw = nullptr;
|
||||||
void* g_surfaceMemory = nullptr;
|
void* g_surfaceMemory = nullptr;
|
||||||
LONG g_pitch = 0;
|
LONG g_pitch = 0;
|
||||||
|
|
||||||
IDirectDrawSurface7* createGdiSurface();
|
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()
|
IDirectDraw7* createDirectDraw()
|
||||||
{
|
{
|
||||||
@ -86,17 +62,13 @@ namespace
|
|||||||
// Release DD critical section acquired by IDirectDrawSurface7::GetDC to avoid deadlocks
|
// Release DD critical section acquired by IDirectDrawSurface7::GetDC to avoid deadlocks
|
||||||
Compat::origProcs.ReleaseDDThreadLock();
|
Compat::origProcs.ReleaseDDThreadLock();
|
||||||
|
|
||||||
cachedDc.surfaceMemoryDesc.surfaceMemory = g_surfaceMemory;
|
|
||||||
cachedDc.surfaceMemoryDesc.pitch = g_pitch;
|
|
||||||
cachedDc.dc = dc;
|
|
||||||
cachedDc.surface = surface;
|
cachedDc.surface = surface;
|
||||||
|
cachedDc.dc = dc;
|
||||||
return cachedDc;
|
return cachedDc;
|
||||||
}
|
}
|
||||||
|
|
||||||
IDirectDrawSurface7* createGdiSurface()
|
IDirectDrawSurface7* createGdiSurface()
|
||||||
{
|
{
|
||||||
Compat::DDrawScopedThreadLock ddLock;
|
|
||||||
|
|
||||||
DDSURFACEDESC2 desc = {};
|
DDSURFACEDESC2 desc = {};
|
||||||
desc.dwSize = sizeof(desc);
|
desc.dwSize = sizeof(desc);
|
||||||
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH | DDSD_LPSURFACE;
|
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH | DDSD_LPSURFACE;
|
||||||
@ -125,66 +97,49 @@ namespace
|
|||||||
return surface;
|
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)
|
void releaseCachedDc(CachedDc cachedDc)
|
||||||
{
|
{
|
||||||
// Reacquire DD critical section that was temporarily released after IDirectDrawSurface7::GetDC
|
// Reacquire DD critical section that was temporarily released after IDirectDrawSurface7::GetDC
|
||||||
Compat::origProcs.AcquireDDThreadLock();
|
Compat::origProcs.AcquireDDThreadLock();
|
||||||
|
|
||||||
if (FAILED(CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.ReleaseDC(
|
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.ReleaseDC(
|
||||||
cachedDc.surface, cachedDc.dc)))
|
cachedDc.surface, cachedDc.dc);
|
||||||
|
if (FAILED(result))
|
||||||
{
|
{
|
||||||
LOG_ONCE("Failed to release a cached DC");
|
LOG_ONCE("Failed to release a cached DC: " << result);
|
||||||
Compat::origProcs.ReleaseDDThreadLock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Release(cachedDc.surface);
|
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Release(cachedDc.surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
void releaseCache(std::vector<CachedDc>& cache)
|
|
||||||
{
|
|
||||||
for (auto& cachedDc : cache)
|
|
||||||
{
|
|
||||||
releaseCachedDc(cachedDc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace CompatGdiDcCache
|
namespace CompatGdiDcCache
|
||||||
{
|
{
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
for (auto& cachedDc : g_cache)
|
||||||
|
{
|
||||||
|
releaseCachedDc(cachedDc);
|
||||||
|
}
|
||||||
|
g_cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
CachedDc getDc()
|
CachedDc getDc()
|
||||||
{
|
{
|
||||||
CachedDc cachedDc = {};
|
CachedDc cachedDc = {};
|
||||||
if (!g_currentCache)
|
if (!g_surfaceMemory)
|
||||||
{
|
{
|
||||||
return cachedDc;
|
return cachedDc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_currentCache->empty())
|
if (g_cache.empty())
|
||||||
{
|
{
|
||||||
LOG_ONCE("Warning: GDI DC cache size is insufficient");
|
|
||||||
cachedDc = createCachedDc();
|
cachedDc = createCachedDc();
|
||||||
if (!cachedDc.dc)
|
|
||||||
{
|
|
||||||
return cachedDc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cachedDc = g_currentCache->back();
|
cachedDc = g_cache.back();
|
||||||
g_currentCache->pop_back();
|
g_cache.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
return cachedDc;
|
return cachedDc;
|
||||||
@ -196,46 +151,20 @@ namespace CompatGdiDcCache
|
|||||||
return nullptr != g_directDraw;
|
return nullptr != g_directDraw;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isReleased()
|
|
||||||
{
|
|
||||||
return g_caches.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void release()
|
|
||||||
{
|
|
||||||
if (g_currentCache)
|
|
||||||
{
|
|
||||||
g_currentCache = nullptr;
|
|
||||||
clearAllCaches();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void releaseDc(const CachedDc& cachedDc)
|
void releaseDc(const CachedDc& cachedDc)
|
||||||
{
|
{
|
||||||
g_caches[cachedDc.surfaceMemoryDesc].push_back(cachedDc);
|
g_cache.push_back(cachedDc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSurfaceMemory(void* surfaceMemory, LONG pitch)
|
void setSurfaceMemory(void* surfaceMemory, LONG pitch)
|
||||||
{
|
{
|
||||||
g_surfaceMemory = surfaceMemory;
|
if (g_surfaceMemory == surfaceMemory && g_pitch == pitch)
|
||||||
g_pitch = pitch;
|
|
||||||
|
|
||||||
if (!surfaceMemory)
|
|
||||||
{
|
{
|
||||||
g_currentCache = nullptr;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceMemoryDesc surfaceMemoryDesc = { surfaceMemory, pitch };
|
g_surfaceMemory = surfaceMemory;
|
||||||
auto it = g_caches.find(surfaceMemoryDesc);
|
g_pitch = pitch;
|
||||||
if (it == g_caches.end())
|
clear();
|
||||||
{
|
|
||||||
g_currentCache = &g_caches[surfaceMemoryDesc];
|
|
||||||
fillCurrentCache();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_currentCache = &it->second;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,23 +8,15 @@
|
|||||||
|
|
||||||
namespace CompatGdiDcCache
|
namespace CompatGdiDcCache
|
||||||
{
|
{
|
||||||
struct SurfaceMemoryDesc
|
|
||||||
{
|
|
||||||
void* surfaceMemory;
|
|
||||||
LONG pitch;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CachedDc
|
struct CachedDc
|
||||||
{
|
{
|
||||||
SurfaceMemoryDesc surfaceMemoryDesc;
|
|
||||||
IDirectDrawSurface7* surface;
|
IDirectDrawSurface7* surface;
|
||||||
HDC dc;
|
HDC dc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void clear();
|
||||||
CachedDc getDc();
|
CachedDc getDc();
|
||||||
bool init();
|
bool init();
|
||||||
bool isReleased();
|
|
||||||
void release();
|
|
||||||
void releaseDc(const CachedDc& cachedDc);
|
void releaseDc(const CachedDc& cachedDc);
|
||||||
void setSurfaceMemory(void* surfaceMemory, LONG pitch);
|
void setSurfaceMemory(void* surfaceMemory, LONG pitch);
|
||||||
}
|
}
|
||||||
|
@ -1,42 +1,30 @@
|
|||||||
#include <algorithm>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "CompatDirectDrawSurface.h"
|
|
||||||
#include "CompatGdi.h"
|
#include "CompatGdi.h"
|
||||||
#include "CompatGdiDc.h"
|
#include "CompatGdiDc.h"
|
||||||
#include "CompatGdiFunctions.h"
|
#include "CompatGdiFunctions.h"
|
||||||
#include "CompatPrimarySurface.h"
|
|
||||||
#include "DDrawLog.h"
|
#include "DDrawLog.h"
|
||||||
#include "DDrawScopedThreadLock.h"
|
|
||||||
#include "RealPrimarySurface.h"
|
|
||||||
|
|
||||||
#include <detours.h>
|
#include <detours.h>
|
||||||
|
|
||||||
namespace
|
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>
|
template <typename Result, typename... Params>
|
||||||
using FuncPtr = Result(WINAPI *)(Params...);
|
using FuncPtr = Result(WINAPI *)(Params...);
|
||||||
|
|
||||||
template <typename OrigFuncPtr, OrigFuncPtr origFunc>
|
bool hasDisplayDcArg(HDC dc)
|
||||||
OrigFuncPtr& getOrigFuncPtr()
|
|
||||||
{
|
{
|
||||||
static OrigFuncPtr origFuncPtr = origFunc;
|
return dc && OBJ_DC == GetObjectType(dc) && DT_RASDISPLAY == GetDeviceCaps(dc, TECHNOLOGY);
|
||||||
return origFuncPtr;
|
}
|
||||||
|
|
||||||
|
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>
|
template <typename T>
|
||||||
@ -47,140 +35,147 @@ namespace
|
|||||||
|
|
||||||
HDC replaceDc(HDC dc)
|
HDC replaceDc(HDC dc)
|
||||||
{
|
{
|
||||||
auto it = std::find_if(g_usedCompatDcs.begin(), g_usedCompatDcs.end(),
|
HDC compatDc = CompatGdiDc::getDc(dc);
|
||||||
[dc](const CompatDc& compatDc) { return compatDc.dc == dc; });
|
return compatDc ? compatDc : dc;
|
||||||
if (it != g_usedCompatDcs.end())
|
}
|
||||||
{
|
|
||||||
return it->dc;
|
|
||||||
}
|
|
||||||
|
|
||||||
CompatDc compatDc = CompatGdiDc::getDc(dc);
|
template <typename T>
|
||||||
if (!compatDc.dc)
|
void releaseDc(T) {}
|
||||||
{
|
|
||||||
return dc;
|
|
||||||
}
|
|
||||||
|
|
||||||
compatDc.origFont = SelectObject(compatDc.dc, GetCurrentObject(dc, OBJ_FONT));
|
void releaseDc(HDC dc)
|
||||||
compatDc.origBrush = SelectObject(compatDc.dc, GetCurrentObject(dc, OBJ_BRUSH));
|
{
|
||||||
compatDc.origPen = SelectObject(compatDc.dc, GetCurrentObject(dc, OBJ_PEN));
|
CompatGdiDc::releaseDc(dc);
|
||||||
SetTextColor(compatDc.dc, GetTextColor(dc));
|
}
|
||||||
SetBkColor(compatDc.dc, GetBkColor(dc));
|
|
||||||
SetBkMode(compatDc.dc, GetBkMode(dc));
|
|
||||||
|
|
||||||
g_usedCompatDcs.push_back(compatDc);
|
template <typename T, typename... Params>
|
||||||
++*g_usedCompatDcCount;
|
void releaseDc(T t, Params... params)
|
||||||
return compatDc.dc;
|
{
|
||||||
|
releaseDc(params...);
|
||||||
|
releaseDc(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
|
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
|
||||||
Result WINAPI compatGdiFunc(Params... params)
|
Result WINAPI compatGdiFunc(Params... params)
|
||||||
{
|
{
|
||||||
CompatGdi::GdiScopedThreadLock gdiLock;
|
if (!hasDisplayDcArg(params...) || !CompatGdi::beginGdiRendering())
|
||||||
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)))
|
|
||||||
{
|
{
|
||||||
return getOrigFuncPtr<OrigFuncPtr, origFunc>()(params...);
|
return CompatGdi::getOrigFuncPtr<OrigFuncPtr, origFunc>()(params...);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result result = getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...);
|
#ifdef _DEBUG
|
||||||
GdiFlush();
|
Compat::LogEnter(CompatGdi::g_funcNames[origFunc], params...);
|
||||||
|
#endif
|
||||||
|
|
||||||
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Unlock(
|
Result result = CompatGdi::getOrigFuncPtr<OrigFuncPtr, origFunc>()(replaceDc(params)...);
|
||||||
CompatPrimarySurface::surface, nullptr);
|
releaseDc(params...);
|
||||||
|
CompatGdi::endGdiRendering();
|
||||||
|
|
||||||
if (0 != usedCompatDcCount)
|
#ifdef _DEBUG
|
||||||
{
|
Compat::LogLeave(CompatGdi::g_funcNames[origFunc], params...) << result;
|
||||||
RealPrimarySurface::update();
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
|
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...>;
|
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) \
|
||||||
{
|
CompatGdi::hookGdiFunction<decltype(&func), &func>( \
|
||||||
#define HOOK_GDI_FUNCTION(module, func) hookGdiFunction<decltype(&func), &func>(#module, #func);
|
#module, #func, getCompatGdiFuncPtr<decltype(&func), &func>(&func));
|
||||||
|
|
||||||
#define HOOK_GDI_TEXT_FUNCTION(module, func) \
|
#define HOOK_GDI_TEXT_FUNCTION(module, func) \
|
||||||
HOOK_GDI_FUNCTION(module, func##A); \
|
HOOK_GDI_FUNCTION(module, func##A); \
|
||||||
HOOK_GDI_FUNCTION(module, func##W)
|
HOOK_GDI_FUNCTION(module, func##W)
|
||||||
|
|
||||||
DetourTransactionBegin();
|
namespace CompatGdiFunctions
|
||||||
HOOK_GDI_FUNCTION(gdi32, BitBlt);
|
{
|
||||||
DetourTransactionCommit();
|
void installHooks()
|
||||||
|
{
|
||||||
|
DetourTransactionBegin();
|
||||||
|
|
||||||
#undef HOOK_GDI_TEXT_FUNCTION
|
// Bitmap functions
|
||||||
#undef HOOK_GDI_FUNCTION
|
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
|
#pragma once
|
||||||
|
|
||||||
class CompatGdiFunctions
|
namespace CompatGdiFunctions
|
||||||
{
|
{
|
||||||
public:
|
void installHooks();
|
||||||
static void hookGdiFunctions();
|
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,6 @@ typedef unsigned long DWORD;
|
|||||||
|
|
||||||
namespace Config
|
namespace Config
|
||||||
{
|
{
|
||||||
const DWORD gdiDcCacheSize = 10;
|
|
||||||
const DWORD minRefreshInterval = 1000 / 60;
|
const DWORD minRefreshInterval = 1000 / 60;
|
||||||
const DWORD minRefreshIntervalAfterFlip = 1000 / 10;
|
const DWORD minRefreshIntervalAfterFlip = 1000 / 10;
|
||||||
const DWORD minPaletteUpdateInterval = 1000 / 60;
|
const DWORD minPaletteUpdateInterval = 1000 / 60;
|
||||||
|
@ -94,7 +94,7 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile>
|
<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>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
@ -121,7 +121,7 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile>
|
<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>
|
<GenerateDebugInformation>No</GenerateDebugInformation>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
@ -146,9 +146,11 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="CompatDirectDrawPalette.h" />
|
<ClInclude Include="CompatDirectDrawPalette.h" />
|
||||||
<ClInclude Include="CompatGdi.h" />
|
<ClInclude Include="CompatGdi.h" />
|
||||||
|
<ClInclude Include="CompatGdiCaret.h" />
|
||||||
<ClInclude Include="CompatGdiDc.h" />
|
<ClInclude Include="CompatGdiDc.h" />
|
||||||
<ClInclude Include="CompatGdiDcCache.h" />
|
<ClInclude Include="CompatGdiDcCache.h" />
|
||||||
<ClInclude Include="CompatGdiFunctions.h" />
|
<ClInclude Include="CompatGdiFunctions.h" />
|
||||||
|
<ClInclude Include="CompatGdiWinProc.h" />
|
||||||
<ClInclude Include="Config.h" />
|
<ClInclude Include="Config.h" />
|
||||||
<ClInclude Include="DDrawProcs.h" />
|
<ClInclude Include="DDrawProcs.h" />
|
||||||
<ClInclude Include="CompatDirectDraw.h" />
|
<ClInclude Include="CompatDirectDraw.h" />
|
||||||
@ -170,8 +172,10 @@
|
|||||||
<ClCompile Include="CompatDirectDrawPalette.cpp" />
|
<ClCompile Include="CompatDirectDrawPalette.cpp" />
|
||||||
<ClCompile Include="CompatDirectDrawSurface.cpp" />
|
<ClCompile Include="CompatDirectDrawSurface.cpp" />
|
||||||
<ClCompile Include="CompatGdi.cpp" />
|
<ClCompile Include="CompatGdi.cpp" />
|
||||||
|
<ClCompile Include="CompatGdiCaret.cpp" />
|
||||||
<ClCompile Include="CompatGdiDcCache.cpp" />
|
<ClCompile Include="CompatGdiDcCache.cpp" />
|
||||||
<ClCompile Include="CompatGdiFunctions.cpp" />
|
<ClCompile Include="CompatGdiFunctions.cpp" />
|
||||||
|
<ClCompile Include="CompatGdiWinProc.cpp" />
|
||||||
<ClCompile Include="CompatVtable.cpp" />
|
<ClCompile Include="CompatVtable.cpp" />
|
||||||
<ClCompile Include="DDrawLog.cpp" />
|
<ClCompile Include="DDrawLog.cpp" />
|
||||||
<ClCompile Include="DllMain.cpp" />
|
<ClCompile Include="DllMain.cpp" />
|
||||||
|
@ -75,6 +75,12 @@
|
|||||||
<ClInclude Include="CompatGdi.h">
|
<ClInclude Include="CompatGdi.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="CompatGdiWinProc.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="CompatGdiCaret.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="DllMain.cpp">
|
<ClCompile Include="DllMain.cpp">
|
||||||
@ -122,6 +128,12 @@
|
|||||||
<ClCompile Include="CompatGdi.cpp">
|
<ClCompile Include="CompatGdi.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="CompatGdiWinProc.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="CompatGdiCaret.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="DDrawCompat.def">
|
<None Include="DDrawCompat.def">
|
||||||
|
@ -302,13 +302,8 @@ bool RealPrimarySurface::isFullScreen()
|
|||||||
|
|
||||||
bool RealPrimarySurface::isLost()
|
bool RealPrimarySurface::isLost()
|
||||||
{
|
{
|
||||||
const bool isLost = g_frontBuffer &&
|
return g_frontBuffer &&
|
||||||
DDERR_SURFACELOST == CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.IsLost(g_frontBuffer);
|
DDERR_SURFACELOST == CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.IsLost(g_frontBuffer);
|
||||||
if (isLost)
|
|
||||||
{
|
|
||||||
CompatGdi::releaseSurfaceMemory();
|
|
||||||
}
|
|
||||||
return isLost;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealPrimarySurface::release()
|
void RealPrimarySurface::release()
|
||||||
@ -380,6 +375,8 @@ void RealPrimarySurface::update()
|
|||||||
|
|
||||||
void RealPrimarySurface::updatePalette()
|
void RealPrimarySurface::updatePalette()
|
||||||
{
|
{
|
||||||
|
CompatGdi::updatePalette();
|
||||||
|
|
||||||
if (isFullScreen())
|
if (isFullScreen())
|
||||||
{
|
{
|
||||||
flip(DDFLIP_WAIT);
|
flip(DDFLIP_WAIT);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user