I can't seem to find the proper way to open and close an excel file.
Here is what I have to open my file, which I find overly complicated:
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(workbookPath,
0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
Microsoft.Office.Interop.Excel.Sheets excelSheets = excelWorkbook.Worksheets;
Worksheet sheet = (Microsoft.Office.Interop.Excel.Worksheet)excelApp.Worksheets[2];
sheet.Select(Type.Missing);
I have no idea how to properly close it. I need to save it with the same path and make sure excel is not still running in the background after it is closed.
Can someone make it easy for me?
Thanks
Release the COM objects when completed...
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
# declare the application object
var xl = new Excel.Application();
# open a file
var wb = xl.Workbooks.Open("some_file.xlsx");
# close the file
wb.Close();
# close the application and release resources
xl.Quit();
#release the COM objects created as a final step:
Marshal.ReleaseComObject(wb);
Marshal.ReleaseComObject(xl);
Semi pseudo-code:
using Excel = Microsoft.Office.Interop.Excel;
# declare the application object
Excel.Application xl = new Excel.Application();
# open a file
Excel.Workbook wb = xl.Workbooks.Open("some_file.xlsx");
# do stuff ....
# close the file
wb.Close();
# close the application and release resources
xl.Quit();
Related
I try to open a CSV file with Excel using the Microsoft.Office.Interop.Excel libary.
And it works fine but all the text is in one column with the delimiter ";".
Here an example:
Id;Name;Zeit
1;Name1;21.05.2019 09:21:04
3;Name2;21.05.2019 09:21:04
This is the code I used to open the CSV in Excel:
object missing = Type.Missing;
Excel.Application ex = new Excel.Application();
Excel.Workbook wbs = ex.Workbooks.Open(#"c:\users\langenwa\desktop\File.csv", 0, false, Excel.XlFileFormat.xlCSV, "", "", false, Excel.XlPlatform.xlWindows, ";", true, false, 0, true, false, false);
Excel.Worksheet mSheet = (Excel.Worksheet)wbs.Worksheets[1];
ex.Visible = true;
Thanks for any help and sorry for my bad English.
The csv file works fine in my excel, likely your system has a different default seperator. You can override this.
try to add this at the top of the csv file:
sep=;
note that this only works when opening csv in excel
See these answers for more details: https://superuser.com/questions/606272/how-to-get-excel-to-interpret-the-comma-as-a-default-delimiter-in-csv-files
I tried to use Spire.Xls library, but it does not support .xlsm and when i convert it to .xlsx hasn`t saved it, same with Microsoft.Office.Excel.Interop.
private void button1_Click(object sender, EventArgs e)
{
//string xlsm = #"D:\foot_Regular B07BNJ56GV B07BNK8S3Q B07BMX2NN4 with3.xlsm";
string xlsx = #"D:\foot_Regular B07BNJ56GV B07BNK8S3Q B07BMX2NN4 with3.xlsx";
//ConverXlsmToXlsx(xlsm, xlsx);
//string xlsx = #"D:\1.xlsx";
/* Load Excel File */
Excel.Application excelApp = new Excel.Application();
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(xlsx, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
/* Load worksheets collection */
Excel.Sheets excelSheets = excelWorkbook.Worksheets;
/* Select first worksheet */
Excel.Worksheet excelWorksheet = (Excel.Worksheet)excelSheets[1];
/* Deleting first 87 Rows */
Excel.Range range = excelWorksheet.get_Range("1:87").EntireRow;
range.Delete(Excel.XlDeleteShiftDirection.xlShiftUp);
/* Save File */
excelWorkbook.SaveAs(#"D:\out_file.xlsx");
excelWorkbook.Close(false);
excelApp.Application.Quit();
/* Release COM objects otherwise Excel remain running */
releaseObject(range);
releaseObject(excelWorkbook);
releaseObject(excelWorksheet);
releaseObject(excelApp);
MessageBox.Show("Finished");
}
Conver function:
public static void ConverXlsmToXlsx(string path, string outputPath)
{
byte[] byteArray = File.ReadAllBytes(path);
using (MemoryStream stream = new MemoryStream())
{
stream.Write(byteArray, 0, (int)byteArray.Length);
using (SpreadsheetDocument spreadsheetDoc = SpreadsheetDocument.Open(stream, true))
{
// Change from template type to workbook type
spreadsheetDoc.ChangeDocumentType(SpreadsheetDocumentType.Workbook);
}
File.WriteAllBytes(outputPath, stream.ToArray());
}
}
How i can easy work with .xlsm files via C#?
Help please with it, I would really appreciate it.
EPPlus seems to be the library to use.
You don't need Interop or an actual installation of MS Excel.
They have a sample how to work with VBA macros, but it seems your problem was just reading and saving files without touching the macros, so you should be good with their basic samples:
using (ExcelPackage package = new ExcelPackage(newFile))
{
// make your modifications
package.Save();
}
I personally use ClosedXML.
ClosedXML makes it easier for developers to create Excel 2007+ (.xlsx, .xlsm, etc) files. It provides a nice object oriented way to manipulate the files (similar to VBA) without dealing with the hassles of XML Documents. It can be used by any .NET language like C# and VisualBasic.NET.
You can find more details here.
Spire.XLS supports .xlsm files, here is the code to directly delete rows from a xlsm file with it:
Workbook workbook = new Workbook();
workbook.LoadFromFile("Input.xlsm");
Worksheet sheet = workbook.Worksheets[0];
sheet.DeleteRow(1,87);
workbook.SaveToFile("Output.xlsm", ExcelVersion.Version2007);
I use the Spire.XLS Pack(Hotfix) Version:8.6.6
I have a wpf application that opens/creates excel files and reads/writes to them. In the normal way of the application running, no excel window is shown to the user.
The Scenario:
Through my application, I browse to excel file "AAA.xlsx", and the application loads it. Then, I try to browse to another excel file, but while on the browse window I choose excel file "BBB.xlsx", right click it and select open, Excel launches with both files open.
If I do the same routine, but beforehand I had the Excel program already open(with or without a file loaded), only the selected file will open.
Below is the constructor
public ExcelManipulator()
{
excelApp = new Excel.Application();
excelApp.Visible = false; //not making any difference
excelApp.IgnoreRemoteRequests = true; //not making any difference
workbooks = excelApp.Workbooks;
workbook = workbooks.Open(path);
...
}
My ultimate goal is the excel files that my application has loaded to be invisible from the user's screen.
I think you are referring to separate 'instances' of Excel.
Try the following.
Process process = new Process();
Process.Start("Excel.exe", myExcelFile);
Other option is, if you use Interop (i.e. Microsoft.Office.Interop.Excel.dll ), you can do it as follows. This will always open the file in a new instance.
Excel.Application excelApp = new Excel.Application();
excelApp.Visible = true;
string workbookPath = (#"C:\Sample.xlsx");
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(workbookPath,
0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
I have an Excel Workbook ("test.xlsx") that has a cell named "gv_epxsize". My goal is to open the excel workbook and write down the string "101" in the cell with the name "gv_epxsize".
The problem is that my code keeps making the file Read Only, so it will not write the string "101" to the named cell. I keep receiving a windows prompt that I already have the file open with Windows privileges and asks if I want to open a Read Only copy. The problem is that I don't have the file open, and there is no EXCEL.EXE process running before I initiated the code.
What I've already done:
I've saved the file as a different name in a different folder - still no luck.
The file is not saved in a shared folder.
I have made sure my TaskManager has every EXCEL.EXE process killed before I run my code.
Can someone please show me what I'm doing wrong here?
Here's the snippet of C#
string filePath = "C:\\Users\\ussatdafa\\Desktop\\Work\\Projects\\test.xlsx";
Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
if (xlApp == null)
{
MessageBox.Show("Excel has not been properly installed");
}
else
{
//string fileName = Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), filePath);
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
Workbooks wbs = excelApp.Workbooks;
Workbook wb = wbs.Open(filePath, 0, false, 5, "", "", false, XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Worksheet ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.Worksheets.get_Item(1);
wb.Names.Item("gv_epxsize").RefersToRange.Value = "101";
}
I'm honestly not sure what's going on, but I have two observations:
You are opening Excel twice -- that appears to be certain. One instance is xlApp and the other is excelApp. If you open your task manager on the instantiation of excelApp I'm pretty sure you will find two instances of Excel running. I have no idea if that's contributing to your issue or not
I always found it helpful, when debugging, to make Excel visible. You can always comment that line out before you deploy, but during debugging it's nice since exposing COM objects during debugging isn't as helpful as native .NET objects -- this way you can see it in its native form
I ran a version of your code with these changes and had no issues changing the cell value of the named range "gv_epxsize."
string filePath = "C:\\Users\\ussatdafa\\Desktop\\Work\\Projects\\test.xlsx";
Microsoft.Office.Interop.Excel.Application excelApp =
new Microsoft.Office.Interop.Excel.Application();
if (excelApp == null)
{
MessageBox.Show("Excel has not been properly installed");
}
else
{
excelApp.Visible = true;
Workbook wb = excelApp.Workbooks.Open(filePath, 0, false, 5, "", "", false,
XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Worksheet ws = wb.Sheets[1];
wb.Names.Item("gv_epxsize").RefersToRange.Value = "101";
}
This worked flawlessly for me. Here is proof:
So that leads me to several possibilities:
(Microsoft.Office.Interop.Excel.Worksheet)wb.Worksheets.get_Item(1);
Isn't what you think it is. Or perhaps, it's not the same as what I used, which was:
Worksheet ws = wb.Sheets[1];
Which will return the first worksheet ("Sheet1" on a new workbook).
And of course, there is the possibility that having two Excels open is causing issues.
I am pretty sure your issue is with WHERE in your code you are saving the file. From your posted code, there is one thing that does not really work and could explain your problem. Take a look at the following snippet:
else {
//string fileName = Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), filePath);
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
Workbooks wbs = excelApp.Workbooks;
Workbook wb = wbs.Open(filePath, 0, false, 5, "", "", false, XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Worksheet ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.Worksheets.get_Item(1);
wb.Names.Item("gv_epxsize").RefersToRange.Value = "101";
}
This is the else portion of the if (xlApp == null) statement. First in this else portion you create a NEW Excel application called excelApp with:
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
Why you are doing this is unknown since you have already created one earlier called xlApp. But this is still ok; you are allowed to open more than one Excel application.
Then open the file and make changes:
Workbooks wbs = excelApp.Workbooks;
Workbook wb = wbs.Open(filePath, 0, false, 5, "", "", false, XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Worksheet ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.Worksheets.get_Item(1);
wb.Names.Item("gv_epxsize").RefersToRange.Value = "101";
You open a workbook using the filePath and call the woorkbook wb. Then grab the first sheet in wb and assign it to a worksheet variable ws. Keep in mind you OPEN the workbook in this else clause. Make the changes to the workbook and then exit the else clause. All seems OK EXCEPT… since we have exited the else clause... excelApp, wbs, wb and ws variables NO LONGER EXIST. Even if you tried to save or close the file outside this else clause you will have no way to reference it because you CREATED those variables inside the else clause.
Since you can not create a new variable named wb if it already exist... Then it is clear the workbook wb is never getting saved or closed.
I put the following lines INSIDE your else clause and was able to open the file correctly even with your program running. It is clear you may be saving and closing the file somewhere later in your code but it’s not the file you opened in this else clause.
else {
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
Workbooks wbs = excelApp.Workbooks;
Workbook wb = wbs.Open(filePath, 0, false, 5, "", "", false, XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Worksheet ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.Worksheets.get_Item(1);
wb.Names.Item("gv_epxsize").RefersToRange.Value = "101";
wb.Save();
wb.Close();
excelApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp);
}
Hope this makes sense.
I am just starting to fiddle with Excel via C# to be able to automate the creation, and addition to an Excel file.
I can open the file and update its data and move through the existing worksheets. My problem is how can I add new sheets?
I tried:
Excel.Worksheet newWorksheet;
newWorksheet = (Excel.Worksheet)excelApp.ThisWorkbook.Worksheets.Add(
Type.Missing, Type.Missing, Type.Missing, Type.Missing);
But I get below COM Exception and my googling has not given me any answer.
Exception from HRESULT: 0x800A03EC Source is: "Interop.Excel"
I am hoping someone maybe able to put me out of my misery.
You need to add a COM reference in your project to the "Microsoft Excel 11.0 Object Library" - or whatever version is appropriate.
This code works for me:
private void AddWorksheetToExcelWorkbook(string fullFilename,string worksheetName)
{
Microsoft.Office.Interop.Excel.Application xlApp = null;
Workbook xlWorkbook = null;
Sheets xlSheets = null;
Worksheet xlNewSheet = null;
try {
xlApp = new Microsoft.Office.Interop.Excel.Application();
if (xlApp == null)
return;
// Uncomment the line below if you want to see what's happening in Excel
// xlApp.Visible = true;
xlWorkbook = xlApp.Workbooks.Open(fullFilename, 0, false, 5, "", "",
false, XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
xlSheets = xlWorkbook.Sheets as Sheets;
// The first argument below inserts the new worksheet as the first one
xlNewSheet = (Worksheet)xlSheets.Add(xlSheets[1], Type.Missing, Type.Missing, Type.Missing);
xlNewSheet.Name = worksheetName;
xlWorkbook.Save();
xlWorkbook.Close(Type.Missing,Type.Missing,Type.Missing);
xlApp.Quit();
}
finally {
Marshal.ReleaseComObject(xlNewSheet);
Marshal.ReleaseComObject(xlSheets);
Marshal.ReleaseComObject(xlWorkbook);
Marshal.ReleaseComObject(xlApp);
xlApp = null;
}
}
Note that you want to be very careful about properly cleaning up and releasing your COM object references. Included in that StackOverflow question is a useful rule of thumb: "Never use 2 dots with COM objects". In your code; you're going to have real trouble with that. My demo code above does NOT properly clean up the Excel app, but it's a start!
Some other links that I found useful when looking into this question:
Opening and Navigating Excel with C#
How to: Use COM Interop to Create an Excel Spreadsheet (C# Programming Guide)
How to: Add New Worksheets to Workbooks
According to MSDN
To use COM interop, you must have
administrator or Power User security
permissions.
Hope that helps.
Would like to thank you for some excellent replies. #AR., your a star and it works perfectly. I had noticed last night that the Excel.exe was not closing; so I did some research and found out about how to release the COM objects. Here is my final code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;
using Excel;
namespace testExcelconsoleApp
{
class Program
{
private String fileLoc = #"C:\temp\test.xls";
static void Main(string[] args)
{
Program p = new Program();
p.createExcel();
}
private void createExcel()
{
Excel.Application excelApp = null;
Excel.Workbook workbook = null;
Excel.Sheets sheets = null;
Excel.Worksheet newSheet = null;
try
{
FileInfo file = new FileInfo(fileLoc);
if (file.Exists)
{
excelApp = new Excel.Application();
workbook = excelApp.Workbooks.Open(fileLoc, 0, false, 5, "", "",
false, XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
sheets = workbook.Sheets;
//check columns exist
foreach (Excel.Worksheet sheet in sheets)
{
Console.WriteLine(sheet.Name);
sheet.Select(Type.Missing);
System.Runtime.InteropServices.Marshal.ReleaseComObject(sheet);
}
newSheet = (Worksheet)sheets.Add(sheets[1], Type.Missing, Type.Missing, Type.Missing);
newSheet.Name = "My New Sheet";
newSheet.Cells[1, 1] = "BOO!";
workbook.Save();
workbook.Close(null, null, null);
excelApp.Quit();
}
}
finally
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(newSheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets);
System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp);
newSheet = null;
sheets = null;
workbook = null;
excelApp = null;
GC.Collect();
}
}
}
}
Thank you for all your help.
Another "Up Tick" for AR..., but if you don't have to use interop I would avoid it altogether. This product is actually quite interesting:
http://www.clearoffice.com/ and it provides a very intuitive, fully managed, api for manipulation excel files and seems to be free. (at least for the time being) SpreadSheetGear is also excellent but pricey.
my two cents.
Do not forget to include Reference to Microsoft Excel 12.0/11.0 object Library
using Excel = Microsoft.Office.Interop.Excel;
// Include this Namespace
Microsoft.Office.Interop.Excel.Application xlApp = null;
Excel.Workbook xlWorkbook = null;
Excel.Sheets xlSheets = null;
Excel.Worksheet xlNewSheet = null;
string worksheetName ="Sheet_Name";
object readOnly1 = false;
object isVisible = true;
object missing = System.Reflection.Missing.Value;
try
{
xlApp = new Microsoft.Office.Interop.Excel.Application();
if (xlApp == null)
return;
// Uncomment the line below if you want to see what's happening in Excel
// xlApp.Visible = true;
xlWorkbook = xlApp.Workbooks.Open(#"C:\Book1.xls", missing, readOnly1, missing, missing, missing, missing, missing, missing, missing, missing, isVisible, missing, missing, missing);
xlSheets = (Excel.Sheets)xlWorkbook.Sheets;
// The first argument below inserts the new worksheet as the first one
xlNewSheet = (Excel.Worksheet)xlSheets.Add(xlSheets[1], Type.Missing, Type.Missing, Type.Missing);
xlNewSheet.Name = worksheetName;
xlWorkbook.Save();
xlWorkbook.Close(Type.Missing, Type.Missing, Type.Missing);
xlApp.Quit();
}
finally
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlNewSheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheets);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkbook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
//xlApp = null;
}
You can use OLEDB to create and manipulate Excel files. See this question for links and samples.
Here are a couple things I figured out:
You can't open more than one instance of the same object at the same time. For Example if you instanciate a new excel sheet object called xlsheet1 you have to release it before creating another excel sheet object ex xlsheet2. It seem as COM looses track of the object and leaves a zombie process on the server.
Using the open method associated with excel.workbooks also becomes difficult to close if you have multiple users accessing the same file. Use the Add method instead, it works just as good without locking the file. eg. xlBook = xlBooks.Add("C:\location\XlTemplate.xls")
Place your garbage collection in a separate block or method after releasing the COM objects.
COM is definitely not a good way to go. More specifically, it's a no go if you're dealing with web environment...
I've used with success the following open source projects:
ExcelPackage for OOXML formats (Office 2007)
NPOI for .XLS format (Office 2003)
Take a look at these blog posts:
Creating Excel spreadsheets .XLS and .XLSX in C#
NPOI with Excel Table and dynamic Chart
This is what i used to add addtional worksheet
Workbook workbook = null;
Worksheet worksheet = null;
workbook = app.Workbooks.Add(1);
workbook.Sheets.Add();
Worksheet additionalWorksheet = workbook.ActiveSheet;
I had a similar problem application-level add-in in VSTO, the exception HRESULT: 0x800A03EC when adding new sheet.
The error code 0x800A03EC (or -2146827284) means NAME_NOT_FOUND; in
other words, you've asked for something, and Excel can't find it.
Dominic Zukiewicz # Excel error HRESULT: 0x800A03EC while trying to get range with cell's name
Then I finally realized ThisWorkbook triggered the exception. ActiveWorkbook went OK.
Excel.Worksheet newSheetException = Globals.ThisAddIn.Application.ThisWorkbook.Worksheets.Add(Type.Missing, sheet, Type.Missing, Type.Missing);
Excel.Worksheet newSheetNoException = Globals.ThisAddIn.Application.ActiveWorkbook.Worksheets.Add(Type.Missing, sheet, Type.Missing, Type.Missing);