views:

374

answers:

2

I have a COM object written in managed code (C++/CLI). I am using that object in standard C++.
How do I force my COM object's destructor to be called immediately when the COM object is released? If that's not possible, call I have Release() call a MyDispose() method on my COM object?

My code to declare the object (C++/CLI):

    [Guid("57ED5388-blahblah")]
    [InterfaceType(ComInterfaceType::InterfaceIsIDispatch)]
    [ComVisible(true)]
    public interface class IFoo
    {
        void Doit();
    };

    [Guid("417E5293-blahblah")]
    [ClassInterface(ClassInterfaceType::None)]
    [ComVisible(true)]
    public ref class Foo : IFoo
    {
    public:
     void MyDispose();
     ~Foo() {MyDispose();} // This is never called
     !Foo() {MyDispose();} // This is called by the garbage collector.
     virtual ULONG Release() {MyDispose();} // This is never called
     virtual void Doit();
    };

My code to use the object (native C++):

#import "..\\Debug\\Foo.tlb"
...
Bar::IFoo setup(__uuidof(Bar::Foo)); // This object comes from the .tlb.
setup.Doit();
setup->Release(); // explicit release, not really necessary since Bar::IFoo's destructor will call Release().

If I put a destructor method on my COM object, it is never called. If I put a finalizer method, it is called when the garbage collector gets around to it. If I explicitly call my Release() override it is never called.

I would really like it so that when my native Bar::IFoo object goes out of scope it automatically calls my .NET object's dispose code. I would think I could do it by overriding the Release(), and if the object count = 0 then call MyDispose(). But apparently I'm not overriding Release() correctly because my Release() method is never called.

Obviously, I can make this happen by putting my MyDispose() method in the interface and requiring the people using my object to call MyDispose() before Release(), but it would be slicker if Release() just cleaned up the object.

Is it possible to force the .NET COM object's destructor, or some other method, to be called immediately when a COM object is released?

Googling on this issue gets me a lot of hits telling me to call System.Runtime.InteropServices.Marshal.ReleaseComObject(), but of course, that's how you tell .NET to release a COM object. I want COM Release() to Dispose of a .NET object.

+1  A: 

You can do this through IDisposable and Finalize.

http://weblogs.asp.net/cnagel/archive/2005/04/27/404809.aspx

Shiraz Bhaiji
A: 

Actually neither the Dispose (or should i say ~Foo) not the Release will be called from the COM client when the last reference is released. It simply is not implemented. Here is some idea how such a thing could be done.

http://blogs.msdn.com/oldnewthing/archive/2007/04/24/2252261.aspx#2269675

But the method is not advised even by author.

If you implement the COM Client as well the best option would be to query for IDisposable and call Dispose explicitly, iid to request is:

{805D7A98-D4AF-3F0F-967F-E5CF45312D2C}

Other option I can think of is to implement some sort of own "COM Garbage Collector". Each object created by COM would be placed in a list (Provided that objects of your type are only creatable by COM - I cannot think of any method to distinguish from where the object is created). And then you would have to periodically check the list, and on each object call something like this:

IntPtr iUnk = Marshal.GetIUnknownForObject(@object);
int refCount = Marshal.Release(iUnk);
if (refCount == 0)
    @object.Dispose();

but this is some crazy idea.

kossib