How to "lock" excel while interacting via COM - c#

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;

Related

Checking process is loaded

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>);

Preventing users from using an instance of Excel

I'm using Microsoft.Office.Interop.Excel to create Excel reports with C#. Those reports have a large amount of graphics and take long time to prepare. During the preparation, The instance of the Excel application that my program uses is hidden from the user.
MY problem is that Microsoft Office tends to share application instances automatically. If the user opens an Excel workbook, Excel will try to find a running instance of Excel and open the document from there. When the user tries to open an Excel workbook while my program is running, it is attached to the instance my program uses.
This generates two problem. First, it forces my reports into visibility before they are supposed to become visible. And second, my program now needs to fight with user over the attention of the Excel instance - and my program usually loses.
So, is there any way to make the Excel instance reject requests(from the user. it should still obey to my program) to open documents, and make Office ignore my instance when it has to decide how to open an Excel document?
You could handle the Application.WorkbookOpen event. In here, either start a second instance of Excel and have it open the workbook, or close the workbook with an error message.
I also saw the Application.Interactive property. I haven't played with this, but it may be of use to you.
You can use NPOI, I suggest you visit the following link
http://npoi.codeplex.com/discussions/36157?ProjectName=npoi
I have done a little experimenting, and I think this will work:
Whenever you begin working with Excel, create two instances, and work with the second. When you're done with your work, delete the second instance and its object, then check the "UserControl" property of the first. If it returns "true", then delete only the object, but leave the process for that instance behind. If it returns "false", then delete the instance as well.
As far as I can tell, the user can open and close any number of workbooks, and it will use the first instance you created, as long as you don't delete it, and the second instance will be unmolested.

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.

Restrict access to excel file opened by C# program

Question 1:
I've opened an excel file with
Excel.Application app = new Excel.ApplicationClass();
Excel.Workbook Wbook = app.Workbooks.Open("aaa.xlsx",...);
Now, I want to stop other programs accessing "aaa.xlsx".
(want to restrict access by other programs like excel.exe & etc)
Are there any options that I can set to lock/block/restrict file open?
Question 2:
Since I've done this
Excel.Application app = new Excel.ApplicationClass();
I've created a new instance of excel.
I want to hide it from external use.
(I don't want it to pop up when some random excel file is double clicked on the system.)
Is there something I can do to prevent it from being called up automatically?
Any help would be much appreciated.
These should probably be separate questions, but I will try.
Also, caveat emptor: It's been a while since I've touched Office Automation and don't have the docs handy, so I'm going off memory.
The Excel.Application object should have a Visible property. Set it to false to hide the application.
As for opening the document, check the docs to see if there are any parameters like "FileAccess". I can't remember off hand, but I will keep looking...
Edit: Okay, I found the documentation on MSDN, but there doesn't appear to be any way to specify that Excel should lock the document while it's open. Sorry.
An ugly solution but you could do it:
Open and lock the file yourself. Copy it to a temporary location, load that temporary into your hidden window. After saving it copy it back to the original location. Note that both of these copies will have to be implemented in your program as the lock will preclude Windows from doing it.

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

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.)

Categories

Resources