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

View File

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

View File

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

View File

@ -8,62 +8,6 @@
#include "DDraw/Surfaces/PrimarySurface.h" #include "DDraw/Surfaces/PrimarySurface.h"
#include "DDraw/Surfaces/Surface.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 namespace DDraw
{ {
template <typename TDirectDraw> template <typename TDirectDraw>
@ -144,13 +88,13 @@ namespace DDraw
if (dwFlags & DDSCL_FULLSCREEN) if (dwFlags & DDSCL_FULLSCREEN)
{ {
CompatPtr<IDirectDraw> dd(Compat::queryInterface<IDirectDraw>(This)); CompatPtr<IDirectDraw> dd(Compat::queryInterface<IDirectDraw>(This));
setFullScreenDirectDraw(*dd); DDraw::FullScreenTagSurface::create(*dd);
ActivateAppHandler::setFullScreenCooperativeLevel( ActivateAppHandler::setFullScreenCooperativeLevel(hWnd, dwFlags);
reinterpret_cast<IUnknown*>(g_fullScreenDirectDraw), 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; return result;

View File

@ -42,6 +42,19 @@ namespace DDraw
SET_COMPAT_METHOD(SetClipper); SET_COMPAT_METHOD(SetClipper);
SET_COMPAT_METHOD(SetPalette); SET_COMPAT_METHOD(SetPalette);
SET_COMPAT_METHOD(Unlock); 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>; template DirectDrawSurface<IDirectDrawSurface>;

View File

@ -15,5 +15,7 @@ namespace DDraw
static void setCompatVtable(Vtable<TSurface>& vtable); 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/SurfaceImpl.h"
#include "DDraw/Surfaces/FullScreenTagSurface.h" #include "DDraw/Surfaces/FullScreenTagSurface.h"
namespace
{
CompatWeakPtr<IDirectDrawSurface> g_surface = nullptr;
}
namespace DDraw namespace DDraw
{ {
FullScreenTagSurface::FullScreenTagSurface(const std::function<void()>& releaseHandler)
: m_releaseHandler(releaseHandler)
{
}
FullScreenTagSurface::~FullScreenTagSurface() FullScreenTagSurface::~FullScreenTagSurface()
{ {
m_releaseHandler(); g_surface = nullptr;
} }
HRESULT FullScreenTagSurface::create(CompatRef<IDirectDraw> dd, IDirectDrawSurface*& surface, HRESULT FullScreenTagSurface::create(CompatRef<IDirectDraw> dd)
const std::function<void()>& releaseHandler)
{ {
destroy();
DDSURFACEDESC desc = {}; DDSURFACEDESC desc = {};
desc.dwSize = sizeof(desc); desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
@ -23,13 +24,39 @@ namespace DDraw
desc.dwHeight = 1; desc.dwHeight = 1;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
IDirectDrawSurface* surface = nullptr;
HRESULT result = Surface::create(dd, desc, surface); HRESULT result = Surface::create(dd, desc, surface);
if (SUCCEEDED(result)) if (SUCCEEDED(result))
{ {
CompatPtr<IDirectDrawSurface7> surface7(Compat::queryInterface<IDirectDrawSurface7>(surface)); 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); attach(*surface7, privateData);
g_surface = surface;
} }
return result; 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 #pragma once
#include <functional>
#include "Common/CompatPtr.h"
#include "DDraw/Surfaces/Surface.h" #include "DDraw/Surfaces/Surface.h"
namespace DDraw namespace DDraw
@ -10,13 +7,11 @@ namespace DDraw
class FullScreenTagSurface : public Surface class FullScreenTagSurface : public Surface
{ {
public: public:
FullScreenTagSurface(const std::function<void()>& releaseHandler);
virtual ~FullScreenTagSurface(); virtual ~FullScreenTagSurface();
static HRESULT create(CompatRef<IDirectDraw> dd, IDirectDrawSurface*& surface, static HRESULT create(CompatRef<IDirectDraw> dd);
const std::function<void()>& releaseHandler); static void destroy();
static CompatPtr<IDirectDraw7> getFullScreenDirectDraw();
private: static CompatPtr<IDirectDrawSurface7> getFullScreenTagSurface();
std::function<void()> m_releaseHandler;
}; };
} }

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 namespace DDraw
@ -56,7 +77,10 @@ namespace DDraw
return refCount; 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, if (SUCCEEDED(dds->SetPrivateData(&dds, IID_CompatSurfacePrivateData,
privateData.get(), sizeof(privateData.get()), DDSPD_IUNKNOWNPOINTER))) 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(); privateData.release();
} }
} }

View File

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

View File

@ -7,6 +7,16 @@
namespace namespace
{ {
struct DirectDrawInterface
{
const void* vtable;
void* ddObject;
DirectDrawInterface* next;
DWORD refCount;
DWORD unknown1;
DWORD unknown2;
};
bool mirrorBlt(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src, bool mirrorBlt(CompatRef<IDirectDrawSurface7> dst, CompatRef<IDirectDrawSurface7> src,
RECT srcRect, DWORD mirrorFx); RECT srcRect, DWORD mirrorFx);
@ -232,6 +242,18 @@ namespace DDraw
{ {
return s_origVtable.GetCaps(This, lpDDSCaps); 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> template <typename TSurface>
HRESULT SurfaceImpl<TSurface>::GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc) HRESULT SurfaceImpl<TSurface>::GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc)

View File

@ -10,8 +10,24 @@
namespace DDraw namespace DDraw
{ {
class Surface;
template <typename TSurface> 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: public:
typedef typename Types<TSurface>::TSurfaceDesc TSurfaceDesc; typedef typename Types<TSurface>::TSurfaceDesc TSurfaceDesc;

View File

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