mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Added separate critical section for GDI emulation
GDI emulation was using the DirectDraw critical section for thread safety, but it caused a deadlock when Alt-Tabbing in Commandos BCD. Now it uses its own critical section and some atomic shared variables.
This commit is contained in:
parent
0474e7f95f
commit
9b62f21a3d
@ -1,6 +1,7 @@
|
|||||||
#define CINTERFACE
|
#define CINTERFACE
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <oleacc.h>
|
#include <oleacc.h>
|
||||||
@ -13,6 +14,7 @@
|
|||||||
#include "CompatPrimarySurface.h"
|
#include "CompatPrimarySurface.h"
|
||||||
#include "DDrawLog.h"
|
#include "DDrawLog.h"
|
||||||
#include "DDrawProcs.h"
|
#include "DDrawProcs.h"
|
||||||
|
#include "DDrawScopedThreadLock.h"
|
||||||
#include "RealPrimarySurface.h"
|
#include "RealPrimarySurface.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -40,7 +42,7 @@ namespace
|
|||||||
HWND rootWnd;
|
HWND rootWnd;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool g_suppressGdiHooks = false;
|
std::atomic<bool> g_suppressGdiHooks = false;
|
||||||
|
|
||||||
class HookRecursionGuard
|
class HookRecursionGuard
|
||||||
{
|
{
|
||||||
@ -72,6 +74,22 @@ namespace
|
|||||||
|
|
||||||
CaretData g_caret = {};
|
CaretData g_caret = {};
|
||||||
|
|
||||||
|
CRITICAL_SECTION g_gdiCriticalSection;
|
||||||
|
|
||||||
|
class GdiScopedThreadLock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GdiScopedThreadLock()
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&g_gdiCriticalSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
~GdiScopedThreadLock()
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(&g_gdiCriticalSection);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
POINT getClientOrigin(HWND hwnd);
|
POINT getClientOrigin(HWND hwnd);
|
||||||
HDC getCompatDc(HWND hwnd, HDC origDc, const POINT& origin);
|
HDC getCompatDc(HWND hwnd, HDC origDc, const POINT& origin);
|
||||||
HDC releaseCompatDc(HDC hdc);
|
HDC releaseCompatDc(HDC hdc);
|
||||||
@ -88,6 +106,7 @@ namespace
|
|||||||
else if (WM_ERASEBKGND == ret->message && ret->lResult)
|
else if (WM_ERASEBKGND == ret->message && ret->lResult)
|
||||||
{
|
{
|
||||||
HDC origDc = reinterpret_cast<HDC>(ret->wParam);
|
HDC origDc = reinterpret_cast<HDC>(ret->wParam);
|
||||||
|
GdiScopedThreadLock gdiLock;
|
||||||
if (g_dcToSurface.find(origDc) == g_dcToSurface.end())
|
if (g_dcToSurface.find(origDc) == g_dcToSurface.end())
|
||||||
{
|
{
|
||||||
HWND hwnd = WindowFromDC(origDc);
|
HWND hwnd = WindowFromDC(origDc);
|
||||||
@ -129,6 +148,8 @@ namespace
|
|||||||
|
|
||||||
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;
|
||||||
@ -184,11 +205,12 @@ namespace
|
|||||||
|
|
||||||
HDC getCompatDc(HWND hwnd, HDC origDc, const POINT& origin)
|
HDC getCompatDc(HWND hwnd, HDC origDc, const POINT& origin)
|
||||||
{
|
{
|
||||||
if (!CompatPrimarySurface::surfacePtr || !origDc || !RealPrimarySurface::isFullScreen() || g_suppressGdiHooks)
|
if (!CompatPrimarySurface::surfacePtr || !origDc || !RealPrimarySurface::isFullScreen() || g_suppressGdiHooks)
|
||||||
{
|
{
|
||||||
return origDc;
|
return origDc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GdiScopedThreadLock gdiLock;
|
||||||
HookRecursionGuard recursionGuard;
|
HookRecursionGuard recursionGuard;
|
||||||
|
|
||||||
IDirectDrawSurface7* surface = createGdiSurface();
|
IDirectDrawSurface7* surface = createGdiSurface();
|
||||||
@ -296,6 +318,7 @@ namespace
|
|||||||
return hdc;
|
return hdc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GdiScopedThreadLock gdiLock;
|
||||||
HookRecursionGuard recursionGuard;
|
HookRecursionGuard recursionGuard;
|
||||||
|
|
||||||
auto it = g_dcToSurface.find(hdc);
|
auto it = g_dcToSurface.find(hdc);
|
||||||
@ -360,6 +383,7 @@ namespace
|
|||||||
{
|
{
|
||||||
if (STATE_SYSTEM_INVISIBLE == getCaretState(accessible))
|
if (STATE_SYSTEM_INVISIBLE == getCaretState(accessible))
|
||||||
{
|
{
|
||||||
|
GdiScopedThreadLock gdiLock;
|
||||||
drawCaret();
|
drawCaret();
|
||||||
g_caret.isDrawn = false;
|
g_caret.isDrawn = false;
|
||||||
}
|
}
|
||||||
@ -369,69 +393,48 @@ namespace
|
|||||||
|
|
||||||
HDC WINAPI getDc(HWND hWnd)
|
HDC WINAPI getDc(HWND hWnd)
|
||||||
{
|
{
|
||||||
Compat::origProcs.AcquireDDThreadLock();
|
|
||||||
Compat::LogEnter("GetDC", hWnd);
|
Compat::LogEnter("GetDC", hWnd);
|
||||||
|
|
||||||
HDC compatDc = getCompatDc(hWnd, g_origGetDc(hWnd), getClientOrigin(hWnd));
|
HDC compatDc = getCompatDc(hWnd, g_origGetDc(hWnd), getClientOrigin(hWnd));
|
||||||
|
|
||||||
Compat::LogLeave("GetDC", hWnd) << compatDc;
|
Compat::LogLeave("GetDC", hWnd) << compatDc;
|
||||||
Compat::origProcs.ReleaseDDThreadLock();
|
|
||||||
return compatDc;
|
return compatDc;
|
||||||
}
|
}
|
||||||
|
|
||||||
HDC WINAPI getDcEx(HWND hWnd, HRGN hrgnClip, DWORD flags)
|
HDC WINAPI getDcEx(HWND hWnd, HRGN hrgnClip, DWORD flags)
|
||||||
{
|
{
|
||||||
Compat::origProcs.AcquireDDThreadLock();
|
|
||||||
Compat::LogEnter("GetDCEx", hWnd);
|
Compat::LogEnter("GetDCEx", hWnd);
|
||||||
|
|
||||||
HDC compatDc = getCompatDc(hWnd, g_origGetDcEx(hWnd, hrgnClip, flags),
|
HDC compatDc = getCompatDc(hWnd, g_origGetDcEx(hWnd, hrgnClip, flags),
|
||||||
flags & (DCX_WINDOW | DCX_PARENTCLIP) ? getWindowOrigin(hWnd) : getClientOrigin(hWnd));
|
flags & (DCX_WINDOW | DCX_PARENTCLIP) ? getWindowOrigin(hWnd) : getClientOrigin(hWnd));
|
||||||
|
|
||||||
Compat::LogLeave("GetDCEx", hWnd) << compatDc;
|
Compat::LogLeave("GetDCEx", hWnd) << compatDc;
|
||||||
Compat::origProcs.ReleaseDDThreadLock();
|
|
||||||
return compatDc;
|
return compatDc;
|
||||||
}
|
}
|
||||||
|
|
||||||
HDC WINAPI getWindowDc(HWND hWnd)
|
HDC WINAPI getWindowDc(HWND hWnd)
|
||||||
{
|
{
|
||||||
Compat::origProcs.AcquireDDThreadLock();
|
|
||||||
Compat::LogEnter("GetWindowDC", hWnd);
|
Compat::LogEnter("GetWindowDC", hWnd);
|
||||||
|
|
||||||
HDC compatDc = getCompatDc(hWnd, g_origGetWindowDc(hWnd), getWindowOrigin(hWnd));
|
HDC compatDc = getCompatDc(hWnd, g_origGetWindowDc(hWnd), getWindowOrigin(hWnd));
|
||||||
|
|
||||||
Compat::LogLeave("GetWindowDC", hWnd) << compatDc;
|
Compat::LogLeave("GetWindowDC", hWnd) << compatDc;
|
||||||
Compat::origProcs.ReleaseDDThreadLock();
|
|
||||||
return compatDc;
|
return compatDc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int WINAPI releaseDc(HWND hWnd, HDC hDC)
|
int WINAPI releaseDc(HWND hWnd, HDC hDC)
|
||||||
{
|
{
|
||||||
Compat::origProcs.AcquireDDThreadLock();
|
|
||||||
Compat::LogEnter("ReleaseDC", hWnd, hDC);
|
Compat::LogEnter("ReleaseDC", hWnd, hDC);
|
||||||
|
|
||||||
int result = g_origReleaseDc(hWnd, releaseCompatDc(hDC));
|
int result = g_origReleaseDc(hWnd, releaseCompatDc(hDC));
|
||||||
|
|
||||||
Compat::LogLeave("ReleaseDC", hWnd, hDC) << result;
|
Compat::LogLeave("ReleaseDC", hWnd, hDC) << result;
|
||||||
Compat::origProcs.ReleaseDDThreadLock();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
HDC WINAPI beginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint)
|
HDC WINAPI beginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint)
|
||||||
{
|
{
|
||||||
Compat::origProcs.AcquireDDThreadLock();
|
|
||||||
Compat::LogEnter("BeginPaint", hWnd, lpPaint);
|
Compat::LogEnter("BeginPaint", hWnd, lpPaint);
|
||||||
|
|
||||||
HDC compatDc = getCompatDc(hWnd, g_origBeginPaint(hWnd, lpPaint), getClientOrigin(hWnd));
|
HDC compatDc = getCompatDc(hWnd, g_origBeginPaint(hWnd, lpPaint), getClientOrigin(hWnd));
|
||||||
lpPaint->hdc = compatDc;
|
lpPaint->hdc = compatDc;
|
||||||
|
|
||||||
Compat::LogLeave("BeginPaint", hWnd, lpPaint) << compatDc;
|
Compat::LogLeave("BeginPaint", hWnd, lpPaint) << compatDc;
|
||||||
Compat::origProcs.ReleaseDDThreadLock();
|
|
||||||
return compatDc;
|
return compatDc;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI endPaint(HWND hWnd, const PAINTSTRUCT* lpPaint)
|
BOOL WINAPI endPaint(HWND hWnd, const PAINTSTRUCT* lpPaint)
|
||||||
{
|
{
|
||||||
Compat::origProcs.AcquireDDThreadLock();
|
|
||||||
Compat::LogEnter("EndPaint", hWnd, lpPaint);
|
Compat::LogEnter("EndPaint", hWnd, lpPaint);
|
||||||
|
|
||||||
BOOL result = FALSE;
|
BOOL result = FALSE;
|
||||||
@ -447,7 +450,6 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
Compat::LogLeave("EndPaint", hWnd, lpPaint) << result;
|
Compat::LogLeave("EndPaint", hWnd, lpPaint) << result;
|
||||||
Compat::origProcs.ReleaseDDThreadLock();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,6 +458,7 @@ namespace
|
|||||||
BOOL result = g_origCreateCaret(hWnd, hBitmap, nWidth, nHeight);
|
BOOL result = g_origCreateCaret(hWnd, hBitmap, nWidth, nHeight);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
|
GdiScopedThreadLock gdiLock;
|
||||||
if (g_caret.isDrawn)
|
if (g_caret.isDrawn)
|
||||||
{
|
{
|
||||||
drawCaret();
|
drawCaret();
|
||||||
@ -470,6 +473,7 @@ namespace
|
|||||||
BOOL WINAPI showCaret(HWND hWnd)
|
BOOL WINAPI showCaret(HWND hWnd)
|
||||||
{
|
{
|
||||||
BOOL result = g_origShowCaret(hWnd);
|
BOOL result = g_origShowCaret(hWnd);
|
||||||
|
GdiScopedThreadLock gdiLock;
|
||||||
if (result && !g_caret.isDrawn)
|
if (result && !g_caret.isDrawn)
|
||||||
{
|
{
|
||||||
IAccessible* accessible = nullptr;
|
IAccessible* accessible = nullptr;
|
||||||
@ -496,6 +500,7 @@ namespace
|
|||||||
BOOL WINAPI hideCaret(HWND hWnd)
|
BOOL WINAPI hideCaret(HWND hWnd)
|
||||||
{
|
{
|
||||||
BOOL result = g_origHideCaret(hWnd);
|
BOOL result = g_origHideCaret(hWnd);
|
||||||
|
GdiScopedThreadLock gdiLock;
|
||||||
if (result && g_caret.isDrawn)
|
if (result && g_caret.isDrawn)
|
||||||
{
|
{
|
||||||
drawCaret();
|
drawCaret();
|
||||||
@ -513,6 +518,7 @@ void CompatGdiSurface::hookGdi()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InitializeCriticalSection(&g_gdiCriticalSection);
|
||||||
g_directDraw = createDirectDraw();
|
g_directDraw = createDirectDraw();
|
||||||
if (g_directDraw)
|
if (g_directDraw)
|
||||||
{
|
{
|
||||||
|
@ -57,6 +57,6 @@ namespace CompatPrimarySurface
|
|||||||
LONG height = 0;
|
LONG height = 0;
|
||||||
DDPIXELFORMAT pixelFormat = {};
|
DDPIXELFORMAT pixelFormat = {};
|
||||||
LONG pitch = 0;
|
LONG pitch = 0;
|
||||||
void* surfacePtr = nullptr;
|
std::atomic<void*> surfacePtr = nullptr;
|
||||||
IReleaseNotifier releaseNotifier(onRelease);
|
IReleaseNotifier releaseNotifier(onRelease);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#define CINTERFACE
|
#define CINTERFACE
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <ddraw.h>
|
#include <ddraw.h>
|
||||||
|
|
||||||
class IReleaseNotifier;
|
class IReleaseNotifier;
|
||||||
@ -25,6 +26,6 @@ namespace CompatPrimarySurface
|
|||||||
extern LONG height;
|
extern LONG height;
|
||||||
extern DDPIXELFORMAT pixelFormat;
|
extern DDPIXELFORMAT pixelFormat;
|
||||||
extern LONG pitch;
|
extern LONG pitch;
|
||||||
extern void* surfacePtr;
|
extern std::atomic<void*> surfacePtr;
|
||||||
extern IReleaseNotifier releaseNotifier;
|
extern IReleaseNotifier releaseNotifier;
|
||||||
}
|
}
|
||||||
|
@ -150,6 +150,7 @@
|
|||||||
<ClInclude Include="DDrawProcs.h" />
|
<ClInclude Include="DDrawProcs.h" />
|
||||||
<ClInclude Include="CompatDirectDraw.h" />
|
<ClInclude Include="CompatDirectDraw.h" />
|
||||||
<ClInclude Include="CompatPrimarySurface.h" />
|
<ClInclude Include="CompatPrimarySurface.h" />
|
||||||
|
<ClInclude Include="DDrawScopedThreadLock.h" />
|
||||||
<ClInclude Include="DDrawTypes.h" />
|
<ClInclude Include="DDrawTypes.h" />
|
||||||
<ClInclude Include="CompatDirectDrawSurface.h" />
|
<ClInclude Include="CompatDirectDrawSurface.h" />
|
||||||
<ClInclude Include="DDrawVtableVisitor.h" />
|
<ClInclude Include="DDrawVtableVisitor.h" />
|
||||||
|
@ -63,6 +63,9 @@
|
|||||||
<ClInclude Include="Config.h">
|
<ClInclude Include="Config.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="DDrawScopedThreadLock.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="DllMain.cpp">
|
<ClCompile Include="DllMain.cpp">
|
||||||
|
20
DDrawCompat/DDrawScopedThreadLock.h
Normal file
20
DDrawCompat/DDrawScopedThreadLock.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "DDrawProcs.h"
|
||||||
|
|
||||||
|
namespace Compat
|
||||||
|
{
|
||||||
|
class DDrawScopedThreadLock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DDrawScopedThreadLock()
|
||||||
|
{
|
||||||
|
origProcs.AcquireDDThreadLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
~DDrawScopedThreadLock()
|
||||||
|
{
|
||||||
|
origProcs.ReleaseDDThreadLock();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include "CompatDirectDraw.h"
|
#include "CompatDirectDraw.h"
|
||||||
#include "CompatDirectDrawSurface.h"
|
#include "CompatDirectDrawSurface.h"
|
||||||
#include "CompatGdiSurface.h"
|
#include "CompatGdiSurface.h"
|
||||||
@ -24,6 +26,8 @@ namespace
|
|||||||
LARGE_INTEGER g_lastUpdateTime = {};
|
LARGE_INTEGER g_lastUpdateTime = {};
|
||||||
LARGE_INTEGER g_qpcFrequency = {};
|
LARGE_INTEGER g_qpcFrequency = {};
|
||||||
|
|
||||||
|
std::atomic<bool> g_isFullScreen(false);
|
||||||
|
|
||||||
bool compatBlt(IDirectDrawSurface7* dest)
|
bool compatBlt(IDirectDrawSurface7* dest)
|
||||||
{
|
{
|
||||||
Compat::LogEnter("RealPrimarySurface::compatBlt", dest);
|
Compat::LogEnter("RealPrimarySurface::compatBlt", dest);
|
||||||
@ -111,6 +115,7 @@ namespace
|
|||||||
|
|
||||||
g_frontBuffer = nullptr;
|
g_frontBuffer = nullptr;
|
||||||
g_backBuffer = nullptr;
|
g_backBuffer = nullptr;
|
||||||
|
g_isFullScreen = false;
|
||||||
if (g_paletteConverterSurface)
|
if (g_paletteConverterSurface)
|
||||||
{
|
{
|
||||||
g_paletteConverterSurface->lpVtbl->Release(g_paletteConverterSurface);
|
g_paletteConverterSurface->lpVtbl->Release(g_paletteConverterSurface);
|
||||||
@ -246,6 +251,8 @@ HRESULT RealPrimarySurface::create(DirectDraw& dd)
|
|||||||
g_frontBuffer->lpVtbl->SetPrivateData(g_frontBuffer,
|
g_frontBuffer->lpVtbl->SetPrivateData(g_frontBuffer,
|
||||||
IID_IReleaseNotifier, &g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
|
IID_IReleaseNotifier, &g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
|
||||||
|
|
||||||
|
g_isFullScreen = isFlippable;
|
||||||
|
|
||||||
return DD_OK;
|
return DD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +297,7 @@ IDirectDrawSurface7* RealPrimarySurface::getSurface()
|
|||||||
|
|
||||||
bool RealPrimarySurface::isFullScreen()
|
bool RealPrimarySurface::isFullScreen()
|
||||||
{
|
{
|
||||||
return nullptr != g_backBuffer;
|
return g_isFullScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RealPrimarySurface::isLost()
|
bool RealPrimarySurface::isLost()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user