Deletion of a COM object in VC6.0

G

Guest

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
 
C

Carl Daniel [VC++ MVP]

lauch2 said:
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
 
G

Guest

Carl Daniel said:
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.
 
G

Guest

sorry, should be:
interface IMyComObject : IDispatch
instead of:
interface ImsqSendQueue : IDispatch
 
C

Carl Daniel [VC++ MVP]

lauch2 said:
Thanks for the reply.

In fact, I am not familar with the COM development. Anyway, the real
situation is as below:

I'm not an ATL user, so rather than speculate, I'll just suggest that you
re-post in

microsoft.public.vc.atl

where you're more likely to find an ATL expert to help. It usually helps if
you can produce (and post) a minimal sample program that exhibits the
behavior you're trying to understand as well.

-cd
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top