Excel application.quit leaves instance of Excel running

  • Thread starter Thread starter ChrisBowringGG
  • Start date Start date
C

ChrisBowringGG

When you use Application.Quit() on an Excel application,
there can still be an instance of Excel running,
as seen in Task Manager.

You can try following the advice on MSDN:

http://support.microsoft.com/kb/Q317109

but this didn't solve the problem for me.

Instead, I used a crow-bar and did the following:

foreach (Process process in Process.GetProcessesByName("Excel")) {
process.Kill();
}

Process belongs to System.Diagnostics.
 
See Inline
When you use Application.Quit() on an Excel application,
there can still be an instance of Excel running,
as seen in Task Manager.

You can try following the advice on MSDN:

http://support.microsoft.com/kb/Q317109

but this didn't solve the problem for me.

It works, but you have to call ReleaseComObject on every!!! excel object
your referencing.
Even on collection.
So instead of
Excel.Workbook workbook = oApp.Workbooks[0]:

you've got to use
Excel.Workbooks workbooks = oApp.Workbooks;
Excel Workbook workbook = workbooks[0];

And then call ReleaseCommObject on workbooks as well.
Instead, I used a crow-bar and did the following:

foreach (Process process in Process.GetProcessesByName("Excel")) {
process.Kill();
}
That's Dangerous.
You can't be sure the user is not running another Excel-session.

Christof
 
Christof,

could you explain why the following code doesn't kill the Excel
process:

Application application = new ApplicationClass();

try {
Workbooks books = application.Workbooks;
Workbook book = books.Open(BookPath, false, true,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing);

application.DisplayAlerts = false;

XmlMaps maps = book.XmlMaps;
XmlMap dataMap = maps["Data_Map"];
dataMap.ImportXml(document.OuterXml, (object)true);
application.Calculate();
XmlMap outputMap = maps["Output_Map"];
outputMap.Export(outputPath, true);

Marshal.ReleaseComObject(outputMap);
outputMap = null;

Marshal.ReleaseComObject(dataMap);
dataMap = null;

Marshal.ReleaseComObject(maps);
maps = null;

Marshal.ReleaseComObject(book);
book = null;

Marshal.ReleaseComObject(books);
books = null;
}
finally {
application.Quit();
Marshal.ReleaseComObject(application);
application = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}

I can't see any objects I've referenced that I haven't released.

Thanks,

Chris.

Christof said:
See Inline
When you use Application.Quit() on an Excel application,
there can still be an instance of Excel running,
as seen in Task Manager.

You can try following the advice on MSDN:

http://support.microsoft.com/kb/Q317109

but this didn't solve the problem for me.

It works, but you have to call ReleaseComObject on every!!! excel object
your referencing.
Even on collection.
So instead of
Excel.Workbook workbook = oApp.Workbooks[0]:

you've got to use
Excel.Workbooks workbooks = oApp.Workbooks;
Excel Workbook workbook = workbooks[0];

And then call ReleaseCommObject on workbooks as well.
Instead, I used a crow-bar and did the following:

foreach (Process process in Process.GetProcessesByName("Excel")) {
process.Kill();
}
That's Dangerous.
You can't be sure the user is not running another Excel-session.

Christof
 
By the way, there are no exceptions caught, so all the code in the try
clause runs.

Chris.
 
Christof,

could you explain why the following code doesn't kill the Excel
process:

Application application = new ApplicationClass();

try {
Workbooks books = application.Workbooks;
Workbook book = books.Open(BookPath, false, true,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing);

application.DisplayAlerts = false;

XmlMaps maps = book.XmlMaps;
XmlMap dataMap = maps["Data_Map"];
dataMap.ImportXml(document.OuterXml, (object)true);
application.Calculate();
XmlMap outputMap = maps["Output_Map"];
outputMap.Export(outputPath, true);

Marshal.ReleaseComObject(outputMap);
outputMap = null;

Marshal.ReleaseComObject(dataMap);
dataMap = null;

Marshal.ReleaseComObject(maps);
maps = null;

Marshal.ReleaseComObject(book);
book = null;

Marshal.ReleaseComObject(books);
books = null;
}
finally {
application.Quit();
Marshal.ReleaseComObject(application);
application = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}

I can't see any objects I've referenced that I haven't released.

I can't see neither.
Maybe there is something strange about the XmlMap or XmlMaps wich I don't
know.
If your sure all ReleaseComObject were called i see know cause why Excel
isn't killed.
 
It is possible to use the Process.Kill method safely if you find all
the Excel processes
just before you create a new one, then find all the processes just
after you create the new one,
and compare them to find the one you've just created.

You could safely kill this one and leave the others unharmed, as long
as a new process isn't started
by the user at the same time as the code, e.g.:

Process[] originalProcesses = Process.GetProcessesByName("Excel");

Application application = new ApplicationClass();

Process[] newProcesses = Process.GetProcessesByName("Excel");

ArrayList list = new ArrayList();
foreach (Process newProcess in newProcesses) {
bool isNew = true;
foreach (Process originalProcess in originalProcesses) {
if (originalProcess.Id == newProcess.Id) {
isNew = false;
break;
}
}
if (isNew) list.Add(newProcess);
}

// Do your stuff

foreach (Process process in list) {
process.Kill();
}

This seems to work.
 
I went through this once. Try closing the workbook first:
book.Close(). In my experience, there is no need to call ReleaseComObject on
every Excel object, but you can play with that and see what works for you.

Christof,

could you explain why the following code doesn't kill the Excel
process:

Application application = new ApplicationClass();

try {
Workbooks books = application.Workbooks;
Workbook book = books.Open(BookPath, false, true,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing);

application.DisplayAlerts = false;

XmlMaps maps = book.XmlMaps;
XmlMap dataMap = maps["Data_Map"];
dataMap.ImportXml(document.OuterXml, (object)true);
application.Calculate();
XmlMap outputMap = maps["Output_Map"];
outputMap.Export(outputPath, true);

Marshal.ReleaseComObject(outputMap);
outputMap = null;

Marshal.ReleaseComObject(dataMap);
dataMap = null;

Marshal.ReleaseComObject(maps);
maps = null;

Marshal.ReleaseComObject(book);
book = null;

Marshal.ReleaseComObject(books);
books = null;
}
finally {
application.Quit();
Marshal.ReleaseComObject(application);
application = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}

I can't see any objects I've referenced that I haven't released.

Thanks,

Chris.

Christof said:
See Inline
When you use Application.Quit() on an Excel application,
there can still be an instance of Excel running,
as seen in Task Manager.

You can try following the advice on MSDN:

http://support.microsoft.com/kb/Q317109

but this didn't solve the problem for me.

It works, but you have to call ReleaseComObject on every!!! excel object
your referencing.
Even on collection.
So instead of
Excel.Workbook workbook = oApp.Workbooks[0]:

you've got to use
Excel.Workbooks workbooks = oApp.Workbooks;
Excel Workbook workbook = workbooks[0];

And then call ReleaseCommObject on workbooks as well.
Instead, I used a crow-bar and did the following:

foreach (Process process in Process.GetProcessesByName("Excel")) {
process.Kill();
}
That's Dangerous.
You can't be sure the user is not running another Excel-session.

Christof
 
It is possible to use the Process.Kill method safely if you find all
the Excel processes
just before you create a new one, then find all the processes just
after you create the new one,
and compare them to find the one you've just created.

You could safely kill this one and leave the others unharmed, as long
as a new process isn't started
by the user at the same time as the code, e.g.:

Process[] originalProcesses = Process.GetProcessesByName("Excel");

Application application = new ApplicationClass();

Process[] newProcesses = Process.GetProcessesByName("Excel");

ArrayList list = new ArrayList();
foreach (Process newProcess in newProcesses) {
bool isNew = true;
foreach (Process originalProcess in originalProcesses) {
if (originalProcess.Id == newProcess.Id) {
isNew = false;
break;
}
}
if (isNew) list.Add(newProcess);
}

// Do your stuff

foreach (Process process in list) {
process.Kill();
}

This seems to work.
Looks to be rather safe.
Whit a very unlikly chance, that there could be started another instance of
Excel
just between the two GetProcessesByName calls. Very very unlikly and easy to
detect. The list will contain more than one process.
Not even sure if it was worth to mention that.
 
Does the code in the finalize function finish???
If you call the GC.WaitForPendingFinalizers(); it waits syncronously
for the finalization queue to empty...... (all the objects which have
finalization methods)

If the code in the finalization section does not finish the process
will not terminate and just hang.
Has finalization on all you're objects completed? Check that you're
function terminates.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top