Wednesday, June 29, 2005 10:17 AM
LarryOsterman
What's wrong with this code, part lucky 13
Today's example is a smidge long, I've stripped out everything I can possibly imagine stripping out to reduce size.
This is a very real world example that we recently hit - only the names have been changed to protect the innocent.
I've used the built-in C++ decorations for interfaces, but that was just to get this stuff to compile in a single source file, it's not related to the bug.
extern CLSID CLSID_FooDerived;
[
object,
uuid("0A0DDEDC-C422-4BB3-9869-4FED020B66C5"),
]
__interface IFooBase : IUnknown
{
HRESULT FooBase();
};
class CFooBase: public IFooBase
{
LONG _refCount;
virtual ~CFooBase()
{
ASSERT(_refCount == 0);
};
public:
CFooBase() : _refCount(1) {};
virtual HRESULT STDMETHODCALLTYPE QueryInterface(const IID& iid, void** ppUnk)
{
HRESULT hr=S_OK;
*ppUnk = NULL;
if (iid == IID_FooBase)
{
AddRef();
*ppUnk = reinterpret_cast<void *>(this);
}
else if (iid == IID_IUnknown)
{
AddRef();
*ppUnk = reinterpret_cast<void *>(this);
}
else
{
hr = E_NOINTERFACE;
}
return hr;
}
virtual ULONG STDMETHODCALLTYPE AddRef(void)
{
return InterlockedIncrement(&_refCount);
}
virtual ULONG STDMETHODCALLTYPE Release(void)
{
LONG refCount;
refCount = InterlockedDecrement(&_refCount);
if (refCount == 0)
{
delete this;
}
return refCount;
}
STDMETHOD(FooBase)(void);
};
class ATL_NO_VTABLE CFooDerived :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CFooDerived, &CLSID_FooDerived>,
public CFooBase
{
virtual ~CFooDerived();
public:
CFooDerived();
DECLARE_NO_REGISTRY()
BEGIN_COM_MAP(CFooDerived)
COM_INTERFACE_ENTRY(IFooBase)
END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
};
OBJECT_ENTRY_AUTO(CLSID_FooDerived, CFooDerived)
As always, tomorrow I'll post the answers along with kudos and mea culpas.
Edit: Fixed missing return value in Release() - without it it doesn't compile. Also added the addrefs - my stupid mistake. mirobin gets major props for those ones.