1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

Fixed GetDDInterface implementation

This commit is contained in:
narzoul 2016-09-17 20:01:10 +02:00
parent d163787437
commit 30bf0435f8
13 changed files with 161 additions and 96 deletions

View File

@ -24,6 +24,7 @@ public:
}
static Vtable<Interface> s_origVtable;
static const Vtable<Interface>* s_origVtablePtr;
};
template <typename CompatInterface, typename Interface>
@ -32,10 +33,9 @@ class CompatVtable : public CompatVtableBase<Interface>
public:
static void hookVtable(const Vtable<Interface>* vtable)
{
static bool isInitialized = false;
if (!isInitialized && vtable)
if (vtable && !s_origVtablePtr)
{
isInitialized = true;
s_origVtablePtr = vtable;
InitVisitor visitor(*vtable);
forEach<Vtable<Interface>>(visitor);
@ -161,6 +161,9 @@ private:
template <typename Interface>
Vtable<Interface> CompatVtableBase<Interface>::s_origVtable = {};
template <typename Interface>
const Vtable<Interface>* CompatVtableBase<Interface>::s_origVtablePtr = nullptr;
template <typename CompatInterface, typename Interface>
Vtable<Interface> CompatVtable<CompatInterface, Interface>::s_compatVtable(getCompatVtable());

View File

@ -4,6 +4,7 @@
#include "DDraw/ActivateAppHandler.h"
#include "DDraw/DirectDraw.h"
#include "DDraw/DisplayMode.h"
#include "DDraw/Surfaces/FullScreenTagSurface.h"
#include "DDraw/Surfaces/PrimarySurface.h"
#include "DDraw/Surfaces/SurfaceImpl.h"
#include "Gdi/Gdi.h"
@ -14,7 +15,6 @@ extern HWND g_mainWindow;
namespace
{
bool g_isActive = true;
CompatWeakPtr<IUnknown> g_fullScreenDirectDraw = nullptr;
HWND g_fullScreenCooperativeWindow = nullptr;
DWORD g_fullScreenCooperativeFlags = 0;
Win32::FontSmoothing::SystemSettings g_fontSmoothingSettings = {};
@ -93,9 +93,9 @@ namespace
Gdi::disableEmulation();
}
if (g_fullScreenDirectDraw)
auto dd(DDraw::FullScreenTagSurface::getFullScreenDirectDraw());
if (dd)
{
CompatPtr<IDirectDraw7> dd(Compat::queryInterface<IDirectDraw7>(g_fullScreenDirectDraw.get()));
if (isActivated)
{
activateApp(*dd);
@ -130,9 +130,8 @@ namespace DDraw
return g_isActive;
}
void setFullScreenCooperativeLevel(CompatWeakPtr<IUnknown> dd, HWND hwnd, DWORD flags)
void setFullScreenCooperativeLevel(HWND hwnd, DWORD flags)
{
g_fullScreenDirectDraw = dd;
g_fullScreenCooperativeWindow = hwnd;
g_fullScreenCooperativeFlags = flags;
}

View File

@ -1,12 +1,8 @@
#pragma once
#define CINTERFACE
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <Unknwnbase.h>
#include "Common/CompatWeakPtr.h"
namespace DDraw
{
@ -14,7 +10,7 @@ namespace DDraw
{
void installHooks();
bool isActive();
void setFullScreenCooperativeLevel(CompatWeakPtr<IUnknown> dd, HWND hwnd, DWORD flags);
void setFullScreenCooperativeLevel(HWND hwnd, DWORD flags);
void uninstallHooks();
}
}

View File

@ -8,62 +8,6 @@
#include "DDraw/Surfaces/PrimarySurface.h"
#include "DDraw/Surfaces/Surface.h"
namespace
{
struct DirectDrawInterface
{
void* vtable;
void* ddObject;
DirectDrawInterface* next;
DWORD refCount;
DWORD unknown1;
DWORD unknown2;
};
DirectDrawInterface* g_fullScreenDirectDraw = nullptr;
CompatWeakPtr<IDirectDrawSurface> g_fullScreenTagSurface;
bool isFullScreenDirectDraw(void* dd)
{
return dd && g_fullScreenDirectDraw &&
static_cast<DirectDrawInterface*>(dd)->ddObject == g_fullScreenDirectDraw->ddObject;
}
void onReleaseFullScreenTagSurface()
{
DDraw::ActivateAppHandler::setFullScreenCooperativeLevel(nullptr, nullptr, 0);
g_fullScreenDirectDraw = nullptr;
g_fullScreenTagSurface = nullptr;
}
void setFullScreenDirectDraw(CompatRef<IDirectDraw> dd)
{
g_fullScreenTagSurface.release();
DDraw::FullScreenTagSurface::create(
dd, g_fullScreenTagSurface.getRef(), &onReleaseFullScreenTagSurface);
/*
IDirectDraw interfaces don't conform to the COM rule about object identity:
QueryInterface with IID_IUnknown does not always return the same pointer for the same object.
The IUnknown (== IDirectDraw v1) interface may even be freed, making the interface invalid,
while the DirectDraw object itself can still be kept alive by its other interfaces.
Unfortunately, the IDirectDrawSurface GetDDInterface method inherits this problem and may
also return an invalid (already freed) interface pointer.
To work around this problem, a copy of the necessary interface data is passed
to CompatActivateAppHandler, which is sufficient for it to use QueryInterface to "safely"
obtain a valid interface pointer (other than IUnknown/IDirectDraw v1) to the full-screen
DirectDraw object.
*/
static DirectDrawInterface fullScreenDirectDraw = {};
ZeroMemory(&fullScreenDirectDraw, sizeof(fullScreenDirectDraw));
DirectDrawInterface& ddIntf = reinterpret_cast<DirectDrawInterface&>(dd.get());
fullScreenDirectDraw.vtable = ddIntf.vtable;
fullScreenDirectDraw.ddObject = ddIntf.ddObject;
g_fullScreenDirectDraw = &fullScreenDirectDraw;
}
}
namespace DDraw
{
template <typename TDirectDraw>
@ -144,13 +88,13 @@ namespace DDraw
if (dwFlags & DDSCL_FULLSCREEN)
{
CompatPtr<IDirectDraw> dd(Compat::queryInterface<IDirectDraw>(This));
setFullScreenDirectDraw(*dd);
ActivateAppHandler::setFullScreenCooperativeLevel(
reinterpret_cast<IUnknown*>(g_fullScreenDirectDraw), hWnd, dwFlags);
DDraw::FullScreenTagSurface::create(*dd);
ActivateAppHandler::setFullScreenCooperativeLevel(hWnd, dwFlags);
}
else if (isFullScreenDirectDraw(This) && g_fullScreenTagSurface)
else if (CompatPtr<IDirectDraw7>(Compat::queryInterface<IDirectDraw7>(This)).get() ==
DDraw::FullScreenTagSurface::getFullScreenDirectDraw().get())
{
g_fullScreenTagSurface.release();
DDraw::FullScreenTagSurface::destroy();
}
}
return result;

View File

@ -42,6 +42,19 @@ namespace DDraw
SET_COMPAT_METHOD(SetClipper);
SET_COMPAT_METHOD(SetPalette);
SET_COMPAT_METHOD(Unlock);
setCompatVtable2(vtable);
}
template <typename TSurface>
void DirectDrawSurface<TSurface>::setCompatVtable2(Vtable<TSurface>& vtable)
{
SET_COMPAT_METHOD(GetDDInterface);
}
template <>
void DirectDrawSurface<IDirectDrawSurface>::setCompatVtable2(Vtable<IDirectDrawSurface>&)
{
}
template DirectDrawSurface<IDirectDrawSurface>;

View File

@ -15,5 +15,7 @@ namespace DDraw
static void setCompatVtable(Vtable<TSurface>& vtable);
private:
static void setCompatVtable2(Vtable<TSurface>& vtable);
};
}

View File

@ -1,21 +1,22 @@
#include "DDraw/Surfaces/SurfaceImpl.h"
#include "DDraw/Surfaces/FullScreenTagSurface.h"
namespace
{
CompatWeakPtr<IDirectDrawSurface> g_surface = nullptr;
}
namespace DDraw
{
FullScreenTagSurface::FullScreenTagSurface(const std::function<void()>& releaseHandler)
: m_releaseHandler(releaseHandler)
{
}
FullScreenTagSurface::~FullScreenTagSurface()
{
m_releaseHandler();
g_surface = nullptr;
}
HRESULT FullScreenTagSurface::create(CompatRef<IDirectDraw> dd, IDirectDrawSurface*& surface,
const std::function<void()>& releaseHandler)
HRESULT FullScreenTagSurface::create(CompatRef<IDirectDraw> dd)
{
destroy();
DDSURFACEDESC desc = {};
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
@ -23,13 +24,39 @@ namespace DDraw
desc.dwHeight = 1;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
IDirectDrawSurface* surface = nullptr;
HRESULT result = Surface::create(dd, desc, surface);
if (SUCCEEDED(result))
{
CompatPtr<IDirectDrawSurface7> surface7(Compat::queryInterface<IDirectDrawSurface7>(surface));
std::unique_ptr<Surface> privateData(new FullScreenTagSurface(releaseHandler));
std::unique_ptr<Surface> privateData(new FullScreenTagSurface());
attach(*surface7, privateData);
g_surface = surface;
}
return result;
}
void FullScreenTagSurface::destroy()
{
g_surface.release();
}
CompatPtr<IDirectDraw7> FullScreenTagSurface::getFullScreenDirectDraw()
{
if (!g_surface)
{
return nullptr;
}
CompatPtr<IUnknown> dd = nullptr;
auto tagSurface(getFullScreenTagSurface());
tagSurface.get()->lpVtbl->GetDDInterface(tagSurface, reinterpret_cast<void**>(&dd.getRef()));
return CompatPtr<IDirectDraw7>(Compat::queryInterface<IDirectDraw7>(dd.get()));
}
CompatPtr<IDirectDrawSurface7> FullScreenTagSurface::getFullScreenTagSurface()
{
return CompatPtr<IDirectDrawSurface7>(
Compat::queryInterface<IDirectDrawSurface7>(g_surface.get()));
}
}

View File

@ -1,8 +1,5 @@
#pragma once
#include <functional>
#include "Common/CompatPtr.h"
#include "DDraw/Surfaces/Surface.h"
namespace DDraw
@ -10,13 +7,11 @@ namespace DDraw
class FullScreenTagSurface : public Surface
{
public:
FullScreenTagSurface(const std::function<void()>& releaseHandler);
virtual ~FullScreenTagSurface();
static HRESULT create(CompatRef<IDirectDraw> dd, IDirectDrawSurface*& surface,
const std::function<void()>& releaseHandler);
private:
std::function<void()> m_releaseHandler;
static HRESULT create(CompatRef<IDirectDraw> dd);
static void destroy();
static CompatPtr<IDirectDraw7> getFullScreenDirectDraw();
static CompatPtr<IDirectDrawSurface7> getFullScreenTagSurface();
};
}

View File

@ -32,6 +32,27 @@ namespace
}
}
}
IID getDdIidFromVtablePtr(const void* vtablePtr)
{
if (CompatVtableBase<IDirectDraw>::s_origVtablePtr == vtablePtr)
{
return IID_IDirectDraw;
}
if (CompatVtableBase<IDirectDraw2>::s_origVtablePtr == vtablePtr)
{
return IID_IDirectDraw2;
}
if (CompatVtableBase<IDirectDraw4>::s_origVtablePtr == vtablePtr)
{
return IID_IDirectDraw4;
}
if (CompatVtableBase<IDirectDraw7>::s_origVtablePtr == vtablePtr)
{
return IID_IDirectDraw7;
}
return IID_IUnknown;
}
}
namespace DDraw
@ -56,7 +77,10 @@ namespace DDraw
return refCount;
}
Surface::Surface() : m_refCount(0)
Surface::Surface()
: m_ddId()
, m_ddObject(nullptr)
, m_refCount(0)
{
}
@ -69,6 +93,20 @@ namespace DDraw
if (SUCCEEDED(dds->SetPrivateData(&dds, IID_CompatSurfacePrivateData,
privateData.get(), sizeof(privateData.get()), DDSPD_IUNKNOWNPOINTER)))
{
CompatPtr<IUnknown> dd;
CompatVtableBase<IDirectDrawSurface7>::s_origVtable.GetDDInterface(
&dds, reinterpret_cast<void**>(&dd.getRef()));
privateData->createImpl();
privateData->m_impl->m_data = privateData.get();
privateData->m_impl2->m_data = privateData.get();
privateData->m_impl3->m_data = privateData.get();
privateData->m_impl4->m_data = privateData.get();
privateData->m_impl7->m_data = privateData.get();
privateData->m_ddId = getDdIidFromVtablePtr(reinterpret_cast<void**>(dd.get())[0]);
privateData->m_ddObject = reinterpret_cast<void**>(dd.get())[1];
privateData.release();
}
}

View File

@ -6,12 +6,13 @@
#include <ddraw.h>
#include "Common/CompatPtr.h"
#include "Common/CompatRef.h"
namespace DDraw
{
template <typename TSurface>
class SurfaceImpl;
template <typename TSurface> class SurfaceImpl;
template <typename TSurface> class SurfaceImpl2;
class Surface
{
@ -43,10 +44,15 @@ namespace DDraw
std::unique_ptr<SurfaceImpl<IDirectDrawSurface7>> m_impl7;
private:
template <typename TDirectDrawSurface>
friend class SurfaceImpl2;
static HRESULT WINAPI attachToLinkedSurfaces(
IDirectDrawSurface7* surface, DDSURFACEDESC2* desc, void* rootSurface);
virtual void createImpl();
IID m_ddId;
void* m_ddObject;
DWORD m_refCount;
};
}

View File

@ -7,6 +7,16 @@
namespace
{
struct DirectDrawInterface
{
const void* vtable;
void* ddObject;
DirectDrawInterface* next;
DWORD refCount;
DWORD unknown1;
DWORD unknown2;
};
bool mirrorBlt(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
RECT srcRect, DWORD mirrorFx);
@ -232,6 +242,18 @@ namespace DDraw
{
return s_origVtable.GetCaps(This, lpDDSCaps);
}
template <typename TSurface>
HRESULT SurfaceImpl2<TSurface>::GetDDInterface(TSurface* /*This*/, LPVOID* lplpDD)
{
DirectDrawInterface dd = {};
dd.vtable = IID_IDirectDraw7 == m_data->m_ddId
? static_cast<const void*>(CompatVtableBase<IDirectDraw>::s_origVtablePtr)
: static_cast<const void*>(CompatVtableBase<IDirectDraw7>::s_origVtablePtr);
dd.ddObject = m_data->m_ddObject;
return CompatVtableBase<IDirectDraw>::s_origVtable.QueryInterface(
reinterpret_cast<IDirectDraw*>(&dd), m_data->m_ddId, lplpDD);
}
template <typename TSurface>
HRESULT SurfaceImpl<TSurface>::GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc)

View File

@ -10,8 +10,24 @@
namespace DDraw
{
class Surface;
template <typename TSurface>
class SurfaceImpl
class SurfaceImpl2
{
public:
SurfaceImpl2() : m_data(nullptr) {}
virtual HRESULT GetDDInterface(TSurface* This, LPVOID* lplpDD);
protected:
friend class Surface;
Surface* m_data;
};
template <typename TSurface>
class SurfaceImpl : public SurfaceImpl2<TSurface>
{
public:
typedef typename Types<TSurface>::TSurfaceDesc TSurfaceDesc;

View File

@ -72,6 +72,7 @@
<TargetName>ddraw</TargetName>
<IncludePath>$(ProjectDir);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>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
@ -94,10 +95,12 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<ModuleDefinitionFile>Dll/DDrawCompat.def</ModuleDefinitionFile>
<AdditionalDependencies>dxguid.lib;detours.lib;msimg32.lib;oleacc.lib;uxtheme.lib;dwmapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -128,6 +131,7 @@
<ModuleDefinitionFile>Dll/DDrawCompat.def</ModuleDefinitionFile>
<AdditionalDependencies>dxguid.lib;detours.lib;msimg32.lib;oleacc.lib;uxtheme.lib;dwmapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>No</GenerateDebugInformation>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">