C# Excel 2007 RTD Server crashes on exit - c#

I have written a c# RTD server based off of Kenny Ker's Multiple Topics in C#
The main difference between his design and mine is that my data comes from a WCF client. I use the same type of timer and every couple of seconds I call m_callback.UpdateNotify();. My RefreshData method calls a function in my WCF client with the topic values and uses the result as the value for excel. It all works excellent.
The problem comes when I close excel.
When I close Excel I get a message box that says "Microft Excel has stopped working"
My ServerTerminate() method clears all of my topics, calls close on my WCF client and exits without error.
I thought the problem might be a COM issue so I have tried adding
while ( Marshal.ReleaseComObject( m_callback ) > 0 ) ;
m_callback = null;
The pop up still showed up so I tried adding
GC.Collect();
GC.WaitForPendingFinalizers(); //SEHException thrown from this
GC.Collect();
GC.WaitForPendingFinalizers();
Adding these lines does throw an exception. if I ignore the exception excel closes without any problems, but if I install my RTD server on a computer with excel 2010, then the pop up box is still there.
I have Excel 2007 (12.0.6665.5003) SP3 MSO (12.0.6662.5000)
I am developing my c# RTD Server using Visual Studio 2008 and my project has a reference to Microsoft.Office.Interop.Excel version 12.0.0.0

The question was fairly vague, but that's because I really had no idea where to start. Every thing seemed to be working correctly.
After playing around with the code I noticed that I had an object that implemented IDisposable that I called Dispose on when I was done with it. The object also had a finalizer that called Dispose. I changed it to be more like this with a protected Dispose(bool).
I also removed the Excel assembly per Kenny Ker again (however just copying his code didn't work. I actually copied the interfaces straight from the excel interop assembly).
After doing that I was able to get rid of the lines I added (for marshalling the garbage collecting) above and excel now closes without a problem.

Related

Why do instances of Excel not close when opened via interop, even though Word apps close just fine?

As far as I can see, this is not a duplicate question, as the question here is about why the accepted answers of seemingly duplicate questions, do not solve my issue in what appears to be the same circumstances.
For days, I have been struggling with my application failing to end instances of Excel, which have been opened using interops.
My application opens and closes Word applications just fine (i.e. the process disappears from task manager), but not Excel apps. Excel always remains open in the task manager. After much, much searching - this seems to be the definite guide on how to close Excel instances. However, if I copy and paste that exact example code - and run it as a console app, in either .NET Framework, or .NET 6 - Excel still fails to close, exactly as per the behaviour of my application.
Presumably, this must be an issue with the latest/newer versions of Word?
Completely and utterly lost on this one...
Code from the above link that leaves Excel open:
using System;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;
namespace TestCsCom
{
class Program
{
static void Main(string[] args)
{
// NOTE: Don't call Excel objects in here...
// Debugger would keep alive until end, preventing GC cleanup
// Call a separate function that talks to Excel
DoTheWork();
// Now let the GC clean up (repeat, until no more)
do
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
while (Marshal.AreComObjectsAvailableForCleanup());
}
static void DoTheWork()
{
Application app = new Application();
Workbook book = app.Workbooks.Add();
Worksheet worksheet = book.Worksheets["Sheet1"];
app.Visible = true;
for (int i = 1; i <= 10; i++) {
worksheet.Cells.Range["A" + i].Value = "Hello";
}
book.Save();
book.Close();
app.Quit();
// NOTE: No calls the Marshal.ReleaseComObject() are ever needed
}
}
}
It does seem a bit weird with the current version of Excel. It depends on how the console program is run. If I double-click in Windows Explorer, it closes perfectly like it used to. But if I run from a console window, then Excel stays open until the console window closes. Similarly when I run from the debugger, Excel only closes when the Debug window is closed and not when the driving process is terminated. It would be good if you can confirm this too.
I suspect Excel has added some defensive code to not close in specific situations - maybe watching for a 'parent' window to close, or something similar.
Aaaaand then. . . . just as I try again after posting this, Excel starts closing beautifully every time, however I run it.
OK, so I've stumbled across the solution to this. The solution is really rather an unrelated issue.
My instance of Excel had the Analysis Toolpak enabled (spelling mistake included!), from some work I was doing a few months back. The add-in is found at File --> Options --> Add-ins --> Analysis ToolPak.
I've disabled the add-in, and now Excel apps open and close just fine, using only explicit garbage collection, as expected.
I should add - the behaviour is still different to Word. Closed Word files kill Word almost instantly on closure of the document, even before the explicit GC. With Excel, I still have the close the form where the Workbook was opened from, which then calls the explicit GC, and sometimes it takes a few seconds, sometimes 30 seconds, sometimes it takes a minute - but having disabled the add-in, Excel does eventually get stopped.

Excel XLL function linkage / race condition causing #NAME

I have a C# ExcelDna XLL function library that I register during startup from a VSTO add-in.
this.Application.RegisterXLL(xllPath);
When I shell execute an Excel file (Process.Start the .xlsx file) then most of the time everything works and the functions evaluate when the workbook opens.
When opening the workbook in this manner Excel reuses a currently running EXCEL.EXE process if one exists. Most of the time this is fine, but under certain conditions, for example if Excel was opened through COM and then closed, then when the Excel instance is closed, it doesn't really close, but instead shuts down all of its add-ins and unregisters all XLLs but remains alive. When process invoking into one of these zombie processes the functions, obviously, no longer evaluate.
To attempt to get around this I have tried to open Excel directly, using the .xlsx file as a command line parameter, but in this case there seems to be some kind of race condition and the workbook opens before the XLL has finished registering and the functions always evaluate as #NAME. If the cell is modified and reevaluated then the function correctly evaluates. Calling Application.CalculateFull() and all possible variations has no effect.
If I open a file via Explorer (i.e. double clicking on it) then strangely it now returns #N\A rather than #NAME but still it is the same problem.
I've even tried registering the XLL so it loads on start-up (see here) and it still doesn't work.
Has anyone else encountered this and found a reliable way to get XLL functions to evaluate when opening an Excel instance?
We've found that, if the Add-In isn't loaded properly and the functions don't calculate, performing a global search and replace (e.g. search for = replace with =) forces a recalc when the regular recalc doesn't work. You could potentially automate this with VBA Application.OnTime

Unexpected behavior when refreshing internal data connections in Excel

I have faced a big and inconvenient problem with Excel spreadsheets that have internal data connections (queries that selects ranges of the own workbook) in them.
I wiil start by showing the problem e exposing how to reproduce it.
Problem: if I have some internal connetion and another instance (pay attention, instance, not other workbook) was already open, when refreshing that connection, the same workbook (which have the internal connection) is instantly opened in readonly mode in another window...
Why this occurs? The problem is that I'm developing a .NET automation application for Excel and this behavior breaks some process flow (because the readonly file stays open and sometimes it causes a non refresh in the original workbook)
To solve this problem I began to use the same instance if it is already open, but this is not the best solution because I need to handle the concurrency when running several VBA macros in the same instance via .NET Interop.
Here a workbook for those who wish to test this issue that I presented (just change the string connection inserting the new file path in your computer):
Excel File for Test
I recorded a video to show you the issue with more details and how to reproduce it. Please, take a look:
Video
I hope someone knows how to solve this problem because I've been searching for this several days...
Thanks
Obs.: The Office version is 2013

Alternatives to Excel Interop SaveAs() method

We are using excel interop to create excel reports in a windows service. Everything works fine in Windows 7 OS. But when the service is deployed in Win2K8R2 server, observed that following exception is thrown while saving the excel document using "SaveAs()" method.
Exception - HRESULT: 0x800A03EC
After researching got to know that, we need to use "SaveCopyAs()" or use "Close()" instead of SaveAs() method. I tried using "SaveCopyAs()" method and found out that excel report creation works fine but "Excel.exe" in task manager remains. This is a memory leak problem.
Hence used "Close(true, filename, false)" method and everything works fine, which includes clearing "Excel.exe" process in task manager.
A common mechanism is considered for disposing the COM objects, by assigning the objects to null after usage for both scenarios tested.
Now, I'm confused with the right approach to take it forward. Please clarify.
Look at Open XML SDK
Microsoft does not recommend Office Interopt for server automation
How to: Create a spreadsheet document by providing a file name (Open XML SDK)
There are also commercial packages like Aspose
And free packages such as EPPlus.
tried using "SaveCopyAs()" method and found out that excel report
creation works fine but "Excel.exe" in task manager remains.
--> This is probably because your workbook is not closed.
--> use Marshal.ReleaseComObject() method before assigning null to excel objects.

Reconnect to a disconnected Excel COM Interop instance

I have a 3rd party app that is exporting data to Excel using the Excel COM Interop. There is a bug in their program causing it to fail before it makes the Excel instance visible. However from where the exception is happening, according to the displayed stack trace, the information I need has already been written out to the Excel Worksheet.
Is there any way to use the Microsoft.Office.Interop.Excel namespace to connect to a existing excel instance instead of it generating it's own? Or is there any other way I could make that orphaned Excel instance visible so I can save what it completed?
As a note, the EXCEL.exe is still visible in task manager after the program closes so the instance is still live and running after the app has disconnected.
More Details: What the program is doing is exporting a report from it's own (proprietary) database, however for some reason some record in the database became malformed and causes a Integer Overflow error to occur while the report is generating. Looking at the stack trace it appears this integer overflow is happing while it is generating the summery at the end of the report.
For my uses I do not need the summary just the line items from the report, so I hoped to see what work it had done so far but the EXCEL.exe instance it was communicating with is not visible.
If I run the report for a different date range the report generates fine, it is just something about one record on one day that causes this specific set of inputs that causes it to fail.
The support contract with the provider of the app as expired and management is not interested in renewing it as we are in the process of switching to a new vendor (that is why the report is being generated, to be used as the data-source for the data conversion). So I have been tasked with "fixing it" so the data can be moved over.
Final Update: The reason I asked the question was solved. I was able to go through each record via the program itself and I found the record that had one of it's fields set to 16274176.00 (normal values are in the 100's (and don't ask me why what appears to be a float causes a Integer Overflow error)), once I changed that to 0.00 the report printed fine. However I still would like to know if there is a answer to my original question as I think it would be a useful tool in my toolbox.
In regards to your original question, I think it actually might be a possible duplicate of what have been asked here: Get instance of Excel application with C# by Handle
A couple of the answers given points to this blog post: Launching Office Apps Programmatically which gives you a palette of options of how to connect to an already running Office application from managed code.
The blog post as well as the answers given also contains sample code to illustrate how this can be done.

Categories