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).
Related
I have created a program that searches excel, word, and txt files for a user entered string. So I open each file, search for the string, and add the file(with info) to a datagrid if the document contains this string.
The program works great, except for some unforseen situations. If the user did not have excel open when they start the search, the program opens a new instance of excel and begins searching. During this search, if the user then opens an excel file from windows explorer, it will open it in the same instance that my program is using, which then proceeds to show all the files it is opening, searching, then closing.
If the user already has excel open, then my program opens it's own instance and there is no issue. The exact same issue applies to word documents as well.
My question is, how can I prevent the user from opening a file in the same instance of excel that my program is currently using?
Here are the basics of how I am accessing excel:
using Excel = Microsoft.Office.Interop.Excel;
Excel.Application xlsApp = new Excel.Application();
Excel.Workbook wkb = null;
Excel.Workbooks wkbs = xlsApp.Workbooks;
xlsApp.DisplayAlerts = false;
wkb = wkbs.Open(filePath, ReadOnly: true);
//Do search here...
//Close the workbook when necessary...
wkb.Close(false);
//Close the app when necessary...
xlsApp.Quit();
I'm hoping there's some parameter I can set to prevent the user from opening documents in the same instance.
Not sure if you are still looking for a solution to this problem after all this time. I have been trying to solve this issue myself and with help from the guys at Add-In Express I have come up with a workable solution. The following should work for you.
Create your Word/Excel instance with ckNewInstance.
Open a new document/workbook
Close it.
Open the document/workbook you intend to work with.
This will normally stop any documents/workbooks being opened via your instance when the user opens via shortcut.
But sometimes this fails (eg if there are left over instances of Word in processes).
To make my instance of Word "exclusive" I am currently doing the following (until something better comes along):
Opening a dummy document as explained above.
Disable all functionality within Word which allows for opening of documents.
Just in case 1 fails try and catch any documents opened by my instance of Word and close them.
The last part of the process is kludgy, but I can't see any other way around it.
Originally, I used DocumentOpen and DocumentNew events to catch document opening and new documents and this works well. You can close the documents in these events and reopen them without apparent issue.
However, further testing showed that DocumentOpen and DocumentNew events only fire if the document is opened using your Word instance ie if the user uses the backstage for example. If they click on a Word shortcut, even though the document opens in your instance, it does not (why ever not MS?) fire the above events.
The only way I can find to capture Word documents opened by whatever means is to use the DocumentChange event and loop through each document and if it isn't the one I want, close it and reopen it.
Unfortunately, this does not work in a straightforward manner. It seems to work okay for new documents, but if the user opens an existing document and you attempt to close it in the DocumentChange event, it causes your principal document to hang (at least it does for me).
To get around this I use the DocumentChange event to find the offending docs and fire off a timer (100 ms seems to do the trick) to handle the actual closing and opening.
All in all utterly horrible and I wish someone will come back and tell me that I have wasted days on the above because Office applications have a "MakeMyInstanceUnique" property which does exactly what I need!
Is there any way I can know if Excel is in dirty state or not.
By dirty state I mean:-
When you do anything on Excel and close save button - Excel asks you to save the file.
So there must be some flag which is set when the file is edited.
Can I know the status of an Excel file through C# code?
Searched a lot, but not much help is available. One option is there which allows you to know if Excel is in edit state or not by looking at GetRibbonControlEnabled("FileNewDefault")
In this case you can see if Excel is in edit state only at the time when you execute this method.
What if I want to know if Excel was edited/made dirty since the time it was open.
Please don't advice to start to background thread which keeps looking if Excel was in edit mode by using the above function.
An help will be extremely appreciated.
Take a look at the Workbook.Saved property. It will tell you if the user has modified the document since it was last opened.
bool isDirty = !Globals.Application.ActiveWorkbook.Saved;
In an Excel VBA module one can test the ActiveWorkbook.Saved property, and if it is False then the workbook has unsaved changes (is "dirty"). Details here. See if you can check that property from your C# code.
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;
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.
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.