Test whether a property name exists - vba

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

Related

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

VBA Error 52 on a function that tests if a file exists

I'm trying to pull text from a bunch of XML files into Word. I'm working from a list of files and have found that some of them don't actually exist in the folder. So, I'm using this function to check whether the files actually exist before opening them. But I'm still getting error 52 (Bad file name or number).
This is the function:
Function FileThere(FileName As String) As Boolean
FileThere = (Dir(FileName) > "")
End Function
And this is the code I'm calling it from:
Sub PullContent()
Dim docList As Document
Dim docCombinedFile As Document
Dim objFileListTable As Table
Dim objRow As Row
Dim strContent As String
Dim strFileCode As String
'Code # for the current file. (Pulled in temporarily, output to the Word doc.)
Dim strFilename As String
'Name of XML file. Created based on strFileCode
Set docCombinedFile = Documents.Add
'The new doc which will list all warnings
Dim strXml As String
'String variable that holds the entire content of the data module
Dim strInvalidCodes
'String listing any invalid file codes. Displayed at the end.
Dim FSO As Object: Set FSO = CreateObject("Scripting.FileSystemObject")
Documents.Open FileName:="C:\Users\kelly.keck\Documents\Triton MTS\IETMs - Test\IETMList.docx"
Set docList = Documents("IETMList.docx")
Set objFileListTable = docList.Tables(1)
For Each objRow In objFileListTable.Rows
strFileCode = objRow.Cells(4).Range.Text
strFileCode = Left(strFileCode, Len(strFileCode) - 2)
strFilename = strFileCode & ".xml"
strPath = "C:\Applications\xml\"
If FileThere(strPath & strFileCode) = True Then
'MsgBox (strPath & strFilename)
strXml = FSO.OpenTextFile(strPath & strFilename).ReadAll
Else
strInvalidCodes = strInvalidCodes & vbCr & strFileCode
End If
Next
MsgBox ("The following filenames were invalid: " & vbCr & strInvalidCodes)
End Sub
Getting this error seems to defeat the purpose of having a function to check if a file exists, but I'm not sure what's wrong with the function.
A bit late to the party, but this hasn't had an accepted answer yet.
I generally use this method to test if a file exists, and your code uses FileSystemObject already so could use that reference.
Public Function FileExists(ByVal FileName As String) As Boolean
Dim oFSO As Object
Set oFSO = CreateObject("Scripting.FileSystemObject")
FileExists = oFSO.FileExists(FileName)
End Function
I believe that you need to be sure that FileThere is actually returning the Boolean value you intend. It would be more reliable if you checked the Len property (the number of characters) or checked whether it actually returns the empty string.
The following is more verbose than absolutely necessary in order to make the logic clear. If you were to use Len, instead, then you'd check Len(Dir(FileName)) > 0
Function FileThere(FileName as String) as Boolean
Dim bFileExists as Boolean
If Dir(FileName) = "" Then
bFileExists = False
Else
bFileExists = True
End If
FileThere = bFileExists
End Function

Workbook not found when trying to call function from Excel-add in

I'm trying to call a function from a 3rd party Excel-add in a VBA-sub. The function loads data from a database into specified cells in the Excel workbook.The function I'm calling is huge and unfortunaly I can't post it in its entirety, but here are the first two lines:
Public Function loadFromDatabase(ByVal XLname As String, ByVal sMark As String)
Dim xlWB As Workbook
Then it declares a bunch of variables before running the following tests:
'
' Get the excel book and check if it is run in compatibility mode
'
Set xlWB = getXLBook(XLname)
If xlWB Is Nothing Then
loadFromDatabase = "Workbook '" + XLname + "' not found!"
Exit Function
End If
bExcel8Limits = True
If isExcel2007orLater Then
bExcel8Limits = bCheckCompMode(xlWB)
End If
Here I get this message: "Workbook " not found!" http://imgur.com/HQFAzoC .
The getXLBook function looks like this:
'
' Routine to get a specified Workbook
'
Function getXLBook(sName As String) As Workbook
Dim xlWB As Workbook
On Error Resume Next
Set xlWB = Nothing
Set xlWB = Application.Workbooks(sName)
On Error GoTo 0
Set getXLBook = xlWB
End Function
A hint here may be that I'm able to call the function from a Private Sub place in a worksheet like this...
Private Sub loadFromDB()
Dim res As Variant
res = Application.Run("loadFromDatabase", Me.Parent.Name, "")
If res <> "OK" Then
MsgBox res
End If
End Sub
...but not from a module in the same workbook like this
Sub loadFromDB_test()
Dim res As Variant
res = Application.Run("loadFromDatabase", XLname, sMark)
If res <> "OK" Then
MsgBox res
End If
End Sub
Any suggestions?
Edit: To clarify, it's when running loadFromDB_test the "Workbook not found" message pops up.
Edit 2: An obvious hotfix (that I didnt think of) is to just call the Private Sub in the worksheet from the Sub in the module.
Sub load_test_new()
Application.Run "Sheet1.loadFromDB"
End Sub
From a learning point of view this is clearly not a good solution as it is inefficient coding.
Based on the msgbox you display, you're passing an empty string to the function getXLBook. (within the scope of getXLBook this value is stored as sName, but the cause of the error is before you call this function).
So, somewhere in your code, before this:
Set xlWB = getXLBook(XLname)
You should have a line like this, where the right side of the statement assigns a string representing a full, valid filepath:
XLName = "C:\filename.xlsx"
I suspect that your code does not contain this assignment statement, so that should explain the error.

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