Interop question: .NET COM object created in C++ doesn't seem to get destroyed

  • Thread starter Thread starter Robert Rossney
  • Start date Start date
R

Robert Rossney

I have built a .NET COM object that's being instantiated by a (non-.NET) C++
application, using the following code:

CoInitialize(NULL);
IMyInterface *pCOMObject = NULL;
HRESULT hr = CoCreateInstance(CLSID_MyDotNetClass,
NULL,
CLSCTX_INPROC_SERVER,
IID_IMyInterface,
reinterpret_cast<void**> (&pCOMObject));

if (SUCCEEDED(hr)) {
pCOMObject->Method(params);
pCOMObject->Release();
pCOMObject=NULL;
}
CoUninitialize();

The object gets created, the method gets called, the parameters get
passed...from that perspective, everything's working.

But the object doesn't seem to get destroyed when I release it. The
object's destructor never gets called, and the DLL containing the object's
code remains locked until the C++ application terminates. This seems wrong
to me -- especially since the above code is itself in a dynamically-loaded
function, and I can happily rebuild *its* DLL while the calling application
is running.

Is there something obvious I'm doing wrong here?

Thanks in advance,

Robert Rossney
(e-mail address removed)
 
Robert Rossney said:
I have built a .NET COM object that's being instantiated by a (non-.NET)
C++
application, using the following code:

CoInitialize(NULL);
IMyInterface *pCOMObject = NULL;
HRESULT hr = CoCreateInstance(CLSID_MyDotNetClass,
NULL,
CLSCTX_INPROC_SERVER,
IID_IMyInterface,
reinterpret_cast<void**> (&pCOMObject));

if (SUCCEEDED(hr)) {
pCOMObject->Method(params);
pCOMObject->Release();
pCOMObject=NULL;
}
CoUninitialize();

The object gets created, the method gets called, the parameters get
passed...from that perspective, everything's working.

But the object doesn't seem to get destroyed when I release it. The
object's destructor never gets called, and the DLL containing the object's
code remains locked until the C++ application terminates. This seems
wrong
to me -- especially since the above code is itself in a dynamically-loaded
function, and I can happily rebuild *its* DLL while the calling
application
is running.

Is there something obvious I'm doing wrong here?

No. All is well.

..NET objects don't have destructors. If you use destructor syntax, you
actually create a finalizer. The difference between a finalizer and a
descructor is that a destructor is called deterministically when the object
goes out of scope or is delete'd. A finalizer is called later, after the
Garbage Collector runs and discovers that the object is no loger reachable
from any application root. Your code will leave the .NET object alive on
the managed heap, but unreachable. Its finalizer will run after garbage
collection.

If you need deterministic cleanup of a .NET object, implement IDisposable
and call IDisposable.Dispose from the client code.

As for the .DLL, when you call CoCreateObject to create the COM-Callable
wrapper for the .NET object, the CLR is fired up in your process and the
target assembly is loaded into the default AppDomain. The CLR, the default
App Domain and your assembly will remain loaded for the duration of your
process.

David
 
: pCOMObject=NULL;

Er, that should be

delete pCOMObject;

Forgot what language I was programming in for a minute there. Sorry about
that.

Robert Rossney
(e-mail address removed)
 
message
: No. All is well.
:
: .NET objects don't have destructors. If you use destructor syntax, you
: actually create a finalizer. The difference between a finalizer and a
: descructor is that a destructor is called deterministically when the
object
: goes out of scope or is delete'd. A finalizer is called later, after the
: Garbage Collector runs and discovers that the object is no loger reachable
: from any application root. Your code will leave the .NET object alive on
: the managed heap, but unreachable. Its finalizer will run after garbage
: collection.
:
: If you need deterministic cleanup of a .NET object, implement IDisposable
: and call IDisposable.Dispose from the client code.

You know, I actually already knew all this. But I knew it on paper. Now I
know it for real.

Also: I see now from various documents I'm reading about managing the
lifetime of COM objects that the delete operator and COM objects don't mix,
and that setting the pointer to NULL was in fact the right thing to do after
calling Release() on it. Deleting the object fired the destructor, but it
caused very bad things to happen.

: As for the .DLL, when you call CoCreateObject to create the COM-Callable
: wrapper for the .NET object, the CLR is fired up in your process and the
: target assembly is loaded into the default AppDomain. The CLR, the
default
: App Domain and your assembly will remain loaded for the duration of your
: process.

That makes sense. It's annoying, because I can presently move a new build
of the C++ DLL into production without forcing all users to log off first,
and I won't once the DLL starts calling .NET objects, but it makes sense.
On the other hand, that also means that the CLR and the assembly aren't
being freshly loaded every time my object gets created, so really it's
better this way.

I went down this whole road because I wanted to make sure that my object was
getting destroyed, and when I implemented a destructor I found that it
wasn't. I think that maybe I'll just trust COM to do its job and worry
about other things.

Thanks for your help.

Robert Rossney
(e-mail address removed)
 
Back
Top