COM Object Reference Counting
by Noam Cohen 

Listing One
// code snippet from CUnknown.h from "Inside COM" by Dale Rogerson, 
// Microsoft Press.
// Modified by Noam Cohen.
///////////////////////////////////////////////////////////
class CUnknown : public INondelegatingUnknown
{
public:
    // Nondelegating IUnknown implementation
    // ...
protected:
    // ...
    // helper functions to register the parameters of the caller
    // of AddRef and Release()
    void RegisterAddRef(DWORD _ebp);
    void RegisterRelease(DWORD _ebp);
private:
    // ...
    // Reference count for this object
    // helper function. get information on the caller of 
    // the function whose ebp == _ebp
    HRESULT ParamsOfCaller(IN DWORD _ebp, OUT ULONG &line,
            OUT char* szSymbolName, IN  UINT    nSymNameLen,
            OUT char* szFileName, INT nFileNameLen,
            OUT ULONG &displacement);
}; // CUnknown


Listing Two
///////////////////////////////////////////////////////////
// Delegating IUnknown
//   - Delegates to the nondelegating IUnknown, or to the
//     outer IUnknown if the component is aggregated.
#define DECLARE_IUNKNOWN                                     \
    virtual HRESULT __stdcall                                \
        QueryInterface(const IID& iid, void** ppv)           \
    {                                                        \
        return GetOuterUnknown()->QueryInterface(iid,ppv) ;  \
    } ;                                                      \
    virtual ULONG __stdcall AddRef()                           \
    {                                                          \
        unsigned int _ebp;                                   \
        __asm {mov _ebp, ebp}                                \
        RegisterAddRef(_ebp);                                \
        return GetOuterUnknown()->AddRef() ;                 \
    } ;                                                      \
    virtual ULONG __stdcall Release()                          \
    {                                                          \
        unsigned int _ebp;                                   \
        __asm {mov _ebp, ebp}                                \
        RegisterRelease(_ebp);                               \
        return GetOuterUnknown()->Release() ;                \
    } ;


Listing Three
BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, void* /*lpReserved*/)
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        CFactory::s_hModule = hModule ;
        // even if we fail, business as usual
        (void)ghSym.LoadSymbols(); 
    }
    return TRUE;
}


Listing Four
// ObjData contains all the data relevant to one key (the interface pointer)
typedef struct { 
ObjectName objName;
    ParamList addRefed;
    ParamList released;
}  ObjData;
// the container of all the <interface pointer, value> associations
typedef std::map<void*, ObjData> ObjectsMap;


Listing Five
/* This interface can be exposed by a COM object that exposes 
some identifying properties. */
interface INamedObject2 : IUnknown
{
    /*------------------------------------------------------------------
    Get a name for this object's clas ( e.g. "TS demuxer" )
    Return: 
        null terminated string
    */
    virtual const char* GetClassName() = 0;
    /*-------------------------------------------------------------------
    Get the CLASS id of this COM object.
    It is recommended to return the CLSID used when creating this object
    Return: 
        S_OK
        E_NOTIMPL
    */
    virtual HRESULT GetClassId(const GUID &) = 0;
    /*-------------------------------------------------------------------
    Get a name for this object ( e.g. "object in server 34" )
    Return: 
        null terminated string
    */
    virtual const char* GetObjectName() = 0;
    /*-------------------------------------------------------------------
    Get the INSTANCE id of this COM object.
    Return: 
        S_OK
        E_NOTIMPL
    */
    virtual HRESULT GetObjectId(const GUID &) = 0;
}; // INamedObject2

// helper macro for those lazy people who need minimal functionality
#define CLASS_NAME_IMPL(szClassName) \
    const char* GetClassName(){return szClassName;} \
    HRESULT GetClassId(const GUID &){ return E_NOTIMPL;}\
    const char* GetObjectName(){return "";}\
    HRESULT GetObjectId(const GUID &){ return E_NOTIMPL;}
#endif








3

