Exit the main sub if a called sub calls `Exit Sub` - excel

I have a sub that calls another sub and most often I need to exit the called sub and stop executing the rest of the sub that called it.
So I have the sub Add_Format_Button_Click that calls another sub:
call CheckEmptyComboboxValues
And most often CheckEmptyComboboxValues will end up on
Exit sub
But the Add_Format_Button_Click will continue executing the rest of it. This is where I need help because when CheckEmptyComboboxValues exits, I need the Add_Format_Button_Click to also exit.
Could someone help me solve this, seemingly simple problem?
EDIT: CheckEmptyComboboxValues contains tens if not hundreds of if statements that follow the structure of:
If Format_Layout.FilmType.Value = "" Then
MsgBox "Specify a film type!", , ("Film Type"): Exit sub
End If
So I guess I need to turn that exit sub value into something I can check in the main sub with an if statement like
if CheckEmptyComboboxValues .value = "Exit sub" Then
exit sub

3 solutions, each of them works for your case. I would go with the first or last solution. Depends a bit on the design of the rest of your project:
1. Function
Function CheckEmptyComboboxValues() As Boolean
If AnythingOddHappens Then
Exit Function
End If
CheckEmptyComboboxValues = True
End Function
The result of this function is only True if it runs through the end, whenever you exit it before it is False
Sub Example()
If Not CheckEmptyComboboxValues Then Exit Sub
'instead of
'Call CheckEmptyComboboxValues
End Sub
2. Procedure with cancel
Sub CheckEmptyComboboxValues(ByRef Cancel As Boolean)
If AnythingOddHappens Then
Cancel = True
Exit Sub
End If
End Sub
Sub Example()
Dim Cancel As Boolean
Call CheckEmptyComboboxValues(Cancel)
If Cancel Then Exit Sub
End Sub
This can be used, but here I see no advantage and would prefer the function above. This method can be useful if you already have a function with a return value and want an additional cancel or in case you write code for an event.
3. Throw an error
Sub CheckEmptyComboboxValues()
If AnythingOddHappens Then
Err.Raise vbObjectError + 513, "CheckEmptyComboboxValues", "Something odd happened"
Exit Sub
End If
End Sub
Sub Example()
On Error Goto ERR_HANDLER
Call CheckEmptyComboboxValues
Exit Sub
ERR_HANDLER:
MsgBox "check failed"
End Sub
This can be an advantage if you have multiple check procedures/functions that can throw errors. Compared with the first or second solution where you need to check the result of each single check procedure/function this solution needs only one error handler, and threfore comes with slim code.
This also has the advantage that the check procedure now can return different type of errors that your calling sub can use to provide further assistance to the user. While the first 2 solutions are more like "It didn't pass the check" the last solution can provide more detailed information like "It didn't pass the check because of A/B/C happened" depending on which error was raised.
Sub CheckEmptyComboboxValues()
If AnythingOddHappens Then
Err.Raise vbObjectError + 513, "CheckEmptyComboboxValues", "Something odd happened"
Exit Sub
End If
' more code here …
If AnythingDifferentOddHappens Then
Err.Raise vbObjectError + 514, "CheckEmptyComboboxValues", "Something different odd happened"
Exit Sub
End If
End Sub
Now you can use the different error numbers to provide a more detailde infomation to the user about what went wrong and not just something went wrong.
Sub Example()
On Error Goto ERR_HANDLER
Call CheckEmptyComboboxValues
Exit Sub
ERR_HANDLER: 'possibility to give a more detailed information
Select Case Err.Number
Case vbObjectError + 513
MsgBox "check A failed"
Case vbObjectError + 514
MsgBox "check B failed"
Case Else
MsgBox "Undefined fail"
End Select
End Sub

Rewrite CheckEmptyComboboxValues to a function which returns a boolean. In Add_Format_Button_Click you can then write
if CheckEmptyComboboxValues then
' You could give a message
Exit Sub
else
' rest of the code of
' Add_Format_Button_Click
end if
CheckEmptyComboboxValues might look like that
Function CheckEmptyComboboxValues as boolean
' code goes here
if .... then
CheckEmptyComboboxValues = False
exit function
else
' other code
end if
CheckEmptyComboboxValues = True
End Function
Update based on the edit
Function CheckEmptyComboboxValues() As Boolean
' ....
If Format_Layout.FilmType.Value = "" Then
MsgBox "Specify a film type!", , ("Film Type")
CheckEmptyComboboxValues = True
Exit Function
End If
' ....
CheckEmptyComboboxValues = False
End Function

Related

Continue loop sub1 to sub 3 in VBA

Couldn't find this question on StackOverflow, so my apologies when not searched well enough...
I have the following code (simplified)
Sub Task_1()
"copy stuff from sheet2 to sheet1"
End Sub
Sub Task_2()
"Print sheet1"
End Sub
Sub Task_3()
"Do ordernumber +1"
End Sub
Now I want to loop this. So after sub Task_3, I want to call Task_1 again untill a certain cell is empty. I have the following, but not sure what to put into the questionmark.
Sub Start_orderprint()
Call Task_1
Call Task_2
Call Task_3
If Sheet1.Range("A4").Value <> Empty
Then ?????
Else
msgbox "Finished"
exit sub
End if
End sub
A Do...Loop to Run Procedures
Do...Loop statement
Using Do...Loop statements
But be careful because this may end up being an endless loop (if it never becomes Empty).
Option Explicit
Sub Start_orderprint()
Do Until Sheet1.Range("A4").Value = Empty
' Or
'Do While Sheet1.Range("A4").Value <> Empty
Task_1
Task_2
Task_3
Loop
MsgBox "Finished"
End Sub
In the previous example, if the value is initially Empty, the loop will never be entered. If you want to enter it once, no matter what, you will have to use the following:
Sub Start_orderprint()
Do
Task_1
Task_2
Task_3
Loop Until Sheet1.Range("A4").Value = Empty
' Or
'Loop While Sheet1.Range("A4").Value <> Empty
MsgBox "Finished"
End Sub

Code is getting into errorhandler even when the task is done without errors

I use a workbook that copy information from others workbooks, using the following Code:
Sub importarbens()
On Error GoTo ErrorHandler
{...}
ErrorHandler:
Workbooks(nomearq2).Close
MsgBox "Arquivo Incompatível"
Exit Sub
End Sub
But apparently my code always get in the ErrorHandler, even when the code runs withouth erros and after the task is done. The message in message box appears
When I disable the errorhandler the code works well
You need to add Exit Sub:
Sub importarbens()
On Error GoTo ErrorHandler
{...}
Exit Sub '<< end of the "happy path" for your code....
ErrorHandler:
Workbooks(nomearq2).Close
MsgBox "Arquivo Incompatível"
Exit Sub '<< Don't really need this since you're already
' at the end of the sub
End Sub

Macro to run when file is protected

I did macro that creates a graph but need to make the file password protected.
Of course, when I protect the file, the macro will stop working.
I inserted the below into my code to unprotect the file, run the code, then protect the file again. As I the code is a function, I had to create two sub procedures, which is maybe the reason why the trick is not functioning.
Any idea how I can fix this?
Option Explicit
Sub protection()
Worksheets("Sheet1").Unprotect "abc123"
End Sub
Function (here is my function code)
End Function
Sub protection2()
Worksheets("Sheet1").protect "abc123"
End Sub
I guess you want to start one sub procedure to do the trick. My example unprotects your sheet, let the function do its magic and protects the sheet.
Option Explicit
Sub protection()
Worksheets("Sheet1").Unprotect "abc123"
Call Function (here may be values for your arguments)
Worksheets("Sheet1").protect "abc123"
End Sub
Function (here may be prameters)
the function code belongs here
End Function
On a protected sheet you can't changed cells which are locked. You may wan't to play around with the attached code:
Option Explicit
Sub SheetSetup()
Range("B3:C7").Locked = False
Range("E3:F7").Locked = True 'This is default
End Sub
Sub Sample_ProtectedSheet()
ClearValues
ChangeAllValues_on_ProtectedSheet
MsgBox ("Only values in ""B4:C7"" are set to ""yes""!")
End Sub
Sub Sample_UnprotectedSheet()
ClearValues
ChangeAllValues_on_UnprotectedSheet
MsgBox ("All values set to ""yes""!")
End Sub
Function ChangeAllValues_on_UnprotectedSheet()
Call Unprotect
On Error Resume Next
Range("B4:C7").Value = "yes"
Range("E4:F7").Value = "yes"
On Error GoTo 0
End Function
Function ClearValues()
Call Unprotect
On Error Resume Next
Range("B4:C7").Value = ""
Range("E4:F7").Value = ""
On Error GoTo 0
End Function
Function ChangeAllValues_on_ProtectedSheet()
Call Protect
On Error Resume Next
Range("B4:C7").Value = "yes"
Range("E4:C7").Value = "yes"
On Error GoTo 0
End Function
Sub Protect()
Worksheets("Sheet1").Protect "abc123"
End Sub
Sub Unprotect()
Worksheets("Sheet1").Unprotect "abc123"
End Sub

Error Handling in Excel VBA Outside of Sub

I know my title is a bit confusing, but this is the problem I have. I basically have one sheet that functions as a wrapper of sorts. It has the ability to run a multitude of macros sequentially, which is done through a Userform. Basically, you check the box, if it's checked, it runs the macro. What I'm trying to do is, if there is an error, I want it to return either what sub it was in.
My first idea was in my if statement for the checkboxes that run the subs to put an On Error statement, but that didn't work, since the error handling goes to the sub that is called and ignores what is before it.
What should I do? Is this possible?
You could do something like this:
Sub ErrorHandler()
On Error GoTo ErrHandler
Call Proc1
Call Proc2
Call Proc3
Exit Sub
ErrHandler:
MsgBox Err.Source & vbCrLf & Err.Description
End Sub
Sub Proc1()
On Error GoTo ErrHandler
' Your code block start
' Your code block end
Exit Sub
ErrHandler:
Err.Raise 513, "Proc1", "Customer Error Message 1|" & Err.Description
End Sub
Sub Proc2()
On Error GoTo ErrHandler
' Your code block start
' Your code block end
Exit Sub
ErrHandler:
Err.Raise 513, "Proc2", "Customer Error Message 2|" & Err.Description
End Sub
Sub Proc3()
On Error GoTo ErrHandler
' Your code block start
' Your code block end
Exit Sub
ErrHandler:
Err.Raise 513, "Proc3", "Customer Error Message 3|" & Err.Description
End Sub

How to manage the no error case when handling errors in VBA? [duplicate]

This question already has answers here:
Why VBA goes to error handling code when there is no error?
(5 answers)
Closed last year.
I need to catch some VBA errors using the GoTo statement:
Sub mySub
On Error GoTo errorHandler:
Workbooks.Open("myWorkbook")
'
' Some Code
'
errorHandler:
MsgBox "ERROR"
End Sub
The problem is that when there is no error the errorHandler section is executed.
I found this discussion but the answer doesn't solve my issue.
I tried adding an Exit Sub statement as explained :
Sub mySub
On Error GoTo errorHandler:
Workbooks.Open("myWorkbook")
Exit Sub
'
' Some Code
'
errorHandler:
MsgBox "ERROR"
End Sub
In this case it exits the method when there is no error.
I also tried :
Sub mySub
On Error GoTo errorHandler:
Workbooks.Open("myWorkbook")
'
' Some Code
'
errorHandler:
MsgBox "ERROR"
Exit Sub
End Sub
But still the same issue: The errorHandler is executed even when no errors occur.
Just put Exit sub in.
Sub mySub
On Error GoTo myHandler:
Workbooks.Open("myWorkbook")
'
' Some Code
'
Exit sub
myHandler:
MsgBox "EROOR !"
err.clear
End Sub
Here's the pattern I prefer:
Sub SomeSub()
On Error GoTo ErrorLabel
'Code goes here
ExitLabel:
'Clean-up code, if any, goes here
Exit Sub
ErrorLabel:
'Error-handling code goes here
Resume ExitLabel
End Sub
Note that Resume clears the error. I like this pattern for a few reasons:
Habitually inserting the exit block before the error-handling block reduces the chance that I'll have the OP's problem of accidentally dropping into the error handler.
I use GoTo ExitLabel for any early exit from the Sub or Function. This way, I'm less likely to skip the clean-up code by accident. Example:
Sub SomeOtherSub()
Dim x As ResourceThatNeedsToBeClosed
Dim i As Long
On Error GoTo ErrorLabel
Set x = GetX
For i = 1 To 100
If x.SomeFunction(i) Then
GoTo ExitLabel
End If
Next
ExitLabel:
x.Close
ErrorLabel:
'Error-handling code goes here
Resume ExitLabel
End Sub
Public Sub MySub
On Error Goto Skip
' Some Codes
Skip:
If err.Number > 0 Then
' Run whatever codes if error occurs
err.Clear
End If
On Error Goto 0
End Su
I am having the exact same issue as you, and the solutions above did not work. They clearly didn't even see you wrote Exit Sub in already in 2 different places in your original post. No site online seems to understand that sometimes there won't be an error (if there was always going to be an error, why did you code it that way?), and when there isn't an error, you obviously don't want to Exit Sub. Nor do you want the myHandler to run when there isn't an error. DUH! This is the solution I cam up with which seems to work.
On Error GoTo ErrorHandler
'This is the thing I am trying to do...
Workbooks("SpreadSolver.xlsb").Activate
'If it works, great.
'Don't touch the error stuff and move on.
'I.e. go to the part that I know works (the rest of the macro)
GoTo ThisPartWorks
'If the thing I am trying to do doesn't work...
ErrorHandler:
MsgBox "Error: Please open Spread Solver and then run the macro."
'Only want to Exit Sub if there is an error.. duh.
Exit Sub
ThisPartWorks:
'the rest of your macro can go here...
'...
End Sub
I use an If statement, within the ErrorHandler, which will stop execution if there is no error. This is achieved by using the Err.Number (Err (object) number (e.g. Run-time error 9: Subscript out of range))
If Err.Number >= 1 Then
MsgBox ("Message")
End
Else: other code
End If
Exit Sub
This is what I have done. Works like a charm
Sub someProgram ()
On Error goto Handler:
x = 7/0
'Some code you wanna execute with or without error
Exit Sub
Handler:
'Write your handler here
Resume next 'After handling error, this line will help you resume the next line
End sub
Use below code in error handler section:
if err.number>0 the
' error handling goes here
else
' some code
end if
sub XYZ ()
on error goto label
"Write your macro"
Label:
If Err.Description <> "" Then
"your code if error occurs for eg:"
msgbox "Error Occured!"
Exit Sub
Else
"Your code when no error occurs for eg"
msgbox " Done."
End If
Exit Sub

Resources