Excel interop from ASP.NET - Process can't be killed

L

Lars-Erik Aabech

Hi!

This issue have been discussed a lot, but I haven't found a solution that
applies to ASP.NET. I have a library which does some operations on Excel
documents, and it will be used in an ASP.NET application. If I use the
library in a Forms application, the Excel process is removed when the
cleanup operations are done, but with ASP.NET all possible ways to clean up
fails.

The following code has been tried:

Application app = new ApplicationClass();
Workbook wb = null;

// some code... no sheet reference done, only doing wb.load, x =
wb.Worksheets.Count, wb.close

// release workbook
ReleaseComObject(wb);
wb = null;

app.Quit();
ReleaseComObject(app);
app = null;

When the method is called from a windows app, Excel is now gone, but when
called from ASP.NET the Excel process remains.

So we gathered that the process had to be killed manually. Off to the Win32
api to find some functions. Et voila, we find GetWindowThreadProcessId. But
what do you know? When the method is called from a windows app, the process
ID is filled and we can kill the process, but when called from ASP.NET, the
process ID is 0, the thread ID is 0, and Excel is still lingering about..

I for one am ready to be committed to the local asylum...

Any help greatly appreciated......

Lars-Erik
 
J

Joyjit Mukherjee

Hi,

try System.GC.Collect to cleanup all COM objects forcefully after you
finished off using them.

HTH
Regards
Joyjit
 
L

Lars-Erik Aabech

I did. Forgot to include it in the sample code.
Also tried GC.WaitForPendingFinalizers().

Still no cigar...

L-E
 
L

Lars-Erik Aabech

I've tried all the workarounds. As you can see from my previous posts, the
..Net client releases excel when ran as a windows application or service.
Only when ran as ASP.NET Excel will stay around. Might be that I have to
create and release a reference to Worksheets too though, but I've allready
rewritten the code to use ADO for this problem. Anyway, thanks for the help
ppl - hope this issue will be resolved for office 2005 ;)

Lars-Erik
 
A

abillmeier

Ever get this to work?
Having the exact same issue.
Excel continues to run, even after releasing the coms, and when I try
and get the process ID I am rewarded with a 0.
 
J

Johnny Fugazzi

Here is a code snippit of what I am trying to do. In general I am doing
the following.

1. creating an excel object
2. loading an xls file into the object
3. reading a value from the file and then updating a value in the file.
4. saving and closing the file.
5. quiting the excel object.
6. attempting to determine the Process ID of the hanging Excel object and
then terminate it. So far I only get a ProcessID of Zero, however.

***********************
Dim xExcel As New Excel.Application

Dim xBook As Object

Dim xBooks As Object

Dim xSheets As Object

Dim xSheet As Object

Dim xRange As Object



xBooks = xExcel.Workbooks

xBook = xBooks.Open(Filename:=strExcelFile, UpdateLinks:=False,
ReadOnly:=False)

Dim objPtr As New IntPtr

Dim intID As Integer = 0

Dim i As Integer = 0

objPtr = New System.IntPtr(xExcel.Hwnd)

i = GetWindowThreadProcessId(objPtr, intID)



If intID > 0 Then

Dim pExcel As New System.Diagnostics.Process

pExcel = System.Diagnostics.Process.GetProcessById(intID)

pExcel.Kill()

End If
 
D

David Jessee

Run....Run fast!

If you look at Microsoft's web site, they strongly discourage anyone from
using office applications from inside of asp.net. If there is any way
around it, then do it. One option would be to use Sql Reporting Services to
create a report and then export that report to an Excel file (file stream
you send back to the client).
 
J

Johnny Fugazzi

Yeah. I know it is STRONGLY discouraged, but it is a request from above and
I need to find out if/how to do it regardless of the warnings.

In theory the code should work. I know it's not elegant.

The Excel part works great, except for leaving a hanging process. After
trying all of the MS reccomendations, I figured it might be best to just
identify the process ID of the hanger and then outright kill it. It is the
identification of the process ID that I am having a problem with at the
moment as it always comes back 0.

Any idea what is wrong?

Are there permissions retrictions that would stop the page from lookingup a
process id. Are there permission restrictions that will also stop me from
killing a process that was started by the page?
 
M

Martin Dechev

objPtr = New System.IntPtr(xExcel.Hwnd)

The excel application is run from a non-interactive user acount in this
case, so it doesn't interact with the desktop and doesn't have a window.

Your best shot would be to use platform invoke to find and exit the
process - EnumProcesses (psapi.dll), OpenProcess (kernel32.dll),
GetModuleBaseName (psapi.dll), ExitProcess (kernel32.dll) and CloseHandle
(kernel32.dll).

Hope this helps
Martin Dechev
ASP.NET MVP
 
D

David Jessee

Then do 2 things.

First, research finding processes and how to kill them (you'll be looking
for Excel.exe...its case sensitive)

Secondly, tell the client that the solution will be unstable, as per
Microsoft's warnings unless they choose to invest in a 3rd party product
that can perform this functionality. You need to keep your posterior
covered because when the server locks up, they need to know that it was
their decision that made it happen.
 
Joined
Jul 11, 2006
Messages
3
Reaction score
0
How to Kill Excel

Excel is a windows app and hence it has windows, even in a non-interactive profile (hence the name of the OS). It is possible to identify the "main window" belonging to an Excel process you control, and thereby find and kill the process. The .NET Fx is not very helpful in finding processes since it relies on performance counters (which noone would have set up for an app that is running in a non-interactive profile). Still, there is a straightforward method using windows API ... please see the article "50 Ways to Kill Excel". http://www.devcity.net/Articles/239/1/article.aspx

--scott
 
Joined
Nov 1, 2006
Messages
1
Reaction score
0
Hi, I've just struggled all morning trying to resolve this and have found a simple solution to this problem. The solution requires one declaration:

Declare Function EndTask Lib "user32.dll" (ByVal hWnd As IntPtr) As Integer

And the following code:

Dim iHandle As IntPtr = New IntPtr(CType(o_Excel.Hwnd, Integer))
EndTask(iHandle)

I hope someone finds this usefull.
 
Joined
Apr 22, 2009
Messages
1
Reaction score
0
SHewison said:
Hi, I've just struggled all morning trying to resolve this and have found a simple solution to this problem. The solution requires one declaration:

Declare Function EndTask Lib "user32.dll" (ByVal hWnd As IntPtr) As Integer

And the following code:

Dim iHandle As IntPtr = New IntPtr(CType(o_Excel.Hwnd, Integer))
EndTask(iHandle)

I hope someone finds this usefull.


(Two years and a new version of Visual Studio, Office and .Net later, and this thread is still being used !)

After hunting high, low, and trying every possible suggestion that Microsoft could come up with, I was still in the situation where the "Excel.exe" process would be left running after use... until I tried this suggestion.

Many thanks - the "EndTask" function worked a treat.

Here's the ASP.Net C# version of the code, for anyone who's interested:

[DllImport("user32")]
private static extern int EndTask(IntPtr hWnd, bool fShutDown, bool fForce);

Excel.Application xlApp = new Excel.ApplicationClass();
int excelHWND = xlApp.Hwnd;

// Do the Excel stuff here !!

// Then try to close the Excel process in the usual manner

int ret = EndTask((IntPtr)excelHWND, false, true);

 
Joined
Jul 10, 2009
Messages
1
Reaction score
0
I used MS Article KB317109, but it did not work alone. I had to also set the Excel.Application object to Nothing. Here is final code:

Dim xlApp As New Excel.Application()
Dim xlWorkbooks As Excel.Workbooks = xlApp.Workbooks
Dim xlWorkbook As Excel.Workbook = xlWorkbooks.Add
Dim xlWorksheet As Excel.Worksheet = xlApp.ActiveSheet

NAR(xlWorksheet)
xlWorkbook.Close(False)
NAR(xlWorkbook)
NAR(xlWorkbooks)
xlApp.Quit()
NAR(xlApp)

xlApp = Nothing

GC.Collect()
GC.WaitForPendingFinalizers()

Private Sub NAR(ByVal o As Object)
System.Runtime.InteropServices.Marshal.ReleaseComObject(o)
o = Nothing
End Sub

Hope this helps someone
 

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

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top