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

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

Related

Access VBA calling function does nothing when run

I have a macro that I'm trying to build in Access which will change the source table on a set of queries. Here is what I've built (based off already written code that I found on a forum):
Function ReplaceSources()
Call SourceQueries
End Function
Sub SourceQueries()
Call UpdateSource("YYYY_Count_of_items_by_floor", Building_Audit_2021, Building_Audit_YYYY)
End Sub
Sub UpdateSource(QueryName, CurrentSourceTable, NewSourceTable)
Dim strQryName, strCTbl, strNTbl, strCsql, strNsql As String
Dim defqry As DAO.QueryDef
strQryName = QueryName
strCTbl = CurrentSourceTable
strNTbl = NewSourceTable
Set defqry = CurrentDb.QueryDefs(strQryName)
strCsql = defqry.SQL
strNsql = Replace(strCsql, strCTbl, strNTbl)
defqry.SQL = strNsql
defqry.Close
End Sub
When I use the RunCode option in the macro builder using function name ReplaceSources(), nothing happens. I get no errors, I can step through the code with no issues, and adding Debug.Print lines throughout the function and subs does nothing. What is preventing this function from doing anything?
ETA:
Maybe it will help if I add the other two parts of code that I'm piecing together with this one. Before the above code, I run:
Function Copy_audit_table()
On Error GoTo Copy_audit_table_Err
Dim strPath As String
strPath = CurrentProject.FullName
DoCmd.TransferDatabase acImport, "Microsoft Access", strPath, acTable, "Building_Audit_2021", "Building_Audit_YYYY", True
DoCmd.CopyObject "", "YYYY_Count_of_items_by_floor", acQuery, "2021_Count_of_items_by_floor"
Copy_audit_table_Exit:
Exit Function
Copy_audit_table_Err:
MsgBox Error$
Resume Copy_audit_table_Exit
End Function
Then after the code in question, I run:
Function Copy_audit_table_rename()
On Error GoTo Copy_audit_table_rename_Err
Dim AuditYear As Variant
AuditYear = InputBox("Enter audit year (YYYY)")
Dim strPath As String
strPath = CurrentProject.FullName
DoCmd.Rename "Building_Audit_" & AuditYear, acTable, "Building_Audit_YYYY"
DoCmd.Rename AuditYear & "_Count_of_items_by_floor", acQuery, "YYYY_Count_of_items_by_floor"
Copy_audit_table_rename_Exit:
Exit Function
Copy_audit_table_rename_Err:
MsgBox Error$
Resume Copy_audit_table_rename_Exit
End Function
I'm not too familiar with VBA, so most of this is code that I found elsewhere that I was able to piece together. I know that I can use the macro builder to run each Function, but I really don't know any other ways. If there are any recommended tutorials that will help me code what I want to do, I'd like to read them.
You must execute the query for something to happen.
And skip the macro and the function. All you need is to call:
Sub UpdateSource(QueryName As String, CurrentSourceTable As String, NewSourceTable As String)
Dim strCsql As String
Dim defqry As DAO.QueryDef
Set defqry = CurrentDb.QueryDefs(QueryName)
strCsql = defqry.SQL
strNsql = Replace(strCsql, CurrentSourceTable, NewSourceTable)
defqry.SQL = strNsql
defqry.Execute
defqry.SQL = strCsql
defqry.Close
End Sub

Creating Specific Folders

I'm using these two functions to create project folders on startup. In the beginning I'm creating only one folder named ProjectName but now there's other folders on the same level with ProjectName named ProjectName_Inputs, ProjectName_Files, ProjectName_Outputs. I want to create them with my below code.
I wonder how can I adapt this to my code. I mean, is it possible to use an array or for loop etc.? path = [/ProjectName, ProjectName_Inputs, ProjectName_Files, ProjectName_Outputs] I don't know if it's possible?
Or can you suggest a more logical way to create them?
Sub CreateFolders()
Dim fso As New FileSystemObject
If Functions.FolderExists(path) Then
Exit Sub
Else
On Error GoTo FolderNotBuilt
fso.CreateFolder path ' could there be any error with this, like if the path is really screwed up?
Exit Sub
End If
FolderNotBuilt:
MsgBox "A folder could not be created for the following path: " & path & ". Check the path name and try again."
FolderCreate = False
Exit Sub
End Sub
This is the function that controls whether or not the directory created before
Function FolderExists(ByVal path As String) As Boolean
FolderExists = False
Dim fso As New FileSystemObject
If fso.FolderExists(path) Then FolderExists = True
End Function
Edited to amend a typo (End With missing) and change Resume to Resume Nextand skip the possibly screwed up path
I’d go like follows
Sub CreateFolders()
Dim path As Variant
With CreateObject("Scripting.FileSystemObject") 'create and reference a FileSystemObject object
For Each path In Array("path1*\", "path2", "path3")
If Not .FolderExists(path) Then 'loop through paths in array
On Error GoTo FolderNotBuilt
.CreateFolder path ' could there be any error with this, like if the path is really screwed up?
End If
Next
End With
Exit Sub
FolderNotBuilt:
MsgBox "A folder could not be created for the following path: " & vbCrLf & vbCrLf & path & vbCrLf & "Check the path name and try again."
Resume Next
End Sub

How to handle error handling once only?

I want to catch my error handling statement only once, if it fails again, resume next. I'm not sure how to achieve that but so far i'm able to rerun the code if it keeps on failing. Reason is i don't want to get stuck in a loop if the file never exist. Here's what i have:
....some code
TryAgain:
....
....
If Not FileExists("C:\" & FileName) Then
GoTo TryAgain >>> Only want to run this once if it fails again continue on down with the next section of codes.
End If
....next code stuff....
.....Dim blnRetry as Boolean
blnRetry =true
TryAgain:
....
....
If Not FileExists("C:\" & FileName) Then
if blnRetry then
blnRetry=false
GoTo TryAgain
end if
End If
My rule about GoTo is that I only use it in an On Error statement. Consider using a Do..Loop and a counter. Here's an example
Sub Test()
Dim sFile As String
Dim lTryCnt As Long
Const lMAXTRYCNT As Long = 10
Do
sFile = InputBox("Enter file name")
lTryCnt = lTryCnt + 1
Loop Until sFile = "False" Or Len(Dir("C:\" & sFile)) > 0 Or lTryCnt >= lMAXTRYCNT
Debug.Print sFile, lTryCnt
End Sub
sfile = "False" is if the user clicks Cancel on the inputbox. Len(Dir()) returns a zero length string if the file doesn't exist.

Test whether a property name exists

I'm getting this error:
Run-time error '424' object required
when I try to run this code:
Sub SuperSaveAs()
Set objFSO = CreateObject("Scripting.FileSystemObject")
Dim pathName As String
Dim myFileName As String
If (ActiveDocument.CustomDocumentProperties("_CheckOutSrcUrl").Value = True) Then
pathName = ActiveDocument.CustomDocumentProperties("_CheckOutSrcUrl").Value
myFileName = pathName + ActiveWorkbook.Name
ActiveWorkbook.SaveAs Filename:= _
myFileName _
, FileFormat:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
Else
MsgBox "_CheckOutSrcUrl is missing"
End If
End Sub
This macro is connected with a button in Excel. The macro checks if the custom document property exists. If the custom document property exists the macro should save the file to the Value of _CheckOutSrcUrl (SharePoint Directory).
How can I fix the error?
You cannot use the above method to test whether a property name exists or not. There are two apparent approaches, and these are not my own personal answers:
Use a loop to examine all the property names and see if "_CheckOutSrcUrl" gets found. See https://answers.microsoft.com/en-us/office/forum/office_2007-word/using-customdocumentproperties-with-vba/91ef15eb-b089-4c9b-a8a7-1685d073fb9f
Use VBA error detection to see if the property "_CheckOutSrcUrl" exists. See http://www.vbaexpress.com/forum/showthread.php?15366-Solved-CustomDocumentProperties-Problem
A snippet example of #1 adapted to your code - would be best in a function:
Dim propertyExists As Boolean
Dim prop As DocumentProperty
propertyExists = False
For Each prop In ActiveDocument.CustomDocumentProperties
If prop.Name = "_CheckOutSrcUrl" Then
propertyExists = True
Exit For
End If
Next prop
A snippet example of #2 adapted to your code:
Dim propertyExists As Boolean
Dim tempObj
On Error Resume Next
Set tempObj = ActiveDocument.CustomDocumentProperties.Item("_CheckOutSrcUrl")
propertyExists = (Err = 0)
On Error Goto 0
Based on #Cybermike:
Function propertyExists(propName) As Boolean
Dim tempObj
On Error Resume Next
Set tempObj = ActiveDocument.CustomDocumentProperties.Item(propName)
propertyExists = (Err = 0)
On Error GoTo 0
End Function

How can I use the FileSystemObject to "Copy and rename"

Using the FileSystemObject in VB/VBA (or native VBA calls, I guess) how can I:
Copy folder
Rename folder
So, something like:
mFSO.CopyAndRename(targetFolder, copyDirectory, copyFolderName)
I have basically done this myself but I would much prefer a more clean method call such as the above (and the CopyFolder method). This seems like a lot of code and a lot of potential failure points...
'
''requires reference to Microsoft Scripting Runtime
Public Function CopyDirectory(ByVal p_copyDirectory As String, p_targetDirectory As String, Optional p_newName As String = "") As Boolean
CopyDirectory = False
Dim m_fso
Set m_fso = New FileSystemObject
Dim mFolder, mNewFolder
If Not Me.DoesPathExist(p_copyDirectory) Then
Exit Function
Else
On Error GoTo errHandler
Set mFolder = m_fso.GetFolder(p_copyDirectory)
mFolder.Copy p_targetDirectory, False
'rename if a "rename" arg is passed
If p_newName <> "" Then
If DoesPathExist(p_targetDirectory & mFolder.Name) Then
Set mNewFolder = m_fso.GetFolder(p_targetDirectory & mFolder.Name)
mNewFolder.Name = "test" & CStr(Rnd(9999))
Else
End If
End If
CopyDirectory = True
On Error GoTo 0
Exit Function
End If
errHandler:
Exit Function
End Function
There is actually a method on Scripting.FileSystemObject called CopyFolder. It can be used to do both the copy and rename in one step, as follows:
Dim objFSO As Object
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.copyFolder "C:\Path\to\source\folder", "C:\Path\to\destination\folder" true
I found the code here: http://vba-tutorial.com/copy-a-folder-and-all-of-its-contents/
Hope this answers your question.
My Fav: SHFileOperation API
This also gives you the visual presentation of Folders being moved.
Option Explicit
Private Declare Function SHFileOperation Lib "shell32.dll" _
Alias "SHFileOperationA" (lpFileOp As SHFILEOPSTRUCT) As Long
Const FO_COPY = &H2 '~~> Copy File/Folder
Const FOF_SILENT = &H4 '~~> Silent Copy
Private Type SHFILEOPSTRUCT
hwnd As Long
wFunc As Long
pFrom As String
pTo As String
fFlags As Integer
fAborted As Boolean
hNameMaps As Long
sProgress As String
End Type
Private Sub Sample()
Dim lresult As Long, lFlags As Long
Dim SHFileOp As SHFILEOPSTRUCT
With SHFileOp
'~~> For Copy
.wFunc = FO_COPY
.pFrom = "C:\Temp"
.pTo = "C:\Temp2\"
'~~> For Silent Copy
'.fFlags = FOF_SILENT
End With
lresult = SHFileOperation(SHFileOp)
'~~> SHFileOp.fAborted will be true if user presses cancel during operation
If lresult <> 0 Or SHFileOp.fAborted Then Exit Sub
MsgBox "Operation Complete", vbInformation, "File Operations"
End Sub
For renaming a folder, here is a one liner
Sub Sample()
Name "C:\Temp2" As "C:\Temp3"
End Sub
Posting this for reference in the future. Using syntax from this answer I fleshed out a class I'd been writing.
I've created a directory manager class in VBA which may be relevant to anyone coming here in the future.
Private m_fso As New FileSystemObject
'
''requires reference to Microsoft Scripting Runtime
Public Function CopyAndRenameDirectory(ByVal p_copyDirectory As String, p_targetDirectory As String, p_newName As String) As Boolean
'example
'p_copyDirectory = "C:\temp\myGoingToBeCopiedDir
'p_targetDirectory = "C:\Temp2"
'p_newName = "AwesomeDir"
'results:
'myGoingToBeCopiedDir --> C:\Temp2\AwesomeDir
CopyAndRenameDirectory = False
p_targetDirectory = p_targetDirectory & "\"
If Not Me.DoesPathExist(p_copyDirectory) Or Not Me.DoesPathExist(p_targetDirectory) Then
Exit Function
End If
On Error GoTo errHandler
m_fso.CopyFolder p_copyDirectory, p_targetDirectory & p_newName, True
On Error GoTo 0
Exit Function
errHandler:
If PRINT_DEBUG Then Debug.Print "Error in CopyAndRenameDirectory: " & Err.Description
Exit Function
End Function
Public Function CopyDirectory(ByVal p_copyDirectory As String, p_targetDirectory As String) As Boolean
'example
'p_copyDirectory = "C:\temp\myGoingToBeCopiedDir
'p_targetDirectory = "C:\Temp2"
'p_newName = ""
'results:
'myGoingToBeCopiedDir --> C:\Temp2\myGoingToBeCopiedDir
CopyDirectory = False
If Not Me.DoesPathExist(p_copyDirectory) Or Not Me.DoesPathExist(p_targetDirectory) Then
Exit Function
End If
p_targetDirectory = p_targetDirectory & "\"
On Error GoTo errHandler
m_fso.CopyFolder p_copyDirectory, p_targetDirectory, True
On Error GoTo 0
Exit Function
errHandler:
If PRINT_DEBUG Then Debug.Print "Error in CopyDirectory: " & Err.Description
Exit Function
End Function
Public Function CreateFolder(ByVal p_path As String) As Boolean
CreateFolder = True
If Me.DoesPathExist(p_path) Then
Exit Function
Else
On Error GoTo errHandler
m_fso.CreateFolder p_path ' could there be any error with this, like if the path is really screwed up?
Exit Function
End If
errHandler:
'MsgBox "A folder could not be created for the following path: " & path & ". Check the path name and try again."
CreateFolder = False
Exit Function
End Function
Public Function DoesPathExist(ByVal p_path As String) As Boolean
DoesPathExist = False
If m_fso.FolderExists(p_path) Then DoesPathExist = True
End Function