What is the proper way to use ErrHandler and Resume Next - vba

This is a project I inherited. I noticed that sometimes it doesn't log errors.
This routine raises an error so that it can log it along with the rest of the message.
But it never returns to the error point and actually logs the error.
I can see what it is supposed to do, but I can't see how to get it to work.
Public Sub PostErrorToLog(lngErrID As Long, strContext As String, Optional strEvent As String)
On Error GoTo ErrHandler:
Dim strErrEvent As String
Dim rst As New ADODB.Recordset
Dim pass As Integer
pass = 0
'Capture event description by triggering the error.
Err.Raise lngErrID ' It gets to here, then jumps
'Use AddNew because SQL may be added into strEvent, causing objSQL.RunADO() to fail.
Set rst = objSQL.GetRST("PostErrorToLog()", "[System Log]", , , adCmdTable)
rst.AddNew ' Never gets here.
rst![UID] = strCurrUID
rst![ErrorID] = lngErrID
rst![Source] = strContext
rst![Event] = ConcatenateStrings(strErrEvent, strEvent, " ")
rst.Update
rst.Close
FlushLog "Error"
Exit Sub
ErrHandler:
strErrEvent = Err.Description
pass = pass + 1
If pass > 2 Then ' Seems like pass is always going to be 1
Resume Next
End If ' It gets to here and exits the routine.
End Sub

Related

Stumbling Block Inventor iProperty doesn't exist

I should start out with this is my first attempt at a vba user form.
I Have some simple code to fill a user form (pulling from Inventor Custom iProperties) the problem I am running into and made a false assumption (that if the property didn't exist it would be ignored) so now I get an error. oProSet1 & oProSet2 work perfectly (Those iProperties will always have a value) oProSet3 Throws an error, I am guessing because the "Setup Time" property doesn't exist & Isn't required (in this case). The code asterisks is my attempt and fail to use an if statement.
Private Sub CommandButton2_Click()
' Get the active document.
Dim oDoc As Document
Set oDoc = ThisApplication.ActiveDocument
' Get the custom property set.
Dim oPropSet As PropertySet
Set oPropSet = oDoc.PropertySets.Item( _
"Inventor User Defined Properties")
Dim oPropSet1 As Property
Set oPropSet1 = oPropSet("Operation 1 Work Center 1")
' Set the value of the property.
TextBox1.Value = oPropSet1.Value
Dim oPropSet2 As Property
Set oPropSet2 = oPropSet("Operation 1 Machine Code 1")
' Set the value of the property.
TextBox2.Value = oPropSet2.Value
*Dim oPropSet3 As Property
Set oPropSet3 = oPropSet("Operation 1 Setup Time 1")
If oPropSet3("Operation 1 Setup Time 1") Is Nothing Then
' Set the value of the property.
oPropSet3.Value = ""
Else TextBox3.Value = oPropSet3.Value*
I would try like this:
Dim oPropSet3 As Property
On Error Resume Next 'ignore error if missing
Set oPropSet3 = oPropSet("Operation 1 Setup Time 1")
On Error Goto 0 'stop ignoring errors
If oPropSet3 Is Nothing Then
Debug.Print "Property not found"
Else
Debug.Print oPropSet3.Value
End If

VBA - Unable to map drive to sharepoint on another computer

I'm mapping to the company's sharepoint drive using VBA. The intention is to save local file to sharepoint, and delete local file and unmapped the drive after success.
On my machine(Windows 10 64bits), the code works perfectly fine, successfully mapped the drive, created folder and file, successfully uploaded to sharepoint and unmap the drive.
However, when I run the same excel workbook that contains the same code on my colleague's computer(Window 7), it failed. There's no error being shown, except that it keeps on loading and loading until Excel Not Responsive. I tried manually mapping the drive, it success.
I tried to debug and found out that the code stops (keeps on loading) at MsgBox "Hello" but could not figure out what's missing.
Both are using Excel 2016
Any help and suggestions are appreciated. let me know if more info is needed. Thanks in advance.
This is my vba code
Sub imgClicked()
Dim fileName As String
Dim SharePointLib As String
Dim MyPath As String
Dim folderPath As String
Dim objNet As Object
Dim copyPath As String
Dim copyFilePath As String
folderPath = Application.ThisWorkbook.path
MyPath = Application.ThisWorkbook.FullName
Dim objFSO As Object
Dim strMappedDriveLetter As String
Dim strPath As String
Dim spPath As String
strPath = "https://company.com/sites/test/test 123/" 'example path
spPath = AvailableDriveLetter + ":\test.xlsm" 'example path
copyPath = folderPath + "\copyPath\"
'Add reference if missing
Call AddReference
Set objFSO = CreateObject("Scripting.FileSystemObject")
With objFSO
strMappedDriveLetter = IsAlreadyMapped(.GetParentFolderName(strPath))
If Not Len(strMappedDriveLetter) > 0 Then
strMappedDriveLetter = AvailableDriveLetter
If Not MapDrive(strMappedDriveLetter, .GetParentFolderName(strPath)) Then
MsgBox "Failed to map SharePoint directory", vbInformation, "Drive Mapping Failure"
Exit Sub
End If
End If
' Check file/folder path If statement here
End With
Set objFSO = Nothing
End Sub
Code for getting available drive
' Returns the available drive letter starting from Z
Public Function AvailableDriveLetter() As String
' Returns the last available (unmapped) drive letter, working backwards from Z:
Dim objFSO As Object
Dim i As Long
Set objFSO = CreateObject("Scripting.FileSystemObject")
For i = Asc("Z") To Asc("A") Step -1
Select Case objFSO.DriveExists(Chr(i))
Case True
Case False
Select Case Chr(i)
Case "C", "D" ' Not actually necessary - .DriveExists should return True anyway...
Case Else
AvailableDriveLetter = Chr(i)
Exit For
End Select
End Select
Next i
Set objFSO = Nothing
MsgBox "This is the next available drive: " + AvailableDriveLetter ' returns Z drive
MsgBox "Hello" ' After this msgBox, starts loading until Not Responsive
End Function
Function to Map drive
Public Function MapDrive(strDriveLetter As String, strDrivePath As String) As Boolean
Dim objNetwork As Object
If Len(IsAlreadyMapped(strDrivePath)) > 0 Then Exit Function
Set objNetwork = CreateObject("WScript.Network")
objNetwork.MapNetworkDrive strDriveLetter & ":", strDrivePath, False
MapDrive = True
MsgBox "Successfully Created the Drive!"
Set objNetwork = Nothing
End Function
Code for MappedDrive
Public Function GetMappedDrives() As Variant
' Returns a 2-D array of (1) drive letters and (2) network paths of all mapped drives on the users machine
Dim objFSO As Object
Dim objDrive As Object
Dim arrMappedDrives() As Variant
Dim i As Long
Set objFSO = CreateObject("Scripting.FileSystemObject")
ReDim arrMappedDrives(1 To 2, 1 To 1)
For i = Asc("A") To Asc("Z")
If objFSO.DriveExists(Chr(i)) Then
Set objDrive = objFSO.GetDrive(Chr(i))
If Not IsEmpty(arrMappedDrives(1, UBound(arrMappedDrives, 2))) Then
ReDim Preserve arrMappedDrives(1 To 2, 1 To UBound(arrMappedDrives, 2) + 1)
End If
arrMappedDrives(1, UBound(arrMappedDrives, 2)) = Chr(i) ' Could also use objDrive.DriveLetter...
arrMappedDrives(2, UBound(arrMappedDrives, 2)) = objDrive.ShareName
End If
Next i
GetMappedDrives = arrMappedDrives
Set objDrive = Nothing
Set objFSO = Nothing
End Function
Public Function IsAlreadyMapped(strPath As String) As String
' Tests if a given network path is already mapped on the users machine
' (Returns corresponding drive letter or ZLS if not found)
Dim strMappedDrives() As Variant
Dim i As Long
strMappedDrives = GetMappedDrives
For i = LBound(strMappedDrives, 2) To UBound(strMappedDrives, 2)
If LCase(strMappedDrives(2, i)) Like LCase(strPath) Then
IsAlreadyMapped = strMappedDrives(1, i)
Exit For
End If
Next i
Set objNetwork = Nothing
End Function
Add Reference
Sub AddReference()
'Macro purpose: To add a reference to the project using the GUID for the
'reference library
Dim strGUID As String, theRef As Variant, i As Long
'Update the GUID you need below.
strGUID = "{420B2830-E718-11CF-893D-00A0C9054228}"
'Set to continue in case of error
On Error Resume Next
'Remove any missing references
For i = ThisWorkbook.VBProject.References.Count To 1 Step -1
Set theRef = ThisWorkbook.VBProject.References.Item(i)
If theRef.isbroken = True Then
ThisWorkbook.VBProject.References.Remove theRef
End If
Next i
'Clear any errors so that error trapping for GUID additions can be evaluated
Err.Clear
'Add the reference
ThisWorkbook.VBProject.References.AddFromGuid _
GUID:=strGUID, Major:=1, Minor:=0
'If an error was encountered, inform the user
Select Case Err.Number
Case Is = 32813
'Reference already in use. No action necessary
Case Is = vbNullString
'Reference added without issue
Case Else
'An unknown error was encountered, so alert the user
MsgBox "A problem was encountered trying to" & vbNewLine _
& "add or remove a reference in this file" & vbNewLine & "Please check the " _
& "references in your VBA project!", vbCritical + vbOKOnly, "Error!"
End Select
On Error GoTo 0
End Sub
Procedure imgClicked is calling function AvailableDriveLetter multiple times. Remember that the function has to execute each time you refer to it.
I ran imgClicked (assuming that's the procedure you start with) and I was told, twice, "Next available letter = Z" and "Hello" and then it crashed Excel (perhaps getting stuck in a loop of creating FileSystem objects to look for an available drive letter?)
Try assigning AvailableDriveLetter to a variable (string) at the beginning of the procedure and referring to the variable each time you need the value, and see if you still have the issue.
(Remember to save before execution -- I get frustrated when troubleshooting "application hanging" issues because I keep forgetting to save my changes and then lose them on the crash!)
If this doesn't work, add a breakpoint (F9) on the End Function line after your "Hello" box and see if the code stops there. (I have trouble believing the MsgBox or End Function are the culprit.) If not, which procedure runs after that?
One more thing whether the issue is resolved or not:
Add Option Explicit at the very beginning of your module and then Compile the project and fix your missing variable declaration(s).
This is recommended whenever troubleshooting an issue as a means to eliminate variable declaration issues as a possible cause.

it is posible to do " if error go to sub "

I need to write code that goes to a specific path and imports data from it,
then goes to another path and do the same.
I need that if path num 1 does not exist, it will jump direct to path num 2.
I wrote a sub for each path. there is a way to do something like:
if error goto sub ___ ?
Thanks in advance
Not directly, but you can do something like
On Error Goto error_sub1
and at the bottom of your function, write
error_sub1:
'ToDo - put your calling code here.
Elsewhere in you function you can switch the error handler to a different label:
On Error Goto error_sub2
and so on.
Try this:
Sub testSO()
On Error GoTo err
I=5/0
Exit Sub
err:
<your sub procedure here>
End Sub
Remember to include Exit Sub or else it will still run even without error!
Would it not be better to avoid the error in the first place and check whether the file exists before attempting to open it?
Sub Test()
Dim sFile1 As String
Dim sFile2 As String
Dim wrkBk As Workbook
On Error GoTo Error_Handler
sFile1 = "C:\Users\Desktop\MyFile1.xls"
sFile2 = "C:\Users\Desktop\MyFile2.xls"
If FileExists(sFile1) Then
Set wrkBk = Workbooks.Open(sFile1)
ElseIf FileExists(sFile2) Then
Set wrkBk = Workbooks.Open(sFile2)
Else
Err.Raise 513, , "File Not Found."
End If
wrkBk.Worksheets(1).Range("A1") = "Opened this file."
On Error GoTo 0
Fast_Exit:
'Any tidying up that needs doing.
Exit Sub
Error_Handler:
MsgBox Err.Description, vbExclamation + vbOKCancel, _
"Error: " & CStr(Err.Number)
Err.Clear
Resume Fast_Exit
End Sub
Public Function FileExists(ByVal FileName As String) As Boolean
Dim oFSO As Object
Set oFSO = CreateObject("Scripting.FileSystemObject")
FileExists = oFSO.FileExists(FileName)
End Function

VB ping macro - object required

I know absolutely nothing about VB but I'm trying to compile a quick ping test macro within a word document to test some malware sandbox software. However, I keep getting the runtime 424 error.
I've done a bit of research but with 0 knowledge of VB, I've failed to identify a solution. The code is as follows.
Sub Ping()
' Ping Macro
If My.Computer.Network.Ping("192.168.1.10") Then
MsgBox ("Server pinged successfully.")
Else
MsgBox ("Ping request timed out.")
End If
End Sub
I'm clearly missing something here. I assumed the object would have been the message box but I was wrong. Anybody know what I'm missing here?
EDIT: Debug shows the first line being the issue.
If My.Computer.Network.Ping("192.168.1.10") Then
Thanks.
My.Computer.Network.Ping() is a VB.Net function and is not available in VBA.
From some time ago I have a function to get the ping time, this should get you going.
You probably need only the StatusCode = 0 check.
' strAddress = IP or name
Public Function PingTime(strAddress) As Long
Dim objPing As Object, objStatus As Object
' Init: Assume error
PingTime = -1
On Error Resume Next
Set objPing = GetObject("WinMgmts:{impersonationLevel=impersonate}").ExecQuery _
("SELECT * FROM Win32_PingStatus WHERE Address = '" & strAddress & "' ")
If Err.Number <> 0 Then
Exit Function
End If
For Each objStatus In objPing
If objStatus.StatusCode = 0 Then
PingTime = objStatus.Properties_("ResponseTime").Value
Exit For
End If
Next
Set objStatus = Nothing
Set objPing = Nothing
End Function

When is it appropriate to explicitly use Err.Clear?

For example, the following function is used for checking whether a workbook is open:
Function BookOpen(Bk As String) As Boolean
Dim T As Excel.Workbook
Err.Clear
On Error Resume Next
Set T = Application.Workbooks(Bk)
BookOpen = Not T Is Nothing
Err.Clear
On Error GoTo 0
End Function
Are these two Err.Clear statements necessary?
In this example
Function BookOpen(Bk As String) As Boolean
Dim T As Excel.Workbook
Err.Clear
On Error Resume Next
Set T = Application.Workbooks(Bk)
BookOpen = Not T Is Nothing
Err.Clear
On Error GoTo 0
End Function
none of the uses is appropriate, because On Error resets the last error, so Err.Clear is redundant.
It's appropriate after actually handling a failed statement.
Function BookOpen(Bk As String) As Boolean
Dim T As Excel.Workbook
On Error Resume Next
Set T = Application.Workbooks(Bk) ' this can fail...
' so handle a possible failure
If Err.Number <> 0 Then
MsgBox "The workbook named """ & Bk & """ does not exist."
Err.Clear
End If
BookOpen = Not T Is Nothing
End Function
If you have On Error Resume Next in effect, the program will continue after an error as if nothing had happened. There is no exception thrown, there is no warning, this is not structured error handling (i.e. it's nothing like try/catch blocks). Your program might end up in a very weird state if you don't do rigorous error checks.
This means you must check errors after. every. statement. that. can. fail. Be prepared to write a lot of If Err.Number <> 0 Then checks. Note that this is harder to get right than it seems.
Better is: Avoid long sections of code that have On Error Resume Next in effect like the plague. Break up operations into smaller functions/subs that do only one thing instead of writing a big function that does it all but can fail halfway through.
In short: Err.Clear makes your program behave predictably after a failed statement in an On Error Resume Next block. It marks the error as handled. That's its purpose.
Of course in your sample it's easy to avoid error handling by using the commonly accepted way of checking whether a workbook (i.e. member of a collection) exists.
Function BookOpen(Bk As String) As Boolean
Dim wb As Variant
BookOpen = False ' not really necessary, VB inits Booleans to False anyway
For Each wb In Application.Workbooks
If LCase(wb.Name) = LCase(Bk) Then
BookOpen = True
Exit For
End If
Next
End Function