by Miles Forrest - Independent Developer
I think we've all been bitten by App.Path's inconsistencies with backslash over the years.
OK, I concede that it's not actually inconsistent, but it isn't consistent either.
OK, I concede that it's actually consistent to include the trailing backslash for root directories and not for others, because the backslash is the start of the directory name, not the end. So that means it's DOS' fault.
OK, I concede it's not actually DOS' fault per se - I mean, what else could DOS do?
Anyway, if you'd stop arguing with me, the point is that that pesky backslash causes me pain. It annoys me. So I fixed the problem.
This little module is invaluable, even though it only contains five small functions.
Type FILETIME ' 8 Bytes dwLowDateTime As Long dwHighDateTime As Long End Type Type WIN32_FIND_DATA ' 318 Bytes dwFileAttributes As Long ftCreationTime As FILETIME ftLastAccessTime As FILETIME ftLastWriteTime As FILETIME nFileSizeHigh As Long nFileSizeLow As Long dwReserved¯ As Long dwReserved1 As Long cFileName As String * 255 cAlternate As String * 14 End Type Private Const INVALID_HANDLE_VALUE& = -1 Private Declare Function GetLogicalDriveStrings& Lib "kernel32" Alias "GetLogicalDriveStringsA"_ (ByVal nBufferLength As Long, ByVal lpBuffer As String) Private Declare Function FindFirstFile& Lib "kernel32" Alias "FindFirstFileA"_ (ByVal lpFileName As String, lpFindFileData As WIN32_FIND_DATA) Private Declare Function FindClose& Lib "kernel32"_ (ByVal hFindFile As Long)The FileExists Function finds a file or directory, and returns True if it exists. Just throw it a file or directory name (with or without trailing backslash!) and Bob's your uncle.
Public Function FileExists(ByVal zvDirectoryFileName As String) As Boolean Dim typpFindFileData As WIN32_FIND_DATA Dim lpHandle As Long Dim lpSuccess As Long Dim lpBufferLength As Long Dim zpLogicalDrives As String * 106 '26 drive letters, 4 characters for each 'and 2 nulls at the end 'Are we dealing with the root directory of a logical drive? '(Put the 2 spaces in just in case the input string is less 'that 2 characters which will case right$ to blow up) If Right$(" " & zvDirectoryFileName, 2) = ":\" Then 'Get a list of the logical drives in the format "A:\#c:\#d:\##" where # is NULL lpSuccess = GetLogicalDriveStrings(106, zpLogicalDrives) FileExists = Not (InStr(1, zpLogicalDrives, zvDirectoryFileName, vbTextCompare) = 0) Else 'Find the file lpHandle = FindFirstFile(zvDirectoryFileName, typpFindFileData) 'If the handle is invalid then the path\file is not found (or errored) FileExists = Not (INVALID_HANDLE_VALUE = lpHandle) 'Zap the structure lpSuccess = FindClose(lpHandle) End If End Function
The PutBackslashPostfix Function is my all purpose "get that trailing backslash there" workhorse. If there's no trailing backslash, there is when this is finished with it!
Public Function PutBackslashPostfix(ByVal svPath As String) As String PutBackslashPostfix = IIf(Len(svPath) = 0, "\", svPath &_ IIf(Right$(svPath, 1) = "\", "", "\")) End FunctionOf course, it's not only trailing backslashes that need to be attacked. Sometimes you need to insert one at the fornt. PutBackslashPrefix handles this.
Public Function PutBackslashPrefix(ByVal svPath As String) As String PutBackslashPrefix = IIf(Len(svPath) = 0, "\", _ IIf(Left$(svPath, 1) = "\", "", "\") & svPath) End FunctionNot surprisingly, I also went to town with a similar pair of removal functions.
Public Function RemoveBackslashPostfix(ByVal svPath As String) As String RemoveBackslashPostfix = IIf(Len(svPath) = 0, "", _ IIf(Right$(svPath, 1) = "\", Left$(svPath, Len(svPath) - 1), svPath)) End Function Public Function RemoveBackslashPrefix(ByVal svPath As String) As String RemoveBackslashPrefix = IIf(Len(svPath) = 0, "", _ IIf(Left$(svPath, 1) = "\", Right$(svPath, Len(svPath) - 1), svPath)) End Function
So now, I don't care whose fault it is, or whether it's inconsistent or not.
The important thing is, it's fixed.