如何迭代COM coclass的vtable?

5

我该如何迭代/访问COM coclass的vtable,以实现其公开接口的方法?

我需要访问存储其接口所有公开方法地址的vtable部分。

例如,Math是COM对象,其公开接口为“操作”,而“Sum”是此接口的方法,我如何获取“Sum”的地址?

2个回答

7
我不会问你为什么要这样做,但也许这可以帮助你... 每个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
点赞,因为你没有试图给出“不良实践”的讲解或询问“你为什么需要它”,而是提供了一个答案。 - icecream
冰淇淋,非常感谢您的评论。我是真心的,因为几乎不可能找到一个在任何可用主题上都不需要纠缠的开发人员。干杯!!! - user472155

0

很抱歉用问题来回答,但我必须问“从哪里开始?”

如果你的意思是如何通过COM客户端迭代vtable,我认为你不能。在客户端上,你只有一个代理,它知道如何与COM服务器通信(可能跨进程或跨应用程序)。你可以探测该代理的vtable,但它永远无法告诉你COM服务器内部函数的地址。

当然,如果服务器实际上在不同的进程中运行,函数的地址对你可能没有什么用处。即使服务器在同一进程中,但在不同的公寓中,获取函数地址可能是危险的:你可以直接调用函数,规避COM的拦截,并打破服务器类对调用线程等方面的假设。

我想迭代vtable只是达到目的的一种手段...?也许你可以发布你实际想要做什么,我认为COM可能有一种方法可以实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接