It turns out that if you set m_xlAppEvents.DisableEventsIfEmbedded to
FALSE, you may still encounter the errors discussed above.
This happens if you extract objects from the Workbook object provided
to events without releasing them. The workaround above releases the
Workbook objects fine, but not other objects you may use. This only
happens if you have m_xlAppEvents.DisableEventsIfEmbedded set to
FALSE. When this is set to TRUE, it does not fire events if the
worksheet is embedded, thus not allowing your code to extract objects
(like Sheets) from the Workbook object. You may want to run Workbook
events in embedded worksheets, however.
For example, this causes errors (m_xlAppEvents.DisableEventsIfEmbedded
= false):
private void xlWorkbookBeforeClose(Excel._Workbook oBook, ref bool
Cancel)
{
foreach (Excel.Worksheet ws in oBook.Sheets)
{
// Blah
}
}
The above code references several objects from the Workbook object:
Sheets and multiple Worksheet objects. The solution is to keep tract
of which objects you reference from the Workbook object provided and
release them when you are done. xlEvents will release the Workbook
object for you. This is your workaround:
private void xlWorkbookBeforeClose(Excel._Workbook oBook, ref bool
Cancel)
{
Excel.Sheets sheets = oBook.Sheets;
foreach (Excel.Worksheet ws in oBook.Sheets)
{
// Blah
System.Runtime.InteropServices.Marshal.ReleaseComObject(ws);
}
System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets);
}
You'll notice that we must keep a reference to Sheets so we can later
release it instead of calling it directly in the foreach statement. As
discussed, the problems result from the .NET managed code not
releasing references to the COM objects. The GC releases those
references eventually, but in the managed environment, we just aren't
sure when that is going to happen and Excel wants those released
immediately.
Hope this helps.