You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

484 lines
19 KiB

Attribute VB_Name = "Utility"
Option Explicit
' Registry access API
Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As Long) As Long
Declare Function RegEnumValue Lib "advapi32.dll" Alias "RegEnumValueA" (ByVal hKey As Long, ByVal dwIndex As Long, ByVal lpValueName As String, lpcbValueName As Long, ByVal lpReserved As Long, lpType As Long, ByVal lpData As String, lpcbData As Long) As Long
Declare Function RegSetValueEx Lib "advapi32.dll" Alias "RegSetValueExA" (ByVal hKey As Long, ByVal lpValueName As String, ByVal Reserved As Long, ByVal dwType As Long, lpData As Any, ByVal cbData As Long) As Long
Declare Function RegQueryInfoKey Lib "advapi32.dll" Alias "RegQueryInfoKeyA" (ByVal hKey As Long, ByVal lpClass As String, lpcbClass As Long, ByVal lpReserved As Long, lpcSubKeys As Long, lpcbMaxSubKeyLen As Long, lpcbMaxClassLen As Long, lpcValues As Long, lpcbMaxValueNameLen As Long, lpcbMaxValueLen As Long, lpcbSecurityDescriptor As Long, ByVal lpftLastWriteTime As Long) As Long
Declare Function RegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExA" (ByVal hKey As Long, ByVal lpValueName As String, ByVal lpReserved As Long, lpType As Long, lpData As Any, lpcbData As Long) As Long
Declare Function RegCreateKeyEx Lib "advapi32.dll" Alias "RegCreateKeyExA" (ByVal hKey As Long, ByVal lpSubKey As String, ByVal Reserved As Long, ByVal lpClass As String, ByVal dwOptions As Long, ByVal samDesired As Long, ByVal lpSecurityAttributes As Long, phkResult As Long, lpdwDisposition As Long) As Long
Declare Function RegDeleteKey Lib "advapi32.dll" Alias "RegDeleteKeyA" (ByVal hKey As Long, ByVal lpSubKey As String) As Long
Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" (ByVal hKey As Long, ByVal lpSubKey As String, ByVal ulOptions As Long, ByVal samDesired As Long, phkResult As Long) As Long
Declare Function GetTempPath Lib "Kernel32" Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Declare Function GetTempFileNameAPI Lib "Kernel32" Alias "GetTempFileNameA" (ByVal lpszPath As String, ByVal lpPrefixString As String, ByVal wUnique As Long, ByVal lpTempFileName As String) As Long
Public Const MAX_PATH = 260
' Registry constants
Public Const ERROR_SUCCESS = 0
Public Const HKEY_CURRENT_USER = &H80000001
Public Const HKEY_LOCAL_MACHINE = &H80000002
Public Const REG_OPTION_NON_VOLATILE = 0
Public Const KEY_ALL_ACCESS = &HF003F ' ((STANDARD_RIGHTS_ALL Or KEY_QUERY_VALUE Or KEY_SET_VALUE Or KEY_CREATE_SUB_KEY Or KEY_ENUMERATE_SUB_KEYS Or KEY_NOTIFY Or KEY_CREATE_LINK) And (Not SYNCHRONIZE))
Public Const REG_SZ = 1
Public Function AddItemToList(ctrControl As Control, ByVal sItem As String) As Boolean
' Adds an item to the control's list if it is not a duplicate
' Returns true if the item was added
Dim i As Integer
Dim bAddItem As Boolean
sItem = Trim(sItem)
With ctrControl
bAddItem = True
For i = 0 To .ListCount - 1
If StrComp(sItem, .List(i), vbTextCompare) = 0 Then
bAddItem = False
Exit For
End If
Next
If bAddItem Then
.AddItem sItem
End If
AddItemToList = bAddItem
End With
End Function
Sub AlignTextToBottom(ctlControl As Control, sText As String)
' Sets the default property of the specified control to the specified text such that the text is aligned to
' to the bottom of the control. Wordwrap must be set to True.
' Currently, only Label controls are supported.
Debug.Assert TypeName(ctlControl) = "Label"
Dim iMaxLines As Integer ' The max number of lines the control can handle
Dim iNumLines As Integer ' The number of lines in the current message
With ctlControl
iMaxLines = Int(.Height / .Parent.TextHeight("A"))
iNumLines = Int(.Parent.TextWidth(sText) / .Width) + 1 ' Leave an additional line for wordwrap overflow
If iNumLines < iMaxLines Then
ctlControl = String(iMaxLines - iNumLines, vbCrLf) & sText ' Pad with blank lines
Else
ctlControl = sText
End If
.Refresh
End With
End Sub
Sub LoadResStrings(frm As Form)
On Error Resume Next
Dim ctl As Control
Dim Obj As Object
Dim iResID As Integer, i As Integer
'set the form's caption
If IsNumeric(frm.Tag) Then
frm.Caption = LoadResString(CInt(frm.Tag))
End If
'set the controls' captions using the caption
'property for menu items and the Tag property
'for all other controls
For Each ctl In frm.Controls
Err.Clear
Select Case TypeName(ctl)
Case "Menu":
iResID = CInt(Left$(ctl.Caption, 5)) ' Upto first 5 characters for res id, pad with spaces
If Err = 0 Then
ctl.Caption = LoadResString(iResID)
End If
Case "SSTab":
For i = 0 To ctl.Tabs - 1
iResID = CInt(Left$(ctl.TabCaption(i), 5)) ' Upto first 5 characters for res id, pad with spaces
If Err = 0 Then
ctl.TabCaption(i) = LoadResString(iResID)
End If
Next
Case "TabStrip":
For Each Obj In ctl.Tabs
Err.Clear
If IsNumeric(Obj.Tag) Then
Obj.Caption = LoadResString(CInt(Obj.Tag))
End If
'check for a tooltip
If IsNumeric(Obj.ToolTipText) Then
If Err = 0 Then
Obj.ToolTipText = LoadResString(CInt(Obj.ToolTipText))
End If
End If
Next
Case "Toolbar":
For Each Obj In ctl.Buttons
Err.Clear
If IsNumeric(Obj.Tag) Then
Obj.ToolTipText = LoadResString(CInt(Obj.Tag))
End If
Next
Case "ListView":
For Each Obj In ctl.ColumnHeaders
Err.Clear
If IsNumeric(Obj.Tag) Then
Obj.Text = LoadResString(CInt(Obj.Tag))
End If
Next
Case Else
If IsNumeric(ctl.Tag) Then
If Err = 0 Then
ctl.Caption = LoadResString(CInt(ctl.Tag))
End If
End If
'check for a tooltip
If IsNumeric(ctl.ToolTipText) Then
If Err = 0 Then
ctl.ToolTipText = LoadResString(CInt(ctl.ToolTipText))
End If
End If
End Select
Next
End Sub
Public Function RegKeyExists(hRootKey As Long, sKey As String) As Boolean
' Returns True if the specified key exists under the specified root key, else returns False
Dim hKey As Long
If RegOpenKeyEx(hRootKey, sKey, 0, KEY_ALL_ACCESS, hKey) = ERROR_SUCCESS Then
RegCloseKey hKey
RegKeyExists = True
Else
RegKeyExists = False
End If
End Function
Public Function SaveRegSetting(strMainKey As String, strSubKey As String, strValueName As String, _
strValue As String) As Boolean
' Saves the specified value in the registry under the key composed of the specified key and subkey.
' Only string values supported for now.
' Returns true if successful
Dim hKey As Long, cbData As Long
Dim strKey As String
On Error GoTo SaveRegSettingError
If strSubKey = "" Then
strKey = strMainKey
Else
strKey = strMainKey & "\" & strSubKey
End If
If (RegCreateKeyEx(HKEY_LOCAL_MACHINE, strKey, 0, vbNullString, _
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, hKey, 0)) = ERROR_SUCCESS Then
cbData = LenB(StrConv(strValue, vbFromUnicode))
If RegSetValueEx(hKey, strValueName, 0, REG_SZ, ByVal strValue, cbData) <> ERROR_SUCCESS Then
RegCloseKey hKey
Err.Raise E_UNEXPECTED
End If
RegCloseKey hKey
SaveRegSetting = True
Else
Err.Raise E_UNEXPECTED
End If
SaveRegSettingResume:
Exit Function
SaveRegSettingError:
SaveRegSetting = False
Resume SaveRegSettingResume
End Function
Public Sub SelectListItem(ctlList As Control, strValue As String)
' Selects the item that matches strValue in ctlList (ListBox or Combo)
Dim i As Integer, iNewIndex As Integer
Debug.Assert TypeName(ctlList) = "ComboBox" Or TypeName(ctlList) = "ListBox"
With ctlList
iNewIndex = -1
For i = 0 To .ListCount - 1
If .List(i) = strValue Then iNewIndex = i
Next
.ListIndex = iNewIndex
End With
End Sub
Public Function GetRegSetting(strMainKey As String, strSubKey As String, strValueName As String, _
Optional strDefault As String = "", Optional hRootKey As Long = HKEY_LOCAL_MACHINE) As String
' Gets the specified value from the registry key composed of the specified key and subkey.
' Only string values supported for now.
Dim hKey As Long, cbData As Long, lType As Long
Dim strKey As String, strData As String * glMAX_NAME_LENGTH
If strSubKey = "" Then
strKey = strMainKey
Else
strKey = strMainKey & "\" & strSubKey
End If
If RegOpenKeyEx(hRootKey, strKey, 0, KEY_ALL_ACCESS, hKey) = ERROR_SUCCESS Then
cbData = LenB(StrConv(strData, vbFromUnicode))
Dim lReserved As Long
If RegQueryValueEx(hKey, strValueName, 0, lType, ByVal strData, cbData) = ERROR_SUCCESS Then
GetRegSetting = TruncateAtNull(strData)
Else
GetRegSetting = strDefault
End If
RegCloseKey hKey
Else
GetRegSetting = strDefault
End If
End Function
Public Function GetTempDir() As String
' Returns the temp directory path
Dim TmpDirLen As Long
Dim TmpDir As String
Dim TmpDirLenActual As Long
TmpDirLen = GetTempPath(0, TmpDir) ' Get the length needed for the temp directory
TmpDir = Space(TmpDirLen) ' Create enough space for it then get it
TmpDirLenActual = GetTempPath(TmpDirLen, TmpDir)
' Strip off any extra stuff
If TmpDirLen > TmpDirLenActual Then
GetTempDir = Left(TmpDir, TmpDirLenActual)
Else
GetTempDir = App.Path & "\" ' This code should never get executed - but, just in case
End If
End Function
Public Function GetTempFileName() As String
' Returns a unique filename.
Dim sTempDir As String, sFileName As String
sTempDir = GetTempDir
sFileName = Space$(MAX_PATH)
If GetTempFileNameAPI(sTempDir, "ape", 0, sFileName) <> 0 Then
GetTempFileName = TruncateAtNull(sFileName)
Else
GetTempFileName = ""
End If
End Function
Function Substitute(sString As String, sFind As String, sReplace As String) As String
' Substitutes string sReplace in place of string sFind in sString
Dim lStart As Long, lEnd As Long, lFindLength As Long
Dim sNewString As String
sNewString = ""
lFindLength = Len(sFind)
lStart = 1
lEnd = InStr(lStart, sString, sFind)
Do While lEnd > 0
sNewString = sNewString & Mid(sString, lStart, lEnd - lStart) & sReplace
lStart = lEnd + lFindLength
lEnd = InStr(lStart, sString, sFind)
Loop
Substitute = sNewString & Mid(sString, lStart)
End Function
Public Function RemoveAmpersands(strString As String) As String
' Removes the ampersands in the specified string.
RemoveAmpersands = Substitute(strString, "&", "")
End Function
Public Function DSNExists(sDSN As String) As Boolean
' Returns True if the specified DSN exists, else returns False.
If sDSN = "" Then
DSNExists = False
Else
DSNExists = RegKeyExists(HKEY_CURRENT_USER, gsODBC_INI_REG_KEY & "\" & sDSN)
End If
End Function
Public Function GetDSNValue(sDSN As String, sValueName As String) As String
' Returns the specified value (sValueName) of the specified DSN (sDSN)
GetDSNValue = GetRegSetting(gsODBC_INI_REG_KEY, sDSN, sValueName, "", HKEY_CURRENT_USER)
End Function
Public Function GetAllRegSettings(strMainKey As String, strSubKey As String) As Variant
' Returns an array of all values under the registry key composed of the specified key and subkey.
' Only string values supported for now.
Dim hKey As Long, cbData As Long, cbValueName As Long, lType As Long
Dim strKey As String, strData As String * giMAX_REG_DATA_LENGTH, strValueName As String * glMAX_NAME_LENGTH
Dim aValues() As String
If strSubKey = "" Then
strKey = strMainKey
Else
strKey = strMainKey & "\" & strSubKey
End If
If (RegCreateKeyEx(HKEY_LOCAL_MACHINE, strKey, 0, vbNullString, _
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, hKey, 0)) = ERROR_SUCCESS Then
' Iterate over all the values in this key
Dim strClass As String * glMAX_NAME_LENGTH
Dim cbClass As Long, cSubKeys As Long, cbMaxSubKeyLen As Long, cbMaxClassLen As Long, lReserved As Long
Dim cValues As Long, cbMaxValueNameLen As Long, cbMaxValueLen As Long, cbSecurityDescriptor As Long
cbClass = LenB(StrConv(strClass, vbFromUnicode))
If RegQueryInfoKey(hKey, strClass, cbClass, lReserved, cSubKeys, cbMaxSubKeyLen, cbMaxClassLen, cValues, cbMaxValueNameLen, _
cbMaxValueLen, cbSecurityDescriptor, 0) = ERROR_SUCCESS Then
If cValues > 0 Then
ReDim aValues(0 To cValues - 1, 0 To 1)
Dim i As Long
For i = 0 To cValues - 1
cbValueName = LenB(StrConv(strValueName, vbFromUnicode))
cbData = LenB(StrConv(strData, vbFromUnicode))
If RegEnumValue(hKey, i, strValueName, cbValueName, 0, lType, strData, cbData) = ERROR_SUCCESS Then
aValues(i, 0) = TruncateAtNull(strValueName)
aValues(i, 1) = TruncateAtNull(strData)
End If
Next
GetAllRegSettings = aValues
End If
End If
RegCloseKey hKey
End If
End Function
Public Function DeleteRegSettings(strMainKey As String, strSubKey As String) As Boolean
' Deletes the specified key and all its sub keys
' Returns true is successful
Dim strKey As String
If strSubKey = "" Then
strKey = strMainKey
Else
strKey = strMainKey & "\" & strSubKey
End If
DeleteRegSettings = (RegDeleteKey(HKEY_LOCAL_MACHINE, strKey) = ERROR_SUCCESS)
End Function
Public Function Min(a, b)
If a < b Then
Min = a
Else
Min = b
End If
End Function
Public Function Max(a, b)
If b > a Then
Max = b
Else
Max = a
End If
End Function
Public Function TruncateAtNull(ByVal strText As String) As String
' Returns the specified string truncated at the first null character
Dim lLen As Long
lLen = InStr(strText, Chr(0))
If lLen < 1 Then
TruncateAtNull = strText
Else
TruncateAtNull = Left(strText, lLen - 1)
End If
End Function
Public Function TruncateFile(sFileName As String, dSize As Double)
' Truncates the specified file to lSize bytes. Truncation occurs at the beginning of the file.
Const CHUNK_SIZE = 65535 ' Size of chunk for copying file contents
Dim dOverflow As Double
dOverflow = CDbl(FileLen(sFileName)) - dSize
If dOverflow > 0 Then
Dim sTempFile As String, baChunk(CHUNK_SIZE) As Byte
Dim lFileNum As Long, lTempFileNum As Long
sTempFile = GetTempFileName
lFileNum = FreeFile
Open sFileName For Binary Access Read As lFileNum
lTempFileNum = FreeFile
Open sTempFile For Binary Access Write As lTempFileNum
Seek lFileNum, dOverflow + 1
' Start copying file from first complete line - fill the very first (incomplete) line with "." characters.
Get lFileNum, , baChunk
Dim l As Long
For l = LBound(baChunk) To UBound(baChunk)
If baChunk(l) <> 13 Then ' = vbCr
baChunk(l) = 46 ' = Asc(".")
Else
Put lTempFileNum, , baChunk
Exit For
End If
Next
Do While Not EOF(lFileNum)
Get lFileNum, , baChunk
Put lTempFileNum, , baChunk
Loop
Close lFileNum
Close lTempFileNum
FileCopy sTempFile, sFileName
Kill sTempFile
End If
End Function
Public Function StripPath(strFileName As String, Optional bStripExtension As Boolean = False) As String
' Strips the path off the specified fully qualified filename. If bStripExtension is True, the file extension is stripped as well.
Dim iStart As Integer, iNext As Integer, iActualStart As Integer
' First, find the beginning of the actual filename
iStart = 0
Do
iNext = InStr(iStart + 1, strFileName, "\")
If iNext = 0 Then
Exit Do
End If
iStart = iNext
Loop
iActualStart = iStart + 1 ' Point to beginning of actual filename
' Next, find the beginning of the extension (which immediately follows the last period in the filename)
If bStripExtension Then
Do
iNext = InStr(iStart + 1, strFileName, ".")
If iNext = 0 Then
Exit Do
End If
iStart = iNext
Loop
End If
If iStart = iActualStart - 1 Then ' If no extension
StripPath = Mid(strFileName, iActualStart)
Else
StripPath = Mid(strFileName, iActualStart, iStart - iActualStart)
End If
End Function
Public Sub SizeToFit(ctl As Control)
' Resizes the control to fit the displayed text
With ctl
Select Case TypeName(ctl)
Case "CheckBox", "OptionButton"
.Width = .Parent.TextWidth(.Caption) + .Height ' Compensate for non-text area
Case Else
Debug.Assert False
End Select
End With
End Sub
Public Function SubstituteParams(bstrString As String, ParamArray aParams()) As String
' Substitutes the parameters in the paramarray for placeholders in the string. The placeholders are of the format
' '%n' where 'n' represents the index of the parameter in the paramarray.
' A maximum of 10 parameters (0 - 9) are supported.
Dim iStart As Integer, iPtr As Integer, iParamNum As Integer
Dim cChar As String * 1
Dim bstrReturn As String
iStart = 1
iPtr = InStr(bstrString, "%")
Do While iPtr > 0 And iPtr < Len(bstrString)
bstrReturn = bstrReturn & Mid$(bstrString, iStart, iPtr - iStart)
cChar = Mid(bstrString, iPtr + 1, 1)
If IsNumeric(cChar) Then
iParamNum = Val(cChar)
If iParamNum <= UBound(aParams) Then
bstrReturn = bstrReturn & aParams(iParamNum)
End If
End If
iStart = iPtr + 2
iPtr = InStr(iStart, bstrString, "%")
Loop
SubstituteParams = bstrReturn & Mid(bstrString, iStart)
End Function