Search code examples
.netvstoms-officeoffice-addinsvisio

Visio VSTO & the Page.GetFormulas method and making sure all COM objects are cleaned up on shutdown


For an amateur developer, the mountain of advice and discussions on Stackoverflow about how to make sure COM objects are cleaned up properly after running an Office VSTO add-in are confusing to put it mildly. The advice is all over the place, from "don't do anything" this will be done for you, to explicitly starting garbage collection (once, or no that is not foolproof, needs to be done twice), to using Marshal.ReleaseComObject to clean up all the COM objects yourself (which requires you to keep track of all COM objects you use).

Some experts with many years of experience developing Office add-ins are adamant that cleaning up COM objects yourself is the way to go for stable, predictable code behavior: https://www.add-in-express.com/creating-addins-blog/2020/07/20/releasing-com-objects-garbage-collector-marshal-relseasecomobject/

So I decided to go the safe route and clean up COM objects as soon as I'm done using them myself, have to make a decision to go forward.

My question for Visio is though, to speed up the code Visio has several functions that allow us to read data from many Visio shapes at once, for instance Page.GetFormulas. Reading data from hundreds of Visio shapes at once like this performs significantly better than reading data from shapes one at a time. Going across the interop once rather than several hundred times is a boon for performance.

I wonder though if this works if I need to clean up all COM objects afterwards, as I know reading data from a shape involves the Visio Cell object which is now used/referenced implicitly.

What is happening 'under the hood' when I call bulk functions like Page.GetResults and Page.DropMany and is this going to lead to instability if I am unable to clean up all the resulting COM objects myself.

Thank you for sharing your insights this is a VERY confusing topic for an amateur developer like myself.


Solution

  • If you want to make sure every single Visio COM object is dead before exiting, you could try this (on unload for example, i.e. in the ThisAddIn_Shutdown, twice to make sure all generations are killed).

    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    GC.WaitForPendingFinalizers();
    

    This assumes you don't have any global references to COM objects, if you do clear those first (assigning null is good enough, if you call GC after that). Note that this operation is relatively slow, so calling that piece of code often is probably not a best idea if you care for the performance.

    It should not be an issue to keep COM objects alive though (as "zombies"), unless you have a specific problem why you want to clean up COM references explicitly. If those "zombies" are something like shape objects, keeping them will basically just waste memory, or produce dead references, which should not be an issue unless you use care about memory consumption or try to use dead objects. Closing the application should kill them all anyway.