Reputation: 121
I have written a VBA program which creates, on Workbook_Open
, a file stream that writes errors to an error log. If I run into a fatal error (and therefore need to halt execution of the macro), the program executes an End
statement, abruptly halting the macro. I know that this solution is not an ideal one, but I can't see a better way to end things quickly if I'm several functions deep (i.e., one function has called another which has called yet another, and the third function produces the error). Exiting the function in which the error occurred will only affect that particular function, leading to the possibility of invalid data, unexpected cell values, etc.
But this approach leads me to another problem -- when End
executes it destroys all of my objects, including the error stream. So when the user does something new and runs across a fatal error, they get a VBA runtime error (91: Object ... not set) because the code writes to the file stream that's now set to Nothing.
Is there a better way to end the macro (and thus avoid unexpected behaviour after an error) without losing all of my objects? The official VBA documentation is of no help. Thanks in advance.
Upvotes: 2
Views: 2616
Reputation: 14053
End:
Terminates execution immediately. Never required by itself but may be placed anywhere in a procedure to end code execution, close files opened with the Open statement and to clear variables. When executed, the End statement resets all module-level variables and all static local variables in all modules.
ThisWorkbook module:
Public fileSystem As FileSystemObject
Public errorStream As TextStream
Private Sub Workbook_Open()
Set fileSystem = New FileSystemObject
Set errorStream = fileSystem.CreateTextFile("c:\temp\error.log", True)
End Sub
Standard module:
Public Sub First()
If (Not ThisWorkbook.errorStream Is Nothing) Then
Debug.Print VBA.TypeName(ThisWorkbook.errorStream)
End If
End
' Exit Sub
End Sub
Public Sub Second()
If (Not ThisWorkbook.errorStream Is Nothing) Then
Debug.Print VBA.TypeName(ThisWorkbook.errorStream)
End If
End Sub
When 'First' method executes first with 'End' in it and then 'Second' method, then errorStream will be Nothing. Instaead of 'End' use 'ExitSub', then the variable will not be reset.
Or you could make error-stream variable private in Thisworkbook class module and add property, which will create the stream if the variable is Nothing. HTH
ThisWorkbook module:
Private m_errorStream As TextStream
Private Const FILE_PATH_NAME As String = "c:\temp\error.log"
Public Property Get ErrorStream() As TextStream
If (m_errorStream Is Nothing) Then
Dim fileSystem As FileSystemObject
Set fileSystem = New FileSystemObject
If (fileSystem.FileExists(FILE_PATH_NAME)) Then
Set m_errorStream = fileSystem.GetFile(FILE_PATH_NAME).OpenAsTextStream
Else
Set m_errorStream = fileSystem.CreateTextFile(FILE_PATH_NAME, False)
End If
End If
Set ErrorStream = m_errorStream
End Property
Standard module:
Public Sub First()
If (Not ThisWorkbook.ErrorStream Is Nothing) Then
Debug.Print VBA.TypeName(ThisWorkbook.ErrorStream)
End If
End
End Sub
Public Sub Second()
If (Not ThisWorkbook.ErrorStream Is Nothing) Then
Debug.Print VBA.TypeName(ThisWorkbook.ErrorStream)
End If
End Sub
Upvotes: 3
Reputation: 15923
use a top level error handler, and only trap errors in routines you want to handle without aborting completely
Demo:
Option Explicit
Sub test()
On Error GoTo Top_Error_Handler
Debug.Print "Error handled in sub routine: test1"
test1
Debug.Print "Error NOT handled in sub routine: test2"
test2
Exit Sub
Top_Error_Handler:
MsgBox "Top Level Error Handler: Error Number:" & Err.Number _
& ":" & Err.Description
End Sub
Sub test1()
On Error Resume Next
Debug.Print 1 / 0
End Sub
Sub test2()
Debug.Print 1 / 0
End Sub
As you can see, the error handling in test1
overrides the handling in the main program, so no error is raised. In the second Sub, test2
, there is no error handling, so the information is passed up to the previous program to handle (and it will pass it up the chain, if that program was called by something else), and the error can be cleanly handled by your main routine to close everything tidily.
Upvotes: 0
Reputation: 394
Maybe try Exit
instead of End
?
If you are trying to exit from a function
Function a()
If blahblah.. Then
Exit Function
End If
End Function
I am unsure of how your objects are declared and handled on what modules so... if you can post the code, it may help greatly.
Upvotes: 0
Reputation: 417
Declare your variables on the module-level, not in the function. In VBA, you see the various sheets on the Project navigation on the left by default. Below the sheets is a folder called "Modules": if you don't see a "Module1" or variant as a child of this folder, right-click the folder and select "Insert\Module."
These should be persistent for you.
Upvotes: 0