I'm looking for a clean way to output errors in C# when using Excel with interop.
When the file is not "right" a have a message like "blabla HRESULT: 0x800AC472".
I'd rather want a message like "The file used has this or that problem". In order to do that I would need to know to what error does each HRESULT map to ?
How to get such a list of errors ?
I've look at MSDN, found some description, but I can't seem to find the list of all codes like the "0x800AC472" mention above.
I have the Excel HRESULT code 0x800AC472 as VBA_E_IGNORE, which indicates that Excel has 'suspended the object browser'.
Under certain circumstances Excel will reject all incoming COM requests. Two cases where this happens are where the user
is busy editing a formula, or
presses down the mouse button on the Excel sheet.
There might well be other cases - for example I'm not sure what the error code is when Excel is busy calculating.
If you are doing COM automation to talk to an Excel instance that is interactively being used, then any COM call you make to Excel might return this error. One approach I take with Excel-DNA (where the interop always happens from an add-in inside the Excel process) is to attempt to call Application.Run(...) to run a macro in the add-in. Once the Application.Run call succeeds, the macro will run on the main Excel thread in a context where the COM requests won't fail due to Excel suspending the COM calls.
Some other COM errors you can expect from Excel are:
const uint RPC_E_SERVERCALL_RETRYLATER = 0x8001010A;
const uint RPC_E_CALL_REJECTED = 0x80010001; // Not sure when we get this one?
// Maybe when trying to get the Application object from another thread,
// triggered by a ribbon handler, while Excel is editing a cell.
const uint VBA_E_IGNORE = 0x800AC472; // Excel has suspended the object browser
const uint NAME_NOT_FOUND = 0x800A03EC; // When called from the main thread, but Excel is busy anyway.
Related
I'm currently using COM Interop in .NET to export the contents of a DataTable to Excel. It's a method I've been using for years, but the problem is that COM is sketchy and throws random, intermittent, untraceable exceptions. This hasn't been a huge issue, since it's always just been code on a machine dedicated for this purpose and the exceptions are pretty rare, but recently I wrote a front-end for a data warehouse and I've got 200+ users on it, and the problem has (as you would expect) grown exponentially.
The problem is finding a method that does what COM does without the problems that come with COM. Namely, creating an Excel file in-memory (no writing to disk) that is a new workbook, so that when the user hits "Save" for the first time, it will ask them where they want to save the file and what they want to call it.
I know I can export a DataTable to an Excel file using OpenXML: Export DataTable to Excel with Open Xml SDK in c#
And I know I can create an OpenXML Excel object in-memory without writing to a file on disk: How to create Excel file using OpenXML without creating a local file?
The problem is the last step: Opening that in-memory file in Excel (without using COM)
Getting this to work would be my ideal option.
Now, I would prefer not to write to a file, but that isn't a deal breaker if there are no other options, so as a backup option I've also considered using OpenXML to create an Excel Template, and opening the Template (using Process.Start).
The problem with that approach is that some users have reported that Templates sometimes open as xltx files in Edit mode by default, instead of opening as new xlsx files: https://answers.microsoft.com/en-us/office/forum/office_2007-customize/is-there-a-way-to-get-my-excel-template-xltx-file/ab36cd4d-f6b0-46e0-8f15-533a4acb357f?page=1
This would be an even bigger issue than the random errors I'm getting from using COM.
Any ideas are appreciated.
EDIT - These are the COM errors I get:
Cannot create ActiveX component.
COM target does not implement IDispatch.
Exception from HRESULT: 0x800AC472
Select method of Range class failed
Operation unavailable (Exception from HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))
The message filter indicated that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVERCALL_RETRYLATER))
The remote procedure call failed. (Exception from HRESULT: 0x800706BE)
Unable to cast COM object of type 'System.__ComObject' to interface type 'System.Collections.IEnumerable'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{496B0ABE-CDEE-11D3-88E8-00902754C43A}' failed due to the following error: 'The requested object does not exist. (Exception from HRESULT: 0x80010114)' and the COM component does not support IDispatch::Invoke calls for DISPID_NEWENUM.
Unable to get the Add property of the Workbooks class
Activate method of Workbook class failed
I've received 107 errors over the course of a few months, but I've gotten more lately since I updated the feature to attach to any existing instance of Excel that the user might already have open instead of creating a new one. Before, when I was always creating a new Excel instance each time, the errors were much more rare (and were largely solved by making Excel invisible while I did the work behind the scenes).
This is a suggestion more than an answer. Consider trying to save the file to a temporary location and set it to Read-Only in the file system. The would force your users to do a SaveAs rather than a Save. Then use the Excel command line options (apparently /n is best) to open the XLSX file as if it were a template.
Those command line options are located here:Excel Command Line Options
I have been working up an Add-In to process data out of Excel files sitting in a directory. My program has run successfully in production under a number of scenarios, so I know my code is generally solid. Until now, I have been reading just the first 'sheet' of the Excel file.
I have been working on a feature that will 'crawl' through the entire Workbook by doing a foreach loop through the Worksheets object. The process works fine for the most part, but on occasion when I change sheets I get the message popup: Compile Error in Hidden Module: Clipboard. I do not at any point call or write anything to the clipboard. I have restarted my machine to clear memory and still get the message.
On breakpoint checks, I get the message after calling Excel.Range oRng = thisExcel.xlWorksheet.get_Range("A1").SpecialCells(Microsoft.Office.Interop.Excel.XlCellType.xlCellTypeLastCell); - at which point it throws that Complile Error message twice (on the same line), and then continues on. It does not cause the program to fail - and if I keep clicking 'Okay' it will proceed to the end and give me my output.
In my code, oRng is a local variable in a function different from the process that sets a new ActiveSheet, so it is null until get_Range is called.
This doesn't happen ever when I read only 1 sheet per Workbook, and it will still run to the end - just throws this message and will not proceed until it is dismissed. I'm using VSTO 2010.
Is there a problem with my use of get_Range? I can share more code on request if that will help shed more light.
UPDATE:
Tried a suggestion that I clear Clipboard. When I try Clipboard.Clear(), I get the same result.
So as it turns out Compile Error in Hidden Module: Clipboard was a message for some specific macros in a few of the workbooks provided to me. It ran all kinds of problems in Excel 2010. But when tested against Excel 2013, there was no problem.
Is there a way to check if an application has finished loading.
For example if I were to use Process newProcess = Process.Start(#"C:\someFile.xls");
is there IsLoaded or IsFinishedLoading or something similar to that, so that another line of code does not fire until the application is fully loaded.
I ask because I get an error when trying to interface with an excel sheet because its not open. Using only Process newProcess = Process.Start(#"C:\someFile.xls"); does the job but only after my application has crashed due to no excel document being open.
Now is there a way to speed up the starting of the program/file? Or have I coded something incorrectly.
There is no generic way to know when an application started or finished opening a document.
Some programs (i.e. Office applications) provide API to communicate/control them, while others (i.e. Notepad) have no way to know this information.
Since you are already using Interop, why not actually create the Excel Application, and load the document?
You can also make the application visible to the user as well, if you need to.
using:
Excel.Application excel = new Excel.ApplicationClass();
Workbook wb = excel.Workbooks.Open(path, <parameters>);
I have a spreadsheet which is probably calling BDDE.EXE. When I open this spreadsheet in Excel, everything works fine. I can see values in cells whose formula starts with "=BDDE". However, when I open the same file using C#, Excel first displayed an Alert
Remote data not accesible.
To access this data Excel needs to start another application. ...
Start application 'BDDE.EXE'?
Then no matter what I click - Yes or No, the formulas are updated, all the values from a previous recalculation are lost.
I then tried forcing Excel not to recalculate by setting XlCalculation to Manual. Open stops working after this change, and threw an COMException (with no other information).
System.Runtime.InteropServices.COMException (0x800A03EC): Exception from HRESULT
: 0x800A03EC
at Microsoft.Office.Interop.Excel.ApplicationClass.set_Calculation(
XlCalculation RHS)
I got completely stuck. I can't recalculate because that would mess up all the numbers. I can't set XlCalcualtion to Manual as it throws Exception.
Any help is appreciated.
You can't set the Calculation property without first opening the workbook. This sounds like Catch 22, but it's not actually the 'calculation' you're trying to prevent here - you just don't want it to update the cells linked to an external source.
The Open method takes an optional UpdateLinks parameter. Set this to false, and you should be fine.
There is a limitation in Excel engine which requires an opened workbook prior to setting XlCalculation property. So easiest solution would be to create a new workbook, and then set XlCalculation to desired mode, prior to opening file with actual data.
I have a c# application that opens up a COM instance of excel and dumps some data from an Access 2000 database via oleDB onto the sheet then releases the excel object, but I get a window after I close the program with the title bar:
DDE Server Error: [applicationName.exe] - Application Error
I think I've narrowed this down to be an issue with closing excel before I close my program. Figuring this was an issue with the com objects I created, I went through my code and tried to find every place where I stored an Excel COM object and make sure it was released before setting it to null. I ignored ones I didn't store e.g.
excelSheet.GetRange("A1", "A1).Value2 = "Hello";
I still recieve the error and I think I've released all my stored COM objects, is there another reason I might still be getting this error?
Perhaps you're not properly cleaning up your Excel references?
Check out this thread on how to do this.