I have created a C# application whose inputs are some large Excel files.
In my code, I open it, process and then close it. The whole process takes some 15-20 minutes. During this time when I try to open some other Excel files(1) externally, anyone of the input Excel files(2) (which is currently being processed) is also getting opened along with this. When I try to close this(2), exception occurs and the tool aborts its process.
I think the problem occurs because the Excel files are opened under the same instance. How can I avoid this?
SpreadsheetGear for .NET will open only the workbooks you want it to open and in most cases runs much faster than using the Excel COM Interop APIs from .NET.
You can see samples here and download a free trial here if you want to try it yourself.
Disclaimer: I own SpreadsheetGear LLC
The following is the code:
Excel.ApplicationClass objExcelApp = new Excel.ApplicationClass();
Excel.Workbook objWorkbook = objExcelApp.Workbooks.Open("File Name",0, true, 1, "", "", true, Excel.XlPlatform.xlWindows,Type.Missing, false, false, 0,true);
Excel.Worksheet objWorksheet = (Excel.Worksheet) objWorkbook.Worksheets.get_Item(1);
Excel.Range objRangeData =objWorksheet.UsedRange;
// Some proces
GC.Collect();
objRangeData.Clear ();
objWorkbook.Close(false, strDictFile, false);
objExcelApp.Workbooks.Close();
objExcelApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(objRangeData);
System.Runtime.InteropServices.Marshal.ReleaseComObject(objWorksheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(objWorkbook); System.Runtime.InteropServices.Marshal.ReleaseComObject(objExcelApp);
objWorksheet = null;
objWorkbook = null;
objExcelApp = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Related
In my application I am automatically generating Excel file using C# code. This application is used on several environments (computers). On one computer generating this file is pretty slow than on all other computers.
For example following code is 90% slower on that computer:
using Excel = Microsoft.Office.Interop.Excel;
...
Microsoft.Office.Interop.Excel.ApplicationClass xlApp = new Excel.ApplicationClass();
Excel.Workbooks workbooks = xlApp.Workbooks;
Excel.Workbook xlBook = workbooks.Open(#"C:\a\a.xlsx", 0, false, 6, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
Excel.Worksheet xlSheet = (Excel.Worksheet)xlBook.Worksheets.get_Item("Sheet1");
Excel.Range oRange = xlSheet.get_Range(xlSheet.Cells[1, 1], xlSheet.Cells[2, 2]);
object[,] a = new object[1, 1];
a[0, 0] = "1";
oRange.Value2 = a;
xlBook.Save();
xlApp.Visible = false;
xlApp.Workbooks.Close();
get_Range method is 2 times slower on that machine.
Does anybody know how can I find out what is slowing down the comunication of Excel Interop COM object and what to do to make it faster?
There are a large number of factors that could affect the performance of your interop code:
Excel version
.NET Framework version
SDK version (if using VSTO)
Presence/absence of service packs
Hardware specs of the machine
Resource usage (RAM, CPU, I/O, etc) at the time of execution
Number of other COM applications installed on the machine
There are ways to speed up Excel interop code, such as hiding the window (you are already doing this) and setting the ScreenUpdating property to false for the duration of the operation.
But, having said all this, COM interop is fundamentally slow and clunky. It is the least efficient way of working with Excel documents. You would be far better off using the OpenXML SDK for this. It is 100% managed code and has no external dependencies (does not even require Office to be installed on the target machine).
I'm wanting to import data from an Excel workbook without actually displaying the open workbook.
I could have sworn I had used the following code on a previous project and it had worked:
var excelApp = new Excel.Application { Visible = false };
var workbook = excelApp.Workbooks.Open(filePath);
Unfortunately when the workbook opens it is displayed to the user which is unnecessary for this application.
I'm using Microsoft Excel 15.0 Object Library on this project when previously I think it was version 12 or 13. Maybe this is the problem, or is my memory fading and the code is incorrect?
I know this is old but just in case anybody still needs this answer...
excelApp.Visible = false;
(excelApp being the name of the variable used for the excel application)
I have an excel application, that gets consolidated lists from SharePoint using power query. I have set the property to refresh on open of the excel application, to refresh the dataset. When I manually open the excel, it refreshes and i get the updated data. However, I am using this excel in my winform application to get the data.
So in order to refresh the data, i am trying to open and close the excel from code.
But the data doesn't get refreshed, and it screws up the power query addin. When I manually open the excel sheet again, after running the code i get the error "The query did not run, or the database table could not be opened."
And the Power Query is not seen anymore on the ribbon.
Below is the code i use to open and close the Excel application:
Excel.Application excelApp = new Excel.Application();
excelApp.Visible = true;
string workbookPath = #"C:\Test\Test.xlsx";
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(workbookPath,
0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
Excel.Sheets excelSheets = excelWorkbook.Worksheets;
string currentSheet = "Sheet1";
Excel.Worksheet excelWorksheet = (Excel.Worksheet)excelSheets.get_Item(currentSheet);
Excel.Range excelCell = (Excel.Range)excelWorksheet.get_Range("A1", "A2");
excelWorkbook.Close(true, "Test.xlxs", null);
Is this the best way to refresh the data?
If your Power Query/BI implementation does not allow usage of the Data Management Gateway (DMG) as suggested by a previous poster, you may want to explore a new piece of software called Power Update to set the update to a schedule.
Plus you may be able to run their Excel data-source update tasks from within your C# application if this is part of the requirement.
Two things to be aware of.
Connections in excel default to background (asynchronous) refresh, which can make your programmatic refresh code non-deterministic.
Power Query does polling to update the status of the query refresh. So if you close the workbook right after the refresh the status won't have a chance to update and next time you open the workbook the status will indicate an error.
In order to get a reliable refresh, you will need to set the connections to no longer background refresh, so the refresh blocks, and then also sleep for a short time after the refresh to let Power Query's polling discover that the refresh is complete.
I would change your script to this
Excel.Application excelApp = new Excel.Application();
excelApp.Visible = true;
string workbookPath = #"C:\Test\Test.xlsx";
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(workbookPath,
0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
excelWorkbook.RefreshAll();
System.Threading.Thread.Sleep(2000);
excelWorkbook.Close(true, "Test.xlxs", null);
You could make this code even better by looping through the queries and setting them to not background refresh like this vba code does
https://social.technet.microsoft.com/Forums/en-US/9cbdd731-d139-49ee-8f30-89de371ba74d/multiple-queries-run-one-after-another?forum=powerquery#df2947a7-585a-4f75-8337-e0ead5068254
I am working on a project that runs MySQL queries on DB. I need to feed out the results to a excel sheet that I will be generating on the fly. I had started the code, using msdn tutorials as well as information I found on stackoverflow, however running the application leaves me with
"Object reference not set to an instance of an object."
At this point I just have the basic code started as I wanted to make this work before I started creating the entire spreadsheet in the code.
var excelApp = new Excel.Application();
excelApp.Visible = true;
Excel.Worksheet workSheet = (Excel.Worksheet)excelApp.ActiveSheet;
((Excel.Range)workSheet.Cells[1, 1]).Value = "Print Date:";
If I can provide any more info just ask. I greatly appreciate any information or insight you can provide me with!
I'd say that workSheet is being set to null as excelApp.ActiveSheet doesn't exist yet.
Here's some code that'll create a worksheet object you can use...
var application = new Application();
var workbooks = application.Workbooks;
var workbook = workbooks.Add(XlWBATemplate.xlWBATWorksheet);
var worksheets = (Sheets)workbook.Worksheets;
var worksheet = worksheets[1];
A few things to note when working with Excel:
Release every object with System.Runtime.InteropServices.Marshal.ReleaseComObject(object) when you're finished with it. If you don't, Excel won't exit when you're done.
Don't use double-dot references (i.e., object1.object2.value). If you do you can't release it properly as above.
Indexes always start from 1, not 0 (in my experience anyway).
The reason you get that error is, you have not created any worksheets in the Application.
Try doing this.
Excel.Worksheet newWorksheet;
newWorksheet = (Excel.Worksheet)excelApp.Worksheets.Add();
Is there a way to save changes to an excel spreadsheet through the excel interop (in this case I am adding a worksheet to it) without having it prompt the user if they want to overwrite the existing file with the changes. I do not want the user to even see the spreadsheet open in my application so having a message box popping up asking them if they want to overwrite the file seems very out of place and possibly confusing to the user.
I am using the workbook.SaveAs(fileloaction) method.
Here is where I am initializing the COM reference objects for the excel interop.
private Excel.Application app = null;
private Excel.Workbook workbook = null;
public Excel.Workbook Workbook
{
get { return workbook; }
set { workbook = value; }
}
private Excel.Worksheet worksheet = null;
private Excel.Range workSheet_range = null;
Below is the code I am using to close/save the excel file. The workbook.close() method line is the one that is reportedly throwing the unhandled exception.
workbook.Close(true, startForm.excelFileLocation, Missing.Value);
Marshal.ReleaseComObject(app);
app = null;
System.GC.Collect();
Basically, all you need is ExcelApp.DisplayAlerts = False - Here's how I do it, though:
ExcelApp.DisplayAlerts = False
ExcelWorkbook.Close(SaveChanges:=True, Filename:=CurDir & FileToSave)
Hope this helps
Only this code will Require for stop override alert or Template already in use
ExcelApp.DisplayAlerts = False
I know this is an old post, but I wanted to share a way to make this work without causing possible frustration in the future.
First what I do not like about using: ExcelApp.DisplayAlerts = False
Setting this flag will set this property on the excel file, not just in your program. This means that if a user makes changes to the file and closes it (by clicking the X), they will not be prompted to save the file and will cause frustration later. It will also disable any other prompts excel would typically post.
I like checking if the file exists before saving it:
if (File.Exists(SaveAsName))
{
File.Delete(SaveAsName);
}