2

I am currently trying to email the graph/chart from a .xls as an image. I can get the graph/chart send the email fine. My issue is when i look in the task manager there is a "EXCEL.EXE" still running after i have called xlApp.quit()

Any help would be appreciated.

Here is the code i am currently using.

Excel.Application xlApp;
Excel.Workbooks xlBooks;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
Excel.ChartObject xlChartObject;
Excel.Chart xlChart;

object misValue = System.Reflection.Missing.Value;

xlApp = new Excel.Application();
xlBooks = xlApp.Workbooks;
xlWorkBook = xlBooks.Add(Properties.Settings.Default.FileToSend);
xlWorkSheet = xlWorkBook.Sheets[1];

xlWorkSheet.EnablePivotTable = true; 
string filename = System.IO.Path.GetTempFileName();

xlChartObject = xlWorkSheet.ChartObjects(1);
xlChart = xlChartObject.Chart;
xlChart.Export(filename + ".gif");

xlWorkBook.Close(false, misValue, misValue);
xlBooks.Close();
xlApp.Application.Quit();

if (xlChart != null)
    Marshal.ReleaseComObject(xlChart); xlChart = null;

if (xlChartObject != null)
    Marshal.ReleaseComObject(xlChartObject); xlChartObject = null;

if (xlWorkSheet != null)
    Marshal.ReleaseComObject(xlWorkSheet); xlWorkSheet = null;

if (xlWorkBook != null)
    Marshal.ReleaseComObject(xlWorkBook); xlWorkBook = null;

if (xlBooks != null)
    Marshal.ReleaseComObject(xlBooks); xlBooks = null;

if (xlApp != null)
    Marshal.ReleaseComObject(xlApp); xlApp = null;

GC.Collect();
GC.WaitForPendingFinalizers();

Ok have edited my code and still not closing excel. It does however die when i exit the program.

Thanks

Xaruth
  • 4,034
  • 3
  • 19
  • 26
Ja77aman
  • 153
  • 2
  • 11
  • 1
    `xlApp.Workbooks.Add` - as follow up from [this answer](http://stackoverflow.com/questions/158706/how-to-properly-clean-up-excel-interop-objects/158752#158752) - `Never use 2 dots with com objects.` – Dmitry Pavliv Mar 11 '14 at 08:45
  • Ok i removed all 2 dots – Ja77aman Mar 11 '14 at 09:17
  • I always implement IDisposable and make a call to GC.COllect in my Dispose method if something is still hanging. Excel can be a pain sometimes –  Mar 11 '14 at 13:53
  • @mehow Can you give me an example? Does not IDisposable just wrap it with a try/catch? – Ja77aman Mar 12 '14 at 05:11
  • I can't find my SO answer but [here's pretty much a copy](http://vba4all.wordpress.com/category/c-and-vba/using-net-connection-string-attributes-in-vba-via-com-library/). I have had a problem with the adodb.connection hanging because Excels garbage collector didn't clear the com resources right away therefore I implemented IDisposable interface and just cleared resources in there, it turned out to be as simple as `cn = null` other stuff was taken care off already. I realize it's a bit different example here but instead of all those if statements that's how I'd go about it –  Mar 12 '14 at 08:11
  • Hi, thanks for that. I have answered my own question, just cant accept it till tomorrow :P – Ja77aman Mar 12 '14 at 08:19

4 Answers4

0

You need to free every object that you use.

It seems that xlApp.Workbooks is used by is not freed.

As a side note, it could also be that there was an exception and thus your cleanup code was missed.

Try something using a try/catch/finally like the following:

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

    xlWorkSheet.EnablePivotTable = true; 
    string filename = System.IO.Path.GetTempFileName();
    xlWorkSheet.ChartObjects("Chart 1").Chart.Export(filename + ".gif");

    xlWorkBook.Close(false, misValue, misValue);
    xlApp.Quit();
}
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);
}
Xaruth
  • 4,034
  • 3
  • 19
  • 26
rhughes
  • 9,257
  • 11
  • 59
  • 87
0

Try adding a second gc.collect after.

                GC.Collect();
                GC.WaitForPendingFinalizers();   //gc calls finalize on objects
                GC.Collect();                    //collect objects just finalized

mehow mentioned implementing IDisposable. I would recommend this as well.

DeveloperGuo
  • 636
  • 5
  • 15
0

Yay finally!

Got it working.

I added

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

out of the function that i was using EXCEL.

private void runExcelWork()
{
   //xlApp, xlBooks, xlWorksheet etc.. Is defined in this function
   //Do your work with Excel here.
   //Clean all excel objects here.
}

public void runExcel()
{
   runExcelWork();
   //call GC
   GC.Collect();
   GC.WaitForPendingFinalizers();
   GC.Collect();
   //at this point EXCEL.EXE closes
}

Thank you to all who helped me with this issue!

I hope someone else finds this useful.

Ja77aman
  • 153
  • 2
  • 11
-1

Have you tried something along the lines of:

 xlWorkBook.Close();
 xlApp.Application.Quit(false);
 xlApp = null;

This should clean up any remaining excel.exe processes

You could try to kill the process directly. (Processname could be in capital letters)

try
{
    foreach (var process in Process.GetProcessesByName("excel"))
    {
     process.Kill();
    }
}
User999999
  • 2,500
  • 7
  • 37
  • 63
  • I have tried that, have a look at what i am using now – Ja77aman Mar 11 '14 at 09:15
  • You kill the process directly (i've adjusted my code) – User999999 Mar 11 '14 at 09:25
  • 1
    Downvoted because this is not the best way to stop Excel when using COM. The reason is because there are still COM objects in memory. What if the user is using Excel for another purpose? – rhughes Mar 11 '14 at 13:40
  • Is my personal opinion aswell. But if nothing else works that (the first bit of code `always` works with me), its sometimes necessary to use crude methods. – User999999 Mar 11 '14 at 17:52