Hung Excel Process in C# - c#

I have a C# program that opens an Excel file, reads a cell, closes the file, and exits Excel. Unfortunately, the Windows Task Manager still shows an Excel.exe process running. I've read just about every article concerning this issue and tried almost all of the solutions . . . and still have the same problem. I believe one of COM objects is not being released and thus hanging the process. However, I also believe that I've been very careful about instantiating the Excel objects (no double ".") and releasing them.
If I remove the "a = xlCells[1,1].Value" line, every thing releases and Excel dies cleanly after the FinalReleaseComObject of the Application instance. Why would this assignment create COM objects or interfere with them?
Excel.Application xlApp = null;
Excel.Workbooks xlWorkbooks = null;
Excel.Workbook xlWorkbook = null;
Excel.Sheets xlSheets = null;
Excel.Worksheet xlWorksheet = null;
Excel.Range xlCells = null;
string inputFile = #"C:\Temp\test.xlsx";
string a;
xlApp = new Excel.Application();
xlApp.Visible = false;
xlApp.DisplayAlerts = false;
xlWorkbooks = xlApp.Workbooks;
xlWorkbook = xlWorkbooks.Open(inputFile);
xlSheets = xlWorkbook.Sheets;
xlWorksheet = xlSheets[1];
xlCells = xlWorksheet.Cells;
a = xlCells[1,1].Value;
Marshal.FinalReleaseComObject(xlCells);
xlCells = null;
Marshal.FinalReleaseComObject(xlWorksheet);
xlWorksheet = null;
Marshal.FinalReleaseComObject(xlSheets);
xlSheets = null;
xlWorkbook.Close(false, Type.Missing, Type.Missing);
Marshal.FinalReleaseComObject(xlWorkbook);
xlWorkbook = null;
xlWorkbooks.Close();
Marshal.FinalReleaseComObject(xlWorkbooks);
xlWorkbooks = null;
xlApp.Quit();
Marshal.FinalReleaseComObject(xlApp);
xlApp = null;

I would make two changes. First, since a Sheets item can be either a worksheet or a graph sheet, it's best to cast with As and check for null. Second, if you just want to get a range with an alphanumeric address, the get_Range() method works well. Otherwise, if you want to go by row and column indexes, then follow #Daneau's comment.
xlWorksheet = xlSheets[1] as Excel.Worksheet;
if(xlWorksheet != null)
{
xlCells = xlWorksheet.get_Range("A1");
a = xlCells[1,1].Value;
Marshal.FinalReleaseComObject(xlCells);
xlCells = null;
Marshal.FinalReleaseComObject(xlWorksheet);
xlWorksheet = null;
}

I changed up the code and added the dummy Range object.
Range tmpCell = xlCell[1,1];
a = tmpCell.Value;
Marshal.ReleaseComObject(tmpCell);
My problems went away. Much thanks, Daneau!
The real routine has several loops with the cell being evaluated. I thought it would work fine using the tmpCell for each new cell assignment, then release tmpCell at the end. That failed. Prior to each new tmpCell assignment to a xlCell[x,y], I had to release tmpCell. This worked, but is certainly cumbersome. It's difficult to believe that there's not a better way to manage this or keep track of the various COM objects.

Related

C# set opened workbook

I started creating an Excel-Add-IN with C#.
what I need to do is simple, I need to set a workbook to a variable, the workbook is already running, I tried this but did not work
Excel.Application excel = new Excel.Application();
Excel.Workbook wb = excel.ActiveWorkbook as Excel.Workbook;
wb.SaveAs("C:\\Users\\ro_sg\\Desktop\\Pasta1.xlsx");
Excel.Worksheet ws = wb.Worksheets["Plan1"];
Excel.Range range = ws.Range["A1"];
range.Value = "Success";
wb.Save();
The wb variable cannot find the workbook (gets null), and I can't see why.
Please, if any of you spot the mistake let me know.
Thanks!
I believe your issue is it may not be finding the active Excel application upstream from when you set your workbook variable. It appears that your code is trying to create a new excel application (without a workbook) rather than get the existing one that is open.
Give this a try:
Excel.Application excel = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
Excel.Workbook wb = (Excel.Workbook)excel.ActiveWorkbook;
wb.SaveAs("D:\\WeeeDueceDuece.xlsx");
I don't know if you need to get a specific Sheet but if you try this: Excel.Worksheet ws = wb.Worksheets[1]; It will get the first Sheet of your Workbook
If your actual code doesn't have more in-between steps, it will always fail. I'm surprised this line didn't error:
Excel.Workbook wb = excel.ActiveWorkbook as Excel.Workbook;
It's because a new instance of Excel does not necessarily create a new workbook. You can check this with the following lines:
Excel.Application application = new Excel.Application();
Excel.Workbooks workbooks = application.Workbooks;
Console.WriteLine(workbooks.Count); // "0"
The new workbook, however, should create the default number of worksheets (usually 3, but editable).

C# Excel Interop Error: The file is being used by another process

In my project, mt aim is to edit and move a file. I have removed all the editing sections for simplicity, as they do not seem to be causing the error. I have tested the error with just this code and it still occurs.
This is my code:
Application xlApp = new Application();
Workbooks xlWorkbooks = xlApp.Workbooks;
Workbook xlWorkbook = xlWorkbooks.Open(Path.GetFullPath(fileNameWithPath));
Sheets xlWorksheets = xlWorkbook.Sheets;
Worksheet xlWorksheet = xlWorksheets.get_Item(1);
Range xlRange = xlWorksheet.UsedRange;
string fileNameWithExtension = GetFileNameWithExtension(fileNameWithPath);
xlWorkbook.Close(false);
xlApp.Quit();
Marshal.FinalReleaseComObject(xlRange);
Marshal.ReleaseComObject(xlWorksheet);
Marshal.ReleaseComObject(xlWorksheets);
Marshal.ReleaseComObject(xlWorkbook);
Marshal.ReleaseComObject(xlWorkbooks);
Marshal.FinalReleaseComObject(xlApp);
xlRange = null;
xlWorksheet = null;
xlWorksheets = null;
xlWorkbook = null;
xlWorkbooks = null;
xlApp = null;
GC.GetTotalMemory(false);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.GetTotalMemory(true);
File.Move(fileNameWithPath, myNewPath);
When running this I am getting an error message when the application tries to move the file: The process cannot access the file because it is being used by another process.
I am pretty sure I have closed off all of the COM objects and have done all the recommendations I could find online to get this to work. Any ideas as to what I have missed?
Use sysinterals to check, which process cause this issue. In general i would proof before doing those things, if you have write access for the file.
Method for proofing write access:
public static bool FileHasWriteAccess(string Path)
{
try
{
System.IO.File.Open(Path, System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite).Dispose();
return true;
}
catch (System.IO.IOException)
{
return false;
}
}
Take a look at: Find out which process is locking a file or folder in Windows.

Insert HTML into Excel cell

I have an auditing system built in ASP.NET and C#, where users can insert comments, and those comments can be HTML formatted with tables (<table>), "enters" (<br>), lists (<ul><li>), underlined text (<u>), latin-accented leters (í, ó, á, é, ú), among others.
I need to export those comments into Excel cells, and that its HTML elements to render correctly, only in ONE cell.
It should look like this:
I tried with interop, but I just see it as plain text
worksheet.Cells[1, 1] = htmlText;
Like this:
I also tried copying it to the clipboard, but I get a mess:
Clipboard.SetText(htmlTable);
Microsoft.Office.Interop.Excel.Application xlexcel;
Microsoft.Office.Interop.Excel.Workbook xlWorkBook;
Microsoft.Office.Interop.Excel.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
xlexcel = new Microsoft.Office.Interop.Excel.Application();
xlexcel.Visible = true;
xlWorkBook = xlexcel.Workbooks.Add(misValue);
xlWorkSheet = (Worksheet)xlWorkBook.Worksheets.get_Item(1);
Microsoft.Office.Interop.Excel.Range CR = (Range)xlWorkSheet.Cells[1, 1];
CR.Select();
xlWorkSheet.Paste(CR, false);
And I see it like this
I also tried with iceblue but it only supports "span" elements and paragraphs, not complex elements as tables, lists, etc.
Any ideas?
Ok, I found something similar here html-text-with-tags-to-formatted-text-in-an-excel-cell
The difference is they are working in Excel and you've got an ASP.NET site; so we're going to have to get a bit creative.
Step 1: Reference the following COM object "Microsoft Internet Controls" (SHDocView)
Step 2: Add the following using statement to your code
using SHDocVw;
Step 3: Try the following code:
var ie = new InternetExplorer();
ie.Visible = false;
ie.Navigate("about:blank");
ie.Document.body.innerHTML = htmlTable; //Yes, this is the correct casing
ie.Document.body.createtextrange.execCommand("Copy");
var xlExcel = new Application();
xlExcel.Visible = true;
var misValue = System.Reflection.Missing.Value;
var xlWorkBook = xlExcel.WorkBooks.Add(misValue);
var xlWorkSheet = (WorkSheet)xlWorkBook.Worksheets.get_Item(1);
var range = (Range)xlWorkSheet.Cells[1, 1];
range.Select();
xlWorkSheet.Paste();

delete excel worksheets programmatically

I have an excel workbook with many, many sheets. I want to delete all the sheets except for three of them.
Specifically, i would like to know if there is a way to remove the sheets using sheet name instead of ordinals (sheet number).
I am using excel interop and C# to work with Excel.
Microsoft.Office.Interop.Excel.Application xlApp = null;
Excel.Workbook xlWorkbook = null;
Excel.Sheets xlSheets = null;
Excel.Worksheet xlNewSheet = null;
xlApp.DisplayAlerts = false;
for (int i = xlApp.ActiveWorkbook.Worksheets.Count; i > 0 ; i--)
{
Worksheet wkSheet = (Worksheet)xlApp.ActiveWorkbook.Worksheets[i];
if (wkSheet.Name == "NameOfSheetToDelete")
{
wkSheet.Delete();
}
}
xlApp.DisplayAlerts = true;
I know this is old but I just use the fallowing
workBook.Sheets["Sheet1"].Delete();
I know this thread is really old but for future visitors, if you know the names of the sheets you want to delete, a better way is to loop over the names of the sheets like this:
Workbook book = excelApp.Workbooks.Open("filePathHere");
string[] sheetsToDelete = {"s1", "s2"};
excelApp.DisplayAlerts = false;
foreach(string sheetToDelete in sheetsToDelete )
{
book.Worksheets[sheetToDelete].Delete();
}
excelApp.DisplayAlerts = true;
It's always good practice to avoid deleting items in a collection while iterating through it.

C# - How to add an Excel Worksheet programmatically - Office XP / 2003

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);

Categories

Resources