.Net Excel Interop Deleting a worksheet - c#

I'm trying to delete a worksheet from a excel document from a .Net c# 3.5 application with the interop Excel class (for excel 2003).
I try many things like :
Worksheet worksheet = (Worksheet)workbook.Worksheets[1];
worksheet.Delete();
It's doesn't work and doesn't throw any error ...

After more than one hour looking I found the answer:
xlApp.DisplayAlerts = false;
worksheet.Delete();
xlApp.DisplayAlerts = true;

When dealing with deleting Excel Worksheets, there are two important things to know:
Excel interop counts from 1 (and not from zero), therefore, removing the second item will cause the third item to take its place!. so, the proper way to remove worksheets is from the last to the first:
// Remove LAST worksheet
MyWorkBook.Worksheets[3].Delete();
// and only then remove the second (which is the last one)
MyWorkBook.Worksheets[2].Delete();
alternatively, you can delete the second item ([2]) on the list twice, which will give you the same result.
The following line will throw exception when you only got one worksheet left:
MyWorkBook.Worksheets[1].Delete();

It is also important to note that the workbook must contain at least one worksheet; this means you cannot delete all worksheets in a workbook.

Microsoft.Office.Interop.Excel.Worksheet worksheet = Microsoft.Office.Interop.Excel.Worksheet)xlWorkBook.Worksheets[1];
worksheet.Delete();

Try to find worksheet by name:
var app = new Microsoft.Office.Interop.Excel.Application();
var workbook = app.Workbooks.Add();
((Microsoft.Office.Interop.Excel.Worksheet)workbook.Worksheets["Sheet3"]).Delete();

we can delete the work sheet like this
Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
if (xlApp == null)
{
return;
}
xlApp.DisplayAlerts = false;
string filePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
+ "\\Sample.xlsx";
Excel.Workbook xlWorkBook = xlApp.Workbooks.Open(filePath, 0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Excel.Sheets worksheets = xlWorkBook.Worksheets;
worksheets[4].Delete();
worksheets[3].Delete();
xlWorkBook.Save();
xlWorkBook.Close();
releaseObject(worksheets);
releaseObject(xlWorkBook);
releaseObject(xlApp);
and use this
static void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
throw ex;
}
finally
{
GC.Collect();
}
}

We delete excel worksheets from a c# console application like this:
Microsoft.Office.Interop.Excel.Worksheet worksheet =
(Worksheet)workbook.Worksheets["Worksheet_Name" (or) "Countings"];
worksheet.Delete();

Related

Deleting a sheet in Excel

I tried almost everything that I could find here on StackOverflow but my code keeps throwing the following error:
Exception from HRESULT: 0x800A03EC
on the line with delete(). I was hoping you people could help me out.
Here's my current code
var xlApp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook book =
xlApp.Workbooks.Open(File_name);
xlApp.DisplayAlerts = false;
Excel.Worksheet worksheet = (Excel.Worksheet)book.Worksheets[2];
worksheet.Delete();
book.Worksheets.Add();
xlApp.DisplayAlerts = true;
book.Save();
book.Close();
xlApp.Quit();
Marshal.ReleaseComObject(worksheet);
Marshal.ReleaseComObject(book);
Marshal.ReleaseComObject(xlApp);
And here's the other code i tried:
oXL.DisplayAlerts = false;
worksheet = (Excel.Worksheet)theWorkbook.Sheets[i];
((Excel.Worksheet)theWorkbook.Sheets[i]).Delete();
oXL.DisplayAlerts = true;
oWB.Save();
oWB.Close(false, missing, missing);
oSheet = null;
oWB = null;
oXL.Quit();
And some more variations
Microsoft.Office.Interop.Excel.Application oXL = new Microsoft.Office.Interop.Excel.Application();
Excel.Workbook oWB;
Excel.Worksheet oSheet;
Excel.Workbooks oMWB;
and i'm using this reference:
using Excel = Microsoft.Office.Interop.Excel;
Working with the Excel Interop libraries, I encountered this error many times. The main cause of this problem (a generic COM exception), most of the times, is that Excel tries to find something you've asked for, but Excel isn't able to find it. See this answer, it helped me a lot.
Reading these lines:
Excel.Worksheet worksheet = (Excel.Worksheet)book.Worksheets[2];
worksheet.Delete();
I think that you're trying to delete a worksheet that's not existing. Check your Excel document.
I just made the most stupid mistake ever..... the excel file was a shared file, that's why i couldn't delete it..
Sorry for making such a stupid mistake, and thanks to everybody who tried to help me!
HRESULT: 0x800A03EC is an unknown COM error. This usually happens when Excel throws some error because your input or parameters were wrong.
This example provide msdn: Programmatically Deleting Worksheets from Workbooks
((Excel.Worksheet)this.Application.ActiveWorkbook.Sheets[4]).Delete();
So try next:
Excel.Worksheet worksheet = (Excel.Worksheet)book.Sheets[2];
worksheet.Delete();
instead of:
Excel.Worksheet worksheet = (Excel.Worksheet)book.Worksheets[2];
worksheet.Delete();
Try this:
xlApp.DisplayAlerts = false;
Excel.Worksheet worksheet = (Excel.Worksheet)book.Worksheets[2];
worksheet.Delete();
xlApp.DisplayAlerts = true;
Also important to keep in mind, interop starts to count from 1, not from 0. so deleting item [0] or deleting the only sheet will throw you an exception. if you plan to remove the [2] worksheet, the third one will take its place. So make sure to remove from the last to the first.
this is code i have used to delete the excel sheet
Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
if (xlApp == null)
{
return;
}
xlApp.DisplayAlerts = false;
string filePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
+ "\\Sample.xlsx";
Excel.Workbook xlWorkBook = xlApp.Workbooks.Open(filePath, 0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Excel.Sheets worksheets = xlWorkBook.Worksheets;
worksheets[4].Delete();
worksheets[3].Delete();
xlWorkBook.Save();
xlWorkBook.Close();
releaseObject(worksheets);
releaseObject(xlWorkBook);
releaseObject(xlApp);
and use this
static void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
throw ex;
}
finally
{
GC.Collect();
}
}

Excel process still runs in background

I'm reading some data from a sheet of an excel file using interop library. I get the data just fine by using Microsoft.Office.Interop.Excel and then reading all data in the sheet.
Application ExcelApp = new Excel.Application();
Workbook excelWorkbook = ExcelApp2.Workbooks.Open(excelFileNamePath);
_Worksheet excelWorksheet = excelWorkbook.Sheets[excelSheetName];
Range excelRange = excelWorksheet.UsedRange;
//...for loops for reading data
ExcelApp.Quit();
But after my application terminates, I tried to edit my excel file and had some problems while opening. Apparently the excel process keeps on running in the background even though I called ExcelApp.Quit(). Is there a way to properly close the excel file that the application uses? I'm new to c# so i'm probably missing something here.
Edit: Solved! Apparently there's a rule for com objects that discourages using 2 dots.
Excel.Application ExcelApp2 = new Excel.Application();
Excel.Workbooks excelWorkbooks = ExcelApp2.Workbooks;
Excel.Workbook excelWorkbook = excelWorkbooks.Open(excelFileName);
Excel._Worksheet excelWorksheet = excelWorkbook.Sheets[excelSheetName];
//...
excelWorkbook.Close();
Marshal.ReleaseComObject(excelWorkbook);
Marshal.ReleaseComObject(excelWorksheet);
Marshal.ReleaseComObject(excelRange);
ExcelApp2.Quit();
There was another similar question - and answer (https://stackoverflow.com/a/17367570/3063884), in which the solution was to avoid using double-dot notation. Instead, define variables for each object used along the way, and individually use Marshal.ReleaseComObject on each one.
Copying straight from the linked solution:
var workbook = excel.Workbooks.Open(/*params*/)
---> instead use -->
var workbooks = excel.Workbooks;
var workbook = workbooks.Open(/*params*/)
Then, when done, release each COM object:
Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(workbooks);
Marshal.ReleaseComObject(excel);
Long time no answer but what worked for me was to call the GC.Collect(); from the caller,
i.e. instead of
main()
{
...
doexcelstuff();
...
}
void doexcelstuff()
{
Excel.Application ExApp2 = new Excel.Application();
Excel.Workbook excelWb = ExApp2 .Workbooks.Open(excelFName);
Excel._Worksheet excelWorksheet = excelWb.Sheets[excelSName];
//...
excelWb.Close();
ExApp2.Quit();
Marshal.ReleaseComObject(excelWb);
Marshal.ReleaseComObject(excelWorksheet);
Marshal.ReleaseComObject(ExApp2);
excelWb = null;
excelWorksheet= null;
ExApp2= null;
GC.Collect();
}
Using above Excel does not die
but a very small change, to where the GC is called from
main()
{
...
doexcelstuff();
GC.Collect(); // <<-- moved the GC to here (the caller)
...
}
void doexcelstuff()
{
Excel.Application ExApp2 = new Excel.Application();
Excel.Workbook excelWb = ExApp2 .Workbooks.Open(excelFName);
Excel._Worksheet excelWorksheet = excelWb.Sheets[excelSName];
//...
excelWb.Close();
ExApp2.Quit();
Marshal.ReleaseComObject(excelWb);
Marshal.ReleaseComObject(excelWorksheet);
Marshal.ReleaseComObject(ExApp2);
excelWb = null;
excelWorksheet= null;
ExApp2= null;
// removed the GC from here
}
My guess is the garbage collector needs to also quietly clean up internally created temp values (including refs/pointers) from the heap - some of which I guess in this case are pointing to COM objects.
(Just takes a smidgen of understanding of how machines work underneath the source code.)
You are not closing your workbook. Close it and then release it before quitting the Excel application:
excelWorkbook.close();
Marshal.ReleaseComObject(excelWorkbook);
ExcelApp.Quit();
For me this worked!
//Initializing
Application excelApp = new Application();
Workbook excelWorkbook = excelApp.Workbooks.Open(pathExcelFile, 0, true, 5, "", "",
true, XlPlatform.xlWindows, "\t", false, false, 0,
true, 1, 0);
Worksheet excelWorksheet = (Worksheet)excelWorkbook.Sheets[1];
//closing
excelWorksheet = null;
excelWorkbook.Close();
excelWorkbook = null;
excelApp.Quit();
excelApp = null;
Interop is notoriously buggy... I use the following method after saving my workbook, and no longer have issues with Excel remaining open when I exit my applications:
while (Marshal.ReleaseComObject(wb) > 0);
while (Marshal.ReleaseComObject(xl) > 0);
wb = null;
xl = null;
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
wb is my workbook object, and xl is my Excel.Application object.
For me this worked :
//opening
var excelFile = new Application();
Workbook workBook1 = excelFile.Workbooks.Open(goldenCopy_path);
Workbook workBook2 = excelFile.Workbooks.Open(new_path);
Worksheet goldWorkSheet, newWorkSheet;
goldWorkSheet = workBook1.Worksheets[1];
newWorkSheet = workBook2.Worksheets[1];
//closing
//it will release the workbook from visual studio
goldWorkSheet = null;
newWorkSheet = null;
workBook1.Close();
workBook2.Close();
workBook1 = null;
workBook2 = null;
excelFile.Quit();
excelFile = null;
This code worked on me.
Excel.Application excelApp = null;
Excel.Workbooks excelWorkbooks = null;
Excel.Workbook excelWorkbook = null;
Excel._Worksheet xlWorkSheet = null;
Excel.Range range = null;
excelApp = new Excel.Application();
excelWorkbooks = excelApp.Workbooks;
excelWorkbook = excelWorkbooks.Open(excelName);
xlWorkSheet = (Excel.Worksheet)excelWorkbook.ActiveSheet;
range = xlWorkSheet.Range["C3"] ;
range.Value = "Update Data";
Marshal.ReleaseComObject(range);
xlWorkSheet.SaveAs(path);
Marshal.ReleaseComObject(xlWorkSheet);
excelWorkbook.Close();
Marshal.ReleaseComObject(excelWorkbook);
excelWorkbooks.Close();
Marshal.ReleaseComObject(excelWorkbooks);
excelApp.Quit();
Marshal.ReleaseComObject(excelApp);

C# Interop - Iterating through rows and deleting

I am using Excel Interop to work with some excel sheets. In a worksheet, I need to iterate through the rows, and if the first cell in the row is empty then I need to delete the entire row iteself. I tried the following-
Excel.Range excelRange = sheet.UsedRange;
foreach (Excel.Range row in excelRange.Rows)
{
String a = ((Excel.Range)row.Cells[Type.Missing, 1]).Value2 as String;
if (a == null || a == "")
{
((Excel.Range)row).Delete(Type.Missing);
}
}
This was not working at all. Is there any different way to do this?
And, is there any quick way to find and remove all formula in a Worksheet?
Let's say your Excel file looks like this.
The best way to delete rows would be to use Excel's inbuilt feature called Autofilter which will filter Col A for blank values and then deleting the entire rows in one go.
TRIED AND TESTED (In VS 2010 Ultimate)
Note: I have changed few lines which I feel could error out in VS 2008. Since I don't have VS 2008, I couldn't test it there. If you get any errors do let me know and I will rectify it.
//~~> Open File
private void button1_Click(object sender, EventArgs e)
{
Microsoft.Office.Interop.Excel.Application xlexcel;
Microsoft.Office.Interop.Excel.Workbook xlWorkBook;
Microsoft.Office.Interop.Excel.Worksheet xlWorkSheet;
Microsoft.Office.Interop.Excel.Range xlRange;
Microsoft.Office.Interop.Excel.Range xlFilteredRange;
xlexcel = new Excel.Application();
xlexcel.Visible = true;
//~~> Open a File
xlWorkBook = xlexcel.Workbooks.Open("C:\\MyFile.xlsx", 0, false, 5, "", "", true,
Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
//~~> Work with Sheet1
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
//~~> Get last row in Col A
int _lastRow = xlWorkSheet.Cells.Find(
"*",
xlWorkSheet.Cells[1,1],
Excel.XlFindLookIn.xlFormulas,
Excel.XlLookAt.xlPart,
Excel.XlSearchOrder.xlByRows,
Excel.XlSearchDirection.xlPrevious,
misValue,
misValue,
misValue
).Row ;
//~~> Set your range
xlRange = xlWorkSheet.Range["A1:A" + _lastRow];
//~~> Remove any filters if there are
xlWorkSheet.AutoFilterMode=false;
//~~> Filter Col A for blank values
xlRange.AutoFilter(1, "=", Excel.XlAutoFilterOperator.xlAnd, misValue, true);
//~~> Identigy the range
xlFilteredRange = xlRange.Offset[1,0].SpecialCells(Excel.XlCellType.xlCellTypeVisible,misValue);
//~~> Delete the range in one go
xlFilteredRange.EntireRow.Delete(Excel.XlDirection.xlUp);
//~~> Remove filters
xlWorkSheet.AutoFilterMode = false;
//~~> Close and cleanup
xlWorkBook.Close(true, misValue, misValue);
xlexcel.Quit();
releaseObject(xlRange);
releaseObject(xlFilteredRange);
releaseObject(xlWorkSheet);
releaseObject(xlWorkBook);
releaseObject(xlexcel);
}
private void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
MessageBox.Show("Unable to release the Object " + ex.ToString());
}
finally
{
GC.Collect();
}
}
Output

Use C# to duplicate a chart in Excel

I've got a spreadsheet that contains a template chart. In the past I've used the copy/paste functionality, but from time to time I run into an error where I copy something onto the clipboard at the same time my code is and I'd like to avoid that. So I looked into the Duplicate method. Should the code below work? The chart does get duplicated fine.
The problem I'm having is that I'm not sure how to get the chart object after it has been duplicated. On this line:
ChartObject chart = (ChartObject)o;
I get this error: Unable to cast COM object of type 'System.__ComObject' to interface type 'Microsoft.Office.Interop.Excel.ChartObject'. Here is my code:
string file = #"D:\test.xlsx";
Microsoft.Office.Interop.Excel.Application app = new Microsoft.Office.Interop.Excel.Application();
app.Visible = true;
ApplicationClass temp = new ApplicationClass();
Microsoft.Office.Interop.Excel.Workbook oBook;
Microsoft.Office.Interop.Excel.Worksheet oSheet;
oBook = app.Workbooks.Open(file, 0, false, 1, "", "", true, XlPlatform.xlWindows, "\t", false, false, 0, true, true, XlCorruptLoad.xlNormalLoad);
oSheet = oBook.Worksheets["template"] as Worksheet;
object o = ((ChartObject)oSheet.ChartObjects("template")).Duplicate();
ChartObject chart = (ChartObject)o;
chart.Name = "TEST";
Can I get the count of ChartObjects? If I were doing it in a macro I could use this line to get the last chart
oSheet.ChartObjects(oSheet.ChartObjects.Count)
Any suggestions? I sincerely appreciate any help.
Thanks,
Nick
In the event anyone is interested in how I ended up doing this. Assuming you have a worksheet named "template" and on that sheet you also have a chart named "template."
Microsoft.Office.Interop.Excel.Worksheet oTemplate = oBook.Worksheets["template"] as Worksheet;
Microsoft.Office.Interop.Excel.Worksheet oOutput = oBook.Worksheets["output"] as Worksheet;
// duplicate template chart
ChartObject chartTemplate = (ChartObject)oTemplate.ChartObjects("template");
object o = chartTemplate.Duplicate();
ChartObject chart = (ChartObject)oTemplate.ChartObjects(GetChartCount(oTemplate));
public static int GetChartCount(Microsoft.Office.Interop.Excel.Worksheet oSheet)
{
int x = 0;
foreach (Microsoft.Office.Interop.Excel.Shape s in oSheet.Shapes)
{
if (s.HasChart == MsoTriState.msoTrue)
x++;
}
return x;
}
Maybe not the best way, but it works.

How to get the selected sheet name in Excel using c#.net

Hi friends,
I am beginner for using Excel. I need to figure out how to find the selected sheet name from the workbook in Excel.
Thanks a lot.
Devaraj
This is a little old. In 2004, but I used it and it helped me. What I understand is you want to call a certain excel sheet to your c# app? Anyway, check this site out, it will help if thats what your doing.
C# - Retrieve Excel Workbook Sheet Names.
You can use this solution ....
Taken from here ....using excel oledb to get sheet names in sheet order
private Dictionary<int,string> GetExcelSheetNames(string fileName)
{
Excel.Application _excel = null;
Excel.Workbook _workBook = null;
Dictionary<int,string> excelSheets = new Dictionary<int,string>();
try
{
object missing = Type.Missing;
object readOnly = true;
Excel.XlFileFormat.xlWorkbookNormal
_excel = new Excel.ApplicationClass();
_excel.Visible = false;
_workBook = _excel.Workbooks.Open(fileName, 0, readOnly, 5, missing,
missing, true, Excel.XlPlatform.xlWindows, "\\t", false, false, 0, true, true, missing);
if (_workBook != null)
{
int index = 0;
foreach (Excel.Worksheet sheet in _workBook.Sheets)
{
// Can get sheet names in order they are in workbook
excelSheets.Add(++index, sheet.Name);
}
}
}
catch (Exception e)
{
return null;
}
finally
{
if (_excel != null)
{
if (_workBook != null)
{
_workBook.Close(false, Type.Missing, Type.Missing);
}
_excel.Application.Quit();
}
_excel = null;
_workBook = null;
}
return excelSheets;
}
Application xlsxApp;
string sheetname = (xlsxApp.ActiveSheet).Name;
Here is a more up to date answer:
Excel.Worksheet activeWorksheet = ((Excel.Worksheet)Application.ActiveSheet);
string activeWorksheetName = activeWorksheet.Name;
hth

Categories