Can't kill Excel.Exe after using Excel component in vb.net
-
12. prosince 2006 12:42
Hi ,
I'm using Excel.Application generating excel report via vb.net 2003 , the problem is excel.exe process reminds even after generated excel report closed . I have been using the followed code to close or dispose the process , but it does'nt work either.
thenks
Dim
procList() As Process = Process.GetProcesses() Dim k As Integer For k = 0 To procList.GetUpperBound(0) Step k + 1 If procList(k).ProcessName = "EXCEL" ThenprocList(k).Close()
procList(k).Dispose()
End If Next
Všechny reakce
-
12. prosince 2006 12:53
Hi,
that is really not the supposed way of releasing a COM server ;)
Call System.Runtime.InteropServices.Marshal.ReleaseComObject on every COM variable when you do not need that COM variable any more. Unfortunately COM wrappers do not follow the IDisposable pattern so you cannot use the using statement but have to remember to put that call in your code at the appropriate places.
After the last COM reference is released excel.exe should go away if it was not started interactively before.
--
SvenC -
14. prosince 2006 18:51
Sadly that (the Interop Marshal release) doesn't always work because Excel XP and lower suck at releasing. I had to use your loop, but replace the Process.Close() and Process.Quit() with Process.Kill(). Works like a charm. Just be careful that you want ALL versions of excel.exe to be killed, because they will.
I use this:
Workbook.Save()
Workbook.Close()
Application.Quit()System.Runtime.InteropServices.Marshal.ReleaseComObject(Application)
Worksheet =
Nothing
Workbook = Nothing
Application = Nothing Dim proc As System.Diagnostics.Process For Each proc In System.Diagnostics.Process.GetProcessesByName("EXCEL")
proc.Kill()
Next- Navržen jako odpověď Airton_Lima 18. února 2010 1:19
-
14. prosince 2006 21:24
Hi Swade,
you might be right about Excel but I am not convinced by your code. Every COM wrapper variable has to be passed to ReleaseComObject. In your case you do not call ReleaseComObject on Workbook and Worksheet. Setting them to Nothing has no immediate effect as those objects are just collectable if not referenced any more, but the collection and with that the Release call on the internal COM interface pointer is only down upon garbage collection.
Good candidates for holding references one might forget are event handlers. I don't know how the WithEvents semantics are when it comes to remove the event connections. Being explicit with AddHandler and RemoveHandler might help.
If Excel is still not exiting you might try calling GC.Collect(). Yes, I know, this is bad practice in general, but if you really used all possible ways to release your COM "connections" to Excel and there still seems to be some object holding onto Excel which is maybe unreachable and so collectable, that might be less "rude" than killing excel.exe.
If that all doesn't work, well, go for killing excel...
--
SvenC -
18. prosince 2006 16:18I agree with you 100%. I hadn't thought of releasing the other COM objects. I was merely using the MSDN reference. I had been adding the other stuff to get it to work (killing the process) and found that it works that way. I'll try yours.
-
18. prosince 2006 16:42
Still didn't work. It may be easier using Office 2003, but Office XP just will not release without killing the proc. Even if I do it in debug and then shut down the program (where it should drop the connection to the COM object), it still stays connected.
Workbook.Save()
Workbook.Close()
Application.Quit()
System.Runtime.InteropServices.Marshal.ReleaseComObject(Worksheet)
System.Runtime.InteropServices.Marshal.ReleaseComObject(Workbook)
System.Runtime.InteropServices.Marshal.ReleaseComObject(Application)
Worksheet = Nothing
Workbook =
NothingApplication =
NothingGC.Collect()
Dim proc As System.Diagnostics.Process For Each proc In System.Diagnostics.Process.GetProcessesByName("EXCEL")proc.Kill()
Next -
19. prosince 2006 18:02If you have a few references to each object, then you need to call ReleaseComObject once for each reference. ReleaseComObject returns a count of the number of references remaining, so you can use a loop and keep calling it until the count <1.
In v2.0 of the framework you get FinalReleaseComObject that does the loop for you. -
19. prosince 2006 20:30
Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Int32 Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Int32, ByVal wMsg As Int32, _ ByVal wParam As Int32, ByVal lParam As Int32) As Int32 Public Function TerminateExcel() Dim ClassName As String = "XLMain" Dim WindowHandle As Int32
When all else fails I use API function calls:Dim ReturnVal As Int32
Const WM_QUIT = &H12
Do
WindowHandle = FindWindow(ClassName, Nothing)
If WindowHandle Then
ReturnVal = PostMessage(WindowHandle, WM_QUIT, 0, 0)
End If
Loop Until WindowHandle = 0
End Function
-
19. prosince 2006 21:56
The FinalReleaseCOMObject and all forms of it do not kill the EXCEL.EXE in the windows task manager. I've run loops, do until, etc.... and nothing.
Unless an actual Microsoft VB Programmer (someone who developed it for MS) comes on here and gives me the specific code that kills an instance of excel using the Marhsall.ReleaseComObject or Marshall.FinalReleaseComObject then I will continue to work under the assumption that Excel XP cannot be shut down without process.kill().
It just doesn't release. Period. (For Office XP)
-
20. prosince 2006 10:59thank's
-
31. prosince 2006 11:38Use a new thread to do all the excel stuff. Do still use the marshal stuff but once the thread quits excel will quit if you called excel.quit.
-
23. ledna 2007 2:25
Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Int32, ByVal wMsg As Int32, _
ByVal wParam As Int32, ByVal lParam As Int32) As Int32
Const WM_QUIT = &H12Dim App As new Excel.Application
Do Excel stuff
PostMessage(App.Hwnd, WM_QUIT, 0, 0)
Rather than terminate all instances of Excel this will terminate the instance you created in code.
Denton
- Navržen jako odpověď Ashpush 21. března 2012 16:42
-
23. ledna 2007 10:22
Hi,
The above method will kill the process. However if there are multiple applications or batch program running independant of eachother and each of them create their own excel object, the above method will kill all of the processes.
Is there anyway to uniquely identify the process pertaining to your application so that we can try to find the process by its id and kill the same?
Another way is to do the following
objExcel.Workbooks.Close()
objExcel.Quit()
Marshal.ReleaseComObject(objExcel)
objExcel =
NothingGC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
But using GC is a performance issue. However this can be used if it does not occur frequently, in the sense that this GC.Collect does not happen at places where the user will have frequent access.
-
23. ledna 2007 15:25
I strongly agree with Denton! Every other approach is a waste of time and energy. This is simple and effective.
Denton wrote: Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Int32, ByVal wMsg As Int32, _
ByVal wParam As Int32, ByVal lParam As Int32) As Int32
Const WM_QUIT = &H12Dim App As new Excel.Application
Do Excel stuff
PostMessage(App.Hwnd, WM_QUIT, 0, 0)
Rather than terminate all instances of Excel this will terminate the instance you created in code.
Denton
-
25. ledna 2007 11:39
you could try this
Public
Declare Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hWnd As IntPtr, ByRef lpdwProcessId As Integer) As Integer Public Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _(
ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
Dim proc As System.Diagnostics.Process Dim intPID As Integer Dim intResult As Integer Dim iHandle As IntPtr Dim strVer As String TryobjExcel =
New Excel.ApplicationobjExcel.Caption = "test"
objExcel.DisplayAlerts =
FalsestrVer = objExcel.Version
iHandle = IntPtr.Zero
If CInt(strVer) > 9 TheniHandle =
New IntPtr(CType(objExcel.Parent.Hwnd, Integer)) ElseiHandle = FindWindow(
Nothing, objExcel.Caption) End IfobjExcel.Workbooks.Close()
objExcel.Quit()
Marshal.ReleaseComObject(objExcel)
objExcel =
NothingintResult = GetWindowThreadProcessId(iHandle, intPID)
proc = System.Diagnostics.Process.GetProcessById(intPID)
proc.Kill()
Catch ex As Exception End Trythis will kill only the associated excel.exe and not all the exe's in the task manager.
Cheers
Ganesh
-
27. ledna 2007 3:35
If your using excel and are using the COM Class library can you provide a bit info on how your trying to close the com object down using the object model, the behaviour your seeing and some information about the machine configuration your trying this on.
I'm trying to pinpoint if there is some issue with Interop with Office 2003 which causes an issue.
-
29. ledna 2007 7:46
Hwnd property is available only for object library 10.0 onwards. for ones below 10.0 you need to use the FindWindow method of the user32.dll to obtain the window handle.
The code is posted above my me.
Cheers
Ganesh
-
29. ledna 2007 7:49
Yes. there is an issue. I get errors while trying to instantiate a 11.0 object library excel object. I get the error as "server execution failed" i have absolutely no clue what it means. It is not related to permissions as i have given permissions for ASPNET to access excel.
Can anybody tell me what the problem couldbe?
-
29. ledna 2007 13:10
-
30. ledna 2007 8:48
The exact error that i get whn creating 11.0 excel object is
System.Runtime.InteropServices.COMException
ErrorCode : -2146959355
Helplink : Nothing
InnerException : Nothing
Message : "Server execution failed"
What should i do?
-
7. února 2007 10:04
Hi,
I am working in XP and i had real problem with closing xl from my .net application. Your code helped me very much.
Thank you.
-
15. ledna 2008 19:40
Perfect! Just what I needed. Thank you very much! -
29. ledna 2008 1:46Code Snippet
Imports System.Runtime.InteropServicesEnd Class
Public Class Form1
Public ExcelApplication As Object
Public lstExcelObject As New System.Collections.Generic.Queue(Of Process)
<DllImport("USER32.DLL", EntryPoint:="IsWindowVisible", CharSet:=CharSet.Ansi)> _
Private Shared Function IsWindowVisible(ByVal hwnd As Integer) As Integer
End Function
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim lstNewProcessID As New System.Collections.Generic.Dictionary(Of Integer, Process)
Dim lstOldProcessID As New System.Collections.Generic.Dictionary(Of Integer, Process)
Dim localAll As Process()
localAll = Process.GetProcesses()
For i As Integer = 0 To localAll.Length - 1
If localAll(i).ProcessName.ToUpper = "EXCEL" Then
lstOldProcessID.Add(localAll(i).Id, localAll(i))
End If
Next
ExcelApplication = CreateObject("Excel.Application")
Dim newProcess As Process = Nothing
localAll = Process.GetProcesses()
For i As Integer = 0 To localAll.Length - 1
If localAll(i).ProcessName.ToUpper = "EXCEL" AndAlso Not lstOldProcessID.ContainsKey(localAll(i).Id) Then
newProcess = localAll(i)
Exit For
End If
Next
lstExcelObject.Enqueue(newProcess)
ExcelApplication.Visible = True
ExcelApplication.workbooks.add()
ReleaseComObject(ExcelApplication)
GC.Collect()
StartExcelWatcher()
End Sub
Public Sub ReleaseComObject(ByRef objComObject As Object)
Dim count As Integer = System.Runtime.InteropServices.Marshal.ReleaseComObject(objComObject)
For i As Integer = count To 0 Step -1
System.Runtime.InteropServices.Marshal.ReleaseComObject(objComObject)
Next
objComObject = Nothing
End Sub
Public Sub StartExcelWatcher()
Dim objThread As System.Threading.Thread = New Threading.Thread(AddressOf ExcelWatcher)
objThread.Start()
End Sub
Public Sub ExcelWatcher()
If lstExcelObject.Count > 0 Then
Dim objExcelApp As Process = lstExcelObject.Dequeue()
Try
Do
If objExcelApp Is Nothing OrElse objExcelApp.HasExited Then
Exit Do
ElseIf IsWindowVisible(objExcelApp.MainWindowHandle) = 0 Then
objExcelApp.Kill()
Exit Do
End If
Threading.Thread.Sleep(2000)
Loop
Catch ex As Exception
End Try
objExcelApp = Nothing
GC.Collect()
End If
End Sub
This is a sample ,I have writed it to close the Excel Process.
Test it ,Hope that it can help to some extent to you:) -
17. března 2008 13:35Hi i have big trouble to close excel file this peice or code work just fine in most cases when you use Excel 2003 wiht proper dlls
but I don't have any success with 2007 I don't know why , it is easy to kill the process but i still have problem to find out which is the proper process to kill , it is not good to kill all excel process on server , so I have to retrieve tre process id when the excel application object is generated but i find ity difficult i don't open excel in open window state otherwise it si easy to determine the right process, so please if tou have any solution help .Closing excel cause me so much pain try several thing but there are still some problems .C Dim i As Integer = 0
For i = 1 To xlWrkBook.Sheets.Count
xlWrkSheet = xlWrkBook.Sheets(i)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWrkSheet)
xlWrkSheet = Nothing
Next
For i = 1 To xlApp.Workbooks.Count
xlWrkBook = xlApp.Workbooks(i)
xlWrkBook.Close(False)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWrkBook)
xlWrkBook = Nothing
Next
xlApp.Quit()
System.Threading.Thread.Sleep(4000)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)
xlApp = Nothing
System.Threading.Thread.CurrentThread.CurrentCulture = oldCI
GC.Collect()
GC.WaitForPendingFinalizers()ode Snippet
http://www.thescarms.com/dotNet/ExcelObject.aspx
http://www.devcity.net/PrintArticle.aspx?ArticleID=239
this links i find helpful check them out you -
10. dubna 2008 8:00
For a great answer, read SWADE's post..
I was lost until I saw the Light from Swade's VB Lantern....
ahhh a pretty lighthouse in the distance...
BUt seriously... worked great... I was so close but nowhere near the KILL Processes FOR loop..
Dim proc As System.Diagnostics.Process
For Each proc In System.Diagnostics.Process.GetProcessesByName("EXCEL")
proc.Kill()
Next
Thanks,
DAVID -
10. dubna 2008 23:20
All due respect to swade's solution, denton's answer is the one I've been searching for for a week and works like a charm.
Now I've gotta go learn how dangit???
From one happy Excel killa!!
-
16. března 2009 13:5250 Ways to Kill Excelhttp://www.devcity.net/Articles/239/1/article.aspxby Scott RutherfordPublished on 6/14/2006
-
4. srpna 2009 7:12
Calling System.Runtime.InteropServices.Marshal.ReleaseComObject() does not release the app from the memory. What you need to do is open the workbook using GetObject().
Please check out the link.
http://social.msdn.microsoft.com/Forums/en-US/innovateonoffice/thread/65f9721f-e1a1-4757-8273-a77f526eee49
Hope this helps... -
27. srpna 2009 11:25You can try this if you want kill one explicit window....
---->
Microsoft.Office.Interop.Excel.Application aplicacion = null;
aplicacion = (Microsoft.Office.Interop.Excel.Application)new Microsoft.Office.Interop.Excel.ApplicationClass();
wBook = aplicacion.Workbooks.Open(excelfile,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
// write your code to modify your workbook...
wBook.Save();
wBook.Close();
IntPtr pointer=new IntPtr(aplicacion.Hwnd);
//killing this unique process (DON´T WORRY IF YOU HAVE OTHERS EXCELS PROCESS OPEN)
aplicacion.Visible = true;
foreach (System.Diagnostics.Process proc in System.Diagnostics.Process.GetProcessesByName("Excel"))
{
if (proc.MainWindowHandle == pointer)
proc.Kill();
} -
5. února 2010 17:44Denton's answer is the one I used. works well I did have to put objApp.Quit() before PostMessage.
objApp.Quit()
PostMessage(objApp.Hwnd, WM_QUIT, 0, 0)
A geek at heart -
19. července 2010 6:03
Hi,
I am using excel com compoent to read the content in excel and close the same. Initially i use to iterate the sheets name from the excel sheet and show it in my combobox. Users will pick the sheet name and import the contents to the database. Everything works fine regarding the data. The problem comes when i release the object.
The Excel object that i open during import is closed but the object while fetching the sheets is not closed.One Excel.exe object is still open and i could locate this in the task manager.
When i do the above process for the second time, both the excel.exe objects that i opened are closed now. But still the previously opened object is not closed. How can i close this object.
ExcelWB.Close() ExcelAPP.Quit() ReleaseObject(ExcelAPP) ReleaseObject(ExcelWB) ReleaseObject(ExcelWS) Private Sub ReleaseObject(ByVal obj As Object) Try System.Runtime.InteropServices.Marshal.ReleaseComObject(obj) obj = Nothing Catch ex As Exception MessageBox.Show(ex.ToString()) Finally obj = Nothing GC.Collect() End Try End SubThe above code is what iam using to release the object.
the code "ReleaseObject(ExcelWS)" will not be used while binding the combobox as i will not be opening the Worksheets.
-
23. července 2010 20:33
Surenyfs,
I may not be fully understanding the overall design of your app, but it seems to me as if you could use the same Excel object for both enumerating the worksheets (populating combobox) and pushing data from the chosen worksheet to your external database. From your description it seems like you are using the same Excel workbook for check your sheet names and for the source of data to be pushed out to your database, so, you don't have to establish that 2nd Excel object. Use the first one, and clean it up after you're done with the data transfer. Your procedure for taking care of Excel cleanup looks good to me. I successfully use a routine that's similar to yours (I'm pulld data into an Excel file and saving it) - see excerpts below:
Imports System.Runtime.InteropServices.Marshal
Imports Microsoft.Office.Interop
...
...
Function StartExcel(Optional ByVal IsVisible As Boolean = True) As Excel.Application
Try
Dim objExcel As New Microsoft.Office.Interop.Excel.ApplicationClass
If Not objExcel.Ready Then
System.Threading.Thread.Sleep(cmTimeoutForGettingFileServer)
End If
objExcel.Visible = IsVisible
If Not objExcel.Ready Then
System.Threading.Thread.Sleep(cmTimeoutForGettingFileServer)
End If
Return objExcel
Catch exe As ApplicationException
blnError = True
My.Application.Log.WriteEntry("Error during StartExcel: " & exe.Message, TraceEventType.Critical)
Return Nothing
Catch ex As Exception
blnError = True
My.Application.Log.WriteEntry("Error during StartExcel: " & ex.Message, TraceEventType.Critical)
Return Nothing
End Try
End Function
Sub ForceExcelToQuit(ByVal objExcel As Excel.Application)
Try
If Not objExcel Is Nothing Then
objExcel.Quit()
ReleaseComObject(objExcel)
End If
Catch exe As ApplicationException
blnError = True
My.Application.Log.WriteEntry("Error during ForceExcelToQuit: " & exe.Message, TraceEventType.Warning)
Catch ex As Exception
blnError = True
My.Application.Log.WriteEntry("Error during ForceExcelToQuit : " & ex.Message, TraceEventType.Warning)
Finally
objExcel = Nothing
GC.Collect()
End Try
End Sub
...
...
objExcel = StartExcel(blnIsVisible)
Try
strFileName = cmTemplateLocation
objWorkbook = objExcel.Workbooks.Add(strFileName)
objSheet = objWorkbook.Sheets(1)
DataTableToExcelSheet(dt, objSheet, 2, 1, 1, MDT, NumberOfWeekdays)
If Not blnIsVisible Then
If strSaveFilename <> "" Then
objWorkbook.SaveAs(strSaveFilename, Excel.XlFileFormat.xlWorkbookDefault, cmDestinationPassword)
If Not objWorkbook.Saved Then
Throw New Exception("Unable to save the resulting Excel file: " & strSaveFilename & ".")
End If
End If
objSheet = Nothing
objWorkbook.Close()
objWorkbook = Nothing
ForceExcelToQuit(objExcel)
End If
Catch exd As DataException
blnError = True
If blnIsVisible Then MsgBox(exd.ToString, MsgBoxStyle.Exclamation, "Error populating workbook. Data issue.")
ForceExcelToQuit(objExcel)
Catch ex As Exception
blnError = True
If blnIsVisible Then MsgBox(ex.ToString, MsgBoxStyle.Exclamation, "Error populating workbook")
ForceExcelToQuit(objExcel)
End Try
Dominik Ras mintol1@poczta.onet.pl- Navržen jako odpověď Dominik Ras 31. srpna 2011 18:04
-
4. listopadu 2010 9:30
So Great Swade!! thanks alot..... this works fine for me.. i use win2003 server and the last loop solves the problem..
thanks again
-
29. září 2011 10:31
Excellent !!!
I have been looking for many days.
Dim proc As System.Diagnostics.Process
For Each proc In System.Diagnostics.Process.GetProcessesByName("EXCEL")
proc.Kill()
NextThis work for me.
-
30. září 2011 11:12
We can use the below code for kill the current excel process, It avoids kill all the excel applications.
I hope it will be useful.
internal void closeApplication(){
if (app != null && !app.Visible){
if (app != null){
app.Quit();
app =
null;}
System.Diagnostics.
Process[] Processes;Processes = System.Diagnostics.
Process.GetProcessesByName("EXCEL");
foreach (System.Diagnostics.Process p in Processes){
if (p.MainWindowTitle.Trim() == "")p.Kill();
}
}
}
- Navržen jako odpověď Naunt_On 25. října 2011 10:21
-
10. října 2011 21:43
i would recomend to take a look at this
http://www.codeproject.com/KB/cs/ExcelAutomation.aspx
It works
-
25. října 2011 10:24
For Each proc In System.Diagnostics.Process.GetProcessesByName("EXCEL") If proc.MainWindowTitle.Trim() = "" Then proc.Kill() End If Next
Thanks, this works really fine on me. :) -
21. listopadu 2011 19:03
I have the issue mentioned above where I get two EXCEL.EXE items in the process list.
I use the following (just going by memory on the exact method names):
Dim ExcelApp as Object = CreateObject("Excel.Application") Dim ExcelWB as Object = ExcelApp.OpenWorkbook(...) Dim xlsSheet as Object = ExcelWB.Sheets(index)
I reassign xlsSheet to access all of the sheets as needed
Problems/Questions:
- I put everything in a class that implements IDisposable so that if my application crashes the COM object should get properly released but the EXCEL.EXE processes don't disappear until I close the VB.NET DLL dialog and then close the host application which is AutoCAD (VB.NET DLL running under AutoCAD). I haven't yet tried the Marshal.ReleaseCOMOBject suggestions above.
- What is the exact reason for two EXCEL.EXE processes?
- I don't reference Excel at all in my code as a project reference, everything is just Object. In my VBA days I found that referencing a specific version of Excel on my dev machine didn't translate well when the end-user had a different version of Excel on their machine. Perhaps I don't need to worry about that anymore and use code similar to Dominik's in one of the above posts? Perhaps performance would improve without the late binding as well? Advice on that would be appreciated.
- If all you are doing is reading values from an Excel spreadsheet, it would be nice if Microsoft released a non-COM .NET interface for that, independent of EXCEL.EXE being on the machine. Is nothing like that available?
Thanks,
Greg
- Upravený GTVic 21. listopadu 2011 19:06
-
15. prosince 2011 5:15
So, I figured while this question is quite old, the problem is fresh even today I might as well throw in another little tidbit of information that seems overlooked quite often.
Often when I'm working with Excel from VB.Net I'm simply getting some info and closing it... And, like any good little code-monkey when I have a situation like that, I stick all of it in a separate function and simply return the info I need... So what can go wrong here? Simply put, I could return a value and exit my function UNINTENTIONALLY and thus never get to the goodie bits of dropping excel and quitting it.
Now, I did see the app.kill loop on this thread... That works great as long as (someone else mentioned) you don't need to one of the instances of excel already open. It is poor practice to assume no one would ever have another instance of excel open while running your app, in fact you could cost a co-worker many frustrating hours trying to redo something they had done when you inadvertently killed their instance... I suggest against this if anyone else will be using your program. Instead, try this first... Here is some sample code to return a value from excel...
Dim xlApp As New Excel.Application Dim xlWB As Excel.Workbook = xlApp.Workbooks.Open(My.Settings.xlPath.ToString, False, True) Dim xlWs As Excel.Worksheet = DirectCast(xlWB.Sheets("Master List"), Excel.Worksheet) xlApp.Visible = False Return xlWs.Range("M1").Value NAR(xlWs) xlWB.Close(False) NAR(xlWB) xlApp.Quit() NAR(xlApp) GC.Collect() GC.WaitForPendingFinalizers()
Note the 'Return xlws.range("M2").value' statement in the middle of the code... This indicates I'm working with a function and returning that value... quite slick code, not assigning a variable, saving memory... hmmm, but actually once .net hits that return line it leaves the function and goes back to your main calling routine... This is what is leaving excel open at this point and nothing you change afterwards will do much of anything... You could spend hours making loops, tests, and debugging to find that were it not for that little line, this could have all been averted."Note: This can happen in routines where you are not just returning a single value, as well. Perhaps you have a loop with a check and once all boxes are populated you dump out of that routine. Finding places where you are letting a routine dump out early are the key to solving this delimma.
So here is some code, inserting a variable, assigning it, and then not returning the value until I have fully dumped out of excel...
Dim xlApp As New Excel.Application Dim xlWB As Excel.Workbook = xlApp.Workbooks.Open(My.Settings.xlPath.ToString, False, True) Dim xlWs As Excel.Worksheet = DirectCast(xlWB.Sheets("Master List"), Excel.Worksheet) xlApp.Visible = False '''inserting a variable Dim res As Integer res = xlWs.Range("M1").Value NAR(xlWs) xlWB.Close(False) NAR(xlWB) xlApp.Quit() NAR(xlApp) GC.Collect() GC.WaitForPendingFinalizers() '''ahhh excel has closed and I can return my variable Return resHope this helps... And lastly, for anyone wondering about the "NAR" routine, that is code taken from MSDN help on the issue... here is the routine for that...
Private Sub NAR(ByVal o As Object) Try System.Runtime.InteropServices.Marshal.ReleaseComObject(o) Catch ex As Exception Finally o = Nothing End Try End SubThis is basically saving you from retyping sys....runtim....intero... etc. etc. etc... and catching any failures to turn them to nothing...
-
17. prosince 2011 2:09
This very interesting and long running discussion caught my attention and has solved my seemingly insoluble problem. I do not know very much about Visual Basic but have used VBA for many years. A set of routines I had written in VBA seemed to me to be useful to a wider audience so I set to, to learn enough VB (using express edition 2010) to produce an executable file in VB. The process is 3 stage. 1 Create an Excel workbook and populate sheet3 with some data (a default set of Accounts codes). 2. User customises this data which forms the essential element in the final product. 3 Programme produces a twelve sheet workbook carrying a special interface on one sheet which has 14 buttons to activate a set of macros in VBA contained in 4 modules. End result – a virtually automated process with applicability in many environments. Total lines of VB code 1225. 5 user forms, four text files for vba codes, 2 readme files, and a partridge in a pear tree.
The problem was that I had to exit the application at the end of stage 1 and stage 2 to avoid being left with an instance of Excel running in the background unseen which might pose a threat to an otherwise safe environment. I wrote a routine using GetObject that would identify close and release any other instance of Excel but it would not close the remnants of my programme though it could identify their presence.
I tried all that was within my limited knowledge sprinkling ReleaseComObjects, and GCs at every conceivable point where exits, closures or exceptions occurred but all to no avail. Then I lighted upon this post.
I have tried Denton’s solution and LO! It works. Like Michael1569 I put the App Quit in front of it. I cannot pretend to understand it all, I am too long in the tooth for that but I am impressed with and grateful for the forums and the co-operative spirit they engender.
MARGAVEN
-
14. února 2012 10:40
try to Close and dipose ur excel workbook object this will work
excelBook.Close()
excelBook = Nothing
excelApp = NothingA.Venkatesan
-
21. března 2012 16:42
This indeed works!
Thank you!
-
22. března 2012 6:20
if (p.MainWindowTitle.Trim() ==""
p.Kill();
This works like charm...
--Amos
-
20. dubna 2012 9:04
Hi,
you can also try this C# / VB.NET Excel component that doesn't use Excel Interop so there is no need to for Excel application and need for killing it.
Here is a sample VB.NET code:
Dim ef As New ExcelFile ' Loads Excel file. ef.LoadXls("filename.xls") ' Selects first worksheet. Dim ws As ExcelWorksheet = ef.Worksheets(0) ' Displays the value of first cell in the messageBox. MessageBox.Show(ws.Cells("A1").Value.ToString())
-
29. července 2012 13:34
Work great!!!!!!
Thanks
-
12. listopadu 2012 12:59
I got similar problem and dont know how to find the good way. I try to explain mayby some could help:
I have a lot automated excel by vb.net. But i got a big problem with one of my projects which is working with two workbooks. Anyway the EXCEL.EXE staying in taskmanager. This is my code i am using:
Imports Excel = Microsoft.Office.Interop.Excel Module Main 'Create Excel objects Public objApp As New Excel.Application Public WorkDirectory = "C:\Users\user\Documents\Visual Studio 2005\Projects\Working with Excels\" Sub Main() Try With objApp .Workbooks.Open(Filename:=Local & "MyMain.xls") .Workbooks.Open(Filename:=Local & "Other.xls") .......... .......... 'operations on two workbooks... .......... .......... .Workbooks("Other.xls").Close(True) .Workbooks("MyMain.xls").Close(True) End With Catch ex As Exception Console.WriteLine("Error occurs: " & ex.ToString) Finally objApp.Quit() NAR(objApp) GC.Collect() GC.WaitForPendingFinalizers() End Try End Sub End Module ------------------------------------------ Module RealaseExcelObjects Public Sub NAR(ByVal o As Object) Try System.Runtime.InteropServices.Marshal.ReleaseComObject(o) Catch Finally o = Nothing End Try End Sub End Module
Anyway after that i have still the EXCEL.EXE in processes.
I found out also this topic, mayby it could be helpfull in my case but i dont know how to implement it in my code:
http://social.msdn.microsoft.com/Forums/en-US/innovateonoffice/thread/65f9721f-e1a1-4757-8273-a77f526eee49?prof=required
Could you please help me, what to do?
-
2. prosince 2012 22:05
I am no expert in this field - but I laboured greatly to overcome this problem. Are you sure that every possible exit from the application is suitably catered for with release of object. My programme has a number of exit points plus of course those which take place when an error occurs and which hopefully you will have covered by try catch procedures. I put the following on all my exit points and on every try catch as well.
' objexcel.ActiveWorkbook.Close(SaveChanges:=False)
' objexcel.Quit()
' objexcel = Nothing
' Me.Close()
This seems to work, for all forseeable events and I don't need GC. However if an unforseen error occurs that is not caught in a try catch the Excel application will almost certainly still be running in the background not visible. I found that the only way to then get rid of it is to power down and start again. Don't forget to save everything first. In order to easily see whether this state existed I wrote this routine which is handy to use when trying to find out what the state of affairs is at any one time. You need just one fomr with two command buttons.
'Public Class Form1
' Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As 'Int32, ByVal wMsg As Int32, _
' ByVal wParam As Int32, ByVal lParam As Int32) As Int32
'' Const WM_QUIT = &H12
' Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As 'System.EventArgs) Handles Button1.Click
' Dim errnum As Integer
' ' Test to see if a copy of Excel is already running.
' ' Private Sub testExcelRunning()
' On Error Resume Next
' ' GetObject called without the first argument returns a
' ' reference to an instance of the application. If the
' ' application is not already running, an error occurs.
' Err.Clear()
'
' Dim excelObj As Object = GetObject(, "Excel.Application")
' If Err.Number = 0 Then
' errnum = Err.Number
' MsgBox("1. Excel is running. Errnum is " & errnum)
' excelObj.Quit()
' PostMessage(excelObj.Hwnd, WM_QUIT, 0, 0)
' ReleaseComObject(excelObj)
'
' GC.WaitForPendingFinalizers()
' GC.Collect()
' Err.Clear()
'
' Else
' errnum = Err.Number
' MsgBox("2. Excel is not running. Errnum is " & errnum)
' End If
' Err.Clear()
' ReleaseComObject(excelObj)
' excelObj = Nothing
' End Sub
' Friend Sub ReleaseComObject(ByVal o As Object)
' Try
' System.Runtime.InteropServices.Marshal.FinalReleaseComObject(o)
' Catch
' Finally
' If o IsNot Nothing Then o = Nothing
' End Try
' MsgBox("This sub was called")
' End Sub
' Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As 'System.EventArgs) Handles Button2.Click
' Me.Close()
' End Sub
I also put in a routine to test for any Excel running when my program starts because it doesn’t like the presence of a parallel application, and to close it if it finds one before running.
Hope this may be of some help
Avenmarg
<//span>