Implementing IUnknown in C++

Implementing QueryInterface, AddRef, and Release in C++ is fairly simple. After some standard validation of the parameters passed in, an implementation of QueryInterface checks the identifier of the requested interface against the list of supported interfaces. If the requested identifier is among those supported, AddRef is called and the this pointer returned. If the requested identifier is not on the supported list, the output pointer is set to NULL and the MAPI_E_INTERFACE_NOT_SUPPORTED value is returned.

The following example shows how QueryInterface can be implemented in C++ for a status object, an object that is a subclass of the IMAPIStatus : IMAPIProp interface. IMAPIStatus inherits from IUnknown through IMAPIProp. Therefore, because these interfaces are related through inheritance, if a caller asks for any of them, the this pointer can be returned.

HRESULT CMyMAPIObject::QueryInterface (REFIID   riid,  
                                       LPVOID * ppvObj) 
{ 
    // Always set out parameter to NULL, validating it first 
    if (IsBadWritePtr(ppvObj, sizeof(LPVOID))) 
        return E_INVALIDARG;  
 
    *ppvObj = NULL; 
 
    if (riid == IID_IUnknown || riid == IID_IMAPIProp || 
        riid == IID_IMAPIStatus) 
    { 
        // Increment reference count and return pointer
        *ppvObj = (LPVOID)this; 
        AddRef(); 
        return NOERROR; 
    } 
 
    return E_NOINTERFACE; 
} 
 

Note that this example is a 32-bit implementation; 16-bit implementations must include a call to ResultFromScode on their return statements to translate the 16-bit status code values to HRESULT values. For example, the final return statement would be recoded for 16-bit platforms as:

return ResultFromScode(E_NOINTERFACE);
 

The following code samples show how to implement the AddRef and Release methods for the CMyMAPIObject object. Because implementing AddRef and Release is so simple, many service providers choose to implement them inline. The calls to the Win32 functions InterlockedIncrement and InterlockedDecrement are to ensure thread safety. The memory for the object is freed by the destructor which is called when the Release method deletes the object.

ULONG CMyMAPIObject::AddRef() 
{    
    InterlockedIncrement(m_cRef); 
    return m_cRef; 
} 
 
ULONG CMyMAPIObject::Release() 
{ 
    // Decrement the object's internal counter 
    ULONG ulRefCount = InterlockedDecrement(m_cRef); 
 
    if (0 == m_cRef) 
    {
        delete this; 
    }
 
    return ulRefCount; 
}