Excel Process does not terminate when quitting Excel

Sep 25, 2013 at 9:16 PM
Hi,

I have come across an "interesting" issue. If I save a spreadsheet containing a function in my Add-In and exit out of Excel, everything appears to quit.

If I look at the processes running in Task Manager, the EXCEL process is still running. Is there anything that I can do about this in the AutoClose event of the class that inherits from IExcelAddIn? Is there a different place that I should put this functionality?

Thanks,

Lee
Coordinator
Sep 25, 2013 at 9:26 PM
Hi Lee,

This is expected if you are accessing the Excel COM Automation object model from other threads.
It also happens, though I'm not as sure why, when you start Excel via Automation, and load an Excel-DNA add-in that accesses the Excel object model. This situation is discussed here: https://exceldna.codeplex.com/discussions/455160

My understanding of the situation is not perfect, but it certainly should not happen if you have a 'vanilla' add-in.

Are you starting separate threads and then accessing the Excel COM Automation interfaces?
Are you consistent in accessing the Excel COM Automation via a call to ExcelDnaUtil.Application and not some new Excel.Application(...) or something?

Can you give some more details on how your add-in interacts with Excel, and perhaps try to make a minimal add-in that exhibits the problem?

-Govert
Sep 26, 2013 at 3:04 PM
Lee,

I suggest a few approaches which can all work together.

First, in the finally block of all methods that manipulate ECOM objects on the stack from non-main thread, I would add cleanup method invocations such as
            finally
            {
                // RCW.CLEAN
                SafeReleaseComObject(workbook);
                SafeReleaseComObject(worksheets);
                workbook = null;
                worksheets = null;
            }

        /// <summary>
        /// Safely release COM Interop object wrappers.
        /// </summary>
        /// <see cref="http://stackoverflow.com/questions/158706/how-to-properly-clean-up-excel-interop-objects"/>
        /// <see cref="http://www.add-in-express.com/creating-addins-blog/2008/10/30/releasing-office-objects-net/"/>
        /// <param name="o"></param>
        private static void SafeReleaseComObject(object o)
        {
            try
            {
                if (o != null)
                {
                    Marshal.ReleaseComObject(o);
                }
            }
            catch (Exception err)
            {
                LogUtil.Debug("Could not release RCW COM object: {0}", err);
            }
        }
Second, implement IDisposable in your addin and modules loaded by the addin. In the Dispose, make sure to invoke SafeReleaseComObject on any ECOM object held as an instance or static variables.

Third, if you have a some kind of View class that extends ExcelDna.Integration.CustomUI.ExcelRibbon, then make sure you override OnBeginShutdown and then invoke the stop/deactivate method on your addin_bootstrapper.

Hope this helps.

/BT
Sep 26, 2013 at 3:55 PM
Thanks Govert and Bishrtabbaa,

I noticed that it seemed to happen when I entered a UDF function. I used the AutoClose method in my class that inherits from IExcelAddIn to release COM objects from the Excel Application.

Lee
Coordinator
Sep 26, 2013 at 4:01 PM
Hi Lee,

Are you accessing the Excel Automation COM stuff from your UDF?
Are your UDFs marked IsThreadSafe = true?

-Govert
Sep 26, 2013 at 5:18 PM
Hi Govert,

The only COM automation that I am doing are calls to set the mouse pointer (i.e. I call the method below from my UDF function).
        public void SetMouseCursor(Microsoft.Office.Interop.Excel.XlMousePointer mousePointer)
        {
            try
            {
                Microsoft.Office.Interop.Excel.Application _app = ExcelDnaUtil.Application as Microsoft.Office.Interop.Excel.Application;
                _app.Cursor = mousePointer;
            }
            catch (Exception ex)
            {
                // don't die as a result of a mouse pointer
            }
        }
In terms of marking the UDF method as IsThreadSafe, how would I do that? I don't see an attribute for IsTreadSafe.

Thanks,

Lee
Jul 4, 2014 at 3:56 PM
bishrtabbaa wrote:
Third, if you have a some kind of View class that extends ExcelDna.Integration.CustomUI.ExcelRibbon, then make sure you override OnBeginShutdown and then invoke the stop/deactivate method on your addin_bootstrapper.
Hi bishrtabbaa,

What is the addin_bootstrapper? I thought it is the COMAddIn object but it does not have the stop/deactivate method. What is the type of the addin_bootstrapper and how can I get it within the ribbon code? Thanks.

Gin
Coordinator
Jul 4, 2014 at 5:41 PM
Hi Gin,

As long as you never access Excel from another thread, you should not have any shutdown issues.
If need be, you can transition to a macro context from another thread with a call to ExcelAsyncUtil.QueueAsMacro(...), and then talk to the Excel object model in the passed delegate.

Are you having shutdown issues?

-Govert
Jul 7, 2014 at 7:14 PM
Hi Govert,

Thank you for the reply. I had the VBA password prompt issue. My testcase is a simple add-in with a single ribbon label for backstage, nothing else. If I load a workbook with a password protected VBA project. The password prompt will appear when I try to exit Excel. I verified that it is caused by ribbon control. Therefore, I like to clean up the ribbon as bishrtabbaa suggested above, but, I have no idea what is meant by addin_bootstrapper.

Gin
Jul 9, 2014 at 4:35 PM
Gin,

The addin_bootstrapper is idiosyncratic and specific to a project I am working on.. for your general purposes, I suggestoverriding the OnBeginShutdown method of the ExcelRibbon class and doing any cleanup of COM RCW objects therein, if you are holding onto such objects (Application, Workbook, Worksheet) as instance variables of your ribbon class or in other addin-related classes you are using.

If not, then Govert's recommendation makes sense too. Hope this helps.

-BT-
Jul 10, 2014 at 3:45 PM
Hi BT,

Thanks for the reply. I do release all the COM objects that I have access to in OnBeginShutdown method. But, something are still not cleaned up if the ribbon event is triggered (i.e. by bringing up the backstage in my case) and I don't have access to the RCW object that is created by the ribbon's event handler. Microsoft's ribbon implementation hides the event handler from the add-in code. That's why I wanted to clean up the ribbon and I thought what you stated is a way to do it.

I am finally able to solve my problem by calling the garbage collector twice after releasing all the COM objects. The garbage collector was only called once before and that only clean up the RCW object. I need to add a second call to clean up the COM object.

Gin
Jul 11, 2014 at 10:06 PM
Gin,

Here are a couple of good posts related to COM and RCW object cleanup that suggest the manual invocation of GC on shutdown that you took (and that I have taken as well) to ensure release of Interop resources. The cost is a slower shutdown for the add-in, but it is worth it.

http://www.add-in-express.com/creating-addins-blog/2008/10/30/releasing-office-objects-net/
http://stackoverflow.com/questions/158706/how-to-properly-clean-up-excel-interop-objects

-BT-
Jul 14, 2014 at 2:40 PM
Thanks BT.

Gin