Question : Excel Instance Left in Memory after Access Automation

The following code leaves an Excel instance in memory, until VBA is "ended" on an artificial error halt ( like x = 1/0) or Access quits.  I would like the Excel instance to be made to go away when this routine ends.   This situation can be reproduced with:

Folder       C:\Test              containing:
1) Access mdb with Table1 only (any field in table OK), and a few records in Table1, and the code below
2) Excel workbook named Testwb.xls

XP Pro, Access 2002

'===================================================
Option Compare Database
Dim xlsDoc, xlsApp, EST_Data_File_Name1, Est_Data_Folder_path, eio, I

'========================Main Routine=======================================
Public Sub App_Test2()

'------initialize app, doc, and delete existing sheets
init_excel2

'-----import to Excel from Access   ==>>> COMMENTING THIS NEXT STATEMENT OUT REMOVES THE PROBLEM
'                                                             The querytable.add in this routine seems to be what creates the
'                                                             "hook" that won't let the last instance of Excel go away until
'                                                             Access quits or Access VBA ends
Insert_Data1

'------save the workbook
xlsDoc.Save

'----Now shut the whole thing off

'----This closes any open QueryTables, but doesn't seem to help
xlsApp.DisplayAlerts = False
For n1 = 1 To xlsDoc.Sheets.Count

start_conn_delete:
If xlsDoc.Sheets(n1).QueryTables.Count > 0 Then
    xlsDoc.Sheets(n1).QueryTables(xlsDoc.Sheets(n1).QueryTables.Count).Delete
    Else: GoTo after_conn_delete
    End If
GoTo start_conn_delete
after_conn_delete:

Next n1
xlsApp.DisplayAlerts = True
'-----------------------------------------------------


'------ close the Excel instance used for this app
    For n = 1 To xlsApp.Workbooks.Count
    If xlsApp.Workbooks(n).Name = EST_Data_File_Name1 Then
        Set xlsDoc = xlsApp.Workbooks(n)
        xlsApp.Quit
'        Set xlsApp = Nothing
    End If
    Next n

'------- close Excel completely if no other workbooks
If xlsApp.Workbooks.Count = 0 Then
    xlsApp.Quit
    Set xlsDoc = Nothing
    Set xlsApp = Nothing
    eio = False
    Set l = Nothing
End If

End Sub

'============================================================================
Public Sub init_excel2()                        'this initializes the Excel app and file
                                                         'may seem a little busy but handles several different cases

On Error GoTo ErrorHandler
EST_Data_File_Name1 = "Testwb.xls"
Est_Data_Folder_path = "C:\Test\"
EST_Data_File_Path1 = Est_Data_Folder_path & EST_Data_File_Name1

  If ExcelIsOpen Then                                               ' separate test function below
    'Excel is open, set xls to the open process:
    Set xlsApp = GetObject(, "Excel.Application")
    eio = True 'For use later in the ErrorHandler
  Else
    'Excel is not open, create a new process:
    Set xlsApp = CreateObject("Excel.Application")
    eio = False 'For use later in the ErrorHandler
  End If


Open_Check:
If xlsApp.Workbooks.Count = 0 Then GoTo Open_It
For n = 1 To xlsApp.Workbooks.Count
Debug.Print xlsApp.Documents(n).Name
If xlsApp.Documents(n).Name = EST_Data_File_Name1 Then
        Set xlsDoc = xlsApp.Documents(n)
        Exit Sub
    End If
Next n
GoTo Open_It
enderr:
a2 = 1

Open_It:
On Error GoTo DocErr
Set xlsDoc = xlsApp.Workbooks.Open(EST_Data_File_Path1)
GoTo Doc_Opened
DocErr:
MsgBox ("didn't find EST work file")
Exit Sub

Doc_Opened:

xlsApp.Visible = True

Exit Sub

ErrorHandler:
  If IsEmpty(xlsApp) = False Then
    'If eio = True then we re-used an existing Excel process so we don't want to
    'close it because we might lose data.
    'Else, if eio = False then we created a new Excel process, let's close it:
    If eio = False Then
      If IsEmpty(xlsApp) = False Then
        For l = 1 To xlsApp.Workbooks.Count 'Loop through all open xls workbooks and close them
                                         'without saving changes
          xlsApp.Workbooks(l).Close savechanges:=False
        Next l
        xlsApp.Quit 'Close the xls process
      End If
    End If
  End If
  Resume UnsetVars2 'Go back to cleanup the variables

UnsetVars2:
  Set xlsApp = Nothing
  eio = False
  Set l = Nothing
  Exit Sub


End Sub

'============================================================================
Private Function ExcelIsOpen()                    'Check to see if Excel is currently open, return True/False
  On Error GoTo ErrorHandler
 
  ExcelIsOpen = False
  Set xlsApp = GetObject(, "Excel.Application")
  ExcelIsOpen = True
UnsetVars:
  Set xlsApp = Nothing
  Exit Function
 
ErrorHandler:
  Resume UnsetVars
End Function
'============================================================================
Sub Insert_Data1()
'-----------------------------this does the import to Excel from Access
'-----------------------------this code was captured by recording an Excel macro and
                                     ' copying it from Excel VBA to Access VBA

    With ActiveSheet.QueryTables.Add(Connection:= _
        "ODBC;DSN=MS Access Database;DBQ=C:\Test\Testdb.mdb;DefaultDir=C:\Test;DriverId=25;FIL=MS Access;MaxBufferSize=2048;PageTimeout=5;" _
        , Destination:=Range("A1"))
        .CommandText = Array("SELECT * FROM `Table1`")
        .Name = "MS Access Database (not sharable)"
        .FieldNames = True
        .RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = True
        .RefreshOnFileOpen = False
        .BackgroundQuery = True
        .RefreshStyle = xlInsertDeleteCells
        .SavePassword = True
        .SaveData = True
        .AdjustColumnWidth = True
        .RefreshPeriod = 0
        .PreserveColumnInfo = True
        .SourceConnectionFile = _
        "C:\Program Files\Common Files\ODBC\Data Sources\MS Access Database (not sharable).dsn"
        .Refresh BackgroundQuery:=False
    End With

End Sub

Answer : Excel Instance Left in Memory after Access Automation

Hi codequest,

I had a play with your code but got similar problems to what you report and could not figure out how to solve them. It was actually quit difficult because it could not be run in break mode.

I suspect that the main problem stems from the fact that the code you are using is desiged to be run from Excel. Perhaps it can be made to work but I think this will be an uphill battle.

I have modified my code to do essentially what your code seemed to do. You can always add stuff if you need it. I think it is pretty quick since it dumps the data in one hit although the column headings are treated separately. This code should not leave any unwanted instances of Excel running.

Steve


Private Sub ExportToExcel()
On Error GoTo ErrorHandler

    Dim xlApp As Object
    Dim xlWb As Object
    Dim xlWs As Object
    Dim strXLFile As String
    Dim strSheet As String
    Dim rst As ADODB.Recordset
    Dim iCols As Integer
   
    strXLFile = "C:\Test\Testwb.xls"
    strSheet = "Sheet1"  '<---Name of worksheet in file
    'Open a the workbook in Excel
    Set xlApp = CreateObject("Excel.Application")
    Set xlWb = xlApp.Workbooks.Open(strXLFile)
    Set xlWs = xlWb.Worksheets(strSheet)
    Set rst = New ADODB.Recordset
    rst.Open "Table1", CurrentProject.Connection, adOpenForwardOnly, adLockReadOnly
    For iCols = 0 To rst.Fields.Count - 1
        xlWs.Cells(1, iCols + 1).Value = rst.Fields(iCols).Name
    Next
    xlWs.Range(xlWs.Cells(1, 1), xlWs.Cells(1, rst.Fields.Count)).Font.Bold = True
    xlWs.Range("A2").CopyFromRecordset rst '<---begin putting data in cell A2
    rst.Close
   
    xlWs.Columns.AutoFit
    xlWb.Save
    xlApp.Quit
   
    Set rst = Nothing
    Set xlApp = Nothing
    Set xlWb = Nothing
    Set xlWs = Nothing
   
ExitRoutine:
    Exit Sub

ErrorHandler:
    If Not xlApp Is Nothing Then
        'make Excel visible if an error occurs
        xlApp.Visible = True
        Set xlApp = Nothing
    End If
    If Not xlWb Is Nothing Then
        Set xlWb = Nothing
    End If
    If Not xlWs Is Nothing Then
        Set xlWs = Nothing
    End If
    'Close rst
    If Not rst Is Nothing Then
        rst.Close
    End If
   
    MsgBox Err.Description & " Error Number: " & Err.Number
    Resume ExitRoutine

End Sub
Random Solutions  
 
programming4us programming4us