Using a com interlop and FinalReleaseComObject RRS feed

  • Question

  • I am converting a very large vb6 project to vb9. I am so moving from ado to but I still have a boat load of ADODB Connections.  I just ran across the FinalReleaseComObject method and I am curios how to implement it properly.  My connections already use the .Close() and = Nothing Lines. Would I put the FinalReleaseComObject line after those two like so: 

    db = New ADODB.Connection

    adoCompany = New ADODB.Recordset
    adoCompany.Open("Select * From Company", db, ADODB.CursorTypeEnum.adOpenStatic, ADODB.LockTypeEnum.adLockReadOnly)
    If Not IsDBNull(adoCompany("USA")) Then
                If adoCompany("USA").Value = True Then
                    glbCountry = "USA"
                End If
    End If
    adoCompany = Nothing

    If Not (db Is Nothing) Then
               If db.State Then db.Close()
    End If
     db = Nothing

    I also use an Ax.MapPointControl in the program.  In the controls containing form's closing event I assume I can also add this:
    refMapObject. ActiveMap.Saved = True
    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(refMapObject )

    Friday, June 26, 2009 7:17 PM


  • In order to answer you question, I have to first explain a little bit of the difference between the COM memory model and the .NET memory model.

    COM uses heap allocation that is very similar to plain vanilla C memory management with some Windows handle stuff added in. When you create an instance of a COM object, that instance maintains a reference count internally. When you reference that instance in your code (VB6, for this example), the compiler is supposed call the COM object's AddRef method behind the scenes, and when that reference is no longer used, the compiler is supposed to call the COM object's Release method. The end effect is that as long as something is referencing the COM object, it stays in memory. When the ref count goes to zero, the object knows it's safe to be deleted from memory.

    The .NET runtime uses a managed heap that is garbage collected. That means you don't explicitly delete objects from memory, because quite frankly, that's exactly what programmers forget to do, and that's why so many programs had memory leaks. In the .NET world, managed objects hang around until garbage collection kicks in. The GC finds all unreachable objects (objects that can't be accessed because they have no in-scope references) and wipes them. There's no AddRef/Release mechanism.

    The tricky part is what happens when you use a COM object from a .NET host. The .NET host natively knows how to deal with garbage collection because that's part of the runtime. But in order to access a COM object properly, it does so with the help of a Runtime Callable Wrapper. This is really nothing more than a thin .NET object that delegates calls to COM objects using COM semantics. But on the .NET side, it makes your COM object look like a .NET object. Every time you add a COM library to your project, Visual Studio automatically makes Runtime Callable Wrappers for all your library's COM classes. When you write your code to use the COM objects, you are in reality just making calls to the wrappers, which then do the COM work for you.

    In the VB6 world, setting a reference to Nothing was an instruction to the compiler to call Release() on the COM object. That doesn't happen in the .NET world. Setting a reference to Nothing just wipes out the internal pointer value (the GC will wipe the object itself out later if necessary). Since your COM objects start with a ref count of 1, this means that settings the reference to Nothing in .NET will never decrement the ref count, and the COM object will never get wiped from memory. But the wrappers are "smart" in a way because they provide another mechanism for dealing with this. VS automatically creates wrappers that implement IDisposable, and also have a finalizer. The code inside the Dispose() function will decrement the ref count for you. So all wrappers basically have a Dispose() method that you can call, which is sort of the equivalent of setting a reference to Nothing in old VB6. Even if you forget to call Dispose(), the finalizer will ensure that Dispose() is called when the wrapper object is about to be wiped by the GC (unless the application crashes or some similar catestrophic event).

    This means that:
    a) setting the reference to Nothing in .NET does nothing useful and can be omitted
    b) you should call the object's Dispose() method instead
    c) Rather than calling Dispose(), you can place your code in a Using block, which automatically calls Dispose() at the end of the block (preferred way of doing things)

    Marshal.FinalReleaseComObject is meant for people writing lower-level code than you are, which is manipulating COM infrastructure and objects directly (therefore explicitly setting and releasing ref counts), or for creating custom runtime callable wrappers. You really shouldn't be using it if all you want to do is "normal" COM object stuff.
    -Rob Teixeira
    • Marked as answer by DeepMaroon Friday, June 26, 2009 11:58 PM
    Friday, June 26, 2009 9:30 PM