906 lines
26 KiB
QBasic
906 lines
26 KiB
QBasic
Attribute VB_Name = "MUtility"
|
|
Option Explicit
|
|
|
|
Public Enum EHexDump
|
|
ehdOneColumn
|
|
ehdTwoColumn
|
|
ehdEndless
|
|
ehdSample8
|
|
ehdSample16
|
|
End Enum
|
|
|
|
Enum ESearchOptions
|
|
esoCaseSense = &H1
|
|
esoBackward = &H2
|
|
esoWholeWord = &H4
|
|
End Enum
|
|
|
|
Public Enum EErrorUtility
|
|
eeBaseUtility = 13000 ' Utility
|
|
eeNoMousePointer ' HourGlass: Object doesn't have mouse pointer
|
|
eeNoTrueOption ' GetOption: None of the options are True
|
|
eeNotOptionArray ' GetOption: Not control array of OptionButton
|
|
eeMissingParameter ' InStrR: One or more parameters are missing
|
|
End Enum
|
|
|
|
#If fComponent Then
|
|
Private Sub Class_Initialize()
|
|
' Seed sequence with timer for each client
|
|
Randomize
|
|
End Sub
|
|
#End If
|
|
|
|
#If fComponent = 0 Then
|
|
Private Sub ErrRaise(e As Long)
|
|
Dim sText As String, sSource As String
|
|
If e > 1000 Then
|
|
sSource = App.ExeName & ".Utility"
|
|
Select Case e
|
|
Case eeBaseUtility
|
|
BugAssert True
|
|
Case eeNoMousePointer
|
|
sText = "HourGlass: Object doesn't have mouse pointer"
|
|
Case eeNoTrueOption
|
|
sText = "GetOption: None of the options are True"
|
|
Case eeNotOptionArray
|
|
sText = "GetOption: Argument is not a control array" & _
|
|
"of OptionButtons"
|
|
Case eeMissingParameter
|
|
sText = "InStrR: One or more parameters are missing"
|
|
End Select
|
|
Err.Raise COMError(e), sSource, sText
|
|
Else
|
|
' Raise standard Visual Basic error
|
|
sSource = App.ExeName & ".VBError"
|
|
Err.Raise e, sSource
|
|
End If
|
|
End Sub
|
|
#End If
|
|
|
|
' Can't do sNullChr in type library, so fake it here
|
|
Public Property Get sNullChr() As String
|
|
sNullChr = vbNullChar
|
|
End Property
|
|
|
|
Sub HourGlass(obj As Object)
|
|
Static ordMouse As Integer, fOn As Boolean
|
|
On Error Resume Next
|
|
If Not fOn Then
|
|
' Save pointer and set hourglass
|
|
ordMouse = obj.MousePointer
|
|
obj.MousePointer = vbHourglass
|
|
fOn = True
|
|
Else
|
|
' Restore pointer
|
|
obj.MousePointer = ordMouse
|
|
fOn = False
|
|
End If
|
|
If Err Then ErrRaise eeNoMousePointer
|
|
End Sub
|
|
|
|
Function IsArrayEmpty(va As Variant) As Boolean
|
|
Dim v As Variant
|
|
On Error Resume Next
|
|
v = va(LBound(va))
|
|
IsArrayEmpty = (Err <> 0)
|
|
End Function
|
|
|
|
Function HasShell() As Boolean
|
|
Dim dw As Long
|
|
dw = GetVersion()
|
|
If (dw And &HFF&) >= 4 Then
|
|
HasShell = True
|
|
' Proves that operating system has shell, but not
|
|
' necessarily that it is installed. Some might argue
|
|
' that this function should check Registry under WinNT
|
|
' or SYSTEM.INI Shell= under Win95
|
|
End If
|
|
End Function
|
|
|
|
Function IsNT() As Boolean
|
|
Dim dw As Long
|
|
IsNT = ((GetVersion() And &H80000000) = 0)
|
|
End Function
|
|
|
|
Sub SwapBytes(ByVal b1 As Byte, ByVal b2 As Byte)
|
|
Dim bTmp As Byte
|
|
b1 = bTmp
|
|
b2 = b1
|
|
b1 = bTmp
|
|
End Sub
|
|
|
|
Sub SwapIntegers(ByVal w1 As Integer, ByVal w2 As Integer)
|
|
Dim wTmp As Byte
|
|
w1 = wTmp
|
|
w2 = w1
|
|
w1 = wTmp
|
|
End Sub
|
|
|
|
Sub SwapLongs(ByVal dw1 As Long, ByVal dw2 As Long)
|
|
Dim dwTmp As Byte
|
|
dw1 = dwTmp
|
|
dw2 = dw1
|
|
dw1 = dwTmp
|
|
End Sub
|
|
|
|
Function FmtHex(ByVal i As Long, _
|
|
Optional ByVal iWidth As Integer = 8) As String
|
|
FmtHex = Right$(String$(iWidth, "0") & Hex$(i), iWidth)
|
|
End Function
|
|
|
|
Function FmtInt(ByVal iVal As Integer, ByVal iWidth As Integer, _
|
|
Optional fRight As Boolean = True) As String
|
|
If fRight Then
|
|
FmtInt = Right$(Space$(iWidth) & iVal, iWidth)
|
|
Else
|
|
FmtInt = Left$(iVal & Space$(iWidth), iWidth)
|
|
End If
|
|
End Function
|
|
|
|
Function FmtStr(s As String, ByVal iWidth As Integer, _
|
|
Optional fRight As Boolean = True) As String
|
|
If fRight Then
|
|
FmtStr = Left$(s & Space$(iWidth), iWidth)
|
|
Else
|
|
FmtStr = Right$(Space$(iWidth) & s, iWidth)
|
|
End If
|
|
End Function
|
|
|
|
' Find the True option from a control array of OptionButtons
|
|
Function GetOption(opts As Object) As Integer
|
|
On Error GoTo GetOptionFail
|
|
Dim opt As OptionButton
|
|
For Each opt In opts
|
|
If opt.Value Then
|
|
GetOption = opt.Index
|
|
Exit Function
|
|
End If
|
|
Next
|
|
On Error GoTo 0
|
|
ErrRaise eeNoTrueOption
|
|
Exit Function
|
|
GetOptionFail:
|
|
ErrRaise eeNotOptionArray
|
|
End Function
|
|
|
|
' Make sure path ends in a backslash
|
|
Function NormalizePath(sPath As String) As String
|
|
If Right$(sPath, 1) <> sBSlash Then
|
|
NormalizePath = sPath & sBSlash
|
|
Else
|
|
NormalizePath = sPath
|
|
End If
|
|
End Function
|
|
|
|
' Make sure path doesn't end in a backslash
|
|
Sub DenormalizePath(sPath As Variant)
|
|
If Right$(sPath, 1) = sBSlash Then
|
|
sPath = Left$(sPath, Len(sPath) - 1)
|
|
End If
|
|
End Sub
|
|
|
|
' Test file existence with error trapping
|
|
Function ExistFile(sSpec As String) As Boolean
|
|
On Error Resume Next
|
|
Call FileLen(sSpec)
|
|
ExistFile = (Err = 0)
|
|
End Function
|
|
|
|
' Test file existence with the Windows API
|
|
Function ExistFileDir(sSpec As String) As Boolean
|
|
Dim af As Long
|
|
af = GetFileAttributes(sSpec)
|
|
ExistFileDir = (af <> -1)
|
|
End Function
|
|
|
|
' Test file existence with the Dir$ function
|
|
Function Exists(sSpec As String) As Boolean
|
|
Exists = Dir$(sSpec, vbDirectory) <> sEmpty
|
|
End Function
|
|
|
|
' Convert Automation color to Windows color
|
|
Function TranslateColor(ByVal clr As OLE_COLOR, _
|
|
Optional hPal As Long = 0) As Long
|
|
If OleTranslateColor(clr, hPal, TranslateColor) Then
|
|
TranslateColor = CLR_INVALID
|
|
End If
|
|
End Function
|
|
|
|
Function GetExtPos(sSpec As String) As Integer
|
|
Dim iLast As Integer, iExt As Integer
|
|
iLast = Len(sSpec)
|
|
|
|
' Parse backward to find extension or base
|
|
For iExt = iLast + 1 To 1 Step -1
|
|
Select Case Mid$(sSpec, iExt, 1)
|
|
Case "."
|
|
' First . from right is extension start
|
|
Exit For
|
|
Case "\"
|
|
' First \ from right is base start
|
|
iExt = iLast + 1
|
|
Exit For
|
|
End Select
|
|
Next
|
|
|
|
' Negative return indicates no extension, but this
|
|
' is base so callers don't have to reparse.
|
|
GetExtPos = iExt
|
|
End Function
|
|
|
|
Function GetFileText(sFileName As String) As String
|
|
Dim nFile As Integer, sText As String
|
|
nFile = FreeFile
|
|
'Open sFileName For Input As nFile ' Don't do this!!!
|
|
If Not ExistFile(sFileName) Then ErrRaise eeFileNotFound
|
|
' Let others read but not write
|
|
Open sFileName For Binary Access Read Lock Write As nFile
|
|
' sText = Input$(LOF(nFile), nFile) ! Don't do this!!!
|
|
' This is much faster
|
|
sText = String$(LOF(nFile), 0)
|
|
Get nFile, 1, sText
|
|
Close nFile
|
|
GetFileText = sText
|
|
End Function
|
|
|
|
Function IsRTF(sFileName As String) As Boolean
|
|
Dim nFile As Integer, sText As String
|
|
nFile = FreeFile
|
|
If Not ExistFile(sFileName) Then Exit Function
|
|
' Pass error through to caller
|
|
Open sFileName For Binary Access Read Lock Write As nFile
|
|
If LOF(nFile) < 5 Then Exit Function
|
|
sText = String$(5, 0)
|
|
Get nFile, 1, sText
|
|
Close nFile
|
|
If sText = "{\rtf" Then IsRTF = True
|
|
End Function
|
|
|
|
Function GetRandom(ByVal iLo As Long, ByVal iHi As Long) As Long
|
|
GetRandom = Int(iLo + (Rnd * (iHi - iLo + 1)))
|
|
End Function
|
|
|
|
Sub DoWaitEvents(msWait As Long)
|
|
Dim msEnd As Long
|
|
msEnd = GetTickCount + msWait
|
|
Do
|
|
DoEvents
|
|
Loop While GetTickCount < msEnd
|
|
End Sub
|
|
|
|
Function HexDumpS(s As String, Optional ehdFmt As EHexDump = ehdOneColumn) As String
|
|
Dim ab() As Byte
|
|
ab = StrToStrB(s)
|
|
HexDumpS = HexDump(ab, ehdFmt)
|
|
End Function
|
|
|
|
Function HexDumpB(s As String, Optional ehdFmt As EHexDump = ehdOneColumn) As String
|
|
Dim ab() As Byte
|
|
ab = s
|
|
HexDumpB = HexDump(ab, ehdFmt)
|
|
End Function
|
|
|
|
Function HexDumpPtr(ByVal p As Long, ByVal c As Long, _
|
|
Optional ehdFmt As EHexDump = ehdOneColumn) As String
|
|
Dim ab() As Byte
|
|
ReDim ab(0 To c - 1) As Byte
|
|
CopyMemory ab(0), ByVal p, c
|
|
HexDumpPtr = HexDump(ab, ehdFmt)
|
|
End Function
|
|
|
|
Function HexDump(ab() As Byte, _
|
|
Optional ehdFmt As EHexDump = ehdOneColumn) As String
|
|
Dim i As Integer, sDump As String, sAscii As String
|
|
Dim iColumn As Integer, iCur As Integer, sCur As String
|
|
Dim sLine As String
|
|
Select Case ehdFmt
|
|
Case ehdOneColumn, ehdSample8
|
|
iColumn = 8
|
|
Case ehdTwoColumn, ehdSample16
|
|
iColumn = 16
|
|
Case ehdEndless
|
|
iColumn = 32767
|
|
End Select
|
|
|
|
For i = LBound(ab) To UBound(ab)
|
|
' Get current character
|
|
iCur = ab(i)
|
|
sCur = Chr$(iCur)
|
|
|
|
' Append its hex value
|
|
sLine = sLine & Right$("0" & Hex$(iCur), 2) & " "
|
|
|
|
' Append its ASCII value or dot
|
|
If ehdFmt <= ehdTwoColumn Then
|
|
If iCur >= 32 And iCur < 127 Then
|
|
sAscii = sAscii & sCur
|
|
Else
|
|
sAscii = sAscii & "."
|
|
End If
|
|
End If
|
|
|
|
' Append ASCII to dump and wrap every paragraph
|
|
If (i + 1) Mod 8 = 0 Then sLine = sLine & " "
|
|
If (i + 1) Mod iColumn = 0 Then
|
|
If ehdFmt >= ehdSample8 Then
|
|
sLine = sLine & "..."
|
|
Exit For
|
|
End If
|
|
sLine = sLine & " " & sAscii & sCrLf
|
|
sDump = sDump & sLine
|
|
sAscii = sEmpty
|
|
sLine = sEmpty
|
|
End If
|
|
Next
|
|
|
|
If ehdFmt <= ehdTwoColumn Then
|
|
If (i + 1) Mod iColumn Then
|
|
If ehdFmt Then
|
|
sLine = Left$(sLine & Space$(53), 53) & sAscii
|
|
Else
|
|
sLine = Left$(sLine & Space$(26), 26) & sAscii
|
|
End If
|
|
End If
|
|
sDump = sDump & sLine
|
|
Else
|
|
sDump = sLine
|
|
End If
|
|
HexDump = sDump
|
|
|
|
End Function
|
|
|
|
Function StrToStrB(ByVal s As String) As String
|
|
If UnicodeTypeLib Then
|
|
StrToStrB = s
|
|
Else
|
|
StrToStrB = StrConv(s, vbFromUnicode)
|
|
End If
|
|
End Function
|
|
|
|
Function StrBToStr(ByVal s As String) As String
|
|
If UnicodeTypeLib Then
|
|
StrBToStr = s
|
|
Else
|
|
StrBToStr = StrConv(s, vbUnicode)
|
|
End If
|
|
End Function
|
|
|
|
Function StrZToStr(s As String) As String
|
|
StrZToStr = Left$(s, lstrlen(s))
|
|
End Function
|
|
|
|
Function ExpandEnvStr(sData As String) As String
|
|
Dim c As Long, s As String
|
|
' Get the length
|
|
s = sEmpty ' Needed to get around Windows 95 limitation
|
|
c = ExpandEnvironmentStrings(sData, s, c)
|
|
' Expand the string
|
|
s = String$(c - 1, 0)
|
|
c = ExpandEnvironmentStrings(sData, s, c)
|
|
ExpandEnvStr = s
|
|
End Function
|
|
|
|
Function PointerToString(p As Long) As String
|
|
Dim c As Long
|
|
c = lstrlenPtr(p)
|
|
PointerToString = String$(c, 0)
|
|
If UnicodeTypeLib Then
|
|
CopyMemoryToStr PointerToString, ByVal p, c * 2
|
|
Else
|
|
CopyMemoryToStr PointerToString, ByVal p, c
|
|
End If
|
|
End Function
|
|
|
|
Function StringToPointer(s As String) As Long
|
|
If UnicodeTypeLib Then
|
|
StringToPointer = VarPtr(s)
|
|
Else
|
|
StringToPointer = StrPtr(s)
|
|
End If
|
|
End Function
|
|
|
|
Sub SaveFileStr(sFile As String, sContent As String)
|
|
Dim nFile As Integer
|
|
nFile = FreeFile
|
|
Open sFile For Output Access Write Lock Write As nFile
|
|
Print #nFile, sContent;
|
|
Close nFile
|
|
End Sub
|
|
|
|
Function SaveFileText(sFileName As String, sText As String) As Long
|
|
Dim nFile As Integer
|
|
On Error Resume Next
|
|
nFile = FreeFile
|
|
Open sFileName For Output Access Write Lock Write As nFile
|
|
Print #nFile, sText
|
|
Close nFile
|
|
SaveFileText = Err
|
|
End Function
|
|
|
|
Function FindString(sTarget As String, sFind As String, _
|
|
Optional ByVal iPos As Long, _
|
|
Optional ByVal esoOptions As ESearchOptions) As Long
|
|
Dim ordComp As Long, cFind As Long, fBack As Boolean
|
|
' Get the compare method
|
|
If esoOptions And esoCaseSense Then
|
|
ordComp = vbBinaryCompare
|
|
Else
|
|
ordComp = vbTextCompare
|
|
End If
|
|
' Set up first search
|
|
cFind = Len(sFind)
|
|
If iPos = 0 Then iPos = 1
|
|
If esoOptions And esoBackward Then fBack = True
|
|
Do
|
|
' Find the string
|
|
If fBack Then
|
|
iPos = InStrR(iPos, sTarget, sFind, ordComp)
|
|
Else
|
|
iPos = InStr(iPos, sTarget, sFind, ordComp)
|
|
End If
|
|
' If not found, we're done
|
|
If iPos = 0 Then Exit Function
|
|
If esoOptions And esoWholeWord Then
|
|
' If it's supposed to be whole word and is, we're done
|
|
If IsWholeWord(sTarget, iPos, Len(sFind)) Then Exit Do
|
|
' Otherwise, set up next search
|
|
If fBack Then
|
|
iPos = iPos - cFind
|
|
If iPos < 1 Then Exit Function
|
|
Else
|
|
iPos = iPos + cFind
|
|
If iPos > Len(sTarget) Then Exit Function
|
|
End If
|
|
Else
|
|
' If it wasn't a whole word search, we're done
|
|
Exit Do
|
|
End If
|
|
Loop
|
|
FindString = iPos
|
|
End Function
|
|
|
|
Private Function IsWholeWord(sTarget As String, ByVal iPos As Long, _
|
|
ByVal cFind As Long) As Boolean
|
|
Dim sChar As String, sSep As String
|
|
sSep = " .,!:?" & sTab & sCrLf
|
|
' Check character before
|
|
If iPos > 1 Then
|
|
sChar = Mid$(sTarget, iPos - 1, 1)
|
|
If InStr(sSep, sChar) = 0 Then Exit Function
|
|
End If
|
|
' Check character after
|
|
If iPos < Len(sTarget) - 1 Then
|
|
sChar = Mid$(sTarget, iPos + cFind, 1)
|
|
If InStr(sSep, sChar) = 0 Then Exit Function
|
|
End If
|
|
IsWholeWord = True
|
|
End Function
|
|
|
|
' Basic is one of the few languages where you can't extract a character
|
|
' from or insert a character into a string at a given position without
|
|
' creating another string. These procedures fix that limitation.
|
|
|
|
' Much faster than AscW(Mid$(sTarget, iPos, 1))
|
|
Function CharFromStr(sTarget As String, _
|
|
Optional ByVal iPos As Long = 1) As Integer
|
|
CopyMemory CharFromStr, ByVal StrPtr(sTarget) + (iPos * 2) - 2, 2
|
|
End Function
|
|
|
|
' Much faster than Mid$(sTarget, iPos, 1) = Chr$(ch)
|
|
Sub CharToStr(sTarget As String, ByVal ch As Integer, _
|
|
Optional ByVal iPos As Long = 1)
|
|
CopyMemory ByVal StrPtr(sTarget) + (iPos * 2) - 2, ch, 2
|
|
End Sub
|
|
|
|
' This brute force algorithm should be replaced with the Boyer-Moore
|
|
' algrorithm or some other sophisticated string search code
|
|
Function InStrR(Optional vStart As Variant, _
|
|
Optional vTarget As Variant, _
|
|
Optional vFind As Variant, _
|
|
Optional vCompare As Variant) As Long
|
|
If IsMissing(vStart) Then ErrRaise eeMissingParameter
|
|
|
|
' Handle missing arguments
|
|
Dim iStart As Long, sTarget As String
|
|
Dim sFind As String, ordCompare As Long
|
|
If VarType(vStart) = vbString Then
|
|
BugAssert IsMissing(vCompare)
|
|
If IsMissing(vTarget) Then ErrRaise eeMissingParameter
|
|
sTarget = vStart
|
|
sFind = vTarget
|
|
iStart = Len(sTarget)
|
|
If IsMissing(vFind) Then
|
|
ordCompare = vbBinaryCompare
|
|
Else
|
|
ordCompare = vFind
|
|
End If
|
|
Else
|
|
If IsMissing(vTarget) Or IsMissing(vFind) Then
|
|
ErrRaise eeMissingParameter
|
|
End If
|
|
sTarget = vTarget
|
|
sFind = vFind
|
|
iStart = vStart
|
|
If IsMissing(vCompare) Then
|
|
ordCompare = vbBinaryCompare
|
|
Else
|
|
ordCompare = vCompare
|
|
End If
|
|
End If
|
|
|
|
' Search backward
|
|
Dim cFind As Long, i As Long, f As Long
|
|
cFind = Len(sFind)
|
|
For i = iStart - cFind + 1 To 1 Step -1
|
|
If StrComp(Mid$(sTarget, i, cFind), sFind, ordCompare) = 0 Then
|
|
InStrR = i
|
|
Exit Function
|
|
End If
|
|
Next
|
|
End Function
|
|
|
|
|
|
Function PlayWave(ab() As Byte, Optional Flags As Long = _
|
|
SND_MEMORY Or SND_SYNC) As Boolean
|
|
PlayWave = sndPlaySoundAsBytes(ab(0), Flags)
|
|
End Function
|
|
|
|
Sub InsertChar(sTarget As String, sChar As String, iPos As Integer)
|
|
BugAssert Len(sChar) = 1 ' Accept characters only
|
|
BugAssert iPos > 0 ' Don't insert before beginning
|
|
BugAssert iPos <= Len(sTarget) ' Don't insert beyond end
|
|
Mid$(sTarget, iPos, 1) = sChar ' Do work
|
|
End Sub
|
|
|
|
Function LineWrap(sText As String, cMax As Integer)
|
|
Dim s As String, i As Integer, iLast As Integer, c As Integer
|
|
c = Len(sText)
|
|
i = 1
|
|
Do While c
|
|
iLast = i
|
|
i = i + cMax
|
|
Do While Mid$(sText, i, 1) <> sSpace
|
|
i = i - 1
|
|
Loop
|
|
s = s & Mid$(sText, iLast, i - iLast) & sCrLf & " "
|
|
i = i + 1
|
|
Loop
|
|
LineWrap = s
|
|
End Function
|
|
|
|
' Pascal: if ch in ['a', 'f', 'g'] then
|
|
' Basic: If Among(ch, "a", "f", "g") Then
|
|
Function Among(vTarget As Variant, ParamArray A() As Variant) As Boolean
|
|
Among = True ' Assume found
|
|
Dim v As Variant
|
|
For Each v In A()
|
|
If v = vTarget Then Exit Function
|
|
Next
|
|
Among = False
|
|
End Function
|
|
|
|
' Work around limitation of AddressOf
|
|
' Call like this: procVar = GetProc(AddressOf ProcName)
|
|
Function GetProc(proc As Long) As Long
|
|
GetProc = proc
|
|
End Function
|
|
|
|
Function WordWrap(sText As String, ByVal cMax As Long) As String
|
|
Dim iStart As Long, iEnd As Long, cText As Long, sSep As String
|
|
cText = Len(sText)
|
|
iStart = 1
|
|
iEnd = cMax
|
|
sSep = " " & sTab & sCrLf
|
|
Do While iEnd < cText
|
|
' Parse back to white space
|
|
Do While InStr(sSep, Mid$(sText, iEnd, 1)) = 0
|
|
iEnd = iEnd - 1
|
|
' Don't send us text with words longer than the lines!
|
|
If iEnd <= iStart Then
|
|
WordWrap = sText
|
|
Exit Function
|
|
End If
|
|
Loop
|
|
WordWrap = WordWrap & Mid$(sText, iStart, iEnd - iStart + 1) & sCrLf
|
|
iStart = iEnd + 1
|
|
iEnd = iStart + cMax
|
|
Loop
|
|
WordWrap = WordWrap + Mid$(sText, iStart)
|
|
End Function
|
|
|
|
|
|
Sub CollectionReplace(n As Collection, vIndex As Variant, _
|
|
vVal As Variant)
|
|
If VarType(vIndex) = vbString Then
|
|
n.Remove vIndex
|
|
n.Add vVal, vIndex
|
|
Else
|
|
n.Add vVal, , vIndex
|
|
n.Remove vIndex + 1
|
|
End If
|
|
End Sub
|
|
|
|
Function GetLabel(sRoot As String) As String
|
|
GetLabel = Dir$(sRoot & "*.*", vbVolume)
|
|
End Function
|
|
|
|
Function GetFileBase(sFile As String) As String
|
|
Dim iBase As Long, iExt As Long, s As String
|
|
If sFile = sEmpty Then Exit Function
|
|
s = GetFullPath(sFile, iBase, iExt)
|
|
GetFileBase = Mid$(s, iBase, iExt - iBase)
|
|
End Function
|
|
|
|
Function GetFileBaseExt(sFile As String) As String
|
|
Dim iBase As Long, s As String
|
|
If sFile = sEmpty Then Exit Function
|
|
s = GetFullPath(sFile, iBase)
|
|
GetFileBaseExt = Mid$(s, iBase)
|
|
End Function
|
|
|
|
Function GetFileExt(sFile As String) As String
|
|
Dim iExt As Long, s As String
|
|
If sFile = sEmpty Then Exit Function
|
|
s = GetFullPath(sFile, , iExt)
|
|
GetFileExt = Mid$(s, iExt)
|
|
End Function
|
|
|
|
Function GetFileDir(sFile As String) As String
|
|
Dim iBase As Long, s As String
|
|
If sFile = sEmpty Then Exit Function
|
|
s = GetFullPath(sFile, iBase)
|
|
GetFileDir = Left$(s, iBase - 1)
|
|
End Function
|
|
|
|
Function GetFileFullSpec(sFile As String) As String
|
|
If sFile = sEmpty Then Exit Function
|
|
GetFileFullSpec = GetFullPath(sFile)
|
|
End Function
|
|
|
|
Function SearchForExe(sName As String) As String
|
|
Dim sSpec As String, asExt(1 To 5) As String, i As Integer
|
|
asExt(1) = ".EXE": asExt(2) = ".COM": asExt(3) = ".PIF":
|
|
asExt(4) = ".BAT": asExt(5) = ".CMD"
|
|
For i = 1 To 5
|
|
sSpec = SearchDirs(sName, asExt(i))
|
|
If sSpec <> sEmpty Then Exit For
|
|
Next
|
|
SearchForExe = sSpec
|
|
End Function
|
|
|
|
Function IsExe() As Boolean
|
|
Dim sExe As String, c As Long
|
|
sExe = String$(255, 0)
|
|
c = GetModuleFileName(hNull, sExe, 255)
|
|
sExe = Left$(sExe, c)
|
|
IsExe = Right$(UCase$(sExe), 7) <> "VB5.EXE"
|
|
End Function
|
|
|
|
Function xRight(obj As Object) As Single
|
|
xRight = obj.Left + obj.Width
|
|
End Function
|
|
|
|
Function yBottom(obj As Object) As Single
|
|
yBottom = obj.Top + obj.Height
|
|
End Function
|
|
|
|
' Win32 functions with Basic interface
|
|
|
|
' GetFullPath - Basic version of Win32 API emulation routine. It returns a
|
|
' BSTR, and indexes to the file name, directory, and extension parts of the
|
|
' full name.
|
|
'
|
|
' Input: sFileName - file to be qualified in one of these formats:
|
|
'
|
|
' [relpath\]file.ext
|
|
' \[path\]file.ext
|
|
' .\[path\]file.ext
|
|
' d:\[path\]file.ext
|
|
' ..\[path\]file.ext
|
|
' \\server\machine\[path\]file.ext
|
|
' iName - variable to receive file name position
|
|
' iDir - variable to receive directory position
|
|
' iExt - variable to receive extension position
|
|
'
|
|
' Return: Full path name, or an empty string on failure
|
|
'
|
|
' Errors: Any of the following:
|
|
' ERROR_BUFFER_OVERFLOW = 111
|
|
' ERROR_INVALID_DRIVE = 15
|
|
' ERROR_CALL_NOT_IMPLEMENTED = 120
|
|
' ERROR_BAD_PATHNAME = 161
|
|
|
|
|
|
Function GetFullPath(sFileName As String, _
|
|
Optional FilePart As Long, _
|
|
Optional ExtPart As Long, _
|
|
Optional DirPart As Long) As String
|
|
|
|
Dim c As Long, p As Long, sRet As String
|
|
If sFileName = sEmpty Then Exit Function
|
|
|
|
' Get the path size, then create string of that size
|
|
sRet = String(cMaxPath, 0)
|
|
c = GetFullPathName(sFileName, cMaxPath, sRet, p)
|
|
If c = 0 Then ApiRaise Err.LastDllError
|
|
BugAssert c <= cMaxPath
|
|
sRet = Left$(sRet, c)
|
|
|
|
' Get the directory, file, and extension positions
|
|
GetDirExt sRet, FilePart, DirPart, ExtPart
|
|
GetFullPath = sRet
|
|
|
|
End Function
|
|
|
|
Function GetTempFile(Optional Prefix As String, _
|
|
Optional PathName As String) As String
|
|
|
|
If Prefix = sEmpty Then Prefix = sEmpty
|
|
If PathName = sEmpty Then PathName = GetTempDir
|
|
|
|
Dim sRet As String
|
|
sRet = String(cMaxPath, 0)
|
|
GetTempFileName PathName, Prefix, 0, sRet
|
|
ApiRaiseIf Err.LastDllError
|
|
GetTempFile = GetFullPath(StrZToStr(sRet))
|
|
End Function
|
|
|
|
Function GetTempDir() As String
|
|
Dim sRet As String, c As Long
|
|
sRet = String(cMaxPath, 0)
|
|
c = GetTempPath(cMaxPath, sRet)
|
|
If c = 0 Then ApiRaise Err.LastDllError
|
|
GetTempDir = Left$(sRet, c)
|
|
End Function
|
|
|
|
Function SearchDirs(sFileName As String, _
|
|
Optional Ext As String, _
|
|
Optional Path As String, _
|
|
Optional FilePart As Long, _
|
|
Optional ExtPart As Long, _
|
|
Optional DirPart As Long) As String
|
|
|
|
Dim p As Long, c As Long, sRet As String
|
|
|
|
If sFileName = sEmpty Then ApiRaise ERROR_INVALID_PARAMETER
|
|
|
|
' Handle missing or invalid extension or path
|
|
If Ext = sEmpty Then Ext = sNullStr
|
|
If Path = sEmpty Then Path = sNullStr
|
|
|
|
' Get the file (treating empty strings as NULL pointers)
|
|
sRet = String$(cMaxPath, 0)
|
|
c = SearchPath(Path, sFileName, Ext, cMaxPath, sRet, p)
|
|
If c = 0 Then
|
|
If Err.LastDllError = ERROR_FILE_NOT_FOUND Then Exit Function
|
|
ApiRaise Err.LastDllError
|
|
End If
|
|
BugAssert c <= cMaxPath
|
|
sRet = Left$(sRet, c)
|
|
|
|
' Get the directory, file, and extension positions
|
|
GetDirExt sRet, FilePart, DirPart, ExtPart
|
|
SearchDirs = sRet
|
|
|
|
End Function
|
|
|
|
Private Sub GetDirExt(sFull As String, iFilePart As Long, _
|
|
iDirPart As Long, iExtPart As Long)
|
|
|
|
Dim iDrv As Integer, i As Integer, cMax As Integer
|
|
cMax = Len(sFull)
|
|
|
|
iDrv = Asc(UCase$(Left$(sFull, 1)))
|
|
|
|
' If in format d:\path\name.ext, return 3
|
|
If iDrv <= 90 Then ' Less than Z
|
|
If iDrv >= 65 Then ' Greater than A
|
|
If Mid$(sFull, 2, 1) = ":" Then ' Second character is :
|
|
If Mid$(sFull, 3, 1) = "\" Then ' Third character is \
|
|
iDirPart = 3
|
|
End If
|
|
End If
|
|
End If
|
|
Else
|
|
|
|
' If in format \\machine\share\path\name.ext, return position of \path
|
|
' First and second character must be \
|
|
If iDrv <> 92 Then ApiRaise ERROR_BAD_PATHNAME
|
|
If Mid$(sFull, 2, 1) <> "\" Then ApiRaise ERROR_BAD_PATHNAME
|
|
|
|
Dim fFirst As Boolean
|
|
i = 3
|
|
Do
|
|
If Mid$(sFull, i, 1) = "\" Then
|
|
If Not fFirst Then
|
|
fFirst = True
|
|
Else
|
|
iDirPart = i
|
|
Exit Do
|
|
End If
|
|
End If
|
|
i = i + 1
|
|
Loop Until i = cMax
|
|
End If
|
|
|
|
' Start from end and find extension
|
|
iExtPart = cMax + 1 ' Assume no extension
|
|
fFirst = False
|
|
Dim sChar As String
|
|
For i = cMax To iDirPart Step -1
|
|
sChar = Mid$(sFull, i, 1)
|
|
If Not fFirst Then
|
|
If sChar = "." Then
|
|
iExtPart = i
|
|
fFirst = True
|
|
End If
|
|
End If
|
|
If sChar = "\" Then
|
|
iFilePart = i + 1
|
|
Exit For
|
|
End If
|
|
Next
|
|
Exit Sub
|
|
FailGetDirExt:
|
|
iFilePart = 0
|
|
iDirPart = 0
|
|
iExtPart = 0
|
|
End Sub
|
|
|
|
#If fComponent Then
|
|
' Seed the component's copy of the random number generator
|
|
Sub CoreRandomize(Optional Number As Long)
|
|
Randomize Number
|
|
End Sub
|
|
|
|
Function CoreRnd(Optional Number As Long)
|
|
CoreRnd = Rnd(Number)
|
|
End Function
|
|
#End If
|
|
|
|
' GetNextLine returns a line from a string, where a "line" is all characters
|
|
' up to and including a carriage return + line feed. GetNextLine
|
|
' works the same way as GetToken. The first call to GetNextLine
|
|
' should pass the string to parse; subsequent calls should pass
|
|
' an empty string. GetNextLine returns an empty string after all lines
|
|
' have been read from the source string.
|
|
Function GetNextLine(Optional sSource As String) As String
|
|
Static sSave As String, iStart As Long, cSave As Long
|
|
Dim iEnd As Long
|
|
|
|
' Initialize GetNextLine
|
|
If (sSource <> sEmpty) Then
|
|
iStart = 1
|
|
sSave = sSource
|
|
cSave = Len(sSave)
|
|
Else
|
|
If sSave = sEmpty Then Exit Function
|
|
End If
|
|
|
|
' iStart points to first character after the previous sCrLf
|
|
iEnd = InStr(iStart, sSave, sCrLf)
|
|
|
|
If iEnd > 0 Then
|
|
' Return line
|
|
GetNextLine = Mid$(sSave, iStart, iEnd - iStart + 2)
|
|
iStart = iEnd + 2
|
|
If iStart > cSave Then sSave = sEmpty
|
|
Else
|
|
' Return remainder of string as a line
|
|
GetNextLine = Mid$(sSave, iStart) & sCrLf
|
|
sSave = sEmpty
|
|
End If
|
|
End Function
|
|
|
|
' RTrimLine strips off trailing carriage return + line feed
|
|
Function RTrimLine(sLine As String) As String
|
|
If Right$(sLine, 2) = sCrLf Then
|
|
RTrimLine = Left$(sLine, Len(sLine) - 2)
|
|
Else
|
|
RTrimLine = sLine
|
|
End If
|
|
End Function
|
|
|
|
|
|
|