6

I have a bit of code that opens an xls workbook;

Excel.Workbooks workBooks;
workBooks = excelApp.Workbooks;
workbook = workBooks.Open(sourceFilePath + sourceFileName + ".xls");

I then get the work sheet;

worksheets = workbook.Worksheets;
worksheet = worksheets.get_Item("Standard");

I then save the file as a csv;

worksheet.SaveAs(sourceFilePath + sourceFileName + ".csv", Excel.XlFileFormat.xlCSVWindows, Type.Missing, Type.Missing, false, false, Excel.XlSaveAsAccessMode.xlNoChange, Type.Missing, Type.Missing, Type.Missing);

Then I try to close the workbook;

Marshal.FinalReleaseComObject(worksheet);
Marshal.FinalReleaseComObject(worksheets);
workbook.Close();
Marshal.FinalReleaseComObject(workbook);

However, every time i get to the line workbook.Close(), the system stops.

If I do not do the SaveAs then the workbook closes just fine.

How do I close a workbook?

edit

Looking at Task Manager shows me that Excel.exe is still running. Closing it will produce an error in my code.

edit 2

I have already seen the referenced SO post and it did not solve the issue.

griegs
  • 22,624
  • 33
  • 128
  • 205
  • Have you tried closing the workbook before releasing the worksheets? Those are referenced by the workbook so maybe they are then missing on close. – Chris Jul 03 '13 at 05:25
  • @Chris, yes and same result – griegs Jul 03 '13 at 05:27
  • possible duplicate of [How to properly clean up Excel interop objects](http://stackoverflow.com/questions/158706/how-to-properly-clean-up-excel-interop-objects) - This is a annoying prolem you should also use [VSTO Contrib](http://jake.ginnivan.net/vsto-com-interop), but even then, sometimes Excel still hangs around and a lot of people seem to resort to killing the process, [which I dont advocate](http://stackoverflow.com/a/13242462/495455) – Jeremy Thompson Jul 03 '13 at 05:29
  • I had already seen that SO post and it did not help. This is not a duplicate – griegs Jul 03 '13 at 05:31

6 Answers6

10

Here is the solution

first: using EXCEL = Microsoft.Office.Interop.Excel;

and then, path is where your excel locates.

        EXCEL.Application excel = new EXCEL.Application();
        try
        {
            EXCEL.Workbook book = excel.Application.Workbooks.Open(path);
            EXCEL.Worksheet sheet = book.Worksheets[1];
            // yout operation

        }
        catch (Exception ex) { MessageBox.Show("readExcel:" + ex.Message); }
        finally
        {
            KillExcel(excel);
            System.Threading.Thread.Sleep(100);
        }



    [DllImport("User32.dll")]
    public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int ProcessId);
    private static void KillExcel(EXCEL.Application theApp)
    {
        int id = 0;
        IntPtr intptr = new IntPtr(theApp.Hwnd);
        System.Diagnostics.Process p = null;
        try
        {
            GetWindowThreadProcessId(intptr, out id);
            p = System.Diagnostics.Process.GetProcessById(id);
            if (p != null)
            {
                p.Kill();
                p.Dispose();
            }
        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show("KillExcel:" + ex.Message);
        }
    }
Hercules
  • 138
  • 1
  • 1
  • 7
6

Why not combine the 2. This will take care of any problems with closing before saving is complete. There is an option in the Close method to save the file.

workbook.Close(true, fileName, Missing.Value);

Also if the file is saving correctly, and your problem is purely because the excel.exe process is still running, it could be because you didn't close and release EVERYTHING needed. I have had this before and developed a more complete close down routine. My code for shutting down an excel file is:

        book.Close(true, fileName, Missing.Value); //close and save individual book
        allBooks.Close(); //close all books
        excel.Quit();
        Marshal.ReleaseComObject(allCells); //any used range objects
        Marshal.ReleaseComObject(sheet);
        Marshal.ReleaseComObject(sheets);
        Marshal.ReleaseComObject(book);
        Marshal.ReleaseComObject(allBooks);
        Marshal.ReleaseComObject(excel);

This works 100% of the time for me.

SeeMoreGain
  • 1,263
  • 16
  • 36
0

Have you considered the fact that the system might still be in the process of saving the file when you attempt to close it? I'm just saying, to be sure add a delay(Thread.Sleep(1000) in C# for example) before the close to see if this is the problem.

Tenescu Andrei
  • 337
  • 1
  • 5
  • 15
  • I've checked the created file and it is complete. There are only 200 lines with 41 columns. I have waited for 10 minutes and nothing changes. – griegs Jul 03 '13 at 05:24
0
    EXCEL.Application excel = new EXCEL.Application();
    try
    {
        EXCEL.Workbook book = excel.Application.Workbooks.Open(path);
        EXCEL.Worksheet sheet = book.Worksheets[1];
        // yout operation

    }
    catch (Exception ex) { MessageBox.Show("readExcel:" + ex.Message); }
    finally
    {
        KillExcel(excel);
        System.Threading.Thread.Sleep(100);
    }


[DllImport("User32.dll")]
public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int ProcessId);
private static void KillExcel(EXCEL.Application theApp)
{
    int id = 0;
    IntPtr intptr = new IntPtr(theApp.Hwnd);
    System.Diagnostics.Process p = null;
    try
    {
        GetWindowThreadProcessId(intptr, out id);
        p = System.Diagnostics.Process.GetProcessById(id);
        if (p != null)
        {
            p.Kill();
            p.Dispose();
        }
    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show("KillExcel:" + ex.Message);
    }
}

Thank you!!!!

fatihyildizhan
  • 8,614
  • 7
  • 64
  • 88
0

This work for me. EXCEL.EXE will be kill after close you program.

Excel.Application objExcel;
Excel._Workbook objBook;
Excel.Workbooks objBooks;
Excel._Worksheet objSheet;
Excel.Sheets objSheets;

objExcel = new Excel.Application();
objBooks = objExcel.Workbooks;
objBook = objExcel.Workbooks.Open(Application.StartupPath+@"/"+"template.xls");
objSheets = objBook.Worksheets;
objSheet = (Excel._Worksheet)objBook.ActiveSheet;

//....you code modify excel book

objBook.Close(true, objBook, Missing.Value);
objExcel.Quit();
Marshal.ReleaseComObject(objSheet);
Marshal.ReleaseComObject(objSheets);
Marshal.ReleaseComObject(objBook);
Marshal.ReleaseComObject(objBooks);
Marshal.ReleaseComObject(objExcel);
VSimanin
  • 5
  • 2
-1

This question keeps popping up see:

How to properly clean up Excel interop objects in C#

You need to call System.Runtime.InteropServices.Marshal.ReleaseComObject() on every excel object you use, even invisible ones, e.g.:

var worksheet = excelApp.Worksheets.Open()

There are two objects here: 1. The obvious 'Worksheet' opened with Open() 2. The "invisible" collection 'Worksheets'.

Both of them need to be released (so you better keep a reference for Worksheets):

var wkCol = excelApp.Worksheets;
var worksheet = wkCol.Open();
Community
  • 1
  • 1
Eli Algranti
  • 8,707
  • 2
  • 42
  • 50
  • This is not true, see https://stackoverflow.com/questions/25134024/clean-up-excel-interop-objects-with-idisposable/25135685#25135685 or https://devblogs.microsoft.com/visualstudio/marshal-releasecomobject-considered-dangerous/ – Pyritie Jun 28 '23 at 13:28
  • @Pyritie this was absolutely true in 2013, when this question was answered. I'm glad this is no longer the case. – Eli Algranti Jun 29 '23 at 06:09
  • Out of curiosity, what could've changed between then and now? – Pyritie Jul 11 '23 at 11:22
  • @Pyritie I can only guess but if you look at the most upvoted answer in https://stackoverflow.com/questions/158706/how-do-i-properly-clean-up-excel-interop-objects (which I link in my answer) you can see calling the GC can release these hidden objects. It could be the .Net GC/COM-Interop has been improved to identify and release these unused COM references. – Eli Algranti Jul 15 '23 at 13:14