Excel automation via OLE - suppressing / catching dialog box errors? - c#

I refresh Excel 2007 data connections via a C# program and OLE. Most of the work is done by a single Workbooks.RefreshAll() statement.
As is the nature of refreshing spreadsheets, various things can go wrong. During the refresh process, the program can give dialog box error messages about "Data cannot be read from file '|'", and a message about "Overlapping pivottable reports". Both of these are fatal, and I should be able to catch these errors, and exit my program with an error.
Unfortunately, I don't seem to be able to catch these problems, and instead my automated program sits until I come along and hit enter on the dialog.
Does anyone know if it's possible to programmatically catch the errors shown in excel dialog boxes, instead of having them displayed to the user?

Your best bet is to set the Application.DisplayAlerts property to False. That is, assuming that your Excel.Application object variable is named "xlApp", all you'd have to do is the following:
xlApp.DisplayAlerts = false;
Note that this will cause the default response to be taken for each dialog box, which is normally what you would want. (There's no good way around this. Leaving DisplayAlerts = True and using SendKeys might be your only other option, but would be ugly and very error prone.)
Since you are making this call via OLE Automation, this call is cross-process, and, therefore, the DisplayAlerts setting will persist until you change it. (If called in-process, via VBA, it is switches back to to true automatically when the routine completes. The same behavior probably applies for a VB.NET or C# add-in called via a CommandBar or Ribbon control, but one would need to test to be certain.)

Related

Microsoft Excel is waiting for another application to complete an OLE action Error

I frequently receive ok-only prompts while automating add-ins in Excel, stating that Microsoft Excel is waiting for another application to complete an OLE action Error. How to use Interop.dll to show a custom message and handle this error programmatically. Before receiving the promptenter link description here
While You possibly can catch these exceptions depending on your automation framework and do something with it - these type of errors typically comes from not closing the files properly when changing from one to another.
Make sure you dispose all that can be disposed and close all which can be closed in reverse order obviously and it should go away.
If You need more details do post your code for opening and closing looks like a bug there which will make it not coming up.
You do not technically have to use interop, could you consider using a more modern package for interacting with excel?
If you are using google drive / file stream then this may be the problem. Turn off "Real Time Presence in Microsoft Office" then the messages go away.

How to "lock" excel while interacting via COM

I have an .NET application that reads a database, does some analysis, and updates stats in an Excel spreadsheet using the COM interface. I have the application to the point where it opens the workbook (or detects it, if it's already open), and finds the sheet it needs to update.
I'm encountering an issue where the user can still interact with Excel (close the application/workbook, change data, etc.) while my application is running. I've considered hiding Excel while my app is chewing on data, but that is application-wide and prevents the user from interacting with any open spreadsheet.
Is there a way to lock Excel from changes through the COM interface, but still have it viewable/readable by the user? Alternatively, is there a way to just hide/lock a single workbook?
Application.Interactive=false;
Application.Interactive=false;
as Sid suggests is your best bet
I would suggest also changing:
Application.ScreenUpdating = false; // to avoid screen flicker
Application.DisplayAlerts = false; // if you wish to suppress most excel messages
Application.EnableEvents = false; // if there is vba in the workbook you wish to avoid triggering
Application.Calulation = xlCalculationManual; // if it's a calc intensive automation
A good idea to collect your status pre your automation and set all of these properties back to their originals when you are finished with your automation.
Would the Worksheets("Sheet1").protect( <password> ) and unprotect(<password>) do the trick?
... The only real intelligent way to do this that I can think of is to create a new instance of an Excel Application, have that one hidden and to do your changes there.
then, if the workbook is already open, just notify the user and ask them to close it.
The best way I can think of doing it is to open and them immediately hide the entire workbook. That way you can still interact with it through Interop, but the user has no visibility to it (unless they specifically unhide it but I think a lot of users don't know how to do that).
xlWorkbook.Windows[1].Visible = false;

Emulate Open Excel in C#

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.

Hiding Opened Excel File

here is my question:
I have developed a program that uses Microsoft.Excel COM components in order to read/write over Excel files. Well, my app is doing good but when I open, for instance, another file directly with Excel while my program is running, the file(s) that my app uses appear within Excel. I do not want this. I tried also the Visibility property of Excel Application class, but that was not the solution, it just does not work.
NOTE : I have checked this question out.
Restrict access to excel file opened by C# program
Yet, it says no proper solution actually.
You can use Application.IgnoreRemoteRequests = true. This will avoid users opening excel files in the same Excel process as the one you are using.
There is one caveat though: you have to make sure that all execution paths of your application reset this property to false. This property WILL NOT reset itself when you quit and release your Excel application which means that Excel will not respond correctly to a subsequent user who double clicks on a *.xls file for example.
EDIT: Possible issues with IgnoreRemoteRequest
Ok, to make this clearer I'll detail a little bit more what issues you can run into using this feature (at least these are the only ones I've run into when I had to use this feature).
When setting IgnoreRemoteRequests = true you have to make sure you reset this property BEFORE quiting and/or releasing the COM Excel application. If you don't, Excel will not respond to DDE requests which means if someone double clicks on a *.xls file, the file will not open (Excel will start up, but it wont open the file automatically).
This however is only true if you quit the application and/or release it without reseting the property. You just have to make sure that wherever it is in your code that you are quitting/resetting you set the IgnoreRemoteRquests back to false before.
If you'r application crashes and it hasn't been able to clean up (unhandled exception) then the EXCEL process will keep running (if invisible, you will only see it in the Task Manager). That is normal as your app didnt have a chance to quit and release the internal Excel it is using. This however is not an issue. If a user ignores this "leaked" Excel process until it's eventually killed in next reboot or whatever, or manually kills it from the task bar, Excel will work perfectly fine.
Note: MS Excel 2007. Don't know about behavior of previous versions.
Have you tried running your program under a service account? This should avoid the excel com object interfering with the instance used by the logged in console user, so they will not see the effects of your com objects. It's probably also better security practice to run COM type applications under a service account instead of a user account as well, but that's for another question.

Launch Excel from C# and close it on "Save"

I want to do the following with C# and Microsoft Excel:
1 - The user chooses a file.
2 - Micorosft Excel is shown to edit that file.
3 - As soon as the user clicks Excel's "Save" button Microsoft Excel should close.The user shouldn't have to click on exit.
Any idea on #3 ?
Regards,
Sebastian
You could have a Excel macro handle the BeforeSave event, cancel the save initiated by the user, save the file in the macro and after saving you'd be in your macro and could then close Excel.
So maybe something like:
Private Sub myBeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If Not HandlingBeforeSave Then
HandlingBeforeSave = True
Cancel = True
Me.Save
Application.Quit
End If
End Sub
This kb article describes adding a Macro to Excel from C#.
Also you may use FileSystemWatcher class to catch up saving moment, and kill Excel on it. Of course, if you know where user have to save file.
My Interop is a bit rusty, but I think there was an event that Excel fires when it saves a file.
However, I think this is a very dangerous feature to implement, since, in my experience, interop tends to be a bit non-deterministic :). Imagine what will happen if the save handler is active when the user is using Excel outside of your application - he clicks on save, and Excel dissapears!
You could use VSTO for Excel. Gives you the ability to write C# code against the Excel object model. Should be able to do exactly what you want.
Still though, SWeko has a good point. You will need to figure out how to determine if it is supposed to close on save. If you don't every save would close Excel.
You could handle the Workbook's BeforeSave event, then run a timer that checks the Saved property every ten seconds, and closes Excel if it's true.
You should exercise caution when closing Excel, since your users will be very angry if you close a (different) file that they're working on.
I am not sure if this helps, but I think it is close to your need
http://www.c-sharpcorner.com/UploadFile/jodonnell/Excel2003fromCSharp12022005021735AM/Excel2003fromCSharp.aspx
I had a similar issue, however I wait until the user closes Excel. See my "solution" at Excel automation: Close event missing.
I find it somehow unintuitive to close excel when the user hits "save". If you insist on the "save" event, you might want to watch the file metadata change as soon as the user saves (e.g. the last modified date).

Categories

Resources