I'm using VBA automation from an Access 2010 to create charts using Excel 2010. My code works fine, but leaves an orphan Excel.exe process running. I have traced the problem to a call to an Excel VBA function in a separate module. If I eliminate the call to this function, the Excel process is closed when the codes finishes. The function is Chip Pearson's FindAll
with modifications to get it to run in Access, such as declaring ranges as Excel.Range
and explicitly referencing the Union
method as Excel.Application.Union
. How do I need to modify this function so that is does not leave an orphaned Excel process running?
The following code binds the Excel application in the main procedure:
Dim oApp As New excel.Application
Dim oBook As excel.Workbook
Dim oSheet As excel.Worksheet
Set oBook = oApp.Workbooks.Add
Set oSheet = oBook.Worksheets(1)
Then, at the end:
oBook.Close False
oApp.Quit
Set oSheet = Nothing
Set oBook = Nothing
Set oApp = Nothing
And I am calling FindAll using this line:
b = FindAll(oSheet.Range("a2", oSheet.Range("a2").End(xlDown)), strWellID).Rows.Count
The FindAll
function is below:
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' modFindAll
' By Chip Pearson, chip@cpearson.com. www.cpearson.com
' 24-October-2007
' This module is described at www.cpearson.com/Excel/FindAll.aspx
' Requires Excel 2000 or later.
'
' This module contains two functions, FindAll and FindAllOnWorksheets that are use
' to find values on a worksheet or multiple worksheets.
'
' FindAll searches a range and returns a range containing the cells in which the
' searched for text was found. If the string was not found, it returns Nothing.
' FindAllOnWorksheets searches the same range on one or more workshets. It return
' an array of ranges, each of which is the range on that worksheet in which the
' value was found. If the value was not found on a worksheet, that worksheet's
' element in the returned array will be Nothing.
'
' In both functions, the parameters that control the search have the same meaning
' and effect as they do in the Range.Find method.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function FindAll(SearchRange As Excel.Range, _
FindWhat As Variant, _
Optional LookIn As XlFindLookIn = xlValues, _
Optional LookAt As XlLookAt = xlWhole, _
Optional SearchOrder As XlSearchOrder = xlByRows, _
Optional MatchCase As Boolean = False) As Range
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' FindAll
' This searches the range specified by SearchRange and returns a Range object
' that contains all the cells in which FindWhat was found. The search parameters to
' this function have the same meaning and effect as they do with the
' Range.Find method. If the value was not found, the function return Nothing.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim FoundCell As Excel.Range
Dim FirstFound As Excel.Range
Dim LastCell As Excel.Range
Dim ResultRange As Excel.Range
With SearchRange
Set LastCell = .Cells(.Cells.Count)
End With
'On Error Resume Next
On Error GoTo 0
Set FoundCell = SearchRange.Find(What:=FindWhat, _
after:=LastCell, _
LookIn:=LookIn, _
LookAt:=LookAt, _
SearchOrder:=SearchOrder, _
MatchCase:=MatchCase)
If Not FoundCell Is Nothing Then
Set FirstFound = FoundCell
Set ResultRange = FoundCell
Set FoundCell = SearchRange.FindNext(after:=FoundCell)
Do Until False ' Loop forever. We'll "Exit Do" when necessary.
If (FoundCell Is Nothing) Then
Exit Do
End If
If (FoundCell.Address = FirstFound.Address) Then
Exit Do
End If
Set ResultRange = Excel.Application.Union(ResultRange, FoundCell)
Set FoundCell = SearchRange.FindNext(after:=FoundCell)
Loop
End If
Set FindAll = ResultRange
'added below
Set ResultRange = Nothing
Set FoundCell = Nothing
Set FirstFound = Nothing
Set LastCell = Nothing
Set SearchRange = Nothing
End Function