as already noted in comments
__thiscall and __fastcall are not the same calling convention
even for x64. for x86 this is obvious - __thiscall - pass first parameter (this) via Ecx register, and next parameters via stack (i skip now float/double parameters case). __fastcall - 1-first via Ecx, 2-second via Edx, and next via stack
in case x64 (again let assume that no float/double parameters) - first 4 parameters via Rcx, Rdx, R8, R9 and next in stack. so look like x64 have single and common calling convention (no difference between __stdcall, __fastcall, __cdecl, __thiscall)
but exist question about implicit parameters. say in case __thiscall - the first parameter - this is implicit parameter, always passed as first parameter via Ecx/Rcx
and now case when function try "return" object. really on any platform function can return something only via cpu registers. it finite count, and only several of it can be used for return value store.
say on x86(x64) - for return value can be used: AL, AX, EAX, RAX, DAX:EAX, RDX:RAX
so function can return only something that have size - 1, 2, 4, 8 (and 16 for x64)
if function try "return" object with another size - this is impossible do direct, compiler need transform your code. for example if you write function:
DriverPose_t GetPose(ITrackedDeviceServerDriver* thisptr)
{
DriverPose_t pos = ...;
return pos;
}
and call
DriverPose_t pos = GetPose(thisptr);
compiler (of course this already implementation details, different compilers can do this in different ways !) can transform this to
void GetPose(DriverPose_t *ppos, ITrackedDeviceServerDriver* thisptr)
{
DriverPose_t pos = ...;
*ppos = pos;
}
and call to
DriverPose_t pos;
GetPose(&pos, thisptr);
so here pointer to object passed to function as first ,hidden/implicit, parameter. but in case member function, still exist another hidden/implicit, parameter - this, which always passed as first, as result hidden/implicit, parameter for return value moved to second place !
struct ITrackedDeviceServerDriver
{
DriverPose_t GetPose()
{
DriverPose_t pos = ...;
return pos;
}
};
and call
ITrackedDeviceServerDriver obj;
DriverPose_t pos = obj.GetPose();
can be transformed to
struct ITrackedDeviceServerDriver
{
void GetPose(DriverPose_t *ppos)
{
DriverPose_t pos = ...;
*ppos = pos;
}
};
and call to
ITrackedDeviceServerDriver obj;
DriverPose_t pos;
obj.GetPose(&pos);
so real signature of function, if "uncover" this parameter is
void ITrackedDeviceServerDriver::GetPose(ITrackedDeviceServerDriver* this, DriverPose_t *ppos)
{
DriverPose_t pos = ...;
*ppos = pos;
}
and call
ITrackedDeviceServerDriver obj;
DriverPose_t pos;
GetPose(&obj, &pos);
so compare
void ITrackedDeviceServerDriver::GetPose(ITrackedDeviceServerDriver* this, DriverPose_t *ppos);
and
void GetPose(DriverPose_t *ppos, ITrackedDeviceServerDriver* thisptr);
you implement
DriverPose_t GetPose_Hook(ITrackedDeviceServerDriver* thisptr);
which will be transformed by compiler to
void GetPose_Hook(DriverPose_t* ,ITrackedDeviceServerDriver* thisptr);
but really you need implement next hook:
void GetPose_Hook(ITrackedDeviceServerDriver* thisptr, DriverPose_t* );
you confuse first and second parameters. however i think not need change object vtable at all, instead need return proxy object to client. possible and very generic implementation for COM interface hooks, but it too long for post here. for your case can be done next example of hook:
struct DriverPose_t
{
int x, y, z;
};
struct __declspec(novtable) IDemoInterface
{
virtual DriverPose_t GetPose() = 0;
virtual ULONG GetComponent( const char * pchComponentNameAndVersion ) = 0;
virtual void Delete() = 0;
};
class DemoObject : public IDemoInterface
{
ULONG v;
DriverPose_t pos;
virtual DriverPose_t GetPose()
{
DbgPrint("%s<%p>\n", __FUNCTION__, this);
return pos;
}
virtual ULONG GetComponent( const char * pchComponentNameAndVersion )
{
DbgPrint("%s<%p>(%s)\n", __FUNCTION__, this, pchComponentNameAndVersion);
return v;
}
virtual void Delete()
{
delete this;
}
public:
DemoObject(ULONG v, int x, int y, int z) : v(v)
{
pos.x = x, pos.y = y, pos.z = z;
DbgPrint("%s<%p>\n", __FUNCTION__, this);
}
virtual ~DemoObject()
{
DbgPrint("%s<%p>\n", __FUNCTION__, this);
}
};
class Hook_DemoInterface : public IDemoInterface
{
IDemoInterface* pItf;
virtual DriverPose_t GetPose()
{
DriverPose_t pos = pItf->GetPose();
DbgPrint("%s<%p>=<%d, %d, %d>\n", __FUNCTION__, this, pos.x, pos.y, pos.z);
return pos;
}
virtual ULONG GetComponent( const char * pchComponentNameAndVersion )
{
ULONG v = pItf->GetComponent(pchComponentNameAndVersion);
DbgPrint("%s<%p>(%s)=%u\n", __FUNCTION__, this, pchComponentNameAndVersion);
return v;
}
virtual void Delete()
{
delete this;
}
public:
Hook_DemoInterface(IDemoInterface* pItf) : pItf(pItf)
{
DbgPrint("%s<%p>\n", __FUNCTION__, this);
}
~Hook_DemoInterface()
{
pItf->Delete();
DbgPrint("%s<%p>\n", __FUNCTION__, this);
}
};
BOOL CreateDemoIface(IDemoInterface** ppItf)
{
if (DemoObject* pObj = new DemoObject (1, -1, 2, 3))
{
*ppItf = pObj;
return TRUE;
}
return FALSE;
}
BOOL Hook_CreateDemoIface(IDemoInterface** ppItf)
{
IDemoInterface* pItf;
if (CreateDemoIface(&pItf))
{
if (Hook_DemoInterface* pObj = new Hook_DemoInterface(pItf))
{
*ppItf = pObj;
return TRUE;
}
*ppItf = pItf;
return TRUE;
}
return FALSE;
}
void UseIface(IDemoInterface* pItf)
{
ULONG v = pItf->GetComponent("some string");
DriverPose_t pos = pItf->GetPose();
DbgPrint("v=%u, pos<%d, %d, %d>\n", v, pos.x, pos.y, pos.z);
}
void test()
{
IDemoInterface* pItf;
if (CreateDemoIface(&pItf))
{
UseIface(pItf);
pItf->Delete();
}
if (Hook_CreateDemoIface(&pItf))
{
UseIface(pItf);
pItf->Delete();
}
}
instead hook object vtable - hook (if possible) object creation CreateDemoIface - replace it to self Hook_CreateDemoIface which return proxy object.
debug output
DemoObject::DemoObject<0000012C31E08F70>
DemoObject::GetComponent<0000012C31E08F70>(some string)
DemoObject::GetPose<0000012C31E08F70>
v=1, pos<-1, 2, 3>
DemoObject::~DemoObject<0000012C31E08F70>
DemoObject::DemoObject<0000012C31E08F70>
Hook_DemoInterface::Hook_DemoInterface<0000012C31DFAA10>
DemoObject::GetComponent<0000012C31E08F70>(some string)
Hook_DemoInterface::GetComponent<0000012C31DFAA10>(some string)=1
DemoObject::GetPose<0000012C31E08F70>
Hook_DemoInterface::GetPose<0000012C31DFAA10>=<-1, 2, 3>
v=1, pos<-1, 2, 3>
DemoObject::~DemoObject<0000012C31E08F70>
Hook_DemoInterface::~Hook_DemoInterface<0000012C31DFAA10>