I have a 2010 Excel ribbon add-in. When you press a button it simply writes some lines of data into the excel app. In order to write this data I need to get the active worksheet. And in order to get the active worksheet I need the activeWorkBook. I can get the xlApp fine with
xlApp = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
And it retrieves the xlApp fine But whenever I try to get the active workbook it returns null. No matter what. Unless I restart my computer. Then it works, but only the first time. Below is the whole block of code in context. I'm wondering how to fix the xlApp.ActiveWorkBook being null. So that I can get the active worksheet. And then write data to the active worksheet.
public void sendData()
{
Excel.Application xlApp = null;
Excel.Workbook xlWorkBook = null;
Excel.Workbooks xlWorkBooks = null;
Excel.Worksheet xlWorkSheet = null;
object misValue = System.Reflection.Missing.Value;
try
{
xlApp = new Excel.Application();
//xlWorkBooks = xlApp.Workbooks;
//xlWorkBook = xlWorkBooks.Add(Properties.Settings.Default.FileToSend);
//xlWorkSheet = xlWorkBook.Sheets[1];
xlApp = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
xlWorkBook = (Excel.Workbook)xlApp.ActiveWorkbook;
xlWorkSheet = (Excel.Worksheet)xlWorkBook.ActiveSheet;
}
catch (Exception ex)
{
// handle error...
}
finally
{
if (xlWorkSheet != null)
Marshal.ReleaseComObject(xlWorkSheet);
if (xlWorkBook != null)
Marshal.ReleaseComObject(xlWorkBook);
if (xlWorkBooks != null)
Marshal.ReleaseComObject(xlWorkBooks);
if (xlApp != null)
Marshal.ReleaseComObject(xlApp);
}
Thanks in advance!
You're probably getting hold of the wrong Excel instance with your call to GetActiveObject. Use the Application reference passed into your COM add-in's OnConnection (or however your ribbon code is bootstrapped).
If you're using the Excel-DNA framework to make your managed Excel add-in, then you get hold of the right Application object with a call to ExcelDnaUtil.Application.
Related
I have to do a program which reads an excel xlsx file and stores the data in to the database. This my actual simple code, I don't even take the values from the excel file, but I'm not able to kill the process. I've googled a lot and I've tried many things, but the excel process stays alive.
public void readFile(path)
{
try
{
Microsoft.Office.Interop.Excel.Application xlApp = null;
Microsoft.Office.Interop.Excel.Workbooks workbooks = null;
Microsoft.Office.Interop.Excel.Workbook xlWorkbook = null;
Microsoft.Office.Interop.Excel.Worksheet xlWorksheet = null;
Microsoft.Office.Interop.Excel.Range xlRange = null;
xlApp = new Microsoft.Office.Interop.Excel.Application();
workbooks = xlApp.Workbooks;
xlWorkbook = workbooks.Open(path);
xlWorksheet = xlWorkbook.Sheets[1];
xlRange = xlWorksheet.UsedRange;
//------Here is where I will read the data
xlWorkbook.Close();
workbooks.Close();
xlApp.Quit();
Marshal.FinalReleaseComObject(xlRange);
Marshal.FinalReleaseComObject(xlWorksheet);
Marshal.FinalReleaseComObject(xlWorkbook);
Marshal.FinalReleaseComObject(workbooks);
Marshal.FinalReleaseComObject(xlApp);
xlRange = null;
xlWorksheet = null;
xlWorkbook = null;
workbooks = null;
xlApp = null;
}
catch (Exception e)
{
}
}
And the process stays alive. I hope you can help me.
I've tried many things... The code below seems to work.
public void readFile(path)
{
try
{
Microsoft.Office.Interop.Excel.Application xlApp = null;
Microsoft.Office.Interop.Excel.Workbooks workbooks = null;
Microsoft.Office.Interop.Excel.Workbook xlWorkbook = null;
Microsoft.Office.Interop.Excel.Sheets xlsheets = null;
Microsoft.Office.Interop.Excel.Worksheet xlWorksheet = null;
Microsoft.Office.Interop.Excel.Range xlRange = null;
xlApp = new Microsoft.Office.Interop.Excel.Application();
workbooks = xlApp.Workbooks;
xlWorkbook = workbooks.Open(path);
xlsheets = xlWorkbook.Sheets;
xlWorksheet = xlsheets[1];
xlRange = xlWorksheet.UsedRange;
//--------------------------------------------------------------------
xlWorkbook.Close();
workbooks.Close();
xlApp.Quit();
Marshal.FinalReleaseComObject(xlRangeColumns);
Marshal.FinalReleaseComObject(xlRangeRows);
Marshal.FinalReleaseComObject(xlRange);
Marshal.FinalReleaseComObject(xlWorksheet);
Marshal.FinalReleaseComObject(xlsheets);
Marshal.FinalReleaseComObject(xlWorkbook);
Marshal.FinalReleaseComObject(workbooks);
Marshal.FinalReleaseComObject(xlApp);
xlRangeColumns = null;
xlRangeRows = null;
xlRange = null;
xlWorksheet = null;
xlsheets = null;
xlWorkbook = null;
workbooks = null;
xlApp = null;
}
catch (Exception e)
{
}
}
There are very little differences. A month ago I would tell you that both codes are the same. Can someone tell me why this code works, while the first code doesn't?
Try putting this at the end of your code and it will kill your excel
foreach (var process in Process.GetProcessesByName("myExcelFilename"))
{
process.Kill();
}
You need either to put the objects into using blocks, or put the closing statements into a finally.
Whenever your application throws an exception, it will leave the interop open. What you should do instead is put your shutdown code in a finally block, which means that code will always be run. Like so:
public void readFile(string path)
{
Microsoft.Office.Interop.Excel.Application xlApp = null;
Microsoft.Office.Interop.Excel.Workbooks workbooks = null;
Microsoft.Office.Interop.Excel.Workbook xlWorkbook = null;
Microsoft.Office.Interop.Excel.Worksheet xlWorksheet = null;
Microsoft.Office.Interop.Excel.Range xlRange = null;
try
{
xlApp = new Microsoft.Office.Interop.Excel.Application();
workbooks = xlApp.Workbooks;
xlWorkbook = workbooks.Open(path);
xlWorksheet = xlWorkbook.Sheets[1];
xlRange = xlWorksheet.UsedRange;
//------Here is where I will read the data
}
catch (Exception e)
{
}
finally
{
xlWorkbook?.Close();
workbooks?.Close();
xlApp?.Quit();
Marshal.FinalReleaseComObject(xlRange);
Marshal.FinalReleaseComObject(xlWorksheet);
Marshal.FinalReleaseComObject(xlWorkbook);
Marshal.FinalReleaseComObject(workbooks);
Marshal.FinalReleaseComObject(xlApp);
xlRange = null;
xlWorksheet = null;
xlWorkbook = null;
workbooks = null;
xlApp = null;
}
}
Another option is not to screw around with interop and use another library, such as EPPlus (available on NuGet), to handle the reading of excel files, which would close when the program closes.
I try to get Excel application in my code with this method:
Excel.Application xlApp = GetApplication();
if (xlApp == null) xlApp = new Excel.Application();
where
private Excel.Application GetApplication()
{
Excel.Application result = null;
try
{
result = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
}
catch (System.Runtime.InteropServices.COMException ex)
{
//Excel is not open
}
return result;
}
but the
System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application")
always throws exception, even when Excel application is open.
Exception: HRESULT: 0x800401E3
StackTrace:
in System.Runtime.InteropServices.Marshal.GetActiveObject(Guid& rclsid, IntPtr reserved, Object& ppunk)
in System.Runtime.InteropServices.Marshal.GetActiveObject(String progID)
in RaceToolTests.UnitTest1.GetApplication() in C:\Users\...
Please try following code:
//import
using Excel = Microsoft.Office.Interop.Excel;
//define
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
private void openXL()
{
string fileName = "PATH\\FILE_NAME.xlsx"; ;
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Open(fileName);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
}
Yes it is possible to not create a new instance of Excel. Use below to get existing instance of Excel app.
var path = #"C:\Temp";
var excelFileName = $#"{path}\Sample.xlsx";
var excelApp = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application") as Excel.Application;
// Make the object visible.
excelApp.Visible = true;
// open workbook
Excel.Workbook xlWorkbook = excelApp.Workbooks.Open(excelFileName);
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();
}
}
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);
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();