mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Fixed GetDDInterface implementation
This commit is contained in:
parent
d163787437
commit
30bf0435f8
@ -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());
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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>;
|
||||
|
@ -15,5 +15,7 @@ namespace DDraw
|
||||
|
||||
static void setCompatVtable(Vtable<TSurface>& vtable);
|
||||
|
||||
private:
|
||||
static void setCompatVtable2(Vtable<TSurface>& vtable);
|
||||
};
|
||||
}
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
};
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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'">
|
||||
|
Loading…
x
Reference in New Issue
Block a user