When Application.Quit is encountered in a subroutine,
it will only stay in memory and continue to run lines under it
and will actually quit until it encounters a «Exit Sub».
When the normal «End Sub» at the primary level is encountered,
it will then also close Excel. But say if the workbook is somehow
closed before reaching the «Exit Sub», «End» or «End Sub» line, then
Excel will not close.
Solution is to create a Public variable called ToQuitNow
with initial False value
and change it to True where you want Excel to quit.
and test right after to see if it is true, then return to previous Sub level
by «Exit Sub» or «End» to quit right away,
and do the same at every subrountine level where
it is expected to return from the deeper subroutine.
When it gets back to the primary level,
then a final «Exit Sub» will actually terminates Excel.
If you do not want Excel to ask for saving changes made,
add line «ThisWorkbook.Saved = True» right after Application.Quit,
or before the final «Exit Sub» at the Primary level
and Excel will quit without saving.
Try the following test below, just run «Test»
Public ToQuitNow As Boolean
Sub Test()
ToQuitNow = False ' initialize with False value
Call SecondSub
MsgBox ("Primary level here. Back from SecondSub")
If ToQuitNow = True Then
Exit Sub 'will actually quit Excel now if True
End If
MsgBox ("This line will not run if ToQuitNow is True")
End Sub
Sub SecondSub()
MsgBox ("SecondSub here")
Call ThirdSub
MsgBox ("SecondSub here. Back from ThirdSub")
If ToQuitNow = True Then
Exit Sub ' will return to Main level if True
End If
MsgBox ("This line from SecondSub will not run if ToQuitNow is True")
End Sub
Sub ThirdSub()
MsgBox ("ThirdSub here")
Call FourthSub
MsgBox ("ThirdSub here. Back from FourthSub")
If ToQuitNow = True Then
Exit Sub ' will return to SecondSub if True
End If
MsgBox ("This line from ThirdSub will not run if ToQuitNow is True")
End Sub
Sub FourthSub()
MsgBox ("FourthSub here")
Application.Quit
ThisWorkbook.Saved = True ' Excel will think changes already saved _
and will quit without saving
ToQuitNow = True ' activate Quit
If ToQuitNow = True Then
MsgBox ("Quit command executed in FourthSub")
Exit Sub ' will return to ThirdSub if True
'Can also put in End in above line to quit right away
End If
MsgBox ("This line from FourthSub will not run if ToQuitNow is True.")
End Sub
- Remove From My Forums
-
Question
-
I am using window 7, Excel 2010, Access 2010. I have a routine (running in Access 2010) that opens an excel file, reads in the data, then closes the excel file.
Everything work fine except for closing the excel file. If I watch Windows Task Manager EXCEL.EXE does not terminate.
Below is a snipit of code that duplicates the problem I am seeing. How can I close and terminated the EXCEL?
The routine is called multiple times. The first time through the process EXCEL does not close. The second time a second copy of EXCEL is created and at the end of the routine it does close, but the first occurance is still there.
If I press the VBA reset (stop) button excel will then terminate.Function TestOpenCloseExcel(sExcelFile
As String) As
IntegerDim ExcelWorkBook
As Workbook
Dim iResult As
Integer
Dim ExcelApp As
Object
On Error
GoTo ErrorTrapDebug.Print «Open»
Set ExcelApp = CreateObject(«Excel.Application»)
Set ExcelWorkBook = ExcelApp.Workbooks.Open(sExcelFile)Debug.Print «Close»
ExcelWorkBook.Close
Set ExcelWorkBook =
Nothing
ExcelApp.Quit ‘this line terminates the process
Set ExcelApp = Nothing
Exit FunctionErrorTrap:
Debug.Print «(« & Err.number &
«) « & Err.Description
End Function
Answers
-
mathew,
The problem most likely lies elsewhere.
Look for *anywhere* in your app where you use any Excel objects or methods in conjunction with a WITH-block of code.
It is a commonly known issue that Unless your code explicitly declares and clears automation-based object variables used as the object of a with-block (With…End With syntax), those objects can get stuck in memory as «orhpaned» com objects. This will then
prevent the release of their automation server classes (since a consitiuent object still has a non-zero COM reference count). This will present as the symptom you are observing: Excel won’t close despite the call to .Quit.Automation-based object instances should ALL be used like this:
Dim objTemp as (Object/Excel.range/whatever)
set objTemp = (whatever)
With ObjTemp
‘do stuff here
End With
set objTemp = Nothingwhat you should NOT be doing is this:
With objExclApp.worksheets(1).range(«myNamedrange»)
‘do stuff
End WithTHIS is the sort of thing that can leave phantom references for a range object (if not also a worksheet object) stuck in memory because they don’t get cleaned up properly.
Examine the rest of your code for anything that fits this pattern and explicitly declare and clear appropriate variables for those object references. This may well eliminate your issue.
Mark Burns, MCAD, MCP
Sr. Microsoft Access Analyst/Developer
Manager LinkedIn.Com community: Professional Microsoft Access Developers Network (PMADN)-
Marked as answer by
Tuesday, February 8, 2011 9:14 AM
-
Marked as answer by
-
As I understand this the piece of code I’ve provided here
http://social.msdn.microsoft.com/Forums/en-US/accessdev/thread/f107ba63-2895-4590-872d-4c37bdd8111cAs I said before I had tested it and hadn’t faced this error. Just for my interest I’ve modified this func a little to run it more than once. I opened Task Manager and was watching on EXCEL.EXE process. It opens and closes properly within every iteration
of the loop and there is no such a behaviour you are describing above.Maybe this function in your full code is being called from another function/sub and the real reason is there? Try to terminate all EXCEL.EXE before testing and then run exactly this function 3-5 times. If there is no problem look at the another place in
your code which can generate this issue.
Andrey V Artemyev | Saint-Petersburg, Russia
-
Marked as answer by
Bessie Zhao
Tuesday, February 8, 2011 9:14 AM
-
Marked as answer by
-
CNC_Matthew:
In the code you have posted, you have not done the following, but I wonder whether, in the code you are actually running:
- you have declared the variable, ExcelApp, in the General Declarations Section (at the top) of your module; and
- you are not setting ExcelApp to Nothing (at least between successive calls to the function).
The above would account for the behaviour you are experiencing.
In the following demo, notice that it is only when the variable ExcelApp is set to Nothing or when the ExcelApp variable goes out of scope that the Excel process finally disappears from the Windows Task Manager.
The Excel process does not disappear from Task Manager when you execute Excel’s Quit command.Private ExcelApp As Excel.Application Function TestOpenCloseExcel(sExcelFile As String) As Integer Dim ExcelWorkBook As Excel.Workbook Dim iResult As Integer On Error GoTo Error_TestOpenCloseExcel Debug.Print "Start Excel" Set ExcelApp = CreateObject("Excel.Application") ' Just so you can see when the Excel icon ' disappears from the Taskbar: ExcelApp.Visible = True Debug.Print "Open Workbook" Set ExcelWorkBook = ExcelApp.Workbooks.Open(sExcelFile) Debug.Print "Close Workbook" ExcelWorkBook.Close Set ExcelWorkBook = Nothing ' > "this line terminates the process" ' Actually, no - it doesn't. ' ' The following code line causes Excel to disappear ' from the Taskbar, but Excel remains in the list ' of processes in Windows Task Manager: ExcelApp.Quit ' The following code line causes the ' Excel process to disappear from Task Manager. Set ExcelApp = Nothing ' NOTE: ' ' If the above code line is omitted, the Excel ' process won't disappear from the Windows Task ' Manager until the ExcelApp variable goes out of ' scope (when this function terminates if the ' variable is declared within this function). ' ' HOWEVER, if the above code line is omitted ' and the ExcelApp variable is declared in the ' General Declarations Section (at the top of ' the module), then the Excel process won't ' disappear from the Windows Task Manager. ' Perhaps that's what you're doing. ' Initialize this function's return value: iResult = 1 Exit_TestOpenCloseExcel: ' Set this function's return value: TestOpenCloseExcel = iResult Exit Function Error_TestOpenCloseExcel: Debug.Print "(" & Err.Number & ") " & Err.Description Resume Exit_TestOpenCloseExcel End Function
-
Marked as answer by
Bessie Zhao
Tuesday, February 8, 2011 9:14 AM
- you have declared the variable, ExcelApp, in the General Declarations Section (at the top) of your module; and
Sorry in advance for the long post but I wanted to provide as much detail as possible.
Running Excel 2016 32-bit. We have a large macro enabled excel file (65+ MB) with ~8 queries to other reports run and placed in a server location, along with many calculations to generate a dashboard report of active projects. We have two VBScripts that run through task scheduler. The first opens and runs macros to refresh all queries, then refresh each pivot table, and finally resize some reporting tables to match the new size of the pivot table. The second copies four sheets to a new excel file, pastes as data, generates a PDF of two of those sheets, then attaches both the new excel and the PDF to an email sent via VB script. I’ll post as much of the codes as possible below.
All files are located on a server (‘ME Based Server’ in the codes below) and run locally on that server. The refresh script takes up to 15 minutes to run and the reporting script then takes ~ 4 minutes. This works without issue ~90% of the time.
The other 10% of the time, a few things may happen:
-
It may run successfully, but leave an instance of Excel open (probably in a non-responsive state) which is tying up more than 50% of the processing cores and ~490,000 KB of RAM.
-
It may run the refresh successfully, but fail on the report script which means we don’t receive the automated email and it leaves an instance of Excel open.
-
It may fail during the refresh and leave an instance of Excel open.
This is scheduled 4 times a day and if one fails then each new run will open a new instance of Excel which will also fail but tie up more of the servers resources.
We’re looking for advice to ensure that the instance of Excel closes even after failures to not bear down or overwork the server. Any advise will be greatly appreciated.
Refresh Code: Set objFSO = CreateObject(«Scripting.FileSystemObject») Set oShell = WScript.CreateObject(«WScript.Shell») On Error Resume Next Const DeleteReadOnly = True
strSourceFolder1 = "\'US Based Server'EngineeringDashboardReport"
strDestFolder1 = "\'ME Based Server'EngineeringDashboardReport"
Set colFiles1 = objFSO.GetFolder(strSourceFolder1)
For Each objFile1 In colFiles1.Files
If objNewestFile1 = "" Then
Set objNewestFile1 = objFile1
Else
If objNewestFile1.DateLastModified < objFile1.DateLastModified Then
Set objNewestFile1 = objFile1
End If
End If
Next
If Not objNewestFile1 Is Nothing Then
objFSO.DeleteFile(strDestFolder1 & "*.xlsx"), DeleteReadOnly
oShell.Run "xcopy.exe " & chr(34) & objNewestFile1 & chr(34) & " " & chr(34) & strDestFolder1 & chr(34) & " /R /Y"
End If
strSourceFolder2 = "\'US Based Server'EPT_BAH Revision Summary"
strDestFolder2 = "\'ME Based Server'EPT_BAH Revision Summary"
Set colFiles2 = objFSO.GetFolder(strSourceFolder2)
For Each objFile2 In colFiles2.Files
If objNewestFile2 = "" Then
Set objNewestFile2 = objFile2
Else
If objNewestFile2.DateLastModified < objFile2.DateLastModified Then
Set objNewestFile2 = objFile2
End If
End If
Next
If Not objNewestFile2 Is Nothing Then
objFSO.DeleteFile(strDestFolder2 & "*.xlsx"), DeleteReadOnly
oShell.Run "xcopy.exe " & chr(34) & objNewestFile2 & chr(34) & " " & chr(34) & strDestFolder2 & chr(34) & " /R /Y"
End If
strSourceFolder3 = "\'US Based Server'EPT_Weekly Forecast"
strDestFolder3 = "\'ME Based Server'EPT_Weekly Forecast"
Set colFiles3 = objFSO.GetFolder(strSourceFolder3)
For Each objFile3 In colFiles3.Files
If objNewestFile3 = "" Then
Set objNewestFile3 = objFile3
Else
If objNewestFile3.DateLastModified < objFile3.DateLastModified Then
Set objNewestFile3 = objFile3
End If
End If
Next
If Not objNewestFile3 Is Nothing Then
objFSO.DeleteFile(strDestFolder3 & "*.xlsx"), DeleteReadOnly
oShell.Run "xcopy.exe " & chr(34) & objNewestFile3 & chr(34) & " " & chr(34) & strDestFolder3 & chr(34) & " /R /Y"
End If
strSourceFolder4 = "\'US Based Server'ISO_Spool Summary"
strDestFolder4 = "\'ME Based Server'ISO_Spool Summary"
Set colFiles4 = objFSO.GetFolder(strSourceFolder4)
For Each objFile4 In colFiles4.Files
If objNewestFile4 = "" Then
Set objNewestFile4 = objFile4
Else
If objNewestFile4.DateLastModified < objFile4.DateLastModified Then
Set objNewestFile4 = objFile4
End If
End If
Next
If Not objNewestFile4 Is Nothing Then
objFSO.DeleteFile(strDestFolder4 & "*.xlsx"), DeleteReadOnly
oShell.Run "xcopy.exe " & chr(34) & objNewestFile4 & chr(34) & " " & chr(34) & strDestFolder4 & chr(34) & " /R /Y"
End If
Set objNewestFile1 = Nothing
Set objNewestFile2 = Nothing
Set objNewestFile3 = Nothing
Set objNewestFile4 = Nothing
MasterDB = "\'ME Based Server'BacklogTracker-BE.accdb"
StaticDB = "\'ME Based Server'Query Lookup DataBacklogTracker-BE.accdb"
objFSO.DeleteFile StaticDB
objFSO.CopyFile MasterDB, StaticDB
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = True
objExcel.ScreenUpdating = True
objExcel.DisplayAlerts = False
objExcel.AskToUpdateLinks = False
objExcel.AlertBeforeOverwriting = False
extension = "xlsm"
sourceDirectory = "\'ME Based Server'ENG PROD TRACKER"
BahBLTracker = "\'ME Based Server'Backlog Tracker Query.xlsm"
Set objWorkbook = objExcel.Workbooks.Open(BahBLTracker)
objExcel.Calculation = xlManual
objExcel.Run "'Backlog Tracker Query.xlsm'!RefreshAll.RefreshAll"
objWorkbook.Save
Set objWorkbook = Nothing
Set objFolder = objFSO.GetFolder(sourceDirectory)
For Each objFile In objFolder.Files
If LCase((objFSO.GetExtensionName(objFile))) = LCase(extension) Then
Filename = objFile.Name
Filename = sourceDirectory & "" & Filename
Set objWorkbook = objExcel.Workbooks.Open(Filename)
objExcel.Calculation = xlManual
RefreshAll = "'" & objFile.Name & "'!RefreshAll.RefreshAll"
ResizeTables = "'" & objFile.Name & "'!ResizeTables.ResizeTables"
objExcel.Run RefreshAll
objExcel.Run ResizeTables
objExcel.Calculation = xlAutomatic
objWorkbook.Save
End If
Next
objExcel.Calculation = xlAutomatic
objExcel.Quit
Set objWorkbook = Nothing
Set objFile = Nothing
Set objFolder = Nothing
Set objExcel = Nothing
Set oShell = Nothing
Set objFSO = Nothing
Reporting Code:
'~~~Copy from Query file to final Excel & PDF report~~~
Dim objExcel, objWbTemp, objWbFin
Dim tempFileName, sourceDirectory, extension, Filename, ReportFilename, PDFReportName
Dim objFSO, objFolder, objFile
On Error Resume Next
Const DeleteReadOnly = True
tempFileName = "\'ME Based Server'EngineeringReportingTemptemp.xlsm"
ReportFilename = "\'ME Based Server'EngineeringProductionTrackerENG PROD TRACKERReports to EmailEngineering Production Tracker " & Right("0" & DatePart("d", Now), 2) & " " & MonthName(Month(Now()),1) & " " & DatePart("YYYY", Now) & " Hour " & Right("0" & Hour(FormatDateTime(Now(),4)), 2) & " AST.xlsx"
Set objExcel = CreateObject("Excel.Application")
' objExcel.ScreenUpdating = False 'When active, causes error on line "NOTED" below
objExcel.Visible = True
objExcel.DisplayAlerts = False
extension = "xlsm"
sourceDirectory = "\'ME Based Server'EngineeringProductionTrackerENG PROD TRACKER"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(sourceDirectory)
objFSO.DeleteFile("\'ME Based Server'EngineeringProductionTrackerENG PROD TRACKERReports to Email*.xlsx"), DeleteReadOnly
objFSO.DeleteFile("\'ME Based Server'EngineeringProductionTrackerENG PROD TRACKERReports to Email*.pdf"), DeleteReadOnly
For Each objFile In objFolder.Files
If LCase((objFSO.GetExtensionName(objFile))) = LCase(extension) Then
Filename = objFile.Name
Filename = sourceDirectory & Filename
objFSO.CopyFile Filename, tempFileName
Set objWbTemp = objExcel.Workbooks.Open(tempFileName)
objWbTemp.Sheets("Engineering Tracker-SP").Select
objExcel.Cells.Select
objExcel.Selection.Copy
objExcel.Selection.PasteSpecial -4163 '-4163 is VBS code for paste values
objExcel.Range("C5").Select
objWbTemp.Sheets("Engineering Tracker-LP").Select
objExcel.Cells.Select
objExcel.Selection.Copy
objExcel.Selection.PasteSpecial -4163 '-4163 is VBS code for paste values
objExcel.Range("C5").Select
objWbTemp.Sheets("USENG@700NotOnHoldDetails").Select
objExcel.Cells.Select
objExcel.Selection.Copy
objExcel.Selection.PasteSpecial -4163 '-4163 is VBS code for paste values
objExcel.Range("A2").Select
objWbTemp.Sheets("USENGOnHoldDetails").Select
objExcel.Cells.Select
objExcel.Selection.Copy
objExcel.Selection.PasteSpecial -4163 '-4163 is VBS code for paste values
objExcel.Range("A2").Select
' Make final report Excel File
Set objWbFin = objExcel.Workbooks.Add()
objWbFin.SaveAs(ReportFilename)
objWbTemp.Sheets("Engineering Tracker-LP").Copy objWbFin.Sheets(objWbFin.Sheets.Count)
objWbTemp.Sheets("Engineering Tracker-SP").Copy objWbFin.Sheets(objWbFin.Sheets.Count)
objWbTemp.Sheets("USENG@700NotOnHoldDetails").Copy objWbFin.Sheets(objWbFin.Sheets.Count)
objWbTemp.Sheets("USENGOnHoldDetails").Copy objWbFin.Sheets(objWbFin.Sheets.Count)
objWbFin.Sheets("Sheet1").Delete
' Convert Summaries to PDF
objWbFin.Sheets(Array("Engineering Tracker-LP", "Engineering Tracker-SP")).Select
PDFReportName = Left(ReportFilename , InstrRev(ReportFilename , ".") - 1) & ".pdf"
objWbFin.ActiveSheet.ExportAsFixedFormat 0, PDFReportName, 0, 1, 0,,,0
objWbFin.Sheets("Engineering Tracker-LP").Select ' "NOTED" line that errors when ScreenUpdating = False
objExcel.Range("C5").Select
' Close and Cleanup
objWbFin.Close True
objWbTemp.Close False
objFSO.DeleteFile tempFileName
End If
Next
'~~> Close and Cleanup
objExcel.Quit
Set objWbFin = Nothing
Set objWbTemp = Nothing
Set objExcel = Nothing
Set objFSO = Nothing
Set objFolder = Nothing
Set objWMIService = Nothing
Set colItems = Nothing
'~~~Send Report file in email~~~
' Create link to CDOmail
Set objEmail = CreateObject("CDO.Message")
' Enter subject of message in quotes
objEmail.Subject = "Engineering Production Tracker " & Right("0" & DatePart("d", Now), 2) & " " & MonthName(Month(Now()),1) & " " & DatePart("YYYY", Now)
' Enter email address of sender within quotes ie
objEmail.From = "sender"
' Enter destination email address in quotes.
objEmail.To = "name"
objEmail.Cc = "names"
' This is the email body.
objEmail.HTMLBody = "This email contains the latest update to the Engineering Production Tracker Report.<hr />This is an automated email.<br />Replies to this address will not be received."
objEmail.AddAttachment ReportFilename 'NOTE: DO NOT USE AN "=" SIGN AFTER "AddAttachment"
objEmail.AddAttachment PDFReportName 'NOTE: DO NOT USE AN "=" SIGN AFTER "AddAttachment"
' Also note replace mail.mcdermott.com and Port 25 with whatever your SMTP Server is using. Port is TYPICALLY 25 but some providers use a custom port
objEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendusing") = #
objEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "domain"
objEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = #
objEmail.Configuration.Fields.Update
objEmail.Send
'Wscript.Echo "DONE"
'Wscript.Quit
RefreshAll VBA Macro:
Sub RefreshAll()
On Error Resume Next
ActiveWorkbook.RefreshAll
End Sub
ResizeTables VBA Macro:
Sub ResizeTables()
On Error Resume Next
Dim RowCount As Long, LastRow As Long
' Resize USONHOLD Table
RowCount = ThisWorkbook.Sheets("US ENG On Hold Details").Range("A4", ThisWorkbook.Sheets("US ENG On Hold Details").Range("A4").End(xlDown)).Rows.Count
LastRow = ThisWorkbook.Sheets("USENGOnHoldDetails").Range("A1", ThisWorkbook.Sheets("USENGOnHoldDetails").Range("A" & RowCount + 1).End(xlDown)).Rows.Count
ThisWorkbook.Sheets("USENGOnHoldDetails").Rows(3 & ":" & LastRow).Delete
ThisWorkbook.Sheets("USENGOnHoldDetails").ListObjects("USOnHold").Resize ThisWorkbook.Sheets("USENGOnHoldDetails").ListObjects("USOnHold").Range.Resize(RowCount - 1)
' Resize US700NOH Table
RowCount = ThisWorkbook.Sheets("US ENG @700 Not On Hold Details").Range("B4", ThisWorkbook.Sheets("US ENG @700 Not On Hold Details").Range("B4").End(xlDown)).Rows.Count
LastRow = ThisWorkbook.Sheets("USENG@700NotOnHoldDetails").Range("A1", ThisWorkbook.Sheets("USENG@700NotOnHoldDetails").Range("A" & RowCount + 1).End(xlDown)).Rows.Count
ThisWorkbook.Sheets("USENG@700NotOnHoldDetails").Rows(3 & ":" & LastRow).Delete
ThisWorkbook.Sheets("USENG@700NotOnHoldDetails").ListObjects("US700NOH").Resize ThisWorkbook.Sheets("USENG@700NotOnHoldDetails").ListObjects("US700NOH").Range.Resize(RowCount - 1)
ThisWorkbook.Sheets("Engineering Tracker-LP").Activate
End Sub
Fluff
MrExcel MVP, Moderator
-
#2
Move the Close line above where you set the variables to Nothing.
-
#3
Move the Close line above where you set the variables to Nothing.
Still the same unfortunatly
Fluff
MrExcel MVP, Moderator
-
#4
How about
VBA Code:
With xls
.Visible = False
ActiveWorkbook.Sheets("log").Range("A" & Rows.Count).End(xlUp).Offset(1).Resize(, 3) = Array(Me.txtProduct.Value, Me.txtQuantity.Value, Me.txtCountUp.Value)
wkb.Close True
xls.Quit
Set wks = Nothing
Set wkb = Nothing
Set xls = Nothing
End With
-
#5
Nope, Compile Error Expected Function Or Variable on the wkb.close D:
This is so frustrating for something that should be so easy!!
Fluff
MrExcel MVP, Moderator
-
#6
Not sure why you are getting that, as it works for me.
I very rarely use Access, so don’t know much about it.
RoryA
MrExcel MVP, Moderator
-
#7
You’re not properly qualifying the Excel objects, which is why you end up with orphaned processes running. Try this:
VBA Code:
Private Sub Export_Click()
Dim xls As Excel.Application
Dim wkb As Excel.Workbook
Dim wks As Excel.Worksheet
Set xls = CreateObject("Excel.Application")
Set wkb = xls.Workbooks.Open("c:usersxdesktoploggerlog.csv")
Set wks = wkb.Worksheets("log")
xls.Visible = False
wks.Range("A" & wks.Rows.Count).End(xlUp).Offset(1).Resize(, 3) = Array(Me.txtProduct.Value, Me.txtQuantity.Value, Me.txtCountUp.Value)
wbk.Close True
Set wks = Nothing
Set wkb = Nothing
Set xls = Nothing
End Sub
-
#8
You’re not properly qualifying the Excel objects, which is why you end up with orphaned processes running. Try this:
VBA Code:
Private Sub Export_Click() Dim xls As Excel.Application Dim wkb As Excel.Workbook Dim wks As Excel.Worksheet Set xls = CreateObject("Excel.Application") Set wkb = xls.Workbooks.Open("c:usersxdesktoploggerlog.csv") Set wks = wkb.Worksheets("log") xls.Visible = False wks.Range("A" & wks.Rows.Count).End(xlUp).Offset(1).Resize(, 3) = Array(Me.txtProduct.Value, Me.txtQuantity.Value, Me.txtCountUp.Value) wbk.Close True Set wks = Nothing Set wkb = Nothing Set xls = Nothing End Sub
Thanks for this, interestingly enough this now works, and runs each time, however it is still creating a Microsoft Excel process in the background, each time I click it it creates a new one, but it now does not error, so that’s progress haha.
Clicking the button 5 times = 5 seperate Excel processes running
RoryA
MrExcel MVP, Moderator
-
#9
Oops — you’re missing a line that looks like:
-
#10
Oops — you’re missing a line that looks like:
I was just about to say, managed to figure that out myself, works perfectly, thank you very much my dude!
-
#1
Okay, this one is driving me bananas.
I have a driver procedure that is supposed to call a number of sub-procedures, then close the spreadsheet I was importing from and quit Excel.
Here is the code. Please excuse the mess, it’s still under development, so this isn’t my final code by any means.
Code:
Private Sub cmdImportCase_Click()
Dim CaseData As Collection
Dim ValCheck As clsFieldData
On Error GoTo ErrHandler
If Not CaseData Is Nothing Then Set CaseData = Nothing
Set CaseData = New Collection
HeaderRow = GetDBOption("ArchiveImport_HeaderRow", otNumber, dbeBackEnd)
CurrentDb.Execute "DELETE * FROM tblArchiveCaseStaging", dbSeeChanges + dbFailOnError
CurrentDb.Execute "DELETE * FROM tblArchiveClaimStaging", dbSeeChanges + dbFailOnError
[COLOR=seagreen]'Open the source file and assign values to xlApp, xlWorkBook, and xlWorkSheet.[/COLOR]
If OpenImportFile() Then
[COLOR=seagreen]'Verify the format of the source file.[/COLOR]
If (VerifyCaseRows() And VerifyColumnNames()) Then
[COLOR=seagreen]'The data file has been found and opened. Import and stage the CASE information.[/COLOR]
If ImportHeader(CaseData) Then
If ImportClaimData() Then
MsgBox "Import Complete."
End If
End If
Else
Beep
ShowMsg "The source file is formatted incorrectly." & vbCrLf & vbCrLf & _
"If you feel you have received this message in error, please contact PIU App Support.", _
"INVALID FILE FORMAT", _
"VALIDATION FAILURE", _
mbCritical
End If
End If
Me.RecordSource = "tblArchiveCaseStaging"
Call ToggleVisibility(True)
If Me.txtFileNumber.Visible Then Me.txtFileNumber.SetFocus
ProcExit:
On Error Resume Next
If Not xlWorkSheet Is Nothing Then Set xlWorkSheet = Nothing
If Not xlWorkBook Is Nothing Then
xlWorkBook.Close SaveChanges:=False
Set xlWorkBook = Nothing
End If
If Not xlApp Is Nothing Then
xlApp.Quit
Set xlApp = Nothing
End If
Exit Sub
ErrHandler:
Trap.Handle Me.Name, "cmdImportCase_Click"
Resume ProcExit
End Sub
The Excel variable declarations are module-level:
Code:
[COLOR=seagreen]'Early bound - FOR DEVELOPMENT ONLY[/COLOR]
Dim xlApp As Excel.Application
Dim xlWorkBook As Excel.Workbook
Dim xlWorkSheet As Excel.Worksheet
[COLOR=seagreen]'Late bound - FOR RELEASE VERSIONS
'Dim xlApp As Object
'Dim xlWorkBook As Object
'Dim xlWorkSheet As Object[/COLOR]
The objects themselves are assigned in OpenImportFile. There is some extra stuff, but the actual assignments are pretty standard:
Code:
[COLOR=seagreen]'Open a new session of Excel and then open the workbook.[/COLOR]
Set xlApp = CreateObject("Excel.Application")
[COLOR=seagreen]'Open the indicated workbook and worksheet[/COLOR]
Set xlWorkBook = xlApp.Workbooks.Open(FileName:=SourceFilePath)
Set xlWorkSheet = xlWorkBook.Sheets("INPUT FILE")
(I’m deliberately opening a new instance of Excel instead of using any existing one specifically so I can hide the workbook and close it when I’m done, since this is a straight validation and data import.)
So here is the situation:
While the cleanup in ProcExit works perfectly if the user has no other instances of Excel open, if they already have any open, then this code opens the spreadsheet being imported in a new, visible instance of Excel, then leaves it open rather than closing it out. Stepping through the cleanup code in ProcExit shows that every line is being executed; they just aren’t DOING anything.
Any thoughts on why this is acting like this or how to fix that would be most appreciated.
-
#2
Also, I’ve checked with it Resume Next turned off, and no errors are being suppressed by it.
JHB
Have been here a while
-
#3
I would also comment that out:
What happen if you only have xlApp.Quit in ProcExit:.
-
#4
It’s not throwing any errors at all, even after removing all error handling. I’ve stepped through the entire procedure, and everything works, except for closing out. It just outright ignores the Workbook.Close and Excel.Quit commands. Doesn’t even throw any errors on them — it just process them and does nothing.
It appears to be something about saving changes — I’ve changed the workbook assignment to include ReadOnly:=True and the issue went away.
I don’t know what precisely was causing it or how to fix it if I ever need to change a workbook and then import something (I tested with Workbook.Close SaveChanges:=True and the behavior never changed), but for now, I’ll take what I can get. I would love to know WHY it was showing the workbook and refusing to close out, though, even if I DID find a work-around.
Oh, nearly forgot:
What happen if you only have xlApp.Quit in ProcExit:.
Absolutely no changes. The workbook appears, Excel stays open, and no errors are thrown.
Last edited: Jun 6, 2018
-
#5
Interestingly, unless I use that ReadOnly:=True, about 5 seconds after the procedure terminates, a pop-up appears in Excel saying ‘ArchiveTest.xlsx is now available for editing. Chose Read-Write to open it for editing.’ with a Read-Write and a Cancel button.