Search code examples
com

Strange use of null smart pointer in COM


As the Picture shows, I don't know why m_spServer, an interface pointer, when tested as null, can be used to call a member function CreateInstance(). Could anyone tell me why?

enter image description here

This is the interface definition, I did't find CreateInstance() in the interface, neither the interface pointer definition.

enter image description here


Solution

  • Look closely at the code:

    m_spServer.CoCreateInstance(...);
    

    Two things to note:

    1. m_spSever is not an actual pointer. Rather it's an instance of a smart pointer template class of type CComPtr. That is, it has overloaded the -> operator to dereference the underlying raw pointer (IAtlasServer*). Similarly, the == operator is overloaded to test for nullness.

    2. The method is invoked as .CoCreateInstance with a "dot". Not ->CoCreateInstance with an "arrow". The smart pointer is never "null". The pointer it contains very well could be. That means the method is getting invoked on the CComPtr instance itself, not on the underlying raw pointer.

    Let's look at the implementation for CComPtr::CoCreateInstance.

    template <class T>
    class CComPtrBase
    {
        ...
    
        bool operator==(_In_opt_ T* pT) const throw()
        {
            return p == pT;
        }
    
        ...
    
        _Check_return_ HRESULT CoCreateInstance(
            _In_ REFCLSID rclsid,
            _Inout_opt_ LPUNKNOWN pUnkOuter = NULL,
            _In_ DWORD dwClsContext = CLSCTX_ALL) throw()
        {
            ATLASSERT(p == NULL);
            return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p);
        }
    
        ...
    
        T* p;
    
        ...
    };
    

    You'll see that CComPtr wraps a native ("raw") pointer member variable named "p". The overloaded == operator tests p against the native pointer type being compared with. The method on CComPtr named CoCreateInstance simply asserts that the raw pointer it contains is already null and then attempts to do a native CoCreateInstance call with the raw pointer as the "out" param.

    Smart pointers are awesome and are excellent for COM programming. The destructor of a CComPtr automatically invokes "Release" on the underlying raw pointer appropirately. If used correctly, you'll avoid common reference count issues without ever having to think about "AddRef" and "Release".