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

149 lines
4.2 KiB
C++

#pragma once
#include <map>
#include <string>
#include <vector>
#include "DDrawLog.h"
#include "DDrawVtableVisitor.h"
#include "Hook.h"
template <typename Interface>
using Vtable = typename std::remove_pointer<decltype(Interface::lpVtbl)>::type;
template <typename Interface>
class CompatVtableBase
{
public:
typedef Interface Interface;
static const Vtable<Interface>& getOrigVtable(Interface& intf)
{
return s_origVtable.AddRef ? s_origVtable : *intf.lpVtbl;
}
static Vtable<Interface> s_origVtable;
};
template <typename CompatInterface, typename Interface>
class CompatVtable : public CompatVtableBase<Interface>
{
public:
static void hookVtable(Interface& intf)
{
static bool isInitialized = false;
if (!isInitialized)
{
isInitialized = true;
s_vtablePtr = intf.lpVtbl;
s_origVtable = *intf.lpVtbl;
InitVisitor visitor;
forEach<Vtable<Interface>>(visitor);
}
}
private:
class InitVisitor
{
public:
template <typename MemberDataPtr, MemberDataPtr ptr>
void visit()
{
if (!(s_compatVtable.*ptr))
{
s_threadSafeVtable.*ptr = s_origVtable.*ptr;
s_compatVtable.*ptr = s_origVtable.*ptr;
}
else
{
s_threadSafeVtable.*ptr = getThreadSafeFuncPtr<MemberDataPtr, ptr>(s_compatVtable.*ptr);
Compat::hookFunction(reinterpret_cast<void*&>(s_origVtable.*ptr), s_threadSafeVtable.*ptr);
}
}
template <typename MemberDataPtr, MemberDataPtr ptr>
void visitDebug(const std::string& vtableTypeName, const std::string& funcName)
{
s_funcNames[getKey<MemberDataPtr, ptr>()] = vtableTypeName + "::" + funcName;
s_threadSafeVtable.*ptr = getThreadSafeFuncPtr<MemberDataPtr, ptr>(s_compatVtable.*ptr);
Compat::hookFunction(reinterpret_cast<void*&>(s_origVtable.*ptr), s_threadSafeVtable.*ptr);
if (!(s_compatVtable.*ptr))
{
s_compatVtable.*ptr = s_origVtable.*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...>;
}
template <typename MemberDataPtr, MemberDataPtr ptr, typename Result, typename IntfPtr, typename... Params>
static Result STDMETHODCALLTYPE threadSafeFunc(IntfPtr This, Params... params)
{
Compat::origProcs.AcquireDDThreadLock();
#ifdef _DEBUG
Compat::LogEnter(s_funcNames[getKey<MemberDataPtr, ptr>()].c_str(), This, params...);
#endif
Result result = (s_compatVtable.*ptr)(This, params...);
#ifdef _DEBUG
Compat::LogLeave(s_funcNames[getKey<MemberDataPtr, ptr>()].c_str(), This, params...) << result;
#endif
Compat::origProcs.ReleaseDDThreadLock();
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<std::vector<unsigned char>, std::string> s_funcNames;
};
template <typename Interface>
Vtable<Interface> CompatVtableBase<Interface>::s_origVtable = {};
template <typename CompatInterface, typename Interface>
Vtable<Interface>* CompatVtable<CompatInterface, Interface>::s_vtablePtr = nullptr;
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<std::vector<unsigned char>, std::string> CompatVtable<CompatInterface, Interface>::s_funcNames;