Coming from an Excel VBA background I would frequently write code such as:
Range("myRange").Offset(0, 1).Resize(1, ccData).EntireColumn.Delete
I'm now moving to VSTO, and have been reading about RCW counters, etc., and the need to explicitly release COM objects. The basic advice seems to be: don't chain together references to Excel objects (as I have above) - hence "one dot good, two dots bad". My question is, am I correct that the above code is not the way to go in VSTO? If so, does that mean that I would need to explicitly declare the 3 ranges implied in the above chain (Offset, Resize & EntireColumn)?
Or even how about something like:
rng.Columns.Count
where rng is a declared Range? Should I be assigning a name to rng.Columns in order to obtain the number of columns in the range??
Yes, you are on the right avenue. You need to declare different objects to release them later. Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Office object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object.
You can read more about that in the Systematically Releasing Objects article. It is related to Outlook, but the same principles can be applied to all Office applications.
BTW: it doesn't depend on VSTO. It comes from the COM world...
There is very detrimental cargo cult behind that "two dot rule" silliness, it completely fails to keep C# programmers out of trouble since version 4. And it endlessly more painful than the simple way to make Office programs quit on demand.
But this is not a problem you have at all, the cargo cult only applies to an out-of-process program that use Automation to activate an Office program. Your code in fact runs inside the Office program, you of course don't care when the program terminates. Because that terminates your code as well.
Just write your code the way you'd write regular C# code, the GC does not need any help.
As often happens with small affirmations, the double-dot rule needs further explanation. You can use it as a mnemonic.
The reason is that each new RCW you get in .NET will hold a reference to the respective COM object. So, if you have (assuming
obj
is an RCW and this is the first time you're getting the other objects):you're getting 3 additional RCWs. As you can see, there is only 1 extra dot. Although properties are probably the most common way of obtaining other COM objects, it's not the only way.
Usually, each RCW will only release the underlying COM object when it's garbage collected, unless you use
Marshal.ReleaseComObject
. Only use this method if you are completely sure you're the only one using the RCW you're releasing.To be perfectly clear about this subject:
Only use
ReleaseComObject
orFinalReleaseComObject
if you really, demonstrably have to, and you are completely, totally sure your piece of code is the only one referring to the RCW.This is tedious, a wrapper might help here:
This would make the previous example a bit friendlier:
To avoid the
ComObj
property, you could implement a proxy, but I'll leave that as an exercise. Specifically, make an efficient proxy generation instead of forwarding by reflection.