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