开发者

How to iterate the vtable of COM coclass?

开发者_StackOverflowHow can I iterate/access the vtable of COM coclass which will implement the methods of its exposed interfaces?

I need to access the part of the vtable where all addresses of exposed methods of its interfaces are stored.

e.g. Math is COM object, its exposed interface is "Operations" and "Sum" is the method of this interface, how do I get the address of "Sum"?


I'm not going to ask why are you doing it this way, but perhaps this could help... Every COM object must implement at least the IUnknown interface. Hence, the first four bytes of the COM object instance is the pointer to IUnknown object. The first four bytes of the IUnknown object (and any other object with virtual functions) is the pointer to vtbl.

(There is no error checking in this example, so please don't split hair on that subject.)

I used an instance of IReferenceClock for demonstration.

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;
}


Sorry to answer with a question, but I have to ask "from where?"

If you mean, how can you iterate through the vtable from a COM client, I don't think you can. On the client side, all you have is a proxy that knows how to communicate (maybe cross-apartment or cross-process) with the COM server. You could maybe probe the vtable of that proxy, but it can never tell you the addresses of the functions inside the COM server.

Of course, if the server is actually running in a different process, the address of the functions might be of little use to you. Even if the server is in the same process, but in a different apartment, getting function addresses might be dangerous: you could call the functions directly, circumventing COM's interception, and break the server class's assumptions around calling thread, etc.

I guess that iterating the vtable is a means-to-an-end...? Maybe post what you're actually trying to do and I think COM probably has a way to do it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜