-1

I am developing a VSTO addin where now I am looking to optimize it. In my code, I does something

public class ExtraOrdinaryClass
{
    public ExtraOrdinaryClass(Excel.Worksheet someGoodSheet)
    {
        tSheetName            = someGoodSheet.Name;
        tDesignSheet          = someGoodSheet;
    }
}

I just got to know I should release all the COM Objects, but I am searching for a proper way to release the someGoodSheet object in a proper way. I suspect if I do something like below is efficient

public class ExtraOrdinaryClass
{
    public ExtraOrdinaryClass(Excel.Worksheet someGoodSheet)
    {
        tSheetName            = someGoodSheet.Name;
        tDesignSheet          = someGoodSheet;
        Marshal.ReleaseComObject(someGoodSheet);
        someGoodSheet = null;
    }
}

Can anyone help me if I am doing it effectively and tell me when parameter objects are collected by garbage collector?

Isham Mohamed
  • 2,629
  • 1
  • 14
  • 27

1 Answers1

0

I just got to know I should release all the COM Objects, but I am searching for a proper way to release the someGoodSheet object in a proper way

It is not necessary to worry about releasing COM objects because you are writing a VSTO add-in. VSTO add-in are in-process COM libraries loaded by the COM application, in this case Excel. The COM object represented by the Excel worksheet was created by Excel and so it has ownership. Attempting to manually release (via Marshal.ReleaseComObject) or reduce the reference count inordinately when you still have a managed reference to it (as in your second example), may crash Excel and/or your application.

Had you been writing a stand-alone process which say launched Excel via COM and fiddled with a few COM objects, then yes, you would need to ensure COM objects are released appropriately.

i.e. do not use this in your constructor:

Marshal.ReleaseComObject(someGoodSheet);

Because you are essentially saying to COM "I'm finished with it" and yet you are not because you still have a managed referenced to it via tDesignSheet. COM/Excel may choose to get rid of the worksheet from under you. The next time you go to access tDesignSheet you may encounter an exception.


Calling Marshal.ReleaseComObject on a parameter that is copied to a field is sort of like using a Font after you called Dispose() - both will lead to the undesirable situation where an obliterated object is accessed. (in the case of COM I assume the reference count reached 0)


Also it is not necessary to call this (because you have a reference to the same object anyway):

someGoodSheet = null;

Your original code (shown below) is fine:

public class ExtraOrdinaryClass
{
    public ExtraOrdinaryClass(Excel.Worksheet someGoodSheet)
    {
        tSheetName            = someGoodSheet.Name;  // you arguably don't need this (just read tDesignSheet.Name)          
        tDesignSheet          = someGoodSheet;
    }
}

and tell me when parameter objects are collected by garbage collector?

I would say that in this case the .NET parameter would not be collected because now you have an additional reference to it in tDesignSheet inside ExtraOrdinaryClass. You would either need to set tDesignSheet to null and wait for the next time the GC runs, whenever that is.

Even if the .NET object is collected, .NET I suspect is smart enough to know that the COM object may still be used by other native COM clients such as Excel itself.

So, just because your .NET now-disposed objects no longer refer to the COM object, you may find the COM object could well be still active. e.g. the worksheet is still open.

  • Yes, the original problem is is my way of releasing COM Object good? – Isham Mohamed Nov 17 '15 at 05:38
  • You are saying "So, just because your .NET now-disposed objects no longer refer to the COM object, you may find the COM object could well be still active. e.g. the worksheet is still open." so that sense I have to Release that COM Object right? while I should not release inside the constructor. – Isham Mohamed Nov 17 '15 at 06:17
  • See update. It is not necessary. NET will do it for you automatically and considering it is in-process COM explicit calling of `Marshal.ReleaseComObject` outside of your constructor is not necessary because you don't have to worry about releasing memory, particularly when Excel is still going to want to keep the worksheet open. –  Nov 17 '15 at 06:31
  • @IshamMohamed If you want you can mark `ExtraOrdinaryClass` as `IDisposable` and call `ReleaseComObject` in your dispose. Generally one would call `Marshal.ReleaseComObject()` when they want control over when the COM object is deleted/shutdown (assuming it is the last reference) and/or for memory reasons. One good time you would call `Marshal.ReleaseComObject()` is if you launched Word via COM and wanted the application to shutdown completely. You would do so by calling Marshal.ReleaseComObject() on the `app` object. –  Nov 17 '15 at 06:46
  • ...but in your case, releasing the worksheet won't achieve much because it won't ultimately reduce the reference count to zero due to Excel having a reference to it still. So you may as well just let .NET handle COM for you. Hope this helps :) –  Nov 17 '15 at 06:48