"Carl Daniel [VC++ MVP]" wrote:
lauch2 wrote: I have a project that contains a COM object running in the in-process
configuration. The project was developed by VC6.0 with SP 3. The
project has been put into production for long period of time and it
worked just fine. Right now, I want to migrate the project to VC7.1.
During the migration, I find that there is a bug in the COM object:
The COM object has wrongly Release() for two times, which result in
the reference counter to COM object to 0, triggering the COM object
to be deleted in VC7.1 code. This bug is supposed to be the same as
in the VC6.0 code. However, I found that, when the reference counter
reaches 0(or even a negative value), the VC6.0 code does not delete
the COM object and this COM object remains in the COM space. I am
wondering:
1. When the reference counter reaches 0, if the VC6.0 code does not
delete the COM object immediately, who and when will perform the
deletion of the COM object?
2. Why the behavior in the VC7.1 has been changed?
Sample code:
CoCreateInstance(CLSID_XXX, NULL, CLSCTX_ALL, IID_XXXX,(void**)ppv1);
CoCreateInstance(CLSID_XXX, NULL, CLSCTX_ALL, IID_XXXX,(void**)ppv2);
ppv2->Release();
ppv2->Release();// In VC7.1, the object of IID_XXXX is deleted
immediately; // In VC6.0, the object of
IID_XXXX would not be
deleted
There's got to be something more to the story that you're overlooking. For
any correctly functioning COM object, a single call to Release() after
CoCreateInstance will destroy the object. Nothing about this has changed in
VC7.1 - it's all called out by the COM specification.
-cd
Thanks for the reply.
In fact, I am not familar with the COM development. Anyway, the real
situation is as below:
My COM object is derived from the ATL class. Assume the COM object name is
MyComObject. Since the COM object is generated by the VC6.0's wizard, there
should be CMyComObject and IMyComObject classes generated as follows:
class ATL_NO_VTABLE CMyComObject:
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<IMyComObject, &CLSID_MyComObject>,
public IDispatchImpl<IMyComObject, &IID_IMyComObject, &LIBID_MSQLib>
{
…
};
interface ImsqSendQueue : IDispatch
{
....
};
The sample should be as follows:
IMyComObject* pMyComObject1;
IMyComObject* pMyComObject2;
CoCreateInstance(CLSID_MYCOMOBJECT, NULL, CLSCTX_ALL, IID_
MYCOMOBJECT,(void**) &pMyComObject1);
CoCreateInstance(CLSID_ MYCOMOBJECT, NULL, CLSCTX_ALL, IID_
MYCOMOBJECT,(void**) &pMyComObject2);
pMyComObject2->Release();
pMyComObject2->Release(); // see the source code below
I also trace into the Release() function, here is implementation of
Release() in vc7.1 and vc6.0:
----------------------------------------------------------------------------------
vc7.1:-
template <class Base>
class CComObjectCached : public Base
{
STDMETHOD_(ULONG, Release)() throw()
{
m_csCached.Lock();
InternalRelease();
ULONG l = m_dwRef;
m_csCached.Unlock();
if (l == 0)
delete this;
else if (l == 1)
_pAtlModule->Unlock();
return l;
}
};
----------------------------------------------------------------------------------
vc6.0:-
template <class Base>
class CComObjectGlobal : public Base
{
STDMETHOD_(ULONG, AddRef)() {return _Module.Lock();}
}
class CComModule : public _ATL_MODULE
{
LONG Unlock()
{
return CComGlobalsThreadModel::Decrement(&m_nLockCnt);
}
};
----------------------------------------------------------------------------------
Any idea?
Thanks,
lauch2.