mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Initial commit
This commit is contained in:
commit
2a5e699c6e
140
DDrawCompat/CompatDirectDraw.cpp
Normal file
140
DDrawCompat/CompatDirectDraw.cpp
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
#include "CompatDirectDraw.h"
|
||||||
|
#include "CompatDirectDrawSurface.h"
|
||||||
|
#include "CompatPrimarySurface.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
template <typename TSurfaceDesc>
|
||||||
|
HRESULT PASCAL enumDisplayModesCallback(
|
||||||
|
TSurfaceDesc* lpDDSurfaceDesc,
|
||||||
|
LPVOID lpContext)
|
||||||
|
{
|
||||||
|
if (lpDDSurfaceDesc)
|
||||||
|
{
|
||||||
|
*static_cast<DDPIXELFORMAT*>(lpContext) = lpDDSurfaceDesc->ddpfPixelFormat;
|
||||||
|
}
|
||||||
|
return DDENUMRET_CANCEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDirectDraw>
|
||||||
|
void CompatDirectDraw<TDirectDraw>::setCompatVtable(Vtable<TDirectDraw>& vtable)
|
||||||
|
{
|
||||||
|
vtable.CreateSurface = &CreateSurface;
|
||||||
|
vtable.RestoreDisplayMode = &RestoreDisplayMode;
|
||||||
|
vtable.SetDisplayMode = &SetDisplayMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDirectDraw>
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDraw<TDirectDraw>::CreateSurface(
|
||||||
|
TDirectDraw* This,
|
||||||
|
TSurfaceDesc* lpDDSurfaceDesc,
|
||||||
|
TSurface** lplpDDSurface,
|
||||||
|
IUnknown* pUnkOuter)
|
||||||
|
{
|
||||||
|
HRESULT result = DD_OK;
|
||||||
|
|
||||||
|
const bool isPrimary = lpDDSurfaceDesc &&
|
||||||
|
(lpDDSurfaceDesc->dwFlags & DDSD_CAPS) &&
|
||||||
|
(lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE);
|
||||||
|
|
||||||
|
if (isPrimary)
|
||||||
|
{
|
||||||
|
result = CompatDirectDrawSurface<TSurface>::createCompatPrimarySurface(
|
||||||
|
*This, *lpDDSurfaceDesc, *lplpDDSurface);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (CompatPrimarySurface::displayMode.pixelFormat.dwSize != 0 &&
|
||||||
|
!(lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT))
|
||||||
|
{
|
||||||
|
lpDDSurfaceDesc->dwFlags |= DDSD_PIXELFORMAT;
|
||||||
|
lpDDSurfaceDesc->ddpfPixelFormat = CompatPrimarySurface::displayMode.pixelFormat;
|
||||||
|
}
|
||||||
|
result = s_origVtable.CreateSurface(This, lpDDSurfaceDesc, lplpDDSurface, pUnkOuter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
CompatDirectDrawSurface<TSurface>::fixSurfacePtrs(**lplpDDSurface);
|
||||||
|
if (isPrimary)
|
||||||
|
{
|
||||||
|
CompatDirectDrawSurface<TSurface>::updateSurfaceParams();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDirectDraw>
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDraw<TDirectDraw>::RestoreDisplayMode(TDirectDraw* This)
|
||||||
|
{
|
||||||
|
HRESULT result = s_origVtable.RestoreDisplayMode(This);
|
||||||
|
if (SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
CompatPrimarySurface::displayMode = CompatPrimarySurface::getDisplayMode(*This);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDirectDraw>
|
||||||
|
template <typename... Params>
|
||||||
|
static HRESULT STDMETHODCALLTYPE CompatDirectDraw<TDirectDraw>::SetDisplayMode(
|
||||||
|
TDirectDraw* This,
|
||||||
|
DWORD dwWidth,
|
||||||
|
DWORD dwHeight,
|
||||||
|
DWORD dwBPP,
|
||||||
|
Params... params)
|
||||||
|
{
|
||||||
|
TSurfaceDesc desc = {};
|
||||||
|
desc.dwSize = sizeof(desc);
|
||||||
|
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
|
||||||
|
desc.dwWidth = dwWidth;
|
||||||
|
desc.dwHeight = dwHeight;
|
||||||
|
desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
|
||||||
|
desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
|
||||||
|
desc.ddpfPixelFormat.dwRGBBitCount = dwBPP;
|
||||||
|
|
||||||
|
switch (dwBPP)
|
||||||
|
{
|
||||||
|
case 1: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED1; break;
|
||||||
|
case 2: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED2; break;
|
||||||
|
case 4: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED4; break;
|
||||||
|
case 8: desc.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED8; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DDPIXELFORMAT pf = {};
|
||||||
|
if (dwBPP > 8)
|
||||||
|
{
|
||||||
|
if (FAILED(s_origVtable.EnumDisplayModes(This, 0, &desc, &pf, &enumDisplayModesCallback)) ||
|
||||||
|
0 == pf.dwSize)
|
||||||
|
{
|
||||||
|
Compat::Log() << "Failed to find the requested display mode: " <<
|
||||||
|
dwWidth << "x" << dwHeight << "x" << dwBPP;
|
||||||
|
return DDERR_INVALIDMODE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pf = desc.ddpfPixelFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT result = s_origVtable.SetDisplayMode(This, dwWidth, dwHeight, 32, params...);
|
||||||
|
if (SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
CompatPrimarySurface::displayMode.width = dwWidth;
|
||||||
|
CompatPrimarySurface::displayMode.height = dwHeight;
|
||||||
|
CompatPrimarySurface::displayMode.pixelFormat = pf;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Compat::Log() << "Failed to set the display mode to " << dwWidth << "x" << dwHeight << "x32";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template CompatDirectDraw<IDirectDraw>;
|
||||||
|
template CompatDirectDraw<IDirectDraw2>;
|
||||||
|
template CompatDirectDraw<IDirectDraw4>;
|
||||||
|
template CompatDirectDraw<IDirectDraw7>;
|
31
DDrawCompat/CompatDirectDraw.h
Normal file
31
DDrawCompat/CompatDirectDraw.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CompatVtable.h"
|
||||||
|
#include "DDrawTypes.h"
|
||||||
|
#include "DirectDrawVtblVisitor.h"
|
||||||
|
|
||||||
|
template <typename TDirectDraw>
|
||||||
|
class CompatDirectDraw : public CompatVtable<CompatDirectDraw<TDirectDraw>, TDirectDraw>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename Types<TDirectDraw>::TCreatedSurface TSurface;
|
||||||
|
typedef typename Types<TDirectDraw>::TSurfaceDesc TSurfaceDesc;
|
||||||
|
|
||||||
|
static void setCompatVtable(Vtable<TDirectDraw>& vtable);
|
||||||
|
|
||||||
|
static HRESULT STDMETHODCALLTYPE CreateSurface(
|
||||||
|
TDirectDraw* This,
|
||||||
|
TSurfaceDesc* lpDDSurfaceDesc,
|
||||||
|
TSurface** lplpDDSurface,
|
||||||
|
IUnknown* pUnkOuter);
|
||||||
|
|
||||||
|
static HRESULT STDMETHODCALLTYPE RestoreDisplayMode(TDirectDraw* This);
|
||||||
|
|
||||||
|
template <typename... Params>
|
||||||
|
static HRESULT STDMETHODCALLTYPE SetDisplayMode(
|
||||||
|
TDirectDraw* This,
|
||||||
|
DWORD dwWidth,
|
||||||
|
DWORD dwHeight,
|
||||||
|
DWORD dwBPP,
|
||||||
|
Params... params);
|
||||||
|
};
|
23
DDrawCompat/CompatDirectDrawPalette.cpp
Normal file
23
DDrawCompat/CompatDirectDrawPalette.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include "CompatDirectDrawPalette.h"
|
||||||
|
#include "CompatPrimarySurface.h"
|
||||||
|
#include "RealPrimarySurface.h"
|
||||||
|
|
||||||
|
void CompatDirectDrawPalette::setCompatVtable(IDirectDrawPaletteVtbl& vtable)
|
||||||
|
{
|
||||||
|
vtable.SetEntries = &SetEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDrawPalette::SetEntries(
|
||||||
|
IDirectDrawPalette* This,
|
||||||
|
DWORD dwFlags,
|
||||||
|
DWORD dwStartingEntry,
|
||||||
|
DWORD dwCount,
|
||||||
|
LPPALETTEENTRY lpEntries)
|
||||||
|
{
|
||||||
|
HRESULT result = s_origVtable.SetEntries(This, dwFlags, dwStartingEntry, dwCount, lpEntries);
|
||||||
|
if (This == CompatPrimarySurface::palette && SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
RealPrimarySurface::updatePalette();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
17
DDrawCompat/CompatDirectDrawPalette.h
Normal file
17
DDrawCompat/CompatDirectDrawPalette.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CompatVtable.h"
|
||||||
|
#include "DirectDrawPaletteVtblVisitor.h"
|
||||||
|
|
||||||
|
class CompatDirectDrawPalette : public CompatVtable<CompatDirectDrawPalette, IDirectDrawPalette>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void setCompatVtable(IDirectDrawPaletteVtbl& vtable);
|
||||||
|
|
||||||
|
static HRESULT STDMETHODCALLTYPE SetEntries(
|
||||||
|
IDirectDrawPalette* This,
|
||||||
|
DWORD dwFlags,
|
||||||
|
DWORD dwStartingEntry,
|
||||||
|
DWORD dwCount,
|
||||||
|
LPPALETTEENTRY lpEntries);
|
||||||
|
};
|
685
DDrawCompat/CompatDirectDrawSurface.cpp
Normal file
685
DDrawCompat/CompatDirectDrawSurface.cpp
Normal file
@ -0,0 +1,685 @@
|
|||||||
|
#include <algorithm>
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "CompatDirectDraw.h"
|
||||||
|
#include "CompatDirectDrawSurface.h"
|
||||||
|
#include "CompatGdiSurface.h"
|
||||||
|
#include "CompatPrimarySurface.h"
|
||||||
|
#include "DDrawProcs.h"
|
||||||
|
#include "IReleaseNotifier.h"
|
||||||
|
#include "RealPrimarySurface.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct SimilarSurface
|
||||||
|
{
|
||||||
|
DWORD width;
|
||||||
|
DWORD height;
|
||||||
|
DDPIXELFORMAT pixelFormat;
|
||||||
|
IDirectDrawSurface7* front;
|
||||||
|
IDirectDrawSurface7* back;
|
||||||
|
};
|
||||||
|
|
||||||
|
SimilarSurface getSimilarSurface(const DDSURFACEDESC2& desc);
|
||||||
|
bool mirrorBlt(IDirectDrawSurface7& dst, IDirectDrawSurface7& src, RECT srcRect, DWORD mirrorFx);
|
||||||
|
|
||||||
|
IDirectDraw7* g_mirrorDirectDraw = nullptr;
|
||||||
|
|
||||||
|
IDirectDraw7* createMirrorDirectDraw()
|
||||||
|
{
|
||||||
|
IDirectDraw7* dd = nullptr;
|
||||||
|
CALL_ORIG_DDRAW(DirectDrawCreateEx, nullptr, reinterpret_cast<void**>(&dd), IID_IDirectDraw7, nullptr);
|
||||||
|
if (!dd ||
|
||||||
|
FAILED(CompatDirectDraw<IDirectDraw7>::s_origVtable.SetCooperativeLevel(dd, nullptr, DDSCL_NORMAL)))
|
||||||
|
{
|
||||||
|
Compat::Log() << "Failed to create a helper DirectDraw object for mirroring";
|
||||||
|
}
|
||||||
|
return dd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fixSurfacePtr(IDirectDrawSurface7& surface, DDSURFACEDESC2& desc)
|
||||||
|
{
|
||||||
|
if ((desc.dwFlags & DDSD_CAPS) && (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DDBLTFX fx = {};
|
||||||
|
fx.dwSize = sizeof(fx);
|
||||||
|
surface.lpVtbl->Blt(&surface, nullptr, nullptr, nullptr, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT WINAPI enumSurfacesCallback(
|
||||||
|
LPDIRECTDRAWSURFACE7 lpDDSurface,
|
||||||
|
LPDDSURFACEDESC2 lpDDSurfaceDesc,
|
||||||
|
LPVOID lpContext)
|
||||||
|
{
|
||||||
|
auto visitedSurfaces = *static_cast<std::set<IDirectDrawSurface7*>*>(lpContext);
|
||||||
|
|
||||||
|
if (visitedSurfaces.find(lpDDSurface) == visitedSurfaces.end())
|
||||||
|
{
|
||||||
|
visitedSurfaces.insert(lpDDSurface);
|
||||||
|
fixSurfacePtr(*lpDDSurface, *lpDDSurfaceDesc);
|
||||||
|
lpDDSurface->lpVtbl->EnumAttachedSurfaces(lpDDSurface, &visitedSurfaces, &enumSurfacesCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
lpDDSurface->lpVtbl->Release(lpDDSurface);
|
||||||
|
return DDENUMRET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fixSurfacePtrs(IDirectDrawSurface7& surface)
|
||||||
|
{
|
||||||
|
DDSURFACEDESC2 desc = {};
|
||||||
|
desc.dwSize = sizeof(desc);
|
||||||
|
surface.lpVtbl->GetSurfaceDesc(&surface, &desc);
|
||||||
|
|
||||||
|
fixSurfacePtr(surface, desc);
|
||||||
|
std::set<IDirectDrawSurface7*> visitedSurfaces{ &surface };
|
||||||
|
surface.lpVtbl->EnumAttachedSurfaces(&surface, &visitedSurfaces, &enumSurfacesCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
IDirectDrawSurface7* getMirroredSurface(IDirectDrawSurface7& surface, RECT* srcRect, DWORD mirrorFx)
|
||||||
|
{
|
||||||
|
auto& origVtable = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable;
|
||||||
|
|
||||||
|
DDSURFACEDESC2 desc = {};
|
||||||
|
desc.dwSize = sizeof(desc);
|
||||||
|
HRESULT result = origVtable.GetSurfaceDesc(&surface, &desc);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
LOG_ONCE("Failed to get surface description for mirroring: " << result);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srcRect)
|
||||||
|
{
|
||||||
|
desc.dwWidth = srcRect->right - srcRect->left;
|
||||||
|
desc.dwHeight = srcRect->bottom - srcRect->top;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimilarSurface similarSurface = getSimilarSurface(desc);
|
||||||
|
if (!similarSurface.front)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
RECT rect = { 0, 0, static_cast<LONG>(desc.dwWidth), static_cast<LONG>(desc.dwHeight) };
|
||||||
|
if ((mirrorFx & DDBLTFX_MIRRORLEFTRIGHT) && (mirrorFx & DDBLTFX_MIRRORUPDOWN))
|
||||||
|
{
|
||||||
|
if (!mirrorBlt(*similarSurface.back, surface, srcRect ? *srcRect : rect, DDBLTFX_MIRRORLEFTRIGHT) ||
|
||||||
|
!mirrorBlt(*similarSurface.front, *similarSurface.back, rect, DDBLTFX_MIRRORUPDOWN))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!mirrorBlt(*similarSurface.front, surface, srcRect ? *srcRect : rect, mirrorFx))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
origVtable.AddRef(similarSurface.front);
|
||||||
|
return similarSurface.front;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
TSurface* getMirroredSurface(TSurface& surface, RECT* rect, DWORD mirrorFx)
|
||||||
|
{
|
||||||
|
auto& origVtable = CompatDirectDrawSurface<TSurface>::s_origVtable;
|
||||||
|
|
||||||
|
IDirectDrawSurface7* surface7 = nullptr;
|
||||||
|
origVtable.QueryInterface(&surface, IID_IDirectDrawSurface7, reinterpret_cast<void**>(&surface7));
|
||||||
|
IDirectDrawSurface7* mirroredSurface7 = getMirroredSurface(*surface7, rect, mirrorFx);
|
||||||
|
surface7->lpVtbl->Release(surface7);
|
||||||
|
|
||||||
|
if (!mirroredSurface7)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& origVtable7 = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable;
|
||||||
|
TSurface* mirroredSurface = nullptr;
|
||||||
|
origVtable7.QueryInterface(mirroredSurface7,
|
||||||
|
CompatDirectDrawSurface<TSurface>::s_iid, reinterpret_cast<void**>(&mirroredSurface));
|
||||||
|
origVtable7.Release(mirroredSurface7);
|
||||||
|
return mirroredSurface;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimilarSurface getSimilarSurface(const DDSURFACEDESC2& desc)
|
||||||
|
{
|
||||||
|
static std::vector<SimilarSurface> similarSurfacesVidMem;
|
||||||
|
static std::vector<SimilarSurface> similarSurfacesSysMem;
|
||||||
|
|
||||||
|
std::vector<SimilarSurface>& similarSurfaces =
|
||||||
|
(desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) ? similarSurfacesSysMem : similarSurfacesVidMem;
|
||||||
|
|
||||||
|
DDPIXELFORMAT pf = desc.ddpfPixelFormat;
|
||||||
|
if (!(pf.dwFlags & DDPF_FOURCC))
|
||||||
|
{
|
||||||
|
pf.dwFourCC = 0;
|
||||||
|
}
|
||||||
|
if (!(pf.dwFlags & (DDPF_ALPHAPIXELS | DDPF_ZPIXELS)))
|
||||||
|
{
|
||||||
|
pf.dwRGBAlphaBitMask = 0;
|
||||||
|
}
|
||||||
|
auto it = std::find_if(similarSurfaces.begin(), similarSurfaces.end(),
|
||||||
|
[&](SimilarSurface& s) { return 0 == memcmp(&s.pixelFormat, &pf, sizeof(pf)); });
|
||||||
|
|
||||||
|
auto& origVtable = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable;
|
||||||
|
SimilarSurface similarSurface = {};
|
||||||
|
if (it != similarSurfaces.end())
|
||||||
|
{
|
||||||
|
if (DDERR_SURFACELOST == origVtable.IsLost(it->front) ||
|
||||||
|
DDERR_SURFACELOST == origVtable.IsLost(it->back))
|
||||||
|
{
|
||||||
|
origVtable.Release(it->front);
|
||||||
|
origVtable.Release(it->back);
|
||||||
|
similarSurfaces.erase(it);
|
||||||
|
it = similarSurfaces.end();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
similarSurface = *it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (similarSurface.width >= desc.dwWidth && similarSurface.height >= desc.dwHeight)
|
||||||
|
{
|
||||||
|
return similarSurface;
|
||||||
|
}
|
||||||
|
|
||||||
|
DDSURFACEDESC2 similarDesc = {};
|
||||||
|
similarDesc.dwSize = sizeof(similarDesc);
|
||||||
|
similarDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS;
|
||||||
|
similarDesc.dwWidth = max(similarSurface.width, desc.dwWidth);
|
||||||
|
similarDesc.dwHeight = max(similarSurface.height, desc.dwHeight);
|
||||||
|
similarDesc.ddpfPixelFormat = pf;
|
||||||
|
similarDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
||||||
|
if (desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
||||||
|
{
|
||||||
|
similarDesc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT result = CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(
|
||||||
|
g_mirrorDirectDraw, &similarDesc, &similarSurface.front, nullptr);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
LOG_ONCE("Failed to create a front surface for mirroring");
|
||||||
|
similarSurface.front = nullptr;
|
||||||
|
return similarSurface;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(
|
||||||
|
g_mirrorDirectDraw, &similarDesc, &similarSurface.back, nullptr);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
LOG_ONCE("Failed to create a back surface for mirroring");
|
||||||
|
origVtable.Release(similarSurface.front);
|
||||||
|
similarSurface.front = nullptr;
|
||||||
|
return similarSurface;
|
||||||
|
}
|
||||||
|
|
||||||
|
similarSurface.width = similarDesc.dwWidth;
|
||||||
|
similarSurface.height = similarDesc.dwHeight;
|
||||||
|
similarSurface.pixelFormat = pf;
|
||||||
|
|
||||||
|
if (it != similarSurfaces.end())
|
||||||
|
{
|
||||||
|
origVtable.Release(it->front);
|
||||||
|
origVtable.Release(it->back);
|
||||||
|
*it = similarSurface;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
similarSurfaces.push_back(similarSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
return similarSurface;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mirrorBlt(IDirectDrawSurface7& dst, IDirectDrawSurface7& src, RECT srcRect, DWORD mirrorFx)
|
||||||
|
{
|
||||||
|
if (DDBLTFX_MIRRORLEFTRIGHT == mirrorFx)
|
||||||
|
{
|
||||||
|
LONG width = srcRect.right - srcRect.left;
|
||||||
|
srcRect.left = srcRect.right - 1;
|
||||||
|
for (LONG x = 0; x < width; ++x)
|
||||||
|
{
|
||||||
|
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.BltFast(
|
||||||
|
&dst, x, 0, &src, &srcRect, DDBLTFAST_WAIT);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
LOG_ONCE("Failed BltFast for mirroring: " << result);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
--srcRect.left;
|
||||||
|
--srcRect.right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LONG height = srcRect.bottom - srcRect.top;
|
||||||
|
srcRect.top = srcRect.bottom - 1;
|
||||||
|
for (LONG y = 0; y < height; ++y)
|
||||||
|
{
|
||||||
|
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.BltFast(
|
||||||
|
&dst, 0, y, &src, &srcRect, DDBLTFAST_WAIT);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
LOG_ONCE("Failed BltFast for mirroring: " << result);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
--srcRect.top;
|
||||||
|
--srcRect.bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
void CompatDirectDrawSurface<TSurface>::setCompatVtable(Vtable<TSurface>& vtable)
|
||||||
|
{
|
||||||
|
vtable.Blt = &Blt;
|
||||||
|
vtable.BltFast = &BltFast;
|
||||||
|
vtable.Flip = &Flip;
|
||||||
|
vtable.GetCaps = &GetCaps;
|
||||||
|
vtable.GetSurfaceDesc = &GetSurfaceDesc;
|
||||||
|
vtable.IsLost = &IsLost;
|
||||||
|
vtable.Lock = &Lock;
|
||||||
|
vtable.QueryInterface = &QueryInterface;
|
||||||
|
vtable.ReleaseDC = &ReleaseDC;
|
||||||
|
vtable.Restore = &Restore;
|
||||||
|
vtable.SetClipper = &SetClipper;
|
||||||
|
vtable.SetPalette = &SetPalette;
|
||||||
|
vtable.Unlock = &Unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
template <typename TDirectDraw>
|
||||||
|
HRESULT CompatDirectDrawSurface<TSurface>::createCompatPrimarySurface(
|
||||||
|
TDirectDraw& dd,
|
||||||
|
TSurfaceDesc compatDesc,
|
||||||
|
TSurface*& compatSurface)
|
||||||
|
{
|
||||||
|
if (0 == CompatPrimarySurface::displayMode.pixelFormat.dwSize)
|
||||||
|
{
|
||||||
|
CompatPrimarySurface::displayMode = CompatPrimarySurface::getDisplayMode(dd);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT result = RealPrimarySurface::create(dd);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompatPrimarySurface::width = CompatPrimarySurface::displayMode.width;
|
||||||
|
CompatPrimarySurface::height = CompatPrimarySurface::displayMode.height;
|
||||||
|
CompatPrimarySurface::pixelFormat = CompatPrimarySurface::displayMode.pixelFormat;
|
||||||
|
|
||||||
|
compatDesc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
|
||||||
|
compatDesc.dwWidth = CompatPrimarySurface::width;
|
||||||
|
compatDesc.dwHeight = CompatPrimarySurface::height;
|
||||||
|
compatDesc.ddsCaps.dwCaps ^= DDSCAPS_PRIMARYSURFACE;
|
||||||
|
compatDesc.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN;
|
||||||
|
compatDesc.ddpfPixelFormat = CompatPrimarySurface::pixelFormat;
|
||||||
|
|
||||||
|
result = CompatDirectDraw<TDirectDraw>::s_origVtable.CreateSurface(
|
||||||
|
&dd, &compatDesc, &compatSurface, nullptr);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
Compat::Log() << "Failed to create the compat primary surface!";
|
||||||
|
RealPrimarySurface::release();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_mirrorDirectDraw = createMirrorDirectDraw();
|
||||||
|
|
||||||
|
s_compatPrimarySurface = compatSurface;
|
||||||
|
initCompatPrimarySurface();
|
||||||
|
return DD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
void CompatDirectDrawSurface<TSurface>::fixSurfacePtrs(TSurface& surface)
|
||||||
|
{
|
||||||
|
IDirectDrawSurface7* surface7 = nullptr;
|
||||||
|
surface.lpVtbl->QueryInterface(&surface, IID_IDirectDrawSurface7, reinterpret_cast<LPVOID*>(&surface7));
|
||||||
|
::fixSurfacePtrs(*surface7);
|
||||||
|
surface7->lpVtbl->Release(surface7);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
void CompatDirectDrawSurface<TSurface>::initPrimarySurfacePtr(const GUID& guid, IUnknown& surface)
|
||||||
|
{
|
||||||
|
if (SUCCEEDED(surface.lpVtbl->QueryInterface(
|
||||||
|
&surface, guid, reinterpret_cast<LPVOID*>(&s_compatPrimarySurface))))
|
||||||
|
{
|
||||||
|
s_compatPrimarySurface->lpVtbl->Release(s_compatPrimarySurface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Blt(
|
||||||
|
TSurface* This,
|
||||||
|
LPRECT lpDestRect,
|
||||||
|
TSurface* lpDDSrcSurface,
|
||||||
|
LPRECT lpSrcRect,
|
||||||
|
DWORD dwFlags,
|
||||||
|
LPDDBLTFX lpDDBltFx)
|
||||||
|
{
|
||||||
|
if ((This == s_compatPrimarySurface || lpDDSrcSurface == s_compatPrimarySurface) &&
|
||||||
|
RealPrimarySurface::isLost())
|
||||||
|
{
|
||||||
|
return DDERR_SURFACELOST;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT result = DD_OK;
|
||||||
|
TSurface* mirroredSrcSurface = nullptr;
|
||||||
|
|
||||||
|
if (lpDDSrcSurface && (dwFlags & DDBLT_DDFX) && lpDDBltFx &&
|
||||||
|
(lpDDBltFx->dwDDFX & (DDBLTFX_MIRRORLEFTRIGHT | DDBLTFX_MIRRORUPDOWN)))
|
||||||
|
{
|
||||||
|
mirroredSrcSurface = getMirroredSurface(*lpDDSrcSurface, lpSrcRect, lpDDBltFx->dwDDFX);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mirroredSrcSurface)
|
||||||
|
{
|
||||||
|
DWORD flags = dwFlags;
|
||||||
|
DDBLTFX fx = *lpDDBltFx;
|
||||||
|
fx.dwDDFX &= ~(DDBLTFX_MIRRORLEFTRIGHT | DDBLTFX_MIRRORUPDOWN);
|
||||||
|
if (0 == fx.dwDDFX)
|
||||||
|
{
|
||||||
|
flags ^= DDBLT_DDFX;
|
||||||
|
}
|
||||||
|
if (flags & DDBLT_KEYSRC)
|
||||||
|
{
|
||||||
|
DDCOLORKEY srcColorKey = {};
|
||||||
|
s_origVtable.GetColorKey(lpDDSrcSurface, DDCKEY_SRCBLT, &srcColorKey);
|
||||||
|
s_origVtable.SetColorKey(mirroredSrcSurface, DDCKEY_SRCBLT, &srcColorKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lpSrcRect)
|
||||||
|
{
|
||||||
|
RECT srcRect = { 0, 0, lpSrcRect->right - lpSrcRect->left, lpSrcRect->bottom - lpSrcRect->top };
|
||||||
|
result = s_origVtable.Blt(This, lpDestRect, mirroredSrcSurface, &srcRect, flags, &fx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = s_origVtable.Blt(This, lpDestRect, mirroredSrcSurface, nullptr, flags, &fx);
|
||||||
|
}
|
||||||
|
|
||||||
|
s_origVtable.Release(mirroredSrcSurface);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = s_origVtable.Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
RealPrimarySurface::update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::BltFast(
|
||||||
|
TSurface* This,
|
||||||
|
DWORD dwX,
|
||||||
|
DWORD dwY,
|
||||||
|
TSurface* lpDDSrcSurface,
|
||||||
|
LPRECT lpSrcRect,
|
||||||
|
DWORD dwTrans)
|
||||||
|
{
|
||||||
|
if ((This == s_compatPrimarySurface || lpDDSrcSurface == s_compatPrimarySurface) &&
|
||||||
|
RealPrimarySurface::isLost())
|
||||||
|
{
|
||||||
|
return DDERR_SURFACELOST;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT result = s_origVtable.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
|
||||||
|
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
RealPrimarySurface::update();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Flip(
|
||||||
|
TSurface* This,
|
||||||
|
TSurface* lpDDSurfaceTargetOverride,
|
||||||
|
DWORD dwFlags)
|
||||||
|
{
|
||||||
|
HRESULT result = s_origVtable.Flip(This, lpDDSurfaceTargetOverride, dwFlags);
|
||||||
|
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
result = RealPrimarySurface::flip(dwFlags);
|
||||||
|
updateSurfaceParams();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::GetCaps(
|
||||||
|
TSurface* This,
|
||||||
|
TDdsCaps* lpDDSCaps)
|
||||||
|
{
|
||||||
|
HRESULT result = s_origVtable.GetCaps(This, lpDDSCaps);
|
||||||
|
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
restorePrimaryCaps(*lpDDSCaps);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::GetSurfaceDesc(
|
||||||
|
TSurface* This,
|
||||||
|
TSurfaceDesc* lpDDSurfaceDesc)
|
||||||
|
{
|
||||||
|
HRESULT result = s_origVtable.GetSurfaceDesc(This, lpDDSurfaceDesc);
|
||||||
|
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
restorePrimaryCaps(lpDDSurfaceDesc->ddsCaps);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::IsLost(TSurface* This)
|
||||||
|
{
|
||||||
|
HRESULT result = s_origVtable.IsLost(This);
|
||||||
|
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
result = RealPrimarySurface::isLost() ? DDERR_SURFACELOST : DD_OK;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Lock(
|
||||||
|
TSurface* This,
|
||||||
|
LPRECT lpDestRect,
|
||||||
|
TSurfaceDesc* lpDDSurfaceDesc,
|
||||||
|
DWORD dwFlags,
|
||||||
|
HANDLE hEvent)
|
||||||
|
{
|
||||||
|
if (This == s_compatPrimarySurface && RealPrimarySurface::isLost())
|
||||||
|
{
|
||||||
|
return DDERR_SURFACELOST;
|
||||||
|
}
|
||||||
|
return s_origVtable.Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::QueryInterface(
|
||||||
|
TSurface* This,
|
||||||
|
REFIID riid,
|
||||||
|
LPVOID* obp)
|
||||||
|
{
|
||||||
|
if (This == s_compatPrimarySurface && riid == IID_IDirectDrawGammaControl)
|
||||||
|
{
|
||||||
|
return RealPrimarySurface::getSurface()->lpVtbl->QueryInterface(
|
||||||
|
RealPrimarySurface::getSurface(), riid, obp);
|
||||||
|
}
|
||||||
|
return s_origVtable.QueryInterface(This, riid, obp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::ReleaseDC(TSurface* This, HDC hDC)
|
||||||
|
{
|
||||||
|
if (This == s_compatPrimarySurface && RealPrimarySurface::isLost())
|
||||||
|
{
|
||||||
|
return DDERR_SURFACELOST;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT result = s_origVtable.ReleaseDC(This, hDC);
|
||||||
|
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
RealPrimarySurface::update();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Restore(TSurface* This)
|
||||||
|
{
|
||||||
|
const bool wasLost = DDERR_SURFACELOST == s_origVtable.IsLost(This);
|
||||||
|
HRESULT result = s_origVtable.Restore(This);
|
||||||
|
if (SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
if (wasLost)
|
||||||
|
{
|
||||||
|
fixSurfacePtrs(*This);
|
||||||
|
}
|
||||||
|
if (This == s_compatPrimarySurface)
|
||||||
|
{
|
||||||
|
result = RealPrimarySurface::restore();
|
||||||
|
if (wasLost)
|
||||||
|
{
|
||||||
|
updateSurfaceParams();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::SetClipper(
|
||||||
|
TSurface* This,
|
||||||
|
LPDIRECTDRAWCLIPPER lpDDClipper)
|
||||||
|
{
|
||||||
|
HRESULT result = s_origVtable.SetClipper(This, lpDDClipper);
|
||||||
|
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
RealPrimarySurface::setClipper(lpDDClipper);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::SetPalette(
|
||||||
|
TSurface* This,
|
||||||
|
LPDIRECTDRAWPALETTE lpDDPalette)
|
||||||
|
{
|
||||||
|
HRESULT result = s_origVtable.SetPalette(This, lpDDPalette);
|
||||||
|
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
CompatPrimarySurface::palette = lpDDPalette;
|
||||||
|
RealPrimarySurface::setPalette(lpDDPalette);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::Unlock(TSurface* This, TUnlockParam lpRect)
|
||||||
|
{
|
||||||
|
HRESULT result = s_origVtable.Unlock(This, lpRect);
|
||||||
|
if (This == s_compatPrimarySurface && SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
RealPrimarySurface::update();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
void CompatDirectDrawSurface<TSurface>::initCompatPrimarySurface()
|
||||||
|
{
|
||||||
|
Compat::LogEnter("CompatDirectDrawSurface::initCompatPrimarySurface");
|
||||||
|
|
||||||
|
IUnknown& unk = reinterpret_cast<IUnknown&>(*s_compatPrimarySurface);
|
||||||
|
CompatDirectDrawSurface<IDirectDrawSurface>::initPrimarySurfacePtr(IID_IDirectDrawSurface, unk);
|
||||||
|
CompatDirectDrawSurface<IDirectDrawSurface2>::initPrimarySurfacePtr(IID_IDirectDrawSurface2, unk);
|
||||||
|
CompatDirectDrawSurface<IDirectDrawSurface3>::initPrimarySurfacePtr(IID_IDirectDrawSurface3, unk);
|
||||||
|
CompatDirectDrawSurface<IDirectDrawSurface4>::initPrimarySurfacePtr(IID_IDirectDrawSurface4, unk);
|
||||||
|
CompatDirectDrawSurface<IDirectDrawSurface7>::initPrimarySurfacePtr(IID_IDirectDrawSurface7, unk);
|
||||||
|
|
||||||
|
if (SUCCEEDED(s_origVtable.QueryInterface(
|
||||||
|
s_compatPrimarySurface,
|
||||||
|
IID_IDirectDrawSurface7,
|
||||||
|
reinterpret_cast<LPVOID*>(&CompatPrimarySurface::surface))))
|
||||||
|
{
|
||||||
|
IReleaseNotifier* releaseNotifier = &CompatPrimarySurface::releaseNotifier;
|
||||||
|
CompatPrimarySurface::surface->lpVtbl->SetPrivateData(CompatPrimarySurface::surface,
|
||||||
|
IID_IReleaseNotifier, releaseNotifier, sizeof(releaseNotifier), DDSPD_IUNKNOWNPOINTER);
|
||||||
|
CompatPrimarySurface::surface->lpVtbl->Release(CompatPrimarySurface::surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
Compat::LogLeave("CompatDirectDrawSurface::initCompatPrimarySurface");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
void CompatDirectDrawSurface<TSurface>::restorePrimaryCaps(TDdsCaps& caps)
|
||||||
|
{
|
||||||
|
caps.dwCaps ^= DDSCAPS_OFFSCREENPLAIN;
|
||||||
|
caps.dwCaps |= DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
void CompatDirectDrawSurface<TSurface>::updateSurfaceParams()
|
||||||
|
{
|
||||||
|
TSurfaceDesc desc = {};
|
||||||
|
desc.dwSize = sizeof(desc);
|
||||||
|
if (SUCCEEDED(s_origVtable.Lock(s_compatPrimarySurface, nullptr, &desc, DDLOCK_WAIT, nullptr)))
|
||||||
|
{
|
||||||
|
s_origVtable.Unlock(s_compatPrimarySurface, nullptr);
|
||||||
|
CompatPrimarySurface::pitch = desc.lPitch;
|
||||||
|
CompatPrimarySurface::surfacePtr = desc.lpSurface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
TSurface* CompatDirectDrawSurface<TSurface>::s_compatPrimarySurface = nullptr;
|
||||||
|
|
||||||
|
template <> const IID& CompatDirectDrawSurface<IDirectDrawSurface>::s_iid = IID_IDirectDrawSurface;
|
||||||
|
template <> const IID& CompatDirectDrawSurface<IDirectDrawSurface2>::s_iid = IID_IDirectDrawSurface2;
|
||||||
|
template <> const IID& CompatDirectDrawSurface<IDirectDrawSurface3>::s_iid = IID_IDirectDrawSurface3;
|
||||||
|
template <> const IID& CompatDirectDrawSurface<IDirectDrawSurface4>::s_iid = IID_IDirectDrawSurface4;
|
||||||
|
template <> const IID& CompatDirectDrawSurface<IDirectDrawSurface7>::s_iid = IID_IDirectDrawSurface7;
|
||||||
|
|
||||||
|
template CompatDirectDrawSurface<IDirectDrawSurface>;
|
||||||
|
template CompatDirectDrawSurface<IDirectDrawSurface2>;
|
||||||
|
template CompatDirectDrawSurface<IDirectDrawSurface3>;
|
||||||
|
template CompatDirectDrawSurface<IDirectDrawSurface4>;
|
||||||
|
template CompatDirectDrawSurface<IDirectDrawSurface7>;
|
||||||
|
|
||||||
|
template HRESULT CompatDirectDrawSurface<IDirectDrawSurface>::createCompatPrimarySurface(
|
||||||
|
IDirectDraw& dd,
|
||||||
|
TSurfaceDesc compatDesc,
|
||||||
|
IDirectDrawSurface*& compatSurface);
|
||||||
|
template HRESULT CompatDirectDrawSurface<IDirectDrawSurface>::createCompatPrimarySurface(
|
||||||
|
IDirectDraw2& dd,
|
||||||
|
TSurfaceDesc compatDesc,
|
||||||
|
IDirectDrawSurface*& compatSurface);
|
||||||
|
template HRESULT CompatDirectDrawSurface<IDirectDrawSurface4>::createCompatPrimarySurface(
|
||||||
|
IDirectDraw4& dd,
|
||||||
|
TSurfaceDesc compatDesc,
|
||||||
|
IDirectDrawSurface4*& compatSurface);
|
||||||
|
template HRESULT CompatDirectDrawSurface<IDirectDrawSurface7>::createCompatPrimarySurface(
|
||||||
|
IDirectDraw7& dd,
|
||||||
|
TSurfaceDesc compatDesc,
|
||||||
|
IDirectDrawSurface7*& compatSurface);
|
72
DDrawCompat/CompatDirectDrawSurface.h
Normal file
72
DDrawCompat/CompatDirectDrawSurface.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CompatVtable.h"
|
||||||
|
#include "DDrawTypes.h"
|
||||||
|
#include "DirectDrawSurfaceVtblVisitor.h"
|
||||||
|
|
||||||
|
template <typename TSurface>
|
||||||
|
class CompatDirectDrawSurface : public CompatVtable<CompatDirectDrawSurface<TSurface>, TSurface>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename Types<TSurface>::TSurfaceDesc TSurfaceDesc;
|
||||||
|
typedef typename Types<TSurface>::TDdsCaps TDdsCaps;
|
||||||
|
typedef typename Types<TSurface>::TUnlockParam TUnlockParam;
|
||||||
|
|
||||||
|
static void setCompatVtable(Vtable<TSurface>& vtable);
|
||||||
|
|
||||||
|
template <typename TDirectDraw>
|
||||||
|
static HRESULT createCompatPrimarySurface(
|
||||||
|
TDirectDraw& dd,
|
||||||
|
TSurfaceDesc compatDesc,
|
||||||
|
TSurface*& compatSurface);
|
||||||
|
|
||||||
|
static void fixSurfacePtrs(TSurface& surface);
|
||||||
|
static void initPrimarySurfacePtr(const GUID& guid, IUnknown& surface);
|
||||||
|
static void updateSurfaceParams();
|
||||||
|
|
||||||
|
static HRESULT STDMETHODCALLTYPE Blt(
|
||||||
|
TSurface* This,
|
||||||
|
LPRECT lpDestRect,
|
||||||
|
TSurface* lpDDSrcSurface,
|
||||||
|
LPRECT lpSrcRect,
|
||||||
|
DWORD dwFlags,
|
||||||
|
LPDDBLTFX lpDDBltFx);
|
||||||
|
|
||||||
|
static HRESULT STDMETHODCALLTYPE BltFast(
|
||||||
|
TSurface* This,
|
||||||
|
DWORD dwX,
|
||||||
|
DWORD dwY,
|
||||||
|
TSurface* lpDDSrcSurface,
|
||||||
|
LPRECT lpSrcRect,
|
||||||
|
DWORD dwTrans);
|
||||||
|
|
||||||
|
static HRESULT STDMETHODCALLTYPE Flip(
|
||||||
|
TSurface* This,
|
||||||
|
TSurface* lpDDSurfaceTargetOverride,
|
||||||
|
DWORD dwFlags);
|
||||||
|
|
||||||
|
static HRESULT STDMETHODCALLTYPE GetCaps(TSurface* This, TDdsCaps* lpDDSCaps);
|
||||||
|
static HRESULT STDMETHODCALLTYPE GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc);
|
||||||
|
static HRESULT STDMETHODCALLTYPE IsLost(TSurface* This);
|
||||||
|
|
||||||
|
static HRESULT STDMETHODCALLTYPE Lock(
|
||||||
|
TSurface* This,
|
||||||
|
LPRECT lpDestRect,
|
||||||
|
TSurfaceDesc* lpDDSurfaceDesc,
|
||||||
|
DWORD dwFlags,
|
||||||
|
HANDLE hEvent);
|
||||||
|
|
||||||
|
static HRESULT STDMETHODCALLTYPE QueryInterface(TSurface* This, REFIID riid, LPVOID* obp);
|
||||||
|
static HRESULT STDMETHODCALLTYPE ReleaseDC(TSurface* This, HDC hDC);
|
||||||
|
static HRESULT STDMETHODCALLTYPE Restore(TSurface* This);
|
||||||
|
static HRESULT STDMETHODCALLTYPE SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper);
|
||||||
|
static HRESULT STDMETHODCALLTYPE SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette);
|
||||||
|
static HRESULT STDMETHODCALLTYPE Unlock(TSurface* This, TUnlockParam lpRect);
|
||||||
|
|
||||||
|
static const IID& s_iid;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void initCompatPrimarySurface();
|
||||||
|
static void restorePrimaryCaps(TDdsCaps& caps);
|
||||||
|
static TSurface* s_compatPrimarySurface;
|
||||||
|
};
|
537
DDrawCompat/CompatGdiSurface.cpp
Normal file
537
DDrawCompat/CompatGdiSurface.cpp
Normal file
@ -0,0 +1,537 @@
|
|||||||
|
#define CINTERFACE
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <oleacc.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <detours.h>
|
||||||
|
|
||||||
|
#include "CompatDirectDraw.h"
|
||||||
|
#include "CompatDirectDrawSurface.h"
|
||||||
|
#include "CompatGdiSurface.h"
|
||||||
|
#include "CompatPrimarySurface.h"
|
||||||
|
#include "DDrawLog.h"
|
||||||
|
#include "DDrawProcs.h"
|
||||||
|
#include "RealPrimarySurface.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct CaretData
|
||||||
|
{
|
||||||
|
HWND hwnd;
|
||||||
|
long left;
|
||||||
|
long top;
|
||||||
|
long width;
|
||||||
|
long height;
|
||||||
|
bool isDrawn;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GdiSurface
|
||||||
|
{
|
||||||
|
IDirectDrawSurface7* surface;
|
||||||
|
HDC origDc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExcludeClipRectsData
|
||||||
|
{
|
||||||
|
HDC compatDc;
|
||||||
|
POINT clientOrigin;
|
||||||
|
HWND rootWnd;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool g_suppressGdiHooks = false;
|
||||||
|
|
||||||
|
class HookRecursionGuard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HookRecursionGuard()
|
||||||
|
{
|
||||||
|
g_suppressGdiHooks = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
~HookRecursionGuard()
|
||||||
|
{
|
||||||
|
g_suppressGdiHooks = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto g_origGetDc = &GetDC;
|
||||||
|
auto g_origGetDcEx = &GetDCEx;
|
||||||
|
auto g_origGetWindowDc = &GetWindowDC;
|
||||||
|
auto g_origReleaseDc = &ReleaseDC;
|
||||||
|
auto g_origBeginPaint = &BeginPaint;
|
||||||
|
auto g_origEndPaint = &EndPaint;
|
||||||
|
|
||||||
|
auto g_origCreateCaret = &CreateCaret;
|
||||||
|
auto g_origShowCaret = &ShowCaret;
|
||||||
|
auto g_origHideCaret = &HideCaret;
|
||||||
|
|
||||||
|
IDirectDraw7* g_directDraw = nullptr;
|
||||||
|
std::unordered_map<HDC, GdiSurface> g_dcToSurface;
|
||||||
|
|
||||||
|
CaretData g_caret = {};
|
||||||
|
|
||||||
|
POINT getClientOrigin(HWND hwnd);
|
||||||
|
HDC getCompatDc(HWND hwnd, HDC origDc, const POINT& origin);
|
||||||
|
HDC releaseCompatDc(HDC hdc);
|
||||||
|
|
||||||
|
LRESULT CALLBACK callWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
if (HC_ACTION == nCode)
|
||||||
|
{
|
||||||
|
auto ret = reinterpret_cast<CWPRETSTRUCT*>(lParam);
|
||||||
|
if (WM_WINDOWPOSCHANGED == ret->message)
|
||||||
|
{
|
||||||
|
InvalidateRect(nullptr, nullptr, TRUE);
|
||||||
|
}
|
||||||
|
else if (WM_ERASEBKGND == ret->message && ret->lResult)
|
||||||
|
{
|
||||||
|
HDC origDc = reinterpret_cast<HDC>(ret->wParam);
|
||||||
|
if (g_dcToSurface.find(origDc) == g_dcToSurface.end())
|
||||||
|
{
|
||||||
|
HWND hwnd = WindowFromDC(origDc);
|
||||||
|
POINT origin = {};
|
||||||
|
ClientToScreen(hwnd, &origin);
|
||||||
|
|
||||||
|
HDC compatDc = getCompatDc(hwnd, origDc, origin);
|
||||||
|
if (compatDc != origDc)
|
||||||
|
{
|
||||||
|
SendMessage(hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(compatDc), 0);
|
||||||
|
releaseCompatDc(compatDc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CallNextHookEx(nullptr, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
IDirectDraw7* createDirectDraw()
|
||||||
|
{
|
||||||
|
IDirectDraw7* dd = nullptr;
|
||||||
|
CALL_ORIG_DDRAW(DirectDrawCreateEx, nullptr, reinterpret_cast<LPVOID*>(&dd), IID_IDirectDraw7, nullptr);
|
||||||
|
if (!dd)
|
||||||
|
{
|
||||||
|
Compat::Log() << "Failed to create a DirectDraw interface for GDI";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(CompatDirectDraw<IDirectDraw7>::s_origVtable.SetCooperativeLevel(dd, nullptr, DDSCL_NORMAL)))
|
||||||
|
{
|
||||||
|
Compat::Log() << "Failed to set the cooperative level on the DirectDraw interface for GDI";
|
||||||
|
dd->lpVtbl->Release(dd);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dd;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDirectDrawSurface7* createGdiSurface()
|
||||||
|
{
|
||||||
|
DDSURFACEDESC2 desc = {};
|
||||||
|
desc.dwSize = sizeof(desc);
|
||||||
|
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_PITCH | DDSD_LPSURFACE;
|
||||||
|
desc.dwWidth = CompatPrimarySurface::width;
|
||||||
|
desc.dwHeight = CompatPrimarySurface::height;
|
||||||
|
desc.ddpfPixelFormat = CompatPrimarySurface::pixelFormat;
|
||||||
|
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
||||||
|
desc.lPitch = CompatPrimarySurface::pitch;
|
||||||
|
desc.lpSurface = CompatPrimarySurface::surfacePtr;
|
||||||
|
|
||||||
|
IDirectDrawSurface7* surface = nullptr;
|
||||||
|
HRESULT result = CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(
|
||||||
|
g_directDraw, &desc, &surface, nullptr);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
LOG_ONCE("Failed to create a GDI surface: " << result);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CompatPrimarySurface::palette)
|
||||||
|
{
|
||||||
|
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetPalette(
|
||||||
|
surface, CompatPrimarySurface::palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CALLBACK excludeClipRectsForOverlappingWindows(HWND hwnd, LPARAM lParam)
|
||||||
|
{
|
||||||
|
auto excludeClipRectsData = reinterpret_cast<ExcludeClipRectsData*>(lParam);
|
||||||
|
if (hwnd == excludeClipRectsData->rootWnd)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
RECT rect = {};
|
||||||
|
GetWindowRect(hwnd, &rect);
|
||||||
|
OffsetRect(&rect, -excludeClipRectsData->clientOrigin.x, -excludeClipRectsData->clientOrigin.y);
|
||||||
|
ExcludeClipRect(excludeClipRectsData->compatDc, rect.left, rect.top, rect.right, rect.bottom);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
POINT getClientOrigin(HWND hwnd)
|
||||||
|
{
|
||||||
|
POINT origin = {};
|
||||||
|
if (hwnd)
|
||||||
|
{
|
||||||
|
ClientToScreen(hwnd, &origin);
|
||||||
|
}
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
HDC getCompatDc(HWND hwnd, HDC origDc, const POINT& origin)
|
||||||
|
{
|
||||||
|
if (!CompatPrimarySurface::surfacePtr || !origDc || !RealPrimarySurface::isFullScreen() || g_suppressGdiHooks)
|
||||||
|
{
|
||||||
|
return origDc;
|
||||||
|
}
|
||||||
|
|
||||||
|
HookRecursionGuard recursionGuard;
|
||||||
|
|
||||||
|
IDirectDrawSurface7* surface = createGdiSurface();
|
||||||
|
if (!surface)
|
||||||
|
{
|
||||||
|
return origDc;
|
||||||
|
}
|
||||||
|
|
||||||
|
HDC compatDc = nullptr;
|
||||||
|
HRESULT result = surface->lpVtbl->GetDC(surface, &compatDc);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
LOG_ONCE("Failed to create a GDI DC: " << result);
|
||||||
|
surface->lpVtbl->Release(surface);
|
||||||
|
return origDc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwnd)
|
||||||
|
{
|
||||||
|
SetWindowOrgEx(compatDc, -origin.x, -origin.y, nullptr);
|
||||||
|
|
||||||
|
HRGN clipRgn = CreateRectRgn(0, 0, 0, 0);
|
||||||
|
GetRandomRgn(origDc, clipRgn, SYSRGN);
|
||||||
|
SelectClipRgn(compatDc, clipRgn);
|
||||||
|
RECT r = {};
|
||||||
|
GetRgnBox(clipRgn, &r);
|
||||||
|
DeleteObject(clipRgn);
|
||||||
|
|
||||||
|
ExcludeClipRectsData excludeClipRectsData = { compatDc, origin, GetAncestor(hwnd, GA_ROOT) };
|
||||||
|
EnumThreadWindows(GetCurrentThreadId(), &excludeClipRectsForOverlappingWindows,
|
||||||
|
reinterpret_cast<LPARAM>(&excludeClipRectsData));
|
||||||
|
}
|
||||||
|
|
||||||
|
GdiSurface gdiSurface = { surface, origDc };
|
||||||
|
g_dcToSurface[compatDc] = gdiSurface;
|
||||||
|
|
||||||
|
// Release DD critical section acquired by IDirectDrawSurface7::GetDC to avoid deadlocks
|
||||||
|
Compat::origProcs.ReleaseDDThreadLock();
|
||||||
|
|
||||||
|
return compatDc;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
POINT getWindowOrigin(HWND hwnd)
|
||||||
|
{
|
||||||
|
POINT origin = {};
|
||||||
|
if (hwnd)
|
||||||
|
{
|
||||||
|
RECT windowRect = {};
|
||||||
|
GetWindowRect(hwnd, &windowRect);
|
||||||
|
origin.x = windowRect.left;
|
||||||
|
origin.y = windowRect.top;
|
||||||
|
}
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FuncPtr>
|
||||||
|
void hookGdiFunction(const char* funcName, FuncPtr& origFuncPtr, FuncPtr newFuncPtr)
|
||||||
|
{
|
||||||
|
origFuncPtr = reinterpret_cast<FuncPtr>(getProcAddress(GetModuleHandle("user32"), funcName));
|
||||||
|
DetourAttach(reinterpret_cast<void**>(&origFuncPtr), newFuncPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
HDC releaseCompatDc(HDC hdc)
|
||||||
|
{
|
||||||
|
if (g_suppressGdiHooks)
|
||||||
|
{
|
||||||
|
return hdc;
|
||||||
|
}
|
||||||
|
|
||||||
|
HookRecursionGuard recursionGuard;
|
||||||
|
|
||||||
|
auto it = g_dcToSurface.find(hdc);
|
||||||
|
|
||||||
|
if (it != g_dcToSurface.end())
|
||||||
|
{
|
||||||
|
// Reacquire DD critical section that was temporarily released after IDirectDrawSurface7::GetDC
|
||||||
|
Compat::origProcs.AcquireDDThreadLock();
|
||||||
|
|
||||||
|
if (FAILED(it->second.surface->lpVtbl->ReleaseDC(it->second.surface, hdc)))
|
||||||
|
{
|
||||||
|
Compat::origProcs.ReleaseDDThreadLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
it->second.surface->lpVtbl->Release(it->second.surface);
|
||||||
|
|
||||||
|
HDC origDc = it->second.origDc;
|
||||||
|
g_dcToSurface.erase(it);
|
||||||
|
|
||||||
|
RealPrimarySurface::update();
|
||||||
|
return origDc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hdc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawCaret()
|
||||||
|
{
|
||||||
|
HDC dc = GetDC(g_caret.hwnd);
|
||||||
|
PatBlt(dc, g_caret.left, g_caret.top, g_caret.width, g_caret.height, PATINVERT);
|
||||||
|
ReleaseDC(g_caret.hwnd, dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
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*/)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HDC WINAPI getDc(HWND hWnd)
|
||||||
|
{
|
||||||
|
Compat::origProcs.AcquireDDThreadLock();
|
||||||
|
Compat::LogEnter("GetDC", hWnd);
|
||||||
|
|
||||||
|
HDC compatDc = getCompatDc(hWnd, g_origGetDc(hWnd), getClientOrigin(hWnd));
|
||||||
|
|
||||||
|
Compat::LogLeave("GetDC", hWnd) << compatDc;
|
||||||
|
Compat::origProcs.ReleaseDDThreadLock();
|
||||||
|
return compatDc;
|
||||||
|
}
|
||||||
|
|
||||||
|
HDC WINAPI getDcEx(HWND hWnd, HRGN hrgnClip, DWORD flags)
|
||||||
|
{
|
||||||
|
Compat::origProcs.AcquireDDThreadLock();
|
||||||
|
Compat::LogEnter("GetDCEx", hWnd);
|
||||||
|
|
||||||
|
HDC compatDc = getCompatDc(hWnd, g_origGetDcEx(hWnd, hrgnClip, flags),
|
||||||
|
flags & (DCX_WINDOW | DCX_PARENTCLIP) ? getWindowOrigin(hWnd) : getClientOrigin(hWnd));
|
||||||
|
|
||||||
|
Compat::LogLeave("GetDCEx", hWnd) << compatDc;
|
||||||
|
Compat::origProcs.ReleaseDDThreadLock();
|
||||||
|
return compatDc;
|
||||||
|
}
|
||||||
|
|
||||||
|
HDC WINAPI getWindowDc(HWND hWnd)
|
||||||
|
{
|
||||||
|
Compat::origProcs.AcquireDDThreadLock();
|
||||||
|
Compat::LogEnter("GetWindowDC", hWnd);
|
||||||
|
|
||||||
|
HDC compatDc = getCompatDc(hWnd, g_origGetWindowDc(hWnd), getWindowOrigin(hWnd));
|
||||||
|
|
||||||
|
Compat::LogLeave("GetWindowDC", hWnd) << compatDc;
|
||||||
|
Compat::origProcs.ReleaseDDThreadLock();
|
||||||
|
return compatDc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WINAPI releaseDc(HWND hWnd, HDC hDC)
|
||||||
|
{
|
||||||
|
Compat::origProcs.AcquireDDThreadLock();
|
||||||
|
Compat::LogEnter("ReleaseDC", hWnd, hDC);
|
||||||
|
|
||||||
|
int result = g_origReleaseDc(hWnd, releaseCompatDc(hDC));
|
||||||
|
|
||||||
|
Compat::LogLeave("ReleaseDC", hWnd, hDC) << result;
|
||||||
|
Compat::origProcs.ReleaseDDThreadLock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
HDC WINAPI beginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint)
|
||||||
|
{
|
||||||
|
Compat::origProcs.AcquireDDThreadLock();
|
||||||
|
Compat::LogEnter("BeginPaint", hWnd, lpPaint);
|
||||||
|
|
||||||
|
HDC compatDc = getCompatDc(hWnd, g_origBeginPaint(hWnd, lpPaint), getClientOrigin(hWnd));
|
||||||
|
lpPaint->hdc = compatDc;
|
||||||
|
|
||||||
|
Compat::LogLeave("BeginPaint", hWnd, lpPaint) << compatDc;
|
||||||
|
Compat::origProcs.ReleaseDDThreadLock();
|
||||||
|
return compatDc;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI endPaint(HWND hWnd, const PAINTSTRUCT* lpPaint)
|
||||||
|
{
|
||||||
|
Compat::origProcs.AcquireDDThreadLock();
|
||||||
|
Compat::LogEnter("EndPaint", hWnd, lpPaint);
|
||||||
|
|
||||||
|
BOOL result = FALSE;
|
||||||
|
if (lpPaint)
|
||||||
|
{
|
||||||
|
PAINTSTRUCT paint = *lpPaint;
|
||||||
|
paint.hdc = releaseCompatDc(lpPaint->hdc);
|
||||||
|
result = g_origEndPaint(hWnd, &paint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = g_origEndPaint(hWnd, lpPaint);
|
||||||
|
}
|
||||||
|
|
||||||
|
Compat::LogLeave("EndPaint", hWnd, lpPaint) << result;
|
||||||
|
Compat::origProcs.ReleaseDDThreadLock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI createCaret(HWND hWnd, HBITMAP hBitmap, int nWidth, int nHeight)
|
||||||
|
{
|
||||||
|
BOOL result = g_origCreateCaret(hWnd, hBitmap, nWidth, nHeight);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
BOOL result = g_origShowCaret(hWnd);
|
||||||
|
if (result && !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 result;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI hideCaret(HWND hWnd)
|
||||||
|
{
|
||||||
|
BOOL result = g_origHideCaret(hWnd);
|
||||||
|
if (result && g_caret.isDrawn)
|
||||||
|
{
|
||||||
|
drawCaret();
|
||||||
|
g_caret.isDrawn = false;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatGdiSurface::hookGdi()
|
||||||
|
{
|
||||||
|
static bool alreadyHooked = false;
|
||||||
|
if (alreadyHooked)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_directDraw = createDirectDraw();
|
||||||
|
if (g_directDraw)
|
||||||
|
{
|
||||||
|
DetourTransactionBegin();
|
||||||
|
hookGdiFunction("GetDC", g_origGetDc, &getDc);
|
||||||
|
hookGdiFunction("GetDCEx", g_origGetDcEx, &getDcEx);
|
||||||
|
hookGdiFunction("GetWindowDC", g_origGetWindowDc, &getWindowDc);
|
||||||
|
hookGdiFunction("ReleaseDC", g_origReleaseDc, &releaseDc);
|
||||||
|
hookGdiFunction("BeginPaint", g_origBeginPaint, &beginPaint);
|
||||||
|
hookGdiFunction("EndPaint", g_origEndPaint, &endPaint);
|
||||||
|
hookGdiFunction("CreateCaret", g_origCreateCaret, &createCaret);
|
||||||
|
hookGdiFunction("ShowCaret", g_origShowCaret, &showCaret);
|
||||||
|
hookGdiFunction("HideCaret", g_origHideCaret, &hideCaret);
|
||||||
|
DetourTransactionCommit();
|
||||||
|
|
||||||
|
DWORD threadId = GetCurrentThreadId();
|
||||||
|
SetWindowsHookEx(WH_CALLWNDPROCRET, callWndRetProc, nullptr, threadId);
|
||||||
|
SetWinEventHook(EVENT_OBJECT_DESTROY, EVENT_OBJECT_DESTROY,
|
||||||
|
nullptr, &caretDestroyEvent, 0, threadId, WINEVENT_OUTOFCONTEXT);
|
||||||
|
}
|
||||||
|
alreadyHooked = true;
|
||||||
|
}
|
7
DDrawCompat/CompatGdiSurface.h
Normal file
7
DDrawCompat/CompatGdiSurface.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CompatGdiSurface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void hookGdi();
|
||||||
|
};
|
51
DDrawCompat/CompatPrimarySurface.cpp
Normal file
51
DDrawCompat/CompatPrimarySurface.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include "CompatDirectDraw.h"
|
||||||
|
#include "CompatPrimarySurface.h"
|
||||||
|
#include "IReleaseNotifier.h"
|
||||||
|
#include "RealPrimarySurface.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void onRelease()
|
||||||
|
{
|
||||||
|
CompatPrimarySurface::surface = nullptr;
|
||||||
|
CompatPrimarySurface::palette = nullptr;
|
||||||
|
CompatPrimarySurface::width = 0;
|
||||||
|
CompatPrimarySurface::height = 0;
|
||||||
|
ZeroMemory(&CompatPrimarySurface::pixelFormat, sizeof(CompatPrimarySurface::pixelFormat));
|
||||||
|
CompatPrimarySurface::pitch = 0;
|
||||||
|
CompatPrimarySurface::surfacePtr = nullptr;
|
||||||
|
|
||||||
|
RealPrimarySurface::release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CompatPrimarySurface
|
||||||
|
{
|
||||||
|
template <typename TDirectDraw>
|
||||||
|
DisplayMode getDisplayMode(TDirectDraw& dd)
|
||||||
|
{
|
||||||
|
DisplayMode dm = {};
|
||||||
|
typename CompatDirectDraw<TDirectDraw>::TSurfaceDesc desc = {};
|
||||||
|
desc.dwSize = sizeof(desc);
|
||||||
|
CompatDirectDraw<TDirectDraw>::s_origVtable.GetDisplayMode(&dd, &desc);
|
||||||
|
dm.width = desc.dwWidth;
|
||||||
|
dm.height = desc.dwHeight;
|
||||||
|
dm.pixelFormat = desc.ddpfPixelFormat;
|
||||||
|
return dm;
|
||||||
|
}
|
||||||
|
|
||||||
|
template DisplayMode getDisplayMode(IDirectDraw& dd);
|
||||||
|
template DisplayMode getDisplayMode(IDirectDraw2& dd);
|
||||||
|
template DisplayMode getDisplayMode(IDirectDraw4& dd);
|
||||||
|
template DisplayMode getDisplayMode(IDirectDraw7& dd);
|
||||||
|
|
||||||
|
DisplayMode displayMode = {};
|
||||||
|
IDirectDrawSurface7* surface = nullptr;
|
||||||
|
LPDIRECTDRAWPALETTE palette = nullptr;
|
||||||
|
LONG width = 0;
|
||||||
|
LONG height = 0;
|
||||||
|
DDPIXELFORMAT pixelFormat = {};
|
||||||
|
LONG pitch = 0;
|
||||||
|
void* surfacePtr = nullptr;
|
||||||
|
IReleaseNotifier releaseNotifier(onRelease);
|
||||||
|
}
|
30
DDrawCompat/CompatPrimarySurface.h
Normal file
30
DDrawCompat/CompatPrimarySurface.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define CINTERFACE
|
||||||
|
|
||||||
|
#include <ddraw.h>
|
||||||
|
|
||||||
|
class IReleaseNotifier;
|
||||||
|
|
||||||
|
namespace CompatPrimarySurface
|
||||||
|
{
|
||||||
|
struct DisplayMode
|
||||||
|
{
|
||||||
|
LONG width;
|
||||||
|
LONG height;
|
||||||
|
DDPIXELFORMAT pixelFormat;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TDirectDraw>
|
||||||
|
DisplayMode getDisplayMode(TDirectDraw& dd);
|
||||||
|
|
||||||
|
extern DisplayMode displayMode;
|
||||||
|
extern IDirectDrawSurface7* surface;
|
||||||
|
extern LPDIRECTDRAWPALETTE palette;
|
||||||
|
extern LONG width;
|
||||||
|
extern LONG height;
|
||||||
|
extern DDPIXELFORMAT pixelFormat;
|
||||||
|
extern LONG pitch;
|
||||||
|
extern void* surfacePtr;
|
||||||
|
extern IReleaseNotifier releaseNotifier;
|
||||||
|
}
|
6
DDrawCompat/CompatVtable.cpp
Normal file
6
DDrawCompat/CompatVtable.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include "CompatVtable.h"
|
||||||
|
|
||||||
|
namespace Compat
|
||||||
|
{
|
||||||
|
std::map<void*, DetouredMethodInfo> detouredMethods;
|
||||||
|
}
|
175
DDrawCompat/CompatVtable.h
Normal file
175
DDrawCompat/CompatVtable.h
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <detours.h>
|
||||||
|
|
||||||
|
#include "DDrawLog.h"
|
||||||
|
#include "DDrawVtableVisitor.h"
|
||||||
|
|
||||||
|
template <typename Interface>
|
||||||
|
using Vtable = typename std::remove_pointer<decltype(Interface::lpVtbl)>::type;
|
||||||
|
|
||||||
|
namespace Compat
|
||||||
|
{
|
||||||
|
struct DetouredMethodInfo
|
||||||
|
{
|
||||||
|
DetouredMethodInfo(void*& updatedOrigMethodPtr, std::map<void*, void*>& vtablePtrToCompatVtable)
|
||||||
|
: updatedOrigMethodPtr(updatedOrigMethodPtr), vtablePtrToCompatVtable(vtablePtrToCompatVtable)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void*& updatedOrigMethodPtr;
|
||||||
|
std::map<void*, void*>& vtablePtrToCompatVtable;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern std::map<void*, DetouredMethodInfo> detouredMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CompatInterface, typename Interface>
|
||||||
|
class CompatVtable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef Interface Interface;
|
||||||
|
|
||||||
|
static void hookVtable(Interface& intf)
|
||||||
|
{
|
||||||
|
static bool isInitialized = false;
|
||||||
|
if (!isInitialized)
|
||||||
|
{
|
||||||
|
isInitialized = true;
|
||||||
|
|
||||||
|
s_vtablePtr = intf.lpVtbl;
|
||||||
|
s_origVtable = *intf.lpVtbl;
|
||||||
|
|
||||||
|
DetourTransactionBegin();
|
||||||
|
InitVisitor visitor;
|
||||||
|
forEach<Vtable<Interface>>(visitor);
|
||||||
|
DetourTransactionCommit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Vtable<Interface> s_origVtable;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class InitVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <typename MemberDataPtr, MemberDataPtr ptr>
|
||||||
|
void visit(const std::string& vtableTypeName, const std::string& funcName)
|
||||||
|
{
|
||||||
|
s_funcNames[getKey<MemberDataPtr, ptr>()] = vtableTypeName + "::" + funcName;
|
||||||
|
|
||||||
|
if (!(s_compatVtable.*ptr))
|
||||||
|
{
|
||||||
|
s_compatVtable.*ptr = s_origVtable.*ptr;
|
||||||
|
s_threadSafeVtable.*ptr = s_origVtable.*ptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_threadSafeVtable.*ptr = getThreadSafeFuncPtr<MemberDataPtr, ptr>(s_compatVtable.*ptr);
|
||||||
|
hookMethod(reinterpret_cast<void*&>(s_origVtable.*ptr), s_threadSafeVtable.*ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename Result, typename... Params>
|
||||||
|
using FuncPtr = Result(STDMETHODCALLTYPE *)(Params...);
|
||||||
|
|
||||||
|
template <typename MemberDataPtr, MemberDataPtr ptr>
|
||||||
|
static std::vector<unsigned char> getKey()
|
||||||
|
{
|
||||||
|
MemberDataPtr mp = ptr;
|
||||||
|
unsigned char* p = reinterpret_cast<unsigned char*>(&mp);
|
||||||
|
return std::vector<unsigned char>(p, p + sizeof(mp));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename MemberDataPtr, MemberDataPtr ptr, typename Result, typename... Params>
|
||||||
|
static FuncPtr<Result, Params...> getThreadSafeFuncPtr(FuncPtr<Result, Params...>)
|
||||||
|
{
|
||||||
|
return &threadSafeFunc<MemberDataPtr, ptr, Result, Params...>;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hookMethod(void*& origMethodPtr, void* newMethodPtr)
|
||||||
|
{
|
||||||
|
auto it = Compat::detouredMethods.find(origMethodPtr);
|
||||||
|
if (it != Compat::detouredMethods.end())
|
||||||
|
{
|
||||||
|
origMethodPtr = it->second.updatedOrigMethodPtr;
|
||||||
|
it->second.vtablePtrToCompatVtable[s_vtablePtr] = &s_compatVtable;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DetourAttach(&origMethodPtr, newMethodPtr);
|
||||||
|
s_vtablePtrToCompatVtable[s_vtablePtr] = &s_compatVtable;
|
||||||
|
Compat::detouredMethods.emplace(origMethodPtr,
|
||||||
|
Compat::DetouredMethodInfo(origMethodPtr, s_vtablePtrToCompatVtable));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename MemberDataPtr, MemberDataPtr ptr, typename Result, typename IntfPtr, typename... Params>
|
||||||
|
static Result STDMETHODCALLTYPE threadSafeFunc(IntfPtr This, Params... params)
|
||||||
|
{
|
||||||
|
Compat::origProcs.AcquireDDThreadLock();
|
||||||
|
Compat::LogEnter(s_funcNames[getKey<MemberDataPtr, ptr>()].c_str(), This, params...);
|
||||||
|
|
||||||
|
Result result;
|
||||||
|
auto it = s_vtablePtrToCompatVtable.find(This->lpVtbl);
|
||||||
|
if (it != s_vtablePtrToCompatVtable.end())
|
||||||
|
{
|
||||||
|
Vtable<Interface>& compatVtable = *static_cast<Vtable<Interface>*>(it->second);
|
||||||
|
result = (compatVtable.*ptr)(This, params...);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = (s_origVtable.*ptr)(This, params...);
|
||||||
|
}
|
||||||
|
|
||||||
|
Compat::origProcs.ReleaseDDThreadLock();
|
||||||
|
Compat::LogLeave(s_funcNames[getKey<MemberDataPtr, ptr>()].c_str(), This, params...) << result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static Vtable<Interface> createCompatVtable()
|
||||||
|
{
|
||||||
|
Vtable<Interface> vtable = {};
|
||||||
|
CompatInterface::setCompatVtable(vtable);
|
||||||
|
return vtable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Vtable<Interface>& getCompatVtable()
|
||||||
|
{
|
||||||
|
static Vtable<Interface> vtable(createCompatVtable());
|
||||||
|
return vtable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Vtable<Interface>* s_vtablePtr;
|
||||||
|
static Vtable<Interface> s_compatVtable;
|
||||||
|
static Vtable<Interface> s_threadSafeVtable;
|
||||||
|
static std::map<void*, void*> s_vtablePtrToCompatVtable;
|
||||||
|
static std::map<std::vector<unsigned char>, std::string> s_funcNames;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename CompatInterface, typename Interface>
|
||||||
|
Vtable<Interface>* CompatVtable<CompatInterface, Interface>::s_vtablePtr = nullptr;
|
||||||
|
|
||||||
|
template <typename CompatInterface, typename Interface>
|
||||||
|
Vtable<Interface> CompatVtable<CompatInterface, Interface>::s_origVtable = {};
|
||||||
|
|
||||||
|
template <typename CompatInterface, typename Interface>
|
||||||
|
Vtable<Interface> CompatVtable<CompatInterface, Interface>::s_compatVtable(CompatInterface::getCompatVtable());
|
||||||
|
|
||||||
|
template <typename CompatInterface, typename Interface>
|
||||||
|
Vtable<Interface> CompatVtable<CompatInterface, Interface>::s_threadSafeVtable = {};
|
||||||
|
|
||||||
|
template <typename CompatInterface, typename Interface>
|
||||||
|
std::map<void*, void*> CompatVtable<CompatInterface, Interface>::s_vtablePtrToCompatVtable;
|
||||||
|
|
||||||
|
template <typename CompatInterface, typename Interface>
|
||||||
|
std::map<std::vector<unsigned char>, std::string> CompatVtable<CompatInterface, Interface>::s_funcNames;
|
10
DDrawCompat/Config.h
Normal file
10
DDrawCompat/Config.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef unsigned long DWORD;
|
||||||
|
|
||||||
|
namespace Config
|
||||||
|
{
|
||||||
|
const DWORD minRefreshInterval = 1000 / 60;
|
||||||
|
const DWORD minRefreshIntervalAfterFlip = 1000 / 10;
|
||||||
|
const DWORD minPaletteUpdateInterval = 1000 / 60;
|
||||||
|
}
|
26
DDrawCompat/DDrawCompat.def
Normal file
26
DDrawCompat/DDrawCompat.def
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
LIBRARY ddraw
|
||||||
|
|
||||||
|
EXPORTS
|
||||||
|
AcquireDDThreadLock
|
||||||
|
CompleteCreateSysmemSurface
|
||||||
|
D3DParseUnknownCommand
|
||||||
|
DDGetAttachedSurfaceLcl
|
||||||
|
DDInternalLock
|
||||||
|
DDInternalUnlock
|
||||||
|
DSoundHelp
|
||||||
|
DirectDrawCreate
|
||||||
|
DirectDrawCreateClipper
|
||||||
|
DirectDrawCreateEx
|
||||||
|
DirectDrawEnumerateA
|
||||||
|
DirectDrawEnumerateExA
|
||||||
|
DirectDrawEnumerateExW
|
||||||
|
DirectDrawEnumerateW
|
||||||
|
DllCanUnloadNow PRIVATE
|
||||||
|
DllGetClassObject PRIVATE
|
||||||
|
GetDDSurfaceLocal
|
||||||
|
GetOLEThunkData
|
||||||
|
GetSurfaceFromDC
|
||||||
|
RegisterSpecialCase
|
||||||
|
ReleaseDDThreadLock
|
||||||
|
SetAppCompatData
|
||||||
|
DirectInputCreateA
|
184
DDrawCompat/DDrawCompat.vcxproj
Normal file
184
DDrawCompat/DDrawCompat.vcxproj
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{1146187A-17DE-4350-B9D1-9F9EAA934908}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>DDrawCompat</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<CharacterSet>NotSet</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<CharacterSet>NotSet</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<TargetName>ddraw</TargetName>
|
||||||
|
<IncludePath>C:\Program Files %28x86%29\Microsoft Research\Detours Express 3.0\include;$(IncludePath)</IncludePath>
|
||||||
|
<LibraryPath>C:\Program Files %28x86%29\Microsoft Research\Detours Express 3.0\lib.X86;$(LibraryPath)</LibraryPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<TargetName>ddraw</TargetName>
|
||||||
|
<IncludePath>C:\Program Files %28x86%29\Microsoft Research\Detours Express 3.0\include;$(IncludePath)</IncludePath>
|
||||||
|
<LibraryPath>C:\Program Files %28x86%29\Microsoft Research\Detours Express 3.0\lib.X86;$(LibraryPath)</LibraryPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level4</WarningLevel>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;DDRAWCOMPAT_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile>
|
||||||
|
<AdditionalDependencies>dxguid.lib;detours.lib;oleacc.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;DDRAWCOMPAT_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level4</WarningLevel>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;DDRAWCOMPAT_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile>
|
||||||
|
<AdditionalDependencies>dxguid.lib;detours.lib;oleacc.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<GenerateDebugInformation>No</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;DDRAWCOMPAT_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<ModuleDefinitionFile>DDrawCompat.def</ModuleDefinitionFile>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="CompatDirectDrawPalette.h" />
|
||||||
|
<ClInclude Include="CompatGdiSurface.h" />
|
||||||
|
<ClInclude Include="Config.h" />
|
||||||
|
<ClInclude Include="DDrawProcs.h" />
|
||||||
|
<ClInclude Include="CompatDirectDraw.h" />
|
||||||
|
<ClInclude Include="CompatPrimarySurface.h" />
|
||||||
|
<ClInclude Include="DDrawTypes.h" />
|
||||||
|
<ClInclude Include="CompatDirectDrawSurface.h" />
|
||||||
|
<ClInclude Include="DDrawVtableVisitor.h" />
|
||||||
|
<ClInclude Include="CompatVtable.h" />
|
||||||
|
<ClInclude Include="DirectDrawPaletteVtblVisitor.h" />
|
||||||
|
<ClInclude Include="DirectDrawSurfaceVtblVisitor.h" />
|
||||||
|
<ClInclude Include="DirectDrawVtblVisitor.h" />
|
||||||
|
<ClInclude Include="DDrawLog.h" />
|
||||||
|
<ClInclude Include="IReleaseNotifier.h" />
|
||||||
|
<ClInclude Include="RealPrimarySurface.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="CompatDirectDraw.cpp" />
|
||||||
|
<ClCompile Include="CompatDirectDrawPalette.cpp" />
|
||||||
|
<ClCompile Include="CompatDirectDrawSurface.cpp" />
|
||||||
|
<ClCompile Include="CompatGdiSurface.cpp" />
|
||||||
|
<ClCompile Include="CompatVtable.cpp" />
|
||||||
|
<ClCompile Include="DDrawLog.cpp" />
|
||||||
|
<ClCompile Include="DllMain.cpp" />
|
||||||
|
<ClCompile Include="CompatPrimarySurface.cpp" />
|
||||||
|
<ClCompile Include="DDrawProcs.cpp" />
|
||||||
|
<ClCompile Include="IReleaseNotifier.cpp" />
|
||||||
|
<ClCompile Include="RealPrimarySurface.cpp" />
|
||||||
|
<ClCompile Include="UnmodifiedDDrawProcs.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="DDrawCompat.def" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
110
DDrawCompat/DDrawCompat.vcxproj.filters
Normal file
110
DDrawCompat/DDrawCompat.vcxproj.filters
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="DDrawProcs.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="CompatDirectDraw.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="DDrawTypes.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="CompatDirectDrawSurface.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="DDrawVtableVisitor.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="CompatVtable.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="DDrawLog.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="DirectDrawSurfaceVtblVisitor.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="DirectDrawVtblVisitor.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="DirectDrawPaletteVtblVisitor.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="CompatDirectDrawPalette.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="CompatGdiSurface.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="RealPrimarySurface.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="CompatPrimarySurface.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="IReleaseNotifier.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Config.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="DllMain.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="UnmodifiedDDrawProcs.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="DDrawProcs.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="DDrawLog.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="RealPrimarySurface.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="CompatPrimarySurface.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="CompatGdiSurface.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="IReleaseNotifier.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="CompatVtable.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="CompatDirectDraw.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="CompatDirectDrawSurface.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="CompatDirectDrawPalette.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="DDrawCompat.def">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
39
DDrawCompat/DDrawLog.cpp
Normal file
39
DDrawCompat/DDrawLog.cpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#include "DDrawLog.h"
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, LPRECT rect)
|
||||||
|
{
|
||||||
|
if (rect)
|
||||||
|
{
|
||||||
|
os << "RECT(" << rect->left << ',' << rect->top << ',' << rect->right << ',' << rect->bottom << ')';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
os << "NullRect";
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Compat
|
||||||
|
{
|
||||||
|
Log::Log()
|
||||||
|
{
|
||||||
|
SYSTEMTIME st = {};
|
||||||
|
GetLocalTime(&st);
|
||||||
|
|
||||||
|
char time[100];
|
||||||
|
sprintf_s(time, "%02hu:%02hu:%02hu.%03hu ", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
|
||||||
|
|
||||||
|
s_logFile << GetCurrentThreadId() << " " << time;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::~Log()
|
||||||
|
{
|
||||||
|
s_logFile << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream Log::s_logFile("ddraw.log");
|
||||||
|
}
|
104
DDrawCompat/DDrawLog.h
Normal file
104
DDrawCompat/DDrawLog.h
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define CINTERFACE
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
struct _GUID;
|
||||||
|
struct tagRECT;
|
||||||
|
|
||||||
|
#define LOG_ONCE(msg) \
|
||||||
|
static bool isAlreadyLogged##__LINE__ = false; \
|
||||||
|
if (!isAlreadyLogged##__LINE__) \
|
||||||
|
{ \
|
||||||
|
Compat::Log() << msg; \
|
||||||
|
isAlreadyLogged##__LINE__ = true; \
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const _GUID& guid)
|
||||||
|
{
|
||||||
|
return os << &guid;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, tagRECT* rect);
|
||||||
|
|
||||||
|
namespace Compat
|
||||||
|
{
|
||||||
|
class Log
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Log();
|
||||||
|
~Log();
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Log& operator<<(const T& t)
|
||||||
|
{
|
||||||
|
s_logFile << t;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template <typename... Params>
|
||||||
|
Log(const char* prefix, const char* funcName, Params... params) : Log()
|
||||||
|
{
|
||||||
|
s_logFile << prefix << ' ' << funcName << '(';
|
||||||
|
toList(params...);
|
||||||
|
s_logFile << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void toList()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Param>
|
||||||
|
void toList(Param param)
|
||||||
|
{
|
||||||
|
s_logFile << param;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Param, typename... Params>
|
||||||
|
void toList(Param firstParam, Params... remainingParams)
|
||||||
|
{
|
||||||
|
s_logFile << firstParam << ", ";
|
||||||
|
toList(remainingParams...);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::ofstream s_logFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
class LogEnter : private Log
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <typename... Params>
|
||||||
|
LogEnter(const char* funcName, Params... params) : Log("-->", funcName, params...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class LogLeave : private Log
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <typename... Params>
|
||||||
|
LogLeave(const char* funcName, Params... params) : Log("<--", funcName, params...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Result>
|
||||||
|
void operator<<(const Result& result)
|
||||||
|
{
|
||||||
|
static_cast<Log&>(*this) << " = " << result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
class LogEnter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <typename... Params> LogEnter(const char*, Params...) {}
|
||||||
|
template <typename Result> void operator<<(const Result&) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef LogEnter LogLeave;
|
||||||
|
#endif
|
||||||
|
}
|
6
DDrawCompat/DDrawProcs.cpp
Normal file
6
DDrawCompat/DDrawProcs.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include "DDrawProcs.h"
|
||||||
|
|
||||||
|
namespace Compat
|
||||||
|
{
|
||||||
|
DDrawProcs origProcs = {};
|
||||||
|
}
|
55
DDrawCompat/DDrawProcs.h
Normal file
55
DDrawCompat/DDrawProcs.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#define VISIT_UNMODIFIED_DDRAW_PROCS(visit) \
|
||||||
|
visit(AcquireDDThreadLock) \
|
||||||
|
visit(CompleteCreateSysmemSurface) \
|
||||||
|
visit(D3DParseUnknownCommand) \
|
||||||
|
visit(DDGetAttachedSurfaceLcl) \
|
||||||
|
visit(DDInternalLock) \
|
||||||
|
visit(DDInternalUnlock) \
|
||||||
|
visit(DSoundHelp) \
|
||||||
|
visit(DirectDrawCreateClipper) \
|
||||||
|
visit(DirectDrawEnumerateA) \
|
||||||
|
visit(DirectDrawEnumerateExA) \
|
||||||
|
visit(DirectDrawEnumerateExW) \
|
||||||
|
visit(DirectDrawEnumerateW) \
|
||||||
|
visit(DllCanUnloadNow) \
|
||||||
|
visit(DllGetClassObject) \
|
||||||
|
visit(GetDDSurfaceLocal) \
|
||||||
|
visit(GetOLEThunkData) \
|
||||||
|
visit(GetSurfaceFromDC) \
|
||||||
|
visit(RegisterSpecialCase) \
|
||||||
|
visit(ReleaseDDThreadLock) \
|
||||||
|
visit(SetAppCompatData)
|
||||||
|
|
||||||
|
#define VISIT_MODIFIED_DDRAW_PROCS(visit) \
|
||||||
|
visit(DirectDrawCreate) \
|
||||||
|
visit(DirectDrawCreateEx)
|
||||||
|
|
||||||
|
#define VISIT_ALL_DDRAW_PROCS(visit) \
|
||||||
|
VISIT_UNMODIFIED_DDRAW_PROCS(visit) \
|
||||||
|
VISIT_MODIFIED_DDRAW_PROCS(visit)
|
||||||
|
|
||||||
|
#define ADD_FARPROC_MEMBER(memberName) FARPROC memberName;
|
||||||
|
|
||||||
|
namespace Compat
|
||||||
|
{
|
||||||
|
struct DDrawProcs
|
||||||
|
{
|
||||||
|
VISIT_ALL_DDRAW_PROCS(ADD_FARPROC_MEMBER);
|
||||||
|
FARPROC DirectInputCreateA;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DDrawProcs origProcs;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef ADD_FARPROC_MEMBER
|
||||||
|
|
||||||
|
#define CALL_ORIG_DDRAW(procName, ...) \
|
||||||
|
(Compat::origProcs.procName ? \
|
||||||
|
reinterpret_cast<decltype(procName)*>(Compat::origProcs.procName)(__VA_ARGS__) : \
|
||||||
|
E_FAIL)
|
79
DDrawCompat/DDrawTypes.h
Normal file
79
DDrawCompat/DDrawTypes.h
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define CINTERFACE
|
||||||
|
|
||||||
|
#include <ddraw.h>
|
||||||
|
|
||||||
|
struct DDrawTypes
|
||||||
|
{
|
||||||
|
typedef IDirectDrawSurface TSurface;
|
||||||
|
typedef IDirectDrawSurface TCreatedSurface;
|
||||||
|
typedef DDSURFACEDESC TSurfaceDesc;
|
||||||
|
typedef DDSCAPS TDdsCaps;
|
||||||
|
typedef LPDDENUMSURFACESCALLBACK TEnumSurfacesCallbackPtr;
|
||||||
|
typedef LPVOID TUnlockParam;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DDrawTypes2
|
||||||
|
{
|
||||||
|
typedef IDirectDrawSurface2 TSurface;
|
||||||
|
typedef IDirectDrawSurface TCreatedSurface;
|
||||||
|
typedef DDSURFACEDESC TSurfaceDesc;
|
||||||
|
typedef DDSCAPS TDdsCaps;
|
||||||
|
typedef LPDDENUMSURFACESCALLBACK TEnumSurfacesCallbackPtr;
|
||||||
|
typedef LPVOID TUnlockParam;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DDrawTypes3
|
||||||
|
{
|
||||||
|
typedef IDirectDrawSurface3 TSurface;
|
||||||
|
typedef IDirectDrawSurface3 TCreatedSurface;
|
||||||
|
typedef DDSURFACEDESC TSurfaceDesc;
|
||||||
|
typedef DDSCAPS TDdsCaps;
|
||||||
|
typedef LPDDENUMSURFACESCALLBACK TEnumSurfacesCallbackPtr;
|
||||||
|
typedef LPVOID TUnlockParam;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DDrawTypes4
|
||||||
|
{
|
||||||
|
typedef IDirectDrawSurface4 TSurface;
|
||||||
|
typedef IDirectDrawSurface4 TCreatedSurface;
|
||||||
|
typedef DDSURFACEDESC2 TSurfaceDesc;
|
||||||
|
typedef DDSCAPS2 TDdsCaps;
|
||||||
|
typedef LPDDENUMSURFACESCALLBACK2 TEnumSurfacesCallbackPtr;
|
||||||
|
typedef LPRECT TUnlockParam;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DDrawTypes7
|
||||||
|
{
|
||||||
|
typedef IDirectDrawSurface7 TSurface;
|
||||||
|
typedef IDirectDrawSurface7 TCreatedSurface;
|
||||||
|
typedef DDSURFACEDESC2 TSurfaceDesc;
|
||||||
|
typedef DDSCAPS2 TDdsCaps;
|
||||||
|
typedef LPDDENUMSURFACESCALLBACK7 TEnumSurfacesCallbackPtr;
|
||||||
|
typedef LPRECT TUnlockParam;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Interface>
|
||||||
|
struct Types;
|
||||||
|
|
||||||
|
#define DD_CONCAT(x, y, ...) x##y
|
||||||
|
|
||||||
|
#define DD_TYPES(Interface, ...) \
|
||||||
|
template <> \
|
||||||
|
struct Types<DD_CONCAT(Interface, __VA_ARGS__)> : DD_CONCAT(DDrawTypes, __VA_ARGS__) \
|
||||||
|
{}
|
||||||
|
|
||||||
|
DD_TYPES(IDirectDraw);
|
||||||
|
DD_TYPES(IDirectDraw, 2);
|
||||||
|
DD_TYPES(IDirectDraw, 4);
|
||||||
|
DD_TYPES(IDirectDraw, 7);
|
||||||
|
|
||||||
|
DD_TYPES(IDirectDrawSurface);
|
||||||
|
DD_TYPES(IDirectDrawSurface, 2);
|
||||||
|
DD_TYPES(IDirectDrawSurface, 3);
|
||||||
|
DD_TYPES(IDirectDrawSurface, 4);
|
||||||
|
DD_TYPES(IDirectDrawSurface, 7);
|
||||||
|
|
||||||
|
#undef DD_TYPES
|
||||||
|
#undef DD_CONCAT
|
41
DDrawCompat/DDrawVtableVisitor.h
Normal file
41
DDrawCompat/DDrawVtableVisitor.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define CINTERFACE
|
||||||
|
|
||||||
|
#include <ddraw.h>
|
||||||
|
#include <typeinfo>
|
||||||
|
|
||||||
|
template <typename Vtable>
|
||||||
|
struct DDrawVtableForEach;
|
||||||
|
|
||||||
|
template <typename Vtable, typename Visitor>
|
||||||
|
void forEach(Visitor& visitor)
|
||||||
|
{
|
||||||
|
DDrawVtableForEach<Vtable>::forEach<Vtable>(visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::string getTypeName()
|
||||||
|
{
|
||||||
|
std::string typeName(typeid(T).name());
|
||||||
|
if (0 == typeName.find("struct "))
|
||||||
|
{
|
||||||
|
typeName = typeName.substr(typeName.find(" ") + 1);
|
||||||
|
}
|
||||||
|
return typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DD_VISIT(member) \
|
||||||
|
visitor.visit<decltype(&Vtable::member), &Vtable::member>(getTypeName<Vtable>(), #member)
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct DDrawVtableForEach<IUnknownVtbl>
|
||||||
|
{
|
||||||
|
template <typename Vtable, typename Visitor>
|
||||||
|
static void forEach(Visitor& visitor)
|
||||||
|
{
|
||||||
|
DD_VISIT(QueryInterface);
|
||||||
|
DD_VISIT(AddRef);
|
||||||
|
DD_VISIT(Release);
|
||||||
|
}
|
||||||
|
};
|
18
DDrawCompat/DirectDrawPaletteVtblVisitor.h
Normal file
18
DDrawCompat/DirectDrawPaletteVtblVisitor.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "DDrawVtableVisitor.h"
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct DDrawVtableForEach<IDirectDrawPaletteVtbl>
|
||||||
|
{
|
||||||
|
template <typename Vtable, typename Visitor>
|
||||||
|
static void forEach(Visitor& visitor)
|
||||||
|
{
|
||||||
|
DDrawVtableForEach<IUnknownVtbl>::forEach<Vtable>(visitor);
|
||||||
|
|
||||||
|
DD_VISIT(GetCaps);
|
||||||
|
DD_VISIT(GetEntries);
|
||||||
|
DD_VISIT(Initialize);
|
||||||
|
DD_VISIT(SetEntries);
|
||||||
|
}
|
||||||
|
};
|
104
DDrawCompat/DirectDrawSurfaceVtblVisitor.h
Normal file
104
DDrawCompat/DirectDrawSurfaceVtblVisitor.h
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "DDrawVtableVisitor.h"
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct DDrawVtableForEach<IDirectDrawSurfaceVtbl>
|
||||||
|
{
|
||||||
|
template <typename Vtable, typename Visitor>
|
||||||
|
static void forEach(Visitor& visitor)
|
||||||
|
{
|
||||||
|
DDrawVtableForEach<IUnknownVtbl>::forEach<Vtable>(visitor);
|
||||||
|
|
||||||
|
DD_VISIT(AddAttachedSurface);
|
||||||
|
DD_VISIT(AddOverlayDirtyRect);
|
||||||
|
DD_VISIT(Blt);
|
||||||
|
DD_VISIT(BltBatch);
|
||||||
|
DD_VISIT(BltFast);
|
||||||
|
DD_VISIT(DeleteAttachedSurface);
|
||||||
|
DD_VISIT(EnumAttachedSurfaces);
|
||||||
|
DD_VISIT(EnumOverlayZOrders);
|
||||||
|
DD_VISIT(Flip);
|
||||||
|
DD_VISIT(GetAttachedSurface);
|
||||||
|
DD_VISIT(GetBltStatus);
|
||||||
|
DD_VISIT(GetCaps);
|
||||||
|
DD_VISIT(GetClipper);
|
||||||
|
DD_VISIT(GetColorKey);
|
||||||
|
DD_VISIT(GetDC);
|
||||||
|
DD_VISIT(GetFlipStatus);
|
||||||
|
DD_VISIT(GetOverlayPosition);
|
||||||
|
DD_VISIT(GetPalette);
|
||||||
|
DD_VISIT(GetPixelFormat);
|
||||||
|
DD_VISIT(GetSurfaceDesc);
|
||||||
|
DD_VISIT(Initialize);
|
||||||
|
DD_VISIT(IsLost);
|
||||||
|
DD_VISIT(Lock);
|
||||||
|
DD_VISIT(ReleaseDC);
|
||||||
|
DD_VISIT(Restore);
|
||||||
|
DD_VISIT(SetClipper);
|
||||||
|
DD_VISIT(SetColorKey);
|
||||||
|
DD_VISIT(SetOverlayPosition);
|
||||||
|
DD_VISIT(SetPalette);
|
||||||
|
DD_VISIT(Unlock);
|
||||||
|
DD_VISIT(UpdateOverlay);
|
||||||
|
DD_VISIT(UpdateOverlayDisplay);
|
||||||
|
DD_VISIT(UpdateOverlayZOrder);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct DDrawVtableForEach<IDirectDrawSurface2Vtbl>
|
||||||
|
{
|
||||||
|
template <typename Vtable, typename Visitor>
|
||||||
|
static void forEach(Visitor& visitor)
|
||||||
|
{
|
||||||
|
DDrawVtableForEach<IDirectDrawSurfaceVtbl>::forEach<Vtable>(visitor);
|
||||||
|
|
||||||
|
DD_VISIT(GetDDInterface);
|
||||||
|
DD_VISIT(PageLock);
|
||||||
|
DD_VISIT(PageUnlock);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct DDrawVtableForEach<IDirectDrawSurface3Vtbl>
|
||||||
|
{
|
||||||
|
template <typename Vtable, typename Visitor>
|
||||||
|
static void forEach(Visitor& visitor)
|
||||||
|
{
|
||||||
|
DDrawVtableForEach<IDirectDrawSurface2Vtbl>::forEach<Vtable>(visitor);
|
||||||
|
|
||||||
|
DD_VISIT(SetSurfaceDesc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct DDrawVtableForEach<IDirectDrawSurface4Vtbl>
|
||||||
|
{
|
||||||
|
template <typename Vtable, typename Visitor>
|
||||||
|
static void forEach(Visitor& visitor)
|
||||||
|
{
|
||||||
|
DDrawVtableForEach<IDirectDrawSurface3Vtbl>::forEach<Vtable>(visitor);
|
||||||
|
|
||||||
|
DD_VISIT(SetPrivateData);
|
||||||
|
DD_VISIT(GetPrivateData);
|
||||||
|
DD_VISIT(FreePrivateData);
|
||||||
|
DD_VISIT(GetUniquenessValue);
|
||||||
|
DD_VISIT(ChangeUniquenessValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct DDrawVtableForEach<IDirectDrawSurface7Vtbl>
|
||||||
|
{
|
||||||
|
template <typename Vtable, typename Visitor>
|
||||||
|
static void forEach(Visitor& visitor)
|
||||||
|
{
|
||||||
|
DDrawVtableForEach<IDirectDrawSurface4Vtbl>::forEach<Vtable>(visitor);
|
||||||
|
|
||||||
|
DD_VISIT(SetPriority);
|
||||||
|
DD_VISIT(GetPriority);
|
||||||
|
DD_VISIT(SetLOD);
|
||||||
|
DD_VISIT(GetLOD);
|
||||||
|
}
|
||||||
|
};
|
74
DDrawCompat/DirectDrawVtblVisitor.h
Normal file
74
DDrawCompat/DirectDrawVtblVisitor.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "DDrawVtableVisitor.h"
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct DDrawVtableForEach<IDirectDrawVtbl>
|
||||||
|
{
|
||||||
|
template <typename Vtable, typename Visitor>
|
||||||
|
static void forEach(Visitor& visitor)
|
||||||
|
{
|
||||||
|
DDrawVtableForEach<IUnknownVtbl>::forEach<Vtable>(visitor);
|
||||||
|
|
||||||
|
DD_VISIT(Compact);
|
||||||
|
DD_VISIT(CreateClipper);
|
||||||
|
DD_VISIT(CreatePalette);
|
||||||
|
DD_VISIT(CreateSurface);
|
||||||
|
DD_VISIT(DuplicateSurface);
|
||||||
|
DD_VISIT(EnumDisplayModes);
|
||||||
|
DD_VISIT(EnumSurfaces);
|
||||||
|
DD_VISIT(FlipToGDISurface);
|
||||||
|
DD_VISIT(GetCaps);
|
||||||
|
DD_VISIT(GetDisplayMode);
|
||||||
|
DD_VISIT(GetFourCCCodes);
|
||||||
|
DD_VISIT(GetGDISurface);
|
||||||
|
DD_VISIT(GetMonitorFrequency);
|
||||||
|
DD_VISIT(GetScanLine);
|
||||||
|
DD_VISIT(GetVerticalBlankStatus);
|
||||||
|
DD_VISIT(Initialize);
|
||||||
|
DD_VISIT(RestoreDisplayMode);
|
||||||
|
DD_VISIT(SetCooperativeLevel);
|
||||||
|
DD_VISIT(SetDisplayMode);
|
||||||
|
DD_VISIT(WaitForVerticalBlank);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct DDrawVtableForEach<IDirectDraw2Vtbl>
|
||||||
|
{
|
||||||
|
template <typename Vtable, typename Visitor>
|
||||||
|
static void forEach(Visitor& visitor)
|
||||||
|
{
|
||||||
|
DDrawVtableForEach<IDirectDrawVtbl>::forEach<Vtable>(visitor);
|
||||||
|
|
||||||
|
DD_VISIT(GetAvailableVidMem);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct DDrawVtableForEach<IDirectDraw4Vtbl>
|
||||||
|
{
|
||||||
|
template <typename Vtable, typename Visitor>
|
||||||
|
static void forEach(Visitor& visitor)
|
||||||
|
{
|
||||||
|
DDrawVtableForEach<IDirectDraw2Vtbl>::forEach<Vtable>(visitor);
|
||||||
|
|
||||||
|
DD_VISIT(GetSurfaceFromDC);
|
||||||
|
DD_VISIT(RestoreAllSurfaces);
|
||||||
|
DD_VISIT(TestCooperativeLevel);
|
||||||
|
DD_VISIT(GetDeviceIdentifier);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct DDrawVtableForEach<IDirectDraw7Vtbl>
|
||||||
|
{
|
||||||
|
template <typename Vtable, typename Visitor>
|
||||||
|
static void forEach(Visitor& visitor)
|
||||||
|
{
|
||||||
|
DDrawVtableForEach<IDirectDraw4Vtbl>::forEach<Vtable>(visitor);
|
||||||
|
|
||||||
|
DD_VISIT(StartModeTest);
|
||||||
|
DD_VISIT(EvaluateMode);
|
||||||
|
}
|
||||||
|
};
|
207
DDrawCompat/DllMain.cpp
Normal file
207
DDrawCompat/DllMain.cpp
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "CompatDirectDraw.h"
|
||||||
|
#include "CompatDirectDrawSurface.h"
|
||||||
|
#include "CompatDirectDrawPalette.h"
|
||||||
|
#include "CompatGdiSurface.h"
|
||||||
|
#include "CompatVtable.h"
|
||||||
|
#include "DDrawProcs.h"
|
||||||
|
|
||||||
|
struct IDirectInput;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
HMODULE g_origDDrawModule = nullptr;
|
||||||
|
HMODULE g_origDInputModule = nullptr;
|
||||||
|
|
||||||
|
template <typename CompatInterface>
|
||||||
|
void hookVtable(const GUID& guid, IUnknown& unk)
|
||||||
|
{
|
||||||
|
typename CompatInterface::Interface* intf = nullptr;
|
||||||
|
if (SUCCEEDED(unk.lpVtbl->QueryInterface(&unk, guid, reinterpret_cast<LPVOID*>(&intf))))
|
||||||
|
{
|
||||||
|
CompatInterface::hookVtable(*intf);
|
||||||
|
intf->lpVtbl->Release(intf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hookDirectDraw(IDirectDraw& dd)
|
||||||
|
{
|
||||||
|
IUnknown& ddUnk = reinterpret_cast<IUnknown&>(dd);
|
||||||
|
hookVtable<CompatDirectDraw<IDirectDraw>>(IID_IDirectDraw, ddUnk);
|
||||||
|
hookVtable<CompatDirectDraw<IDirectDraw2>>(IID_IDirectDraw2, ddUnk);
|
||||||
|
hookVtable<CompatDirectDraw<IDirectDraw4>>(IID_IDirectDraw4, ddUnk);
|
||||||
|
hookVtable<CompatDirectDraw<IDirectDraw7>>(IID_IDirectDraw7, ddUnk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hookDirectDrawSurface(IDirectDraw& dd)
|
||||||
|
{
|
||||||
|
DDSURFACEDESC desc = {};
|
||||||
|
desc.dwSize = sizeof(desc);
|
||||||
|
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
|
||||||
|
desc.dwWidth = 1;
|
||||||
|
desc.dwHeight = 1;
|
||||||
|
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
||||||
|
|
||||||
|
IDirectDrawSurface* surface = nullptr;
|
||||||
|
if (SUCCEEDED(dd.lpVtbl->CreateSurface(&dd, &desc, &surface, nullptr)))
|
||||||
|
{
|
||||||
|
IUnknown& surfaceUnk = reinterpret_cast<IUnknown&>(*surface);
|
||||||
|
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface>>(IID_IDirectDrawSurface, surfaceUnk);
|
||||||
|
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface2>>(IID_IDirectDrawSurface2, surfaceUnk);
|
||||||
|
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface3>>(IID_IDirectDrawSurface3, surfaceUnk);
|
||||||
|
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface4>>(IID_IDirectDrawSurface4, surfaceUnk);
|
||||||
|
hookVtable<CompatDirectDrawSurface<IDirectDrawSurface7>>(IID_IDirectDrawSurface7, surfaceUnk);
|
||||||
|
surface->lpVtbl->Release(surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hookDirectDrawPalette(IDirectDraw& dd)
|
||||||
|
{
|
||||||
|
PALETTEENTRY paletteEntries[2] = {};
|
||||||
|
IDirectDrawPalette* palette = nullptr;
|
||||||
|
if (SUCCEEDED(dd.lpVtbl->CreatePalette(&dd, DDPCAPS_1BIT, paletteEntries, &palette, nullptr)))
|
||||||
|
{
|
||||||
|
CompatDirectDrawPalette::hookVtable(*palette);
|
||||||
|
palette->lpVtbl->Release(palette);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void installHooks()
|
||||||
|
{
|
||||||
|
static bool isAlreadyInstalled = false;
|
||||||
|
if (!isAlreadyInstalled)
|
||||||
|
{
|
||||||
|
Compat::Log() << "Installing DirectDraw hooks";
|
||||||
|
IDirectDraw* dd = nullptr;
|
||||||
|
if (SUCCEEDED(CALL_ORIG_DDRAW(DirectDrawCreate, nullptr, &dd, nullptr)))
|
||||||
|
{
|
||||||
|
dd->lpVtbl->SetCooperativeLevel(dd, nullptr, DDSCL_NORMAL);
|
||||||
|
|
||||||
|
hookDirectDraw(*dd);
|
||||||
|
hookDirectDrawSurface(*dd);
|
||||||
|
hookDirectDrawPalette(*dd);
|
||||||
|
|
||||||
|
Compat::Log() << "Installing GDI hooks";
|
||||||
|
CompatGdiSurface::hookGdi();
|
||||||
|
|
||||||
|
dd->lpVtbl->Release(dd);
|
||||||
|
}
|
||||||
|
Compat::Log() << "Finished installing hooks";
|
||||||
|
isAlreadyInstalled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool loadLibrary(const std::string& systemDirectory, const std::string& dllName, HMODULE& module)
|
||||||
|
{
|
||||||
|
const std::string systemDllPath = systemDirectory + '\\' + dllName;
|
||||||
|
|
||||||
|
module = LoadLibrary(systemDllPath.c_str());
|
||||||
|
if (!module)
|
||||||
|
{
|
||||||
|
Compat::Log() << "Failed to load system " << dllName << " from " << systemDllPath;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void suppressEmulatedDirectDraw(GUID*& guid)
|
||||||
|
{
|
||||||
|
if (reinterpret_cast<GUID*>(DDCREATE_EMULATIONONLY) == guid)
|
||||||
|
{
|
||||||
|
LOG_ONCE("Warning: suppressed a request to create an emulated DirectDraw object");
|
||||||
|
guid = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOAD_ORIGINAL_DDRAW_PROC(procName) \
|
||||||
|
Compat::origProcs.procName = GetProcAddress(g_origDDrawModule, #procName);
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/)
|
||||||
|
{
|
||||||
|
if (fdwReason == DLL_PROCESS_ATTACH)
|
||||||
|
{
|
||||||
|
char currentDllPath[MAX_PATH] = {};
|
||||||
|
GetModuleFileName(hinstDLL, currentDllPath, MAX_PATH);
|
||||||
|
Compat::Log() << "Loading DDrawCompat from " << currentDllPath;
|
||||||
|
|
||||||
|
char systemDirectory[MAX_PATH] = {};
|
||||||
|
GetSystemDirectory(systemDirectory, MAX_PATH);
|
||||||
|
|
||||||
|
std::string systemDDrawDllPath = std::string(systemDirectory) + "\\ddraw.dll";
|
||||||
|
if (0 == _stricmp(currentDllPath, systemDDrawDllPath.c_str()))
|
||||||
|
{
|
||||||
|
Compat::Log() << "DDrawCompat cannot be installed as the system ddraw.dll";
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loadLibrary(systemDirectory, "ddraw.dll", g_origDDrawModule) ||
|
||||||
|
!loadLibrary(systemDirectory, "dinput.dll", g_origDInputModule))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIT_ALL_DDRAW_PROCS(LOAD_ORIGINAL_DDRAW_PROC);
|
||||||
|
Compat::origProcs.DirectInputCreateA = GetProcAddress(g_origDInputModule, "DirectInputCreateA");
|
||||||
|
|
||||||
|
SetProcessAffinityMask(GetCurrentProcess(), 1);
|
||||||
|
|
||||||
|
if (Compat::origProcs.SetAppCompatData)
|
||||||
|
{
|
||||||
|
typedef HRESULT WINAPI SetAppCompatDataFunc(DWORD, DWORD);
|
||||||
|
auto setAppCompatData = reinterpret_cast<SetAppCompatDataFunc*>(Compat::origProcs.SetAppCompatData);
|
||||||
|
const DWORD disableMaxWindowedMode = 12;
|
||||||
|
setAppCompatData(disableMaxWindowedMode, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Compat::Log() << "DDrawCompat loaded successfully";
|
||||||
|
}
|
||||||
|
else if (fdwReason == DLL_PROCESS_DETACH)
|
||||||
|
{
|
||||||
|
FreeLibrary(g_origDInputModule);
|
||||||
|
FreeLibrary(g_origDDrawModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" HRESULT WINAPI DirectDrawCreate(
|
||||||
|
GUID* lpGUID,
|
||||||
|
LPDIRECTDRAW* lplpDD,
|
||||||
|
IUnknown* pUnkOuter)
|
||||||
|
{
|
||||||
|
Compat::LogEnter(__func__, lpGUID, lplpDD, pUnkOuter);
|
||||||
|
installHooks();
|
||||||
|
suppressEmulatedDirectDraw(lpGUID);
|
||||||
|
HRESULT result = CALL_ORIG_DDRAW(DirectDrawCreate, lpGUID, lplpDD, pUnkOuter);
|
||||||
|
Compat::LogLeave(__func__, lpGUID, lplpDD, pUnkOuter) << result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" HRESULT WINAPI DirectDrawCreateEx(
|
||||||
|
GUID* lpGUID,
|
||||||
|
LPVOID* lplpDD,
|
||||||
|
REFIID iid,
|
||||||
|
IUnknown* pUnkOuter)
|
||||||
|
{
|
||||||
|
Compat::LogEnter(__func__, lpGUID, lplpDD, iid, pUnkOuter);
|
||||||
|
installHooks();
|
||||||
|
suppressEmulatedDirectDraw(lpGUID);
|
||||||
|
HRESULT result = CALL_ORIG_DDRAW(DirectDrawCreateEx, lpGUID, lplpDD, iid, pUnkOuter);
|
||||||
|
Compat::LogLeave(__func__, lpGUID, lplpDD, iid, pUnkOuter) << result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" HRESULT WINAPI DirectInputCreateA(
|
||||||
|
HINSTANCE hinst,
|
||||||
|
DWORD dwVersion,
|
||||||
|
IDirectInput** lplpDirectInput,
|
||||||
|
LPUNKNOWN punkOuter)
|
||||||
|
{
|
||||||
|
Compat::LogEnter(__func__, hinst, dwVersion, lplpDirectInput, punkOuter);
|
||||||
|
HRESULT result = CALL_ORIG_DDRAW(DirectInputCreateA, hinst, dwVersion, lplpDirectInput, punkOuter);
|
||||||
|
Compat::LogLeave(__func__, hinst, dwVersion, lplpDirectInput, punkOuter) << result;
|
||||||
|
return result;
|
||||||
|
}
|
7
DDrawCompat/IReleaseNotifier.cpp
Normal file
7
DDrawCompat/IReleaseNotifier.cpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include "IReleaseNotifier.h"
|
||||||
|
|
||||||
|
#include <initguid.h>
|
||||||
|
|
||||||
|
// {7810158A-CB51-448A-8706-443A7DF6D4ED}
|
||||||
|
DEFINE_GUID(IID_IReleaseNotifier,
|
||||||
|
0x7810158a, 0xcb51, 0x448a, 0x87, 0x6, 0x44, 0x3a, 0x7d, 0xf6, 0xd4, 0xed);
|
37
DDrawCompat/IReleaseNotifier.h
Normal file
37
DDrawCompat/IReleaseNotifier.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <Unknwnbase.h>
|
||||||
|
|
||||||
|
// {7810158A-CB51-448A-8706-443A7DF6D4ED}
|
||||||
|
DEFINE_GUID(IID_IReleaseNotifier,
|
||||||
|
0x7810158a, 0xcb51, 0x448a, 0x87, 0x6, 0x44, 0x3a, 0x7d, 0xf6, 0xd4, 0xed);
|
||||||
|
|
||||||
|
class IReleaseNotifier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IReleaseNotifier(const std::function<void()>& notifyHandler)
|
||||||
|
: m_notifyHandler(notifyHandler)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID*)
|
||||||
|
{
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ULONG STDMETHODCALLTYPE AddRef()
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ULONG STDMETHODCALLTYPE Release()
|
||||||
|
{
|
||||||
|
m_notifyHandler();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<void()> m_notifyHandler;
|
||||||
|
};
|
376
DDrawCompat/RealPrimarySurface.cpp
Normal file
376
DDrawCompat/RealPrimarySurface.cpp
Normal file
@ -0,0 +1,376 @@
|
|||||||
|
#include "CompatDirectDraw.h"
|
||||||
|
#include "CompatDirectDrawSurface.h"
|
||||||
|
#include "CompatGdiSurface.h"
|
||||||
|
#include "CompatPrimarySurface.h"
|
||||||
|
#include "Config.h"
|
||||||
|
#include "DDrawProcs.h"
|
||||||
|
#include "DDrawTypes.h"
|
||||||
|
#include "IReleaseNotifier.h"
|
||||||
|
#include "RealPrimarySurface.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void onRelease();
|
||||||
|
void updateNow();
|
||||||
|
|
||||||
|
IDirectDrawSurface7* g_frontBuffer = nullptr;
|
||||||
|
IDirectDrawSurface7* g_backBuffer = nullptr;
|
||||||
|
IDirectDrawSurface7* g_paletteConverterSurface = nullptr;
|
||||||
|
IReleaseNotifier g_releaseNotifier(onRelease);
|
||||||
|
|
||||||
|
HANDLE g_updateThread = nullptr;
|
||||||
|
HANDLE g_updateEvent = nullptr;
|
||||||
|
bool g_isFlipEvent = false;
|
||||||
|
LARGE_INTEGER g_lastUpdateTime = {};
|
||||||
|
LARGE_INTEGER g_qpcFrequency = {};
|
||||||
|
|
||||||
|
bool compatBlt(IDirectDrawSurface7* dest)
|
||||||
|
{
|
||||||
|
Compat::LogEnter("RealPrimarySurface::compatBlt", dest);
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
const auto& origVtable = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable;
|
||||||
|
|
||||||
|
if (!RealPrimarySurface::isFullScreen())
|
||||||
|
{
|
||||||
|
IDirectDrawClipper* clipper = nullptr;
|
||||||
|
if (FAILED(origVtable.GetClipper(g_frontBuffer, &clipper)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
clipper->lpVtbl->Release(clipper);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_paletteConverterSurface)
|
||||||
|
{
|
||||||
|
origVtable.Blt(g_paletteConverterSurface, nullptr, CompatPrimarySurface::surface, nullptr,
|
||||||
|
DDBLT_WAIT, nullptr);
|
||||||
|
|
||||||
|
HDC destDc = nullptr;
|
||||||
|
origVtable.GetDC(dest, &destDc);
|
||||||
|
HDC converterDc = nullptr;
|
||||||
|
origVtable.GetDC(g_paletteConverterSurface, &converterDc);
|
||||||
|
|
||||||
|
result = TRUE == BitBlt(destDc, 0, 0,
|
||||||
|
RealPrimarySurface::s_surfaceDesc.dwWidth, RealPrimarySurface::s_surfaceDesc.dwHeight,
|
||||||
|
converterDc, 0, 0, SRCCOPY);
|
||||||
|
|
||||||
|
origVtable.ReleaseDC(g_paletteConverterSurface, converterDc);
|
||||||
|
origVtable.ReleaseDC(dest, destDc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = SUCCEEDED(origVtable.Blt(
|
||||||
|
dest, nullptr, CompatPrimarySurface::surface, nullptr, DDBLT_WAIT, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
Compat::LogLeave("RealPrimarySurface::compatBlt", dest);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename DirectDraw>
|
||||||
|
HRESULT createPaletteConverterSurface(DirectDraw& dd)
|
||||||
|
{
|
||||||
|
if (CompatPrimarySurface::displayMode.pixelFormat.dwRGBBitCount > 8 &&
|
||||||
|
RealPrimarySurface::s_surfaceDesc.ddpfPixelFormat.dwRGBBitCount > 8)
|
||||||
|
{
|
||||||
|
return DD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
typename Types<DirectDraw>::TSurfaceDesc desc = {};
|
||||||
|
desc.dwSize = sizeof(desc);
|
||||||
|
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS;
|
||||||
|
desc.dwWidth = RealPrimarySurface::s_surfaceDesc.dwWidth;
|
||||||
|
desc.dwHeight = RealPrimarySurface::s_surfaceDesc.dwHeight;
|
||||||
|
desc.ddpfPixelFormat = CompatPrimarySurface::displayMode.pixelFormat;
|
||||||
|
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
||||||
|
|
||||||
|
typename Types<DirectDraw>::TCreatedSurface* surface = nullptr;
|
||||||
|
HRESULT result = dd.lpVtbl->CreateSurface(&dd, &desc, &surface, nullptr);
|
||||||
|
if (SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
surface->lpVtbl->QueryInterface(
|
||||||
|
surface, IID_IDirectDrawSurface7, reinterpret_cast<LPVOID*>(&g_paletteConverterSurface));
|
||||||
|
surface->lpVtbl->Release(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD getTimeElapsedInMs(const LARGE_INTEGER& time)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER currentTime = {};
|
||||||
|
QueryPerformanceCounter(¤tTime);
|
||||||
|
return static_cast<DWORD>((currentTime.QuadPart - time.QuadPart) * 1000 / g_qpcFrequency.QuadPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onRelease()
|
||||||
|
{
|
||||||
|
g_frontBuffer = nullptr;
|
||||||
|
g_backBuffer = nullptr;
|
||||||
|
g_paletteConverterSurface->lpVtbl->Release(g_paletteConverterSurface);
|
||||||
|
g_paletteConverterSurface = nullptr;
|
||||||
|
|
||||||
|
SetEvent(g_updateEvent);
|
||||||
|
if (WAIT_TIMEOUT == WaitForSingleObject(g_updateThread, 500))
|
||||||
|
{
|
||||||
|
TerminateThread(g_updateThread, 0);
|
||||||
|
}
|
||||||
|
g_updateThread = nullptr;
|
||||||
|
|
||||||
|
CloseHandle(g_updateEvent);
|
||||||
|
g_updateEvent = nullptr;
|
||||||
|
|
||||||
|
ZeroMemory(&RealPrimarySurface::s_surfaceDesc, sizeof(RealPrimarySurface::s_surfaceDesc));
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateNow()
|
||||||
|
{
|
||||||
|
QueryPerformanceCounter(&g_lastUpdateTime);
|
||||||
|
|
||||||
|
if (g_backBuffer)
|
||||||
|
{
|
||||||
|
if (compatBlt(g_backBuffer))
|
||||||
|
{
|
||||||
|
g_frontBuffer->lpVtbl->Flip(g_frontBuffer, nullptr, DDFLIP_NOVSYNC | DDFLIP_WAIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
compatBlt(g_frontBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI updateThreadProc(LPVOID /*lpParameter*/)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(g_updateEvent, INFINITE);
|
||||||
|
if (!g_frontBuffer)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Compat::origProcs.AcquireDDThreadLock();
|
||||||
|
ResetEvent(g_updateEvent);
|
||||||
|
|
||||||
|
if (!g_isFlipEvent)
|
||||||
|
{
|
||||||
|
updateNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD timeSinceLastUpdate = getTimeElapsedInMs(g_lastUpdateTime);
|
||||||
|
DWORD minRefreshInterval = g_isFlipEvent ?
|
||||||
|
Config::minRefreshIntervalAfterFlip : Config::minRefreshInterval;
|
||||||
|
DWORD minRefreshIntervalTimeout = timeSinceLastUpdate < minRefreshInterval ?
|
||||||
|
minRefreshInterval - timeSinceLastUpdate : 0;
|
||||||
|
|
||||||
|
g_isFlipEvent = false;
|
||||||
|
Compat::origProcs.ReleaseDDThreadLock();
|
||||||
|
|
||||||
|
if (minRefreshIntervalTimeout)
|
||||||
|
{
|
||||||
|
Sleep(minRefreshIntervalTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DDSURFACEDESC2 RealPrimarySurface::s_surfaceDesc = {};
|
||||||
|
|
||||||
|
template <typename DirectDraw>
|
||||||
|
HRESULT RealPrimarySurface::create(DirectDraw& dd)
|
||||||
|
{
|
||||||
|
typename Types<DirectDraw>::TSurfaceDesc desc = {};
|
||||||
|
desc.dwSize = sizeof(desc);
|
||||||
|
desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
|
||||||
|
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
|
||||||
|
desc.dwBackBufferCount = 1;
|
||||||
|
|
||||||
|
typename Types<DirectDraw>::TCreatedSurface* surface = nullptr;
|
||||||
|
HRESULT result = CompatDirectDraw<DirectDraw>::s_origVtable.CreateSurface(
|
||||||
|
&dd, &desc, &surface, nullptr);
|
||||||
|
|
||||||
|
bool isFlippable = true;
|
||||||
|
if (DDERR_NOEXCLUSIVEMODE == result)
|
||||||
|
{
|
||||||
|
desc.dwFlags = DDSD_CAPS;
|
||||||
|
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
||||||
|
desc.dwBackBufferCount = 0;
|
||||||
|
isFlippable = false;
|
||||||
|
result = CompatDirectDraw<DirectDraw>::s_origVtable.CreateSurface(
|
||||||
|
&dd, &desc, &surface, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
Compat::Log() << "Failed to create the real primary surface";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
surface->lpVtbl->QueryInterface(
|
||||||
|
surface, IID_IDirectDrawSurface7, reinterpret_cast<LPVOID*>(&g_frontBuffer));
|
||||||
|
surface->lpVtbl->Release(surface);
|
||||||
|
|
||||||
|
s_surfaceDesc.dwSize = sizeof(s_surfaceDesc);
|
||||||
|
g_frontBuffer->lpVtbl->GetSurfaceDesc(g_frontBuffer, &s_surfaceDesc);
|
||||||
|
|
||||||
|
result = createPaletteConverterSurface(dd);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
Compat::Log() << "Failed to create palette converter surface";
|
||||||
|
g_frontBuffer->lpVtbl->Release(g_frontBuffer);
|
||||||
|
g_frontBuffer = nullptr;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFlippable)
|
||||||
|
{
|
||||||
|
DDSCAPS2 backBufferCaps = {};
|
||||||
|
backBufferCaps.dwCaps = DDSCAPS_BACKBUFFER;
|
||||||
|
g_frontBuffer->lpVtbl->GetAttachedSurface(g_frontBuffer, &backBufferCaps, &g_backBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryPerformanceFrequency(&g_qpcFrequency);
|
||||||
|
|
||||||
|
g_updateEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||||
|
g_updateThread = CreateThread(nullptr, 0, &updateThreadProc, nullptr, 0, nullptr);
|
||||||
|
SetThreadPriority(g_updateThread, THREAD_PRIORITY_ABOVE_NORMAL);
|
||||||
|
|
||||||
|
g_frontBuffer->lpVtbl->SetPrivateData(g_frontBuffer,
|
||||||
|
IID_IReleaseNotifier, &g_releaseNotifier, sizeof(&g_releaseNotifier), DDSPD_IUNKNOWNPOINTER);
|
||||||
|
|
||||||
|
return DD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template HRESULT RealPrimarySurface::create(IDirectDraw&);
|
||||||
|
template HRESULT RealPrimarySurface::create(IDirectDraw2&);
|
||||||
|
template HRESULT RealPrimarySurface::create(IDirectDraw4&);
|
||||||
|
template HRESULT RealPrimarySurface::create(IDirectDraw7&);
|
||||||
|
|
||||||
|
HRESULT RealPrimarySurface::flip(DWORD flags)
|
||||||
|
{
|
||||||
|
if (!g_backBuffer)
|
||||||
|
{
|
||||||
|
return DDERR_NOTFLIPPABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & DDFLIP_NOVSYNC)
|
||||||
|
{
|
||||||
|
update();
|
||||||
|
return DD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
compatBlt(g_backBuffer);
|
||||||
|
if (flags & DDFLIP_DONOTWAIT)
|
||||||
|
{
|
||||||
|
flags ^= DDFLIP_DONOTWAIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT result = g_frontBuffer->lpVtbl->Flip(g_frontBuffer, nullptr, flags | DDFLIP_WAIT);
|
||||||
|
if (SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
QueryPerformanceCounter(&g_lastUpdateTime);
|
||||||
|
g_isFlipEvent = true;
|
||||||
|
SetEvent(g_updateEvent);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDirectDrawSurface7* RealPrimarySurface::getSurface()
|
||||||
|
{
|
||||||
|
return g_frontBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RealPrimarySurface::isFullScreen()
|
||||||
|
{
|
||||||
|
return nullptr != g_backBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RealPrimarySurface::isLost()
|
||||||
|
{
|
||||||
|
return g_frontBuffer &&
|
||||||
|
DDERR_SURFACELOST == CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.IsLost(g_frontBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RealPrimarySurface::release()
|
||||||
|
{
|
||||||
|
if (g_frontBuffer)
|
||||||
|
{
|
||||||
|
g_frontBuffer->lpVtbl->Release(g_frontBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT RealPrimarySurface::restore()
|
||||||
|
{
|
||||||
|
return g_frontBuffer->lpVtbl->Restore(g_frontBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RealPrimarySurface::setClipper(LPDIRECTDRAWCLIPPER clipper)
|
||||||
|
{
|
||||||
|
if (g_paletteConverterSurface)
|
||||||
|
{
|
||||||
|
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetClipper(
|
||||||
|
g_paletteConverterSurface, clipper);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
LOG_ONCE("Failed to set the clipper on the converter surface: " << result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetClipper(
|
||||||
|
g_frontBuffer, clipper);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
LOG_ONCE("Failed to set clipper on the real primary surface: " << result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RealPrimarySurface::setPalette(LPDIRECTDRAWPALETTE palette)
|
||||||
|
{
|
||||||
|
if (g_paletteConverterSurface && CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
|
||||||
|
{
|
||||||
|
HRESULT result = g_paletteConverterSurface->lpVtbl->SetPalette(g_paletteConverterSurface, palette);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
LOG_ONCE("Failed to set the palette on the converter surface: " << result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_surfaceDesc.ddpfPixelFormat.dwRGBBitCount <= 8)
|
||||||
|
{
|
||||||
|
HRESULT result = g_frontBuffer->lpVtbl->SetPalette(g_frontBuffer, palette);
|
||||||
|
if (FAILED(result) && DDERR_NOPALETTEATTACHED != result)
|
||||||
|
{
|
||||||
|
LOG_ONCE("Failed to set the palette on the real primary surface: " << result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePalette();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RealPrimarySurface::update()
|
||||||
|
{
|
||||||
|
g_isFlipEvent = false;
|
||||||
|
SetEvent(g_updateEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RealPrimarySurface::updatePalette()
|
||||||
|
{
|
||||||
|
if (isFullScreen())
|
||||||
|
{
|
||||||
|
flip(DDFLIP_WAIT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
static LARGE_INTEGER lastUpdateTime = {};
|
||||||
|
DWORD timeSinceLastUpdate = getTimeElapsedInMs(lastUpdateTime);
|
||||||
|
if (timeSinceLastUpdate < Config::minPaletteUpdateInterval)
|
||||||
|
{
|
||||||
|
Sleep(Config::minPaletteUpdateInterval - timeSinceLastUpdate);
|
||||||
|
}
|
||||||
|
QueryPerformanceCounter(&lastUpdateTime);
|
||||||
|
}
|
25
DDrawCompat/RealPrimarySurface.h
Normal file
25
DDrawCompat/RealPrimarySurface.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define CINTERFACE
|
||||||
|
|
||||||
|
#include <ddraw.h>
|
||||||
|
|
||||||
|
class RealPrimarySurface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <typename DirectDraw>
|
||||||
|
static HRESULT create(DirectDraw& dd);
|
||||||
|
|
||||||
|
static HRESULT flip(DWORD flags);
|
||||||
|
static IDirectDrawSurface7* getSurface();
|
||||||
|
static bool isFullScreen();
|
||||||
|
static bool isLost();
|
||||||
|
static void release();
|
||||||
|
static HRESULT restore();
|
||||||
|
static void setClipper(LPDIRECTDRAWCLIPPER clipper);
|
||||||
|
static void setPalette(LPDIRECTDRAWPALETTE palette);
|
||||||
|
static void update();
|
||||||
|
static void updatePalette();
|
||||||
|
|
||||||
|
static DDSURFACEDESC2 s_surfaceDesc;
|
||||||
|
};
|
9
DDrawCompat/UnmodifiedDDrawProcs.cpp
Normal file
9
DDrawCompat/UnmodifiedDDrawProcs.cpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include "DDrawProcs.h"
|
||||||
|
|
||||||
|
#define CREATE_DDRAW_PROC_STUB(procName) \
|
||||||
|
extern "C" __declspec(naked) void __stdcall procName() \
|
||||||
|
{ \
|
||||||
|
__asm jmp Compat::origProcs.procName \
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIT_UNMODIFIED_DDRAW_PROCS(CREATE_DDRAW_PROC_STUB)
|
Loading…
x
Reference in New Issue
Block a user