My program uses office interop by starting an Excel application (process) and opening an existing workbook.
I must be absolutely certain that all changes written to the workbook by the program can be saved, i.e. something similar to opening a System.IO.File with FileShare.Read or FileShare.None
If file is already opened for writing, my program must be able to detect that.
Anyone knows how to do?
You may check readonly or isDirty.
With a sample program this may be checked quickly by opening the same workbook in Excel at the same time.
Related
I have a doubt about the excel sheet. When I apply the formula column. If my code throws any exceptions/errors then my excel file is set as a read-only mode. So, here I want my file remains in read-write mode. Please, help me to solve this problem.
There are multiple reasons why the file may only be available in read-only mode:
Someone other process is using the file. Perhaps one of your earlier Excel instances you left opened after a crash / exception? Utilize Task Manager to kill ghost instances of Excel or other apps that may be using the file.
The file is opened in read only mode. Here's some info on how to open it in editable mode. https://www.stellarinfo.com/article/excel-cannot-open-read-only-document.php
I am creating a web page to select data to download an Excel workbook (complete with macros), with that data filled in to the appropriate cells.
I was given a .vbs as a starting point for filling out an Excel workbook.
In the .vbs, the original programmer calls
Set objExcel = CreateObject("Excel.Application")
set ObjWorkbook =objExcel.Workbooks.Open(blankFile)
`...
objWorkbook.Saveas(outputFile)
objExcel.Quit
I'm trying to make a web page using C# and MVC, so I looked into Excel.Application and found this and this. I developed an action, just to test things out:
public FileResult filledOutWorkbook()
{
Excel.Application oXL;
Excel._Workbook oWB;
Excel._Worksheet oSheet;
Excel.Range oRng;
oXL = new Excel.Application();
oXL.Visible = false;
oWB = oXL.Workbooks.Open(Server.MapPath("~/Content/Worksheet2.xlsm"));
oSheet = oWB.Sheets["Information Sheet"];
oSheet.Range["V2"].Value2 = "customer test lol";
if (!Directory.Exists(Server.MapPath("~/App_Data/temp")))
{
Directory.CreateDirectory(Server.MapPath("~/App_Data/temp"));
}
var filename = Server.MapPath("~/App_Data/temp/") + DateTime.Now.ToString("o").Replace(":", "") + ".xlsm";
oWB.SaveCopyAs(filename);
oXL.Visible = false;
oXL.Quit();
return File(filename, "application/vnd.ms-excel.sheet.macroEnabled.12", "Worksheet.xlsm");
}
(I'm going to do a scheduled task or something to clear these out because I'm pretty sure I can't just get a byte stream of the file.)
The problem is, this doesn't close Excel. Apparently C# is not interacting with a library that understands Excel workbooks' formatting, you're automating Excel. I would install Excel on the production server, but when I tell it to quit Excel it doesn't quit. It asks the user if they want to save changes to the template document. I don't know how many times this page is going to get used but I think it's bad practice to have to click "no" however many times on the server to free up memory.
Can I circumvent this? Is there a better library than the COM object Microsoft.Office.Interop.Excel? Can I force Excel to close or is my best bet to write all the Excel interaction in VB and call that from the controller action?
As someone who has used and suffered with the Microsoft Excel Interoperability Library, I'm glad you are looking for an alternative.
Don't get me wrong. The interoperability library is extremely useful if you're trying to automate some simple task with small amounts of data. But it's ridiculously slow when it involves large amounts of data. And if you want this on a web server, you need to have Excel Installed on the server as well.
I suggest you use ClosedXML. It's open source and MIT licensed. It's basically a wrapper around OpenXML. It's also very easy to use, much faster and doesn't need Excel installed on the server
https://github.com/ClosedXML/ClosedXML
If it asks you to save, then it means it thinks the workbook has unsaved changes. Just close the workbook and don't save changes before quitting:
oWB.Close(false);
You might also need to close the first default workbook, in fact that might actually be the one that's causing the save message. Look for another workbook and close it without saving. Something like:
oXL.Workbooks[0].Close(false);
Or just enumerate the collection and close all of them.
It will depend on the actual state that Excel is in. If you're unsure of what to do, show Excel instead of closing it, and try to see what it is that it thinks is unsaved and decide if you want to save it or discard it.
You have two good answers here, but as an alternative, you could also tell Excel to suspend warnings. This is helpful any time you do something that would normally prompt a dialog, such as "Save As" on a file that already exists.
The DisplayAlerts property on the Excel object controls this and is true by default. Changing it to false will suspend alerts, so this should also work:
application.DisplayAlerts = false;
application.Quit();
application.DisplayAlerts = true;
I would suggest you take a different approach here. I would create a tab in the excel workbook where the user enters their choices that drive the data selection. Then write some script to use those settings to pull the data from a web service. See this article as an example: https://atinkerersnotebook.com/2012/12/28/creating-consuming-web-services-with-excel/
Now all you have to do is write the web service to return the requested data.
I want to suggest a bit of a different way to generate an excel file. For medium complexity worksheets it's much easier to use Report Designer to design the report, and then export it to an excel file. It can be generated to a stream, you don't even have to generate a file.
I'm currently developing an Excel Add-In using the Excel-DNA library. Sadly I need to serialize the Add-In somehow into the workbook so if the workbook is opened, the Add-In's code may be executed.
Before, I worked with VBA and Excel macros which've been run greatly, I could serialize the macro and upload the workbook. A software put data into it and delivered the edited workbook and I just had to open the workbook for the macro to execute.
I tried that with an Add-In (e.g. loading the Add-In and saving the workbook) but that didn't work, the Add-In seems to be not saved at all. Is there any other chance in serializing the Add-In into a workbook so people who just got the workbook can execute the Add-In's code?
You can include code in the Excel workbook that will install the add-in if it isn't already. You could also have it uninstall the add-in on close if you only want the add-in installed while the workbook is open.
Check out JKP's Name Manager, specifically the code in the Setup Name Manager file.
http://www.jkp-ads.com/OfficeMarketPlaceNM-EN.asp
It finds the add-in, which is assumed to be in the same path and as the Setup file, and copies it to the UserLibrary, which is the default path for add-ins. Then it sets the Addin.Installed property to True.
JKP's addin is and native Excel add-in, not an Excel DNA one, so there may be some differences (and I don't know what they are). But you may have to deal with Application.COMAddins rather than Application.Addins.
The way I understand Add-Ins, they sit separately in a way they can't be bound together with a workbook. The way I have understood them (and used them up to this point) is, for lack of a better term, a weird 'mini-program' that sits loaded inside Excel itself, not inside your workbook - you install it, it has access to more PC resources, Add-Ins even land in the list of programs for Windows, unlike a VBA macro.
Add-Ins solve a lot of problems, but do create a new one in the process. Even if you built a process that reached out on launch for the addin to install, I think it would still require a restart of Excel to be accessible from within the application, which would be frustrating. Add-In deployment is still fairly clunky, in my opinion.
Where I work we have a deployment process to deliver a Start Menu entry that will open excel and the correct version of the xll.
I have never heard of people embedding the addin in the workbook. But you can do the opposite, your addin can be coupled with a XLA or you can create an Addin menu with entries for the user to open a specific version of the workbook. This tie the workbook to a specific version of the addin rather than the opposite like you asked but it may be useful for your purposes. Uou could use a network drive for a basic implementation.
This would achieve kind of the same result by inverting your logic. However this is a costly solution in terms of manpower to create this infrastructure.
I have a process that builds an Excel report, then opens it for the user. The problem is if someone leaves the file open, it stays locked and nobody else can build the report until the first person exits the excel file.
Is there a way to open an Excel file without locking it, using either Process.Start or Microsoft's Interop.Excel library?
I use the Interop library to build the file each time the report is run, and save it as a static file name in a shared network folder where this application is run from
using Excel = Microsoft.Office.Interop.Excel;
...
xlsBook.SaveAs(newFileName, Excel.XlFileFormat.xlWorkbookNormal);
And open the file using Process.Start
Process.Start(newFileName);
You can try to open the file in read-only mode:
var app = new Microsoft.Office.Interop.Excel.Application();
var workbook = app.Workbooks.Open(filename, ReadOnly: true);
Or you can try to save it in shared mode:
workbook.SaveAs(filename, AccessMode: XlSaveAsAccessMode.xlShared);
If the end user only has to read the file instead of also modifying it, you could create a shadow copy and then open that copy.
Simply copy the original file to a temporary location and open it from there. The original file remains untouched and can thus be opened by others.
I have UI tests. When the UI tests finish, they open the result files in an Excel document (Excel 2007 is installed on the test environment) - but the problem is that the excel document is not saved anywhere on the computer. They exist only when the AutoRecover feature saves the temporary files as a .xar file, so this is useless to us.
We use a C# .NET program to launch the UI tests (and do a bunch of other things), so I'm looking to see if it's possible to save this OPENED excel document programmatically.
Is that possible?
Thanks
This may help you How to: Save Workbooks
Example
This example creates a new workbook, prompts the user for a file name, and then saves the workbook.
Set NewBook = Workbooks.Add
Do
fName = Application.GetSaveAsFilename
Loop Until fName <> False
NewBook.SaveAs Filename:=fName