如何迭代/访问COM coclass的vtable,它将实现其公开接口的方法?
我需要访问vtable中存储其接口的所有公开地址的部分。
e.g。 Math是COM对象,它的公开接口是“Operations”,“Sum”是这个接口的方法,我如何得到“Sum”的地址?
答案 0 :(得分:6)
我不会问为什么你这样做,但也许这可能会有所帮助...... 每个COM对象必须至少实现IUnknown接口。因此,COM对象实例的前四个字节是指向IUnknown对象的指针。 IUnknown对象的前四个字节(以及任何其他具有虚函数的对象)是指向vtbl的指针。
(此示例中没有错误检查,因此请不要在该主题上拆分。)
我使用了一个IReferenceClock实例进行演示。
int main()
{
CoInitialize( NULL );
IReferenceClock* pRefClock;
HRESULT hr = CoCreateInstance( CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, IID_IReferenceClock, (void**)&pRefClock );
DWORD* pIUnknownAddress = (DWORD*)pRefClock;
DWORD* pVTBLaddress = (DWORD*)*pIUnknownAddress;
// for example, the next interface could be accessed like this
DWORD* pNextInterfaceAddress = ( (DWORD*)pRefClock ) + 1;
DWORD* pNextVTBLaddress = (DWORD*)*pNextInterfaceAddress;
// and you would access virtual functions in the same way as QueryInterface, AddRef and Release below in this example
HRESULT (__stdcall *pQueryInterfaceFunction)(void*, REFIID, void**);
ULONG (__stdcall *pAddRef)( void* );
ULONG (__stdcall *pRelease)( void* );
// IUnknown looks like this:
//
// virtual HRESULT QueryInterface( REFIID riid, void** ppvObject);
// virtual ULONG AddRef( void );
// virtual ULONG Release( void );
//
// So, the first function in vtbl is QueryInterface, the second is AddRef...
pQueryInterfaceFunction = (HRESULT (__stdcall*)(void*, REFIID, void**))*pVTBLaddress;
pAddRef = (ULONG (__stdcall *)( void* ))*( pVTBLaddress + 1 );
pRelease = (ULONG (__stdcall *)( void* ))*( pVTBLaddress + 2 );
// Note: extra void* is actually this pointer.. see below that we pass pRefClock to every call
IUnknown* pUnknown;
UINT nRefCount;
hr = pQueryInterfaceFunction( pRefClock, IID_IUnknown, (void**)&pUnknown );
if( SUCCEEDED( hr ) )
{
nRefCount = pUnknown->Release();
ATLTRACE( TEXT( "nRefCount = %d\n" ), nRefCount );
}
nRefCount = pAddRef( pRefClock );
ATLTRACE( TEXT( "nRefCount after AddRef() call = %d\n" ), nRefCount );
nRefCount = pRelease( pRefClock );
ATLTRACE( TEXT( "nRefCount after Release() call = %d\n" ), nRefCount );
nRefCount = pRefClock->Release();
CoUninitialize();
return 0;
}
答案 1 :(得分:0)
很抱歉回答一个问题,但我不得不问“从哪里来?”
如果你的意思是,你怎么能从COM客户端迭代vtable,我认为你不能。在客户端,您所拥有的只是一个知道如何与COM服务器进行通信(可能是跨公寓或跨进程)的代理。您可以探测该代理的vtable,但它永远无法告诉您COM服务器内部函数的地址。
当然,如果服务器实际上是在不同的进程中运行,那么函数的地址对您来说可能没用。即使服务器处于相同的进程中,但是在不同的公寓中,获取函数地址可能也很危险:您可以直接调用函数,绕过COM的拦截,并打破服务器类围绕调用线程等的假设。
我想迭代vtable是一种手段到端......?也许发布你实际上想要做的事情,我认为COM可能有办法做到这一点。