4

I have a COM type (created using tlbimp.exe) and a C# class that wraps this object. I want to perform some clean up in the finalizer for my C# wrapper. Following the guidelines here I might write something like this:

public class MyClass : IDisposable
{
    private IMyComObject comObject;

    public MyClass()
    {
        comObject = new MyComObject();
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~MyClass()
    {
        Dispose(false);
    }

    protected virtual void Dispose(bool disposing)
    {
        // Be tollerant of partially constructed instances
        if (comObject != null)
        {
            comObject.Cleanup();
            // Account for object being disposed twice
            comObject = null;
        }
    }

    // Other bits go here...
}

I know that finalizers can run in any order and so I should not attempt to use any object that implements a finalizer, however as far as I can tell tlbimp generated COM types don't implement a finalizer and so the above should be OK.

I haven't been able to find any official documentation on this however, so my question is is it safe to reference and use COM objects in a finalizer?

Justin
  • 84,773
  • 49
  • 224
  • 367
  • Did you try to invoke the GC at the beginning of your Dispose method? – Ventsyslav Raikov Nov 08 '11 at 14:00
  • They *do* implement a finalizer, that's how COM objects are released. So, no, it isn't safe. – Hans Passant Nov 08 '11 at 14:01
  • @HansPassant I used to think that but I can't find any documentation that states this and I also can't see a finalizer in the disassembly – Justin Nov 08 '11 at 14:08
  • possible duplicate of [Is it safe to call an RCW from a finalizer?](http://stackoverflow.com/questions/1573977/is-it-safe-to-call-an-rcw-from-a-finalizer) – Justin Nov 08 '11 at 14:19
  • The finalizer exists on the RCW created by the CLR. You can't see it. – Hans Passant Nov 08 '11 at 14:19
  • Side note: Any unhandled exception thrown in finalizer code will force the CLR to immediatelly terminate your process, so make sure you understand exactly what exceptions can be thrown and handle them. – Mahol25 May 15 '12 at 11:26

1 Answers1

0

I created a abstract com wrapper class, from which I derive all my com wrapper classes. It works very well. My original code is VB, since I need late binding (this was before C# introduced the dynamic type). The rest of my app is written in c#.

public abstract class ComWrapper : IDisposable
{
    protected internal object _comObject;
    protected ComWrapper(object comObject)
    {
        _comObject = comObject;
    }

    #region " IDisposable Support "

    private bool _disposed = false;

    protected virtual void FreeManagedObjects()
    {
    }

    protected virtual void FreeUnmanagedObjects()
    {
        ReleaseComObject(_comObject);
    }

    private void Dispose(bool disposing)
    {
        if (!_disposed) {
            if (disposing) {
                FreeManagedObjects();
            }
            FreeUnmanagedObjects();
            _disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected override void Finalize()
    {
        Dispose(false);
        base.Finalize();
    }

    #endregion
}

and

public static class Helpers
{
    public static void ReleaseComObject(ref object o)
    {
        if ((o != null)) {
            try {
                Marshal.ReleaseComObject(o);
            } catch {
            } finally {
                o = null;
            }
        }
    }

    public static string ToDotNetString(object comString)
    {
        if (comString == null) {
            return string.Empty;
        }
        string s = comString.ToString();
        ReleaseComObject(ref comString);
        return s;
    }
}
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188