I am writing a program that loops through all of the sheets in an Excel workbook and saves each sheet as its own workbook. It turned out to be a bit trickier than I expected
Below is code that works for me (NOTE order that I release objects, which is important)
xlWorkBook.Close()
xlApp.Quit()
ReleaseObject(xlWorkSheet)
ReleaseObject(xlWorkBook)
ReleaseObject(xlApp)
Private Sub ReleaseObject(ByVal obj As Object)
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
obj = Nothing
Catch ex As Exception
obj = Nothing
Finally
GC.Collect()
End Try
End Sub
Okay, this works form me for a very simple worksheet. Let me know if you have any questions.
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
'Get information from text boxes
Dim InputLocation As String
Dim OutputLocation As String
InputLocation = InputLoc.Text & "\" & Filename.Text
If OutputLoc.Text = "" Then
OutputLocation = InputLoc.Text
Else
OutputLocation = OutputLoc.Text
End If
'Make file to save files in
' Get date and time in filename as well
Dim TLDateTime As String
Dim TLDay As String
Dim TLMonth As Integer
Dim TLYear As Integer
Dim TLHour As Integer
Dim TLMinute As Integer
Dim TLDate As String
Dim TLTime As String
Dim TLSecond As Integer
TLDay = DateTime.Now.Day
TLMonth = DateTime.Now.Month
TLYear = DateTime.Now.Year
TLHour = DateTime.Now.Hour
TLMinute = DateTime.Now.Minute
TLSecond = DateTime.Now.Second
Dim MyDate As New DateTime(TLYear, TLMonth, TLDay, TLHour, TLMinute, TLSecond)
Dim MyString As String = MyDate.ToString("MMMddyyyy_HHmmss")
TLDate = TLMonth.ToString + TLDay.ToString + TLYear.ToString
TLTime = TLHour.ToString + TLMinute.ToString
TLDateTime = TLDate + "_" + TLTime
Try
Directory.CreateDirectory(OutputLocation & "\" & "Field Sales Report Graphs " & TLDateTime)
OutputLocation = OutputLocation & "\" & "Field Sales Report Graphs " & TLDateTime
Catch
MsgBox("Trying to create a file that exists, please delete it. If the file does not exist check to make sure your output location exists")
End Try
'Open up excel file with information in it
Dim xlApp1 As Excel.Application = New Excel.Application
xlApp1.Visible = True
xlApp1.Application.DisplayAlerts = False
Dim locs As Excel.Workbook
locs = xlApp1.Workbooks.Open(InputLocation)
Dim fileNames As New ArrayList
Dim counter As Integer = 1
For Each ws As Excel.Worksheet In locs.Worksheets
fileNames.Add(ws.Name)
ws = xlApp1.Workbooks(counter).Sheets(1)
ws.SaveAs(Filename:=OutputLocation & "\" & fileNames(counter - 1) & ".xlsx")
'close excel and release com objects
System.Runtime.InteropServices.Marshal.ReleaseComObject(ws)
xlApp1.Workbooks(counter).Close(False)
counter += 1
Next
System.Runtime.InteropServices.Marshal.ReleaseComObject(locs)
locs = Nothing
xlApp1.Quit()
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp1)
xlApp1 = Nothing
End Sub
You might need to do the following if you have unreferenced COM objects that are being created:
GC.Collect()
GC.WaitForPendingFinalizers()
Taken from this MSDN forum post: http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/cb5f7948-c229-483e-846b-a1cfbbcd86ca/
The solution I finally came across was to add
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp1.ActiveWorkbook)
xlApp1.ActiveWorkbook.Close()
to the loop. I found this answer in the comments of The first answer on another stack overflow post. Basically, the problem I was having is that the worksheet.copy method creates a workbook object with no reference, but it turns out it can be referenced by referring to the activesheet. If you wanted to do more with it than just kick it out the door like I am, I imagine you could create a new workbook object and assign it or as the post I link to suggests, you can save it as something as well. For my puposes, it is just fine to release it after saving the worksheet I want and this removed my excel.exe hanging process.
If you want a bit more elgant code option you should check out the ron tornambe post where he does the for each loop I managed to not get right instead of the wonky thing I create. Basically you would want to use his loop in my code and you would have it all set up. Thanks as always stack overflow.