Handle with Error on excel vba - vba

I can't figure out how to handle the error raised in my macro.
Through an application.Vlookup I search for a value. The problem is, if that value doesn't exist macro stops.
I tried a On Error Resume Next which works fine, but I would like to tell the user the value doesn't exist.
Private Sub CommandButton1_Click()
Dim Num As Double
Dim Cle As Integer
Dim Dpt As String
Dim Age As Integer
Dim Essaidate As String
Dim CommNaiss As String
Dim NumOrdre As String
Dim Reg As String
'Initialisons la date du jour
CeJour = Date
Num = TextBox1.Text
Cle = 97 - (Num - (Int(Num / 97) * 97))
If Cle < 10 Then
Label2.Caption = "0" & Cle
Else
Label2.Caption = Cle
End If
If Mid(TextBox1.Text, 1, 1) = "1" Then
Label4.Caption = "Masculin"
Else
Label4.Caption = "Féminin"
End If
Essaidate = "1" & "/" & Mid(TextBox1, 4, 2) & "/" & "19" & Mid(TextBox1, 2, 2)
'MsgBox ("La date de naissance (sans le jour) de cette personne est :" & Essaidate)
Dpt = Application.VLookup(Mid(TextBox1.Text, 6, 2), Range("M1:N96"), 2, False)
Label6.Caption = Dpt & " (" & Mid(TextBox1.Text, 6, 2) & ")"
Reg = Application.VLookup(Mid(TextBox1.Text, 6, 2), Range("M1:O96"), 3, False)
Label15.Caption = Reg
'On Error Resume Next
CommNaiss = Application.VLookup(CLng(Mid(TextBox1.Text, 6, 5)), Range("AV1:AW36529"), 2, False) 'That's the line I get an error if value does't exist....

I would use a GoTo ErrorHandler:, have a MsgBox, then resume next.
On Error GoTo ErrorHandler
ErrorHandler:
MsgBox "Value does not exist"
Resume Next

Tim's answer - using an error handler is best but if you want to use on error resume next then you can use IsError:
On Error Resume Next
CommNaiss = Application.VLookup(CLng(Mid(TextBox1.Text, 6, 5)), Range("AV1:AW36529"), 2, False)
if IsError(CommNaiss) then msgbox("value not found")
On Error Goto 0 ' remember to turn on error resume next off again

here follow two possible ways
1) "On Error..." way
On Error Resume Next
Dpt = Application.VLookup(Mid(TextBox1.Text, 6, 2), Range("M1:N96"), 2, False)
On Error GoTo 0
If Dpt = "" Then
MsgBox "Value : " & Mid(TextBox1.Text, 6, 2) & " not found in Range(""M1:N96"")"
Else
Label6.Caption = Dpt & " (" & Mid(TextBox1.Text, 6, 2) & ")"
End If
2) "Find" way
Dim found As Range
Set found = Range("M1:M96").Find(What:=Mid(TextBox1.Text, 6, 2), LookIn:=xlValues, LookAt:=xlWhole)
If found Is Nothing Then
MsgBox "Value : " & Mid(TextBox1.Text, 6, 2) & " not found in Range(""M1:N96"")"
Else
Label6.Caption = Dpt & " (" & Mid(TextBox1.Text, 6, 2) & ")"
End If
and the same for Reg

This any good? -
CommNaiss = Application.WorksheetFunction.IfError( _
Application.WorksheetFunction.VLookup(CLng(Mid(TextBox1.Text, 6, 5)) _
, Range("AV1:AW36529"), 2, False), "Error")

No need to add On-Error-GoTo because the VLookup function doesn't throw error but it returns it. Try to declare the variable Dpt as Variant and check with IsError if the VLookup returned an error.
Sub test()
Dim Dpt As Variant
Dpt = Application.VLookup("searched-text", Range("A1:C3"), 2, False)
If IsError(Dpt) Then
MsgBox "Error '" & DecodeError(Dpt) & "' occured.", vbCritical
End If
End Sub
Here an example of function which will decode the error number returned by VLookup to string with description.
Private Function DecodeError(ByVal error As Variant) As String
On Error Resume Next
Select Case CLng(error)
Case xlErrDiv0
DecodeError = "#DIV/0!"
Case xlErrNA
DecodeError = "#N/A"
Case xlErrName
DecodeError = "#NAME?"
Case xlErrNull
DecodeError = "#NULL!"
Case xlErrNum
DecodeError = "#NUM!"
Case xlErrRef
DecodeError = "#REF!"
Case xlErrValue
DecodeError = "#VALUE!"
Case Else
DecodeError = "Unknown error"
End Select
End Function

Related

450 Wrong number of arguments or invalid property assignment

I have a macro that uses Tiny Term Emulator and connects to the session and enters user ID and password to login. I am having issues because for some reason its not loading the defualt keyboard and it fails on the line below and when I check my dbug spreadsheet in my vBA macro it gives the error of Wrong number of arguments or invalid property assignment. The line thats bolded is where the macro fails. Can someone please review and assist
Public Sub ShellExecuteTinyTerm(Optional ByVal iForeGround As Integer = 1, _
Optional ByVal iBackGround As Integer = 8)
'Declarations
Dim lKeyBoard As Long
Dim lErr As Long, sErr As String
Const sSource As String = "ShellExecuteTinyTerm()"
On Error GoTo ErrorHandler
StackTrace msModule, sSource
'Call Trap(msModule & " " & sSource, "This proc/func has been trapped")
'Code Start:
If (iBackGround < 0) Or (iBackGround > 8) Then
Err.Raise MDEBUG_Framework.glHANDLED_ERROR, msModule & " " & sSource, ""
End If
If Not gFrmTE.teIBS.IsConnected Then
With gFrmTE.teIBS
.Node = msHOST_NAME
.NetPort = miTELNET_PORT
'
.ConnectionType = miTELNET_CONNECTION
.Emulation = 18
.AutoLogin = miAUTOLOGIN_OFF
.DuplexMode = 0
**lKeyBoard = .LoadKeyboard("C:\\Program Files\\Century\\TinyTERM\\keyboard.dat", "Default.keyboard")**
'
.WindowsLookandFeel = True
'Basic
.SetFGColor 0, iForeGround
.SetBGColor 0, iBackGround
'Reverse
.SetFGColor 1, iForeGround
.SetBGColor 1, iBackGround
'Underlined.
.SetFGColor 3, iForeGround
.SetBGColor 3, iBackGround
.RevDim (1)
'Cursor
.CursorType = 0
.SetFGColor 2, iForeGround
.SetBGColor 2, iBackGround
.SetFGColor 5, iForeGround
.SetBGColor 5, iBackGround
.DestructiveBackspace = False
.connect
End With
End If
If gFrmTE.Visible = False Then
gFrmTE.Show vbModeless
End If
Set MGEN_Globals.gTTEScreen = gFrmTE.teIBS
Finished:
Exit Sub
ErrorHandler:
lErr = Err.Number
sErr = Err.Description
If gbDebug_Mode Then
DebugPrint msModule & " " & sSource, lErr & " " & sErr
Stop
Resume
Else
'Error Cleanup
DebugPrint msModule & " " & sSource, lErr & " " & sErr
Err.Raise lErr, msModule & " " & sSource, sErr
End If
End Sub

VBA get a value in brackets from a cell and check if it is available in other sheet

I am trying to get a specific cell value in brackets and check if this value is in other sheet. This is the column with the possible values:
StrS Format
HEADER
NOBREAK
IGNORE
REPEATABLE …-n can be up to 100
I want to split the string in the cell, check if its value is one of the above, if it is equal with "REPEATABLE" extract the following block specifications: . If is not defined in “BY Variables” show error. This is a similar issue with this one:
VBA-Count and collect every found match in regular expression -again have to get values with brackets
Here is my code:
Public Function IsItGood(aWord As Variant) As Boolean
Dim s As String
s = "|" '-means or
'tmp = s & aWord & s
tmp = Replace(s & aWord & s, ",", "")
patern = ""
patern = patern & "HEADER|NOBREAK|REPEATABLE" & s
If InStr(1, patern, tmp) > 0 Then
IsItGood = True
Else
IsItGood = False
End If
End Function
Function check_cell_values()
On Error Resume Next
Application.EnableEvents = False
Dim msg As String
msg = ""
Dim arr As Variant
Dim a As Variant
arr = Split(Target, " ")
For Each a In arr
If Target.Column = 10 And (Target.Row > 2 And Target.Row <= 308) Then
If IsItGood(a) Then
msg = msg & vbCrLf & (" In cell" + Target.Address(0, 0)) & vbCrLf & a & vbCrLf + "is ok"
Else
msg = msg & vbCrLf & (" In cell" + Target.Address(0, 0)) & vbCrLf & a & vbCrLf + "is invalid value"
Application.Undo
End If
End If
Next a
If msg <> "" Then MsgBox msg
check_cell_values = msg
End Function
Sub by_blocks_check()
Application.EnableEvents = False
Dim func1
func1 = check_cell_values()
End Sub
I think instead of a regular expression it is better to use an array from the possible values but I don`t know how to get the value after "Repeatable".
Example output:

Object variable or with block variable not set, with my On Error GoTo

So I have code that loops through every row on one sheet (DataWS) and uses other sheets to find strings, if the strings are not found then I want the code to go to wherever the On Error tells it to. So if the part is not found on a worksheet, then go to (somewhere).
If the strings are found on a worksheet then the DataWS is updated or the found variable is used later on in the code to reference the row it was found on in the other sheets.
Sub MM011_to_Data()
Dim Dlr As Long, Dlc As Long, x As Long
Dim DataWS As String, MMWS As String, OmitWS As String
On Error GoTo DataSheetInvalid
Sheets("Data").Activate
DataWS = Sheets("Data").Name
On Error GoTo 0
On Error GoTo MM011SheetInvalid
MMWS = Sheets("MM011").Name
On Error GoTo 0
On Error GoTo OmitSheetInvalid
OmitWS = Sheets("Omit Parts").Name
On Error GoTo 0
'********************BELOW ARE VARIABLES IN THE DATA SHEET********************
Dim DStatuscol As Integer, DSupplySourcecol As Integer, DPOcol As Integer, DPOIcol As Integer, DPRcol As Integer
Dim DPLOcol As Integer, DWillShipcol As Integer, DSOLIcol As Integer, DRelPNcol As Integer
DStatuscol = Sheets(DataWS).Rows(1).Find("Status", lookat:=xlWhole).Column
DSupplySourcecol = Sheets(DataWS).Rows(1).Find("Supply Source", lookat:=xlWhole).Column
DPOcol = Sheets(DataWS).Rows(1).Find("PO#", lookat:=xlWhole).Column
DPOIcol = Sheets(DataWS).Rows(1).Find("PO Item", lookat:=xlWhole).Column
DPRcol = Sheets(DataWS).Rows(1).Find("PR#", lookat:=xlWhole).Column
DPLOcol = Sheets(DataWS).Rows(1).Find("PLO", lookat:=xlWhole).Column
DWillShipcol = Sheets(DataWS).Rows(1).Find("Will Ship", lookat:=xlWhole).Column
DSOLIcol = Sheets(DataWS).Rows(1).Find("CC SO/LI", lookat:=xlWhole).Column
DRelPNcol = Sheets(DataWS).Rows(1).Find("RELEASED PN", lookat:=xlWhole).Column
'********************BELOW ARE VARIABLES IN THE MM011 SHEET********************
Dim MMSupplySourcecol As Integer, MMInvcol As Integer, MMPOcol As Integer, MMPOIcol As Integer, MMPLOcol As Integer, MMPRcol As Integer
Dim MMPOShipDatecol As Integer, MMStatuscol As Integer, MMPNConcatcol As Integer
MMPNConcatcol = Sheets(MMWS).Rows(1).Find("PN Concatenate", lookat:=xlWhole).Column
MMSupplySourcecol = Sheets(MMWS).Rows(1).Find("Supply Source", lookat:=xlWhole).Column
MMInvcol = Sheets(MMWS).Rows(1).Find("Inventory Qty", lookat:=xlWhole).Column
MMPOcol = Sheets(MMWS).Rows(1).Find("PO Number", lookat:=xlWhole).Column
MMPOIcol = Sheets(MMWS).Rows(1).Find("PO Item", lookat:=xlWhole).Column
MMPLOcol = Sheets(MMWS).Rows(1).Find("Supply Work Order", lookat:=xlWhole).Column
MMPRcol = Sheets(MMWS).Rows(1).Find("Requisition Number", lookat:=xlWhole).Column
MMPOShipDatecol = Sheets(MMWS).Rows(1).Find("Supply Delivery Calendar Date", lookat:=xlWhole).Column
'********************BELOW ARE THE VARIABLES IN THE OMIT SHEET********************
Dim OPNcol As Integer, OPNrow As Long
OPNcol = Sheets(OmitWS).Rows(1).Find("Part Number", lookat:=xlWhole).Column
'********************LOOP TO UPDATE THE DATA SHEET********************
Dim DConcatPNSO As String, MMConcatrow As String
Dim SupplySource As String, PO_Number As String, PO_Item As String, PLO_WO As String, Requisition_Number As String, Supply_Del_Date As String
Dim DPartNumber As String
Dlr = Sheets(DataWS).Cells(Rows.Count, 1).End(xlUp).Row
Dlc = Sheets(DataWS).Cells(1, Columns.Count).End(xlToLeft).Column
For x = 2 To Dlr
'DConcatPNSO is the variable for the Data WS which concatenates the Released PN and the SO LI
DConcatPNSO = Sheets(DataWS).Cells(x, DRelPNcol) & " " & Sheets(DataWS).Cells(x, DSOLIcol)
DPartNumber = Sheets(DataWS).Cells(x, DRelPNcol)
'If there is no sales order then skip and say no sales order (NSO)
If Sheets(DataWS).Cells(x, DSOLIcol) = "" Then
Sheets(DataWS).Cells(x, DSupplySourcecol) = "NSO"
GoTo Updated
End If
'Checks to see if the part is on the Omit list
On Error GoTo NotOmit
OPNrow = Sheets(OmitWS).Columns(OPNcol).Find(What:=DPartNumber, lookat:=xlWhole).Row
On Error GoTo 0
If OPNrow > 0 Then
Cells(x, DSupplySourcecol) = "Omit"
GoTo Updated
End If
NotOmit:
On Error GoTo PN_SO_NotFound
MMConcatrow = Sheets(MMWS).Columns(MMPNConcatcol).Find(DConcatPNSO, lookat:=xlWhole).Row
On Error GoTo 0
'Hold all of the info from cells into variables
SupplySource = Sheets(MMWS).Cells(MMConcatrow, MMSupplySourcecol)
PO_Number = Sheets(MMWS).Cells(MMConcatrow, MMPOcol)
PO_Item = Sheets(MMWS).Cells(MMConcatrow, MMPOIcol)
PLO_WO = Sheets(MMWS).Cells(MMConcatrow, MMPLOcol)
Requisition_Number = Sheets(MMWS).Cells(MMConcatrow, MMPRcol)
Supply_Del_Date = Format(Sheets(MMWS).Cells(MMConcatrow, MMPOShipDatecol), "MM/DD/YYYY")
'If the Supply Source is PO then do the below
If SupplySource = "PO" Then
Sheets(DataWS).Cells(x, DStatuscol) = SupplySource & " " & Sheets(MMWS).Cells(MMConcatrow, MMPOcol) _
& " " & Sheets(MMWS).Cells(MMConcatrow, MMPOIcol) & " " & Format(Sheets(MMWS).Cells(MMConcatrow, MMPOShipDatecol), "MM/DD/YYYY")
Sheets(DataWS).Cells(x, DSupplySourcecol) = SupplySource
Sheets(DataWS).Cells(x, DPOcol) = Sheets(MMWS).Cells(MMConcatrow, MMPOcol)
Sheets(DataWS).Cells(x, DPOIcol) = Sheets(MMWS).Cells(MMConcatrow, MMPOIcol)
Sheets(DataWS).Cells(x, DWillShipcol) = Format(Sheets(MMWS).Cells(MMConcatrow, MMPOShipDatecol), "MM/DD/YYYY")
GoTo Updated
End If
'If the Supply Source is PLO then do the below
If SupplySource = "PLO" Then
Sheets(DataWS).Cells(x, DStatuscol) = SupplySource & " " & Sheets(MMWS).Cells(MMConcatrow, MMPLOcol)
Sheets(DataWS).Cells(x, DSupplySourcecol) = SupplySource
Sheets(DataWS).Cells(x, DPLOcol) = Sheets(MMWS).Cells(MMConcatrow, MMPLOcol)
GoTo Updated
End If
'If the Supply Source is PR then do the below
If SupplySource = "PR" Then
Sheets(DataWS).Cells(x, DStatuscol) = SupplySource & " " & Sheets(MMWS).Cells(MMConcatrow, MMPRcol)
Sheets(DataWS).Cells(x, DSupplySourcecol) = SupplySource
Sheets(DataWS).Cells(x, DPRcol) = Sheets(MMWS).Cells(MMConcatrow, MMPRcol)
GoTo Updated
End If
'If the Supply Source is BPL then do the below
If SupplySource = "BPL" Then
Sheets(DataWS).Cells(x, DStatuscol) = SupplySource & " " & "Borrow Payback Loan"
Sheets(DataWS).Cells(x, DSupplySourcecol) = SupplySource
GoTo Updated
End If
'If the Supply Source is QA then do the below
If SupplySource = "QA" Then
Sheets(DataWS).Cells(x, DStatuscol) = SupplySource & ", PO is " & Sheets(MMWS).Cells(MMConcatrow, MMPOcol) _
& " " & Sheets(MMWS).Cells(MMConcatrow, MMPOIcol) & " " & Format(Sheets(MMWS).Cells(MMConcatrow, MMPOShipDatecol), "MM/DD/YYYY")
Sheets(DataWS).Cells(x, DSupplySourcecol) = SupplySource
Sheets(DataWS).Cells(x, DPRcol) = Sheets(MMWS).Cells(MMConcatrow, MMPRcol)
GoTo Updated
End If
Updated:
Next x
Exit Sub
'****************ERROR HANDLING****************
DataSheetInvalid:
MsgBox "The worksheet with the MS2 All Open Order Report should be titled ""Data""." & vbCr & vbCr & "Please rename the worksheet and restart this sub.", vbCritical, "Worksheet Name"
Exit Sub
MM011SheetInvalid:
MsgBox "The worksheet with Cognos (MM011) data should be titled ""MM011""." & vbCr & vbCr & "Please rename the worksheet and restart this sub.", vbCritical, "Worksheet Name"
Exit Sub
OmitSheetInvalid:
MsgBox "The worksheet with Omit Parts data should be titled ""Omit Parts""." & vbCr & vbCr & "Please rename the worksheet and restart this sub.", vbCritical, "Worksheet Name"
Exit Sub
PN_SO_NotFound:
Sheets(DataWS).Cells(x, DSupplySourcecol) = "N/A"
GoTo Updated
End Sub
So within this code, the part that keeps getting the Run-Time Error is either one of these On Error handlers:
'Checks to see if the part is on the Omit list
On Error GoTo NotOmit
OPNrow = Sheets(OmitWS).Columns(OPNcol).Find(What:=DPartNumber, lookat:=xlWhole).Row
On Error GoTo 0
If OPNrow > 0 Then
Cells(x, DSupplySourcecol) = "Omit"
GoTo Updated
End If
NotOmit:
On Error GoTo PN_SO_NotFound
MMConcatrow = Sheets(MMWS).Columns(MMPNConcatcol).Find(DConcatPNSO, lookat:=xlWhole).Row
On Error GoTo 0
On the first loop they both work, but when it comes to any loop afterwards, I get the error.
To fix these errors I used this code:
Set OPNrng = Sheets(OmitWS).Columns(OPNcol).Find(What:=DPartNumber, lookat:=xlWhole)
If OPNrng Is Nothing Then
GoTo NotOmit
Else
OPNrow = OPNrng.Row
End If
If OPNrow > 0 Then
Cells(x, DSupplySourcecol) = "Omit"
GoTo Updated
End If
NotOmit:
Set MMConcatrng = Sheets(MMWS).Columns(MMPNConcatcol).Find(DConcatPNSO, lookat:=xlWhole)
If MMConcatrng Is Nothing Then
GoTo PN_SO_NotFound
Else
MMConcatrow = MMConcatrng.Row
End If
Is there a reason why the "On Error GoTo" syntax was not working?? I cannot figure out why.
Also, is there a better way to do it besides what I have??
If I can explain anything else further please let me know, I tried to give you the whole picture as well as the code separated out where I am having these issues.
PN_SO_NotFound:
Sheets(DataWS).Cells(x, DSupplySourcecol) = "N/A"
GoTo Updated
This. You're in an error-handling subroutine - the VBA runtime is in an error state, and you're GoTo-jumping all over the place.
When execution goes to the Updated label after hitting PN_SO_NotFound, VBA is still in an error state because you never reset it. So as far as it understands your code, the Updated label is just another part of your error-handling subroutine.
And while it thinks it's still handling a runtime error, it's not going to heed any On Error statements it encounters, because it's already in an error state.
Replace GoTo Updated with Resume Updated and, well, honestly, fingers crossed, it should "work".
But definitely consider some SERIOUS refactoring here. Spaghetti code like this isn't getting any easier to debug anytime soon without a serious series of refactorings: you'll know you're done when there's a grand total of 0 GoTo jumps and all procedures fit into a single screen, each doing one single thing.
Instead of using only On Error GoTo 0 use the combination of On Error GoTo 0 : On Error Goto -1 to reset both the exception handler and the error state.

VBA Error Handle - Resume and print error

I'm trying to build an structure like this below.
where I have a loop and sometimes one of the loop steps can return error but I want to skip it and continue loop till the end.
But if any of the loops execution had error I want to know it printing in a cell something like "Missing loads: ( 1 ,20 ,36)" Where this number are unique values that one of my variables on the loop receive.
So I think every time one of my loop executions return error I need to build a list of this variable value and at the end of the loop process use this list to return this error msg.
UPDATE:
For the below I want to know the list of any eventual "sProdId" value that was in the SQL query wen it fail to execute by ANY error. Usually it try to insert #Value in a numeric SQL field.
Sub SavetoSQL()
Dim conn As New ADODB.Connection
Dim iRowNo As Integer
Dim Ddate
Ddate = Range("refdate")
Dim RngRefdate As Date
RngRefdate = DateSerial(Year(Ddate), Month(Ddate), Day(Ddate))
With Sheets("Hist Prods temp")
'Open a connection to SQL Server
conn.Open "Provider=SQLOLEDB;Data Source=XXXXX;Initial Catalog=XXXXXX;User Id=XXXX;Password=XXXXXXX;"
'Skip the header row
iRowNo = 2
'Loop until empty cell in sRefDate
Do Until .Cells(iRowNo, 1) = ""
sRefDate = .Cells(iRowNo, 1)
sProdId = .Cells(iRowNo, 2)
sPrice = .Cells(iRowNo, 3)
sValue = .Cells(iRowNo, 4)
sDV01 = .Cells(iRowNo, 5)
sDelta1 = .Cells(iRowNo, 6)
sDeltaPct = .Cells(iRowNo, 7)
sGamma = .Cells(iRowNo, 8)
sVega = .Cells(iRowNo, 9)
sTheta = .Cells(iRowNo, 10)
sDelta2 = .Cells(iRowNo, 11)
sIVol = .Cells(iRowNo, 12)
'Generate and execute sql statement to import the excel rows to SQL Server table
conn.Execute "INSERT INTO [dbo].[Prices] ([Date],[Id_Product],[Price],[Value],[DV01],[Delta1$],[Delta%],[Gamma$],[Vega$],[Theta$],[Delta2$],[Ivol],[Last_Update]) values ('" & sRefDate & "', '" & sProdId & "'," & sPrice & "," & sValue & "," & sDV01 & "," & sDelta1 & "," & sDeltaPct & "," & sGamma & "," & sVega & "," & sTheta & "," & sDelta2 & "," & sIVol & ",GETDATE())"
iRowNo = iRowNo + 1
Loop
conn.Close
Set conn = Nothing
End With
End Sub
Well you are a bit confused about Error Handling in VBA, have a look into Chip's website on proper Error Handling in VBA.
Your code should be something like,
Sub MyMacro()
On Error GoTo Errhandler
Dim errLog As String
Do Until
' My loop code
'Save variable X value in a list of error values.
Loop
ExitErrHandler:
If Len(errLog) > 0 Then
Range("M2") = "Missing loads: (" & Left(errLog, Len(errLog) - 2) & ")"
End If
Exit Sub
Errhandler:
'Make a Note of the Error Number and substitute it with 1234
If Err.Number = 1234 Then
' If an error occurs, display a message in a cell with all X values on the list.
errLog = errLog & yourUniqueValue & ", "
Resume Next
Else
MsgBox "Another Error occurred." & vbCrLf & vbCrLf & Err.Number & " - " & Err.Description
Resume ExitErrHandler
End If
End Sub
Your code makes no sense because you are turning off error handling (On Error GoTo 0) before you ever get to the loop code that would throw the error.
Here is one way to do it. I have my error handler inside the loop. It appends the x value to a string. Because x = x + 1 is in the error handler you don't have to worry about x not incrementing when you get an error. If you only care about certain Err.Number values, then change the if statement in my error handler. At the end of the code I print the error message to cell A1 of Sheet2 if and only if the error message string has at least one value. Otherwise I reset that output cell. On Error GoTo -1 is important to reset the error handler.
Sub MyMacro()
Dim x As Integer
Dim errMsg As String
Dim outWs As Worksheet
Set outWs = ThisWorkbook.Worksheets("Sheet1")
errMsg = ""
On Error GoTo CurrRecFail
x = 1
Do Until x = 15
' My loop code
CurrRecFail:
If Err.Number > 0 Then
errMsg = errMsg & x & ", "
End If
On Error GoTo -1
x = x + 1
Loop
If Len(errMsg) > 0 Then
outWs.Cells(1, 1).Value = "Missing Loads: " & Left(errMsg, Len(errMsg) - 2)
Else
outWs.Cells(1, 1).Value = ""
End If
End Sub
The code above will jump to the next loop iteration when it hits an error. If you wish instead to proceed through the rest of the lines in the current loop iteration, change On Error GoTo CurrRecFail to On Error Resume Next and delete the line CurrRecFail: which is now a meaningless label.

Automatically generating handling of issues

This is more an observation than a real question: MS-Access (and VBA in general) is desperately missing a tool where error handling code can be generated automatically, and where the line number can be displayed when an error occurs. Did you find a solution? What is it? I just realized how many hundreds of hours I spared since I found the right answer to this basic problem a few years ago, and I'd like to see what are your ideas and solutions on this very important issue.
What about using "Erl", it will display the last label before the error (e.g., 10, 20, or 30)?
Private Sub mySUB()
On Error GoTo Err_mySUB
10:
Dim stDocName As String
Dim stLinkCriteria As String
20:
stDocName = "MyDoc"
30:
DoCmd.openform stDocName, acFormDS, , stLinkCriteria
Exit_mySUB:
Exit Sub
Err_mySUB:
MsgBox Err.Number & ": " & Err.Description & " (" & Erl & ")"
Resume Exit_mySUB
End Sub
My solution is the following:
install MZ-Tools, a very interesting add-on for VBA. No they did not pay me to write this. Version 3 was free, but since version 8.0, the add-in is commercially sold.
program a standard error handler code such as this one (see MZ-Tools menu/Options/Error handler):
On Error GoTo {PROCEDURE_NAME}_Error
{PROCEDURE_BODY}
On Error GoTo 0
Exit {PROCEDURE_TYPE}
{PROCEDURE_NAME}_Error:
debug.print "#" & Err.Number, Err.description, "l#" & erl, "{PROCEDURE_NAME}", "{MODULE_NAME}"
This standard error code can be then automatically added to all of your procs and function by clicking on the corresponding button in the MZ-Tools menu. You'll notice that we refer here to a hidden and undocumented function in the VBA standard library, 'Erl', which stands for 'error line'. You got it! If you ask MZ-Tools to automatically number your lines of code, 'Erl' will then give you the number of the line where the error occured. You will have a complete description of the error in your immediate window, such as:
#91, Object variable or With block variable not set, l# 30, addNewField, Utilities
Of course, once you realize the interest of the system, you can think of a more sophisticated error handler, that will not only display the data in the debug window but will also:
display it as a message on the screen
Automatically insert a line in an error log file with the description of the error or
if you are working with Access or if you are connected to a database, automatically add a record to a Tbl_Error table!
meaning that each error generated at the user level can be stored either in a file or a table, somewhere on the machine or the network. Are we talking about building an automated error reporting system working with VBA?
Well there are a couple of tools that will do what you ask MZ Tools and FMS Inc come to mind.
Basically they involve adding an:
On Error GoTo ErrorHandler
to the top of each proc
and at the end they put an:
ErrorHandler:
Call MyErrorhandler Err.Number, Err.Description, Err.LineNumber
label with usually a call to a global error handler where you can display and log custom error messages
You can always roll your own tool like Chip Pearson did. VBA can actually access it's own IDE via the Microsoft Visual Basic for Applications Extensibility 5.3 Library. I've written a few class modules that make it easier to work with myself. They can be found on Code Review SE.
I use it to insert On Error GoTo ErrHandler statements and the appropriate labels and constants related to my error handling schema. I also use it to sync up the constants with the actual procedure names (if the function names should happen to change).
There is no need to buy tools DJ mentioned. Here is my code for free:
Public Sub InsertErrHandling(modName As String)
Dim Component As Object
Dim Name As String
Dim Kind As Long
Dim FirstLine As Long
Dim ProcLinesCount As Long
Dim Declaration As String
Dim ProcedureType As String
Dim Index As Long, i As Long
Dim LastLine As Long
Dim StartLines As Collection, LastLines As Collection, ProcNames As Collection, ProcedureTypes As Collection
Dim gotoErr As Boolean
Kind = 0
Set StartLines = New Collection
Set LastLines = New Collection
Set ProcNames = New Collection
Set ProcedureTypes = New Collection
Set Component = Application.VBE.ActiveVBProject.VBComponents(modName)
With Component.CodeModule
' Remove empty lines on the end of the code
For i = .CountOfLines To 1 Step -1
If Component.CodeModule.Lines(i, 1) = "" Then
Component.CodeModule.DeleteLines i, 1
Else
Exit For
End If
Next i
Index = .CountOfDeclarationLines + 1
Do While Index < .CountOfLines
gotoErr = False
Name = .ProcOfLine(Index, Kind)
FirstLine = .ProcBodyLine(Name, Kind)
ProcLinesCount = .ProcCountLines(Name, Kind)
Declaration = Trim(.Lines(FirstLine, 1))
LastLine = FirstLine + ProcLinesCount - 2
If InStr(1, Declaration, "Function ", vbBinaryCompare) > 0 Then
ProcedureType = "Function"
Else
ProcedureType = "Sub"
End If
Debug.Print Component.Name & "." & Name, "First: " & FirstLine, "Lines:" & ProcLinesCount, "Last: " & LastLine, Declaration
Debug.Print "Declaration: " & Component.CodeModule.Lines(FirstLine, 1), FirstLine
Debug.Print "Closing Proc: " & Component.CodeModule.Lines(LastLine, 1), LastLine
' do not insert error handling if there is one already:
For i = FirstLine To LastLine Step 1
If Component.CodeModule.Lines(i, 1) Like "*On Error*" Then
gotoErr = True
Exit For
End If
Next i
If Not gotoErr Then
StartLines.Add FirstLine
LastLines.Add LastLine
ProcNames.Add Name
ProcedureTypes.Add ProcedureType
End If
Index = FirstLine + ProcLinesCount + 1
Loop
For i = LastLines.Count To 1 Step -1
If Not (Component.CodeModule.Lines(StartLines.Item(i) + 1, 1) Like "*On Error GoTo *") Then
Component.CodeModule.InsertLines LastLines.Item(i), "ExitProc_:"
Component.CodeModule.InsertLines LastLines.Item(i) + 1, " Exit " & ProcedureTypes.Item(i)
Component.CodeModule.InsertLines LastLines.Item(i) + 2, "ErrHandler_:"
Component.CodeModule.InsertLines LastLines.Item(i) + 3, " Call LogError(Err, Me.Name, """ & ProcNames.Item(i) & """)"
Component.CodeModule.InsertLines LastLines.Item(i) + 4, " Resume ExitProc_"
Component.CodeModule.InsertLines LastLines.Item(i) + 5, " Resume ' use for debugging"
Component.CodeModule.InsertLines StartLines.Item(i) + 1, " On Error GoTo ErrHandler_"
End If
Next i
End With
End Sub
Put it in a module and call it from Immediate Window every time you add new function or sub to a form or module like this (Form1 is name of your form):
MyModule.InsertErrHandling "Form_Form1"
It will alter your ode in Form1 from this:
Private Function CloseIt()
DoCmd.Close acForm, Me.Name
End Function
to this:
Private Function CloseIt()
On Error GoTo ErrHandler_
DoCmd.Close acForm, Me.Name
ExitProc_:
Exit Function
ErrHandler_:
Call LogError(Err, Me.Name, "CloseIt")
Resume ExitProc_
Resume ' use for debugging
End Function
Create now in a module a Sub which will display the error dialog and where you can add inserting the error to a text file or database:
Public Sub LogError(ByVal objError As ErrObject, moduleName As String, Optional procName As String = "")
On Error GoTo ErrHandler_
Dim sql As String
MsgBox "Error " & Err.Number & " Module " & moduleName & Switch(procName <> "", " in " & procName) & vbCrLf & " (" & Err.Description & ") ", vbCritical
Exit_:
Exit Sub
ErrHandler_:
MsgBox "Error in LogError procedure " & Err.Number & ", " & Err.Description
Resume Exit_
Resume ' use for debugging
End Sub
This code does not enter error handling if there is already "On Error" statement in a proc.
Love it Vlado!
I realize this is an old post, but I grabbed it and gave it a try, but I ran into a number of issues with it, which I managed to fix. Here's the code with fixes:
First of course, be sure to add the "Microsoft Visual Basic for Applications Extensibility 5.3" library to your project, and add these subroutines / modules to your project as well.
First, the module with the main code was named "modVBAChecks", and contained the following two subroutines:
To go through all modules (behind forms, sheets, the workbook, and classes as well, though not ActiveX Designers):
Sub AddErrorHandlingToAllProcs()
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent
Dim lCtr As Long
StartNewWorksheetLog
Set VBProj = Workbooks("LabViewAnalysisTools.xla").VBProject
For Each VBComp In VBProj.VBComponents
If VBComp.Type <> vbext_ct_ActiveXDesigner Then
If VBComp.Name <> "modVBAChecks" And VBComp.Name <> "modLogToWorksheet" Then
AddToWksLog "============ Looking at Module """ & VBComp.Name & """"
'InsertErrHandling VBComp.Name
AddToWksLog
AddToWksLog
End If
End If
Next
MsgBox "Done!", vbSystemModal
End Sub
Then the modified version of your code (including a suggested change by
Rafał B.):
Public Sub InsertErrHandling(modsProcName As String)
' Modified from code submitted to StackOverflow by user Vlado, originally found
' here: https://stackoverflow.com/questions/357822/automatically-generating-handling-of-issues
Dim vbcmA As VBIDE.CodeModule
Dim ProcKind As VBIDE.vbext_ProcKind
Dim LineProcKind As VBIDE.vbext_ProcKind
Dim sProcName As String
Dim sLineProcName As String
Dim lFirstLine As Long
Dim lProcLinesCount As Long
Dim lLastLine As Long
Dim sDeclaration As String
Dim sProcType As String
Dim lLine As Long, lLine2 As Long
Dim sLine As String
Dim lcStartLines As Collection, lcLastlines As Collection, scProcsProcNames As Collection, scProcTypes As Collection
Dim bAddHandler As Boolean
Dim lLinesAbove As Long
Set lcStartLines = New Collection
Set lcLastlines = New Collection
Set scProcsProcNames = New Collection
Set scProcTypes = New Collection
Set vbcmA = Application.VBE.ActiveVBProject.VBComponents(modsProcName).CodeModule
' Remove empty lines on the end of the module. Cleanup, not error handling.
lLine = vbcmA.CountOfLines
If lLine = 0 Then Exit Sub ' Nothing to do!
Do
If Trim(vbcmA.Lines(lLine, 1)) <> "" Then Exit Do
vbcmA.DeleteLines lLine, 1
lLine = lLine - 1
Loop
lLine = vbcmA.CountOfDeclarationLines + 1
Do While lLine < vbcmA.CountOfLines
bAddHandler = False
' NOTE: ProcKind is RETRUNED from ProcOfLine!
sProcName = vbcmA.ProcOfLine(lLine, ProcKind)
' Fortunately ProcBodyLine ALWAYS returns the first line of the procedure declaration!
lFirstLine = vbcmA.ProcBodyLine(sProcName, ProcKind)
sDeclaration = Trim(vbcmA.Lines(lFirstLine, 1))
Select Case ProcKind
Case VBIDE.vbext_ProcKind.vbext_pk_Proc
If sDeclaration Like "*Function *" Then
sProcType = "Function"
ElseIf sDeclaration Like "*Sub *" Then
sProcType = "Sub"
End If
Case VBIDE.vbext_ProcKind.vbext_pk_Get, VBIDE.vbext_ProcKind.vbext_pk_Let, VBIDE.vbext_ProcKind.vbext_pk_Set
sProcType = "Property"
End Select
' The "lProcLinesCount" function will sometimes return ROWS ABOVE
' the procedure, possibly up until the prior procedure,
' and often rows BELOW the procedure as well!!!
lProcLinesCount = vbcmA.ProcCountLines(sProcName, ProcKind)
lLinesAbove = 0
lLine2 = lFirstLine - 1
If lLine2 > 0 Then
Do
sLineProcName = vbcmA.ProcOfLine(lLine2, LineProcKind)
If Not (sLineProcName = sProcName And LineProcKind = ProcKind) Then Exit Do
lLinesAbove = lLinesAbove + 1
lLine2 = lLine2 - 1
If lLine2 = 0 Then Exit Do
Loop
End If
lLastLine = lFirstLine + lProcLinesCount - lLinesAbove - 1
' Now need to trim off any follower lines!
Do
sLine = Trim(vbcmA.Lines(lLastLine, 1))
If sLine = "End " & sProcType Or sLine Like "End " & sProcType & " '*" Then Exit Do
lLastLine = lLastLine - 1
Loop
AddToWksLog modsProcName & "." & sProcName, "First: " & lFirstLine, "Lines:" & lProcLinesCount, "Last: " & lLastLine
AddToWksLog "sDeclaration: " & vbcmA.Lines(lFirstLine, 1), lFirstLine
AddToWksLog "Closing Proc: " & vbcmA.Lines(lLastLine, 1), lLastLine
If lLastLine - lFirstLine < 8 Then
AddToWksLog " --------------- Too Short to bother!"
Else
bAddHandler = True
' do not insert error handling if there is one already:
For lLine2 = lFirstLine To lLastLine Step 1
If vbcmA.Lines(lLine2, 1) Like "*On Error GoTo *" And Not vbcmA.Lines(lLine2, 1) Like "*On Error GoTo 0" Then
bAddHandler = False
Exit For
End If
Next lLine2
If bAddHandler Then
lcStartLines.Add lFirstLine
lcLastlines.Add lLastLine
scProcsProcNames.Add sProcName
scProcTypes.Add sProcType
End If
End If
AddToWksLog
lLine = lFirstLine + lProcLinesCount + 1
Loop
For lLine = lcLastlines.Count To 1 Step -1
vbcmA.InsertLines lcLastlines.Item(lLine), "ExitProc:"
vbcmA.InsertLines lcLastlines.Item(lLine) + 1, " Exit " & scProcTypes.Item(lLine)
vbcmA.InsertLines lcLastlines.Item(lLine) + 2, "ErrHandler:"
vbcmA.InsertLines lcLastlines.Item(lLine) + 3, " ShowErrorMsg Err, """ & scProcsProcNames.Item(lLine) & """, """ & modsProcName & """"
vbcmA.InsertLines lcLastlines.Item(lLine) + 4, " Resume ExitProc"
' Now replace any "On Error Goto 0" lines with "IF ErrorTrapping Then On Error Goto ErrHandler"
For lLine2 = lcStartLines(lLine) To lcLastlines(lLine)
sLine = vbcmA.Lines(lLine2, 1)
If sLine Like "On Error GoTo 0" Then
vbcmA.ReplaceLine lLine2, Replace(sLine, "On Error Goto 0", "IF ErrorTrapping Then On Error Goto ErrHandler")
End If
Next
lLine2 = lcStartLines.Item(lLine)
Do
sLine = vbcmA.Lines(lLine2, 1)
If Not sLine Like "* _" Then Exit Do
lLine2 = lLine2 + 1
Loop
vbcmA.InsertLines lLine2 + 1, " If ErrorTrapping Then On Error GoTo ErrHandler"
Next lLine
End Sub
And rather than pushing things to the Immediate window I used subroutines in a module I named "modLogToWorksheet", the full module being here:
Option Explicit
Private wksLog As Worksheet
Private lRow As Long
Public Sub StartNewWorksheetLog()
Dim bNewSheet As Boolean
bNewSheet = True
If ActiveSheet.Type = xlWorksheet Then
Set wksLog = ActiveSheet
bNewSheet = Not (wksLog.UsedRange.Cells.Count = 1 And wksLog.Range("A1").Formula = "")
End If
If bNewSheet Then Set wksLog = ActiveWorkbook.Worksheets.Add
lRow = 1
End Sub
Public Sub AddToWksLog(ParamArray sMsg() As Variant)
Dim lCol As Long
If wksLog Is Nothing Or lRow = 0 Then StartNewWorksheetLog
If Not (IsNull(sMsg)) Then
For lCol = 0 To UBound(sMsg)
If sMsg(lCol) <> "" Then wksLog.Cells(lRow, lCol + 1).Value = "'" & sMsg(lCol)
Next
End If
lRow = lRow + 1
End Sub
And finally, here's my Error Dialog generator:
Public Sub ShowErrorMsg(errThis As ErrObject, strSubName As String, strModName As String _
, Optional vbMBStyle As VbMsgBoxStyle = vbCritical, Optional sTitle As String = APP_TITLE)
If errThis.Number <> 0 Then
MsgBox "An Error Has Occurred in the Add-in. Please inform " & ADMINS & " of this problem." _
& vbCrLf & vbCrLf _
& "Error #: " & errThis.Number & vbCrLf _
& "Description: " & " " & errThis.Description & vbCrLf _
& "Subroutine: " & " " & strSubName & vbCrLf _
& "Module: " & " " & strModName & vbCrLf _
& "Source: " & " " & errThis.Source & vbCrLf & vbCrLf _
& "Click OK to continue.", vbMBStyle Or vbSystemModal, sTitle
End If
End Sub
Hope future users find it useful!