Charlotte Foust
cfoust at infostatsystems.com
Tue Dec 2 15:16:15 CST 2003
Don't blame Microsoft for the way area codes are allocated around the globe. They don't have *quite* that much pull ... Yet. <VBG> I ran into this issue years ago when I worked for a company that handled event registration and discovered that area codes and even country codes aren't quite the indicator of country that you might expect. Charlotte Foust -----Original Message----- From: MartyConnelly [mailto:martyconnelly at shaw.ca] Sent: Tuesday, December 02, 2003 11:15 AM To: Access Developers discussion and problem solving Subject: Re: [AccessD] Registry tweaks Yes, I see what you mean. I didn't realize Guantanamo Bay was a seperate country. Recognized by the soverign state of Microsoft, no doubt ;) Charlotte Foust wrote: >The one caution I would suggest here is that the country names are >coming from a telephony key. The problem is that there are separate >"countries" which happen to be islands and which share an area code, so >some of those country names may not be entirely reliable. > >I always have to refresh my memory on callbacks as well, but it's >perfectly possible to create a recordset entirely in memory using ADO >and then persist it to either an ADTG or XML format instead of creating >a table. > >Charlotte Foust > >-----Original Message----- >From: MartyConnelly [mailto:martyconnelly at shaw.ca] >Sent: Monday, December 01, 2003 6:39 PM >To: Access Developers discussion and problem solving >Subject: Re: [AccessD] Registry tweaks > > > >Just use sortcountrylist function as intial call. You don't have to >QuikSort just put in a query after moving to a table >I was going to put into an array at one point. Should give you 230 >countries. > >I find it a pain to use callbacks. I keep having to refresh my memory >as > >to how to use them. > > >Public Const HKEY_CLASSES_ROOT As Long = &H80000000 >Public Const HKEY_CURRENT_USER = &H80000001 >Public Const HKEY_LOCAL_MACHINE As Long = &H80000002 >Public Const HKEY_USERS As Long = &H80000003 >Public Const HKEY_PERFORMANCE_DATA As Long = &H80000004 >Public Const HKEY_CURRENT_CONFIG As Long = &H80000005 >Public Const HKEY_DYN_DATA As Long = &H80000006 > >Const ValueName As String = "Name" >Const MasterKey As String = >"SOFTWARE\Microsoft\Windows\CurrentVersion\Telephony\Country List\" >Public Function getregcountries() As String 'Enumerate the keys inside >the Registry key: ' parts of this from >http://www.vb-helper.com/howto_list_countries.html >' HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\ >' CurrentVersion\Telephony\Country List\ > > Dim KeyCol As Collection > Dim CountryCol As Collection > Dim strCountry As String > strCountry = "" > If CheckRegistryKey(HKEY_LOCAL_MACHINE, MasterKey) Then > > Set KeyCol = EnumRegistryKeys(HKEY_LOCAL_MACHINE, MasterKey) > Dim TheKey As Variant > Set CountryCol = New Collection > > For Each TheKey In KeyCol > If TheKey <> "800" And > GetRegistryValue(HKEY_LOCAL_MACHINE, > >MasterKey & TheKey, "InternationalRule", "") <> "00EFG#" Then > 'CboCountry.AddItem >GetRegistryValue(HKEY_LOCAL_MACHINE, > >MasterKey & TheKey, ValueName, "") > Debug.Print GetRegistryValue(HKEY_LOCAL_MACHINE, >MasterKey & TheKey, ValueName, "") > strCountry = strCountry & >GetRegistryValue(HKEY_LOCAL_MACHINE, MasterKey & TheKey, ValueName, "") >& ";" > End If > Next > End If > getregcountries = strCountry >End Function > > >Function SortCountriesString() As String >Dim arrtemp As Variant >Dim arrCountries(300) As String >Dim strCountries As String >Dim strOutCountries As String >Dim i As Long > ' Get Countries from Registry > strCountries = getregcountries > ' Move countries string to array unsorted > arrtemp = Split(strCountries, ";") > 'put variant array into string array > For i = LBound(arrtemp) To UBound(arrtemp) > arrCountries(i) = arrtemp(i) > Next i > ' now sort array by country name > Quicksort arrCountries, LBound(arrtemp), UBound(arrtemp) > 'put array into string for combobox maybe too long > 2048 bytes > For i = LBound(arrtemp) To UBound(arrtemp) > strOutCountries = strOutCountries & arrCountries(i) & ";" > Next i > > SortCountriesString = strOutCountries > 'Debug.Print Len(SortCountriesString) > ' put sorted array into table > > MoveIntoTable arrCountries(), UBound(arrtemp) >End Function > >Function MoveIntoTable(arrCountries() As String, imax As Long) Dim rs >As Recordset Dim iRow As Integer, iCol As Integer Dim db As Database >Set db = CurrentDb 'pre create table with 1 text field "Country Name" >Set rs = >db.OpenRecordset("CountryName") If rs.RecordCount > 1 Then > MsgBox "table exists already" > Exit Function >End If >With rs > For iRow = 0 To imax > .AddNew > ' 0'th field is autonumber > .Fields(1) = arrCountries(iRow) > .Update > Next > .Close >End With >Set rs = Nothing > >End Function > >Public Sub Quicksort(list() As String, ByVal min As Long, _ > ByVal max As Long) >Dim med_value As String >Dim hi As Long >Dim lo As Long >Dim i As Long > > ' If min >= max, the list contains 0 or 1 items so it > ' is sorted. > If min >= max Then Exit Sub > > ' Pick the dividing value. > i = Int((max - min + 1) * Rnd + min) > med_value = list(i) > > ' Swap it to the front. > list(i) = list(min) > > lo = min > hi = max > Do > ' Look down from hi for a value < med_value. > Do While list(hi) >= med_value > hi = hi - 1 > If hi <= lo Then Exit Do > Loop > If hi <= lo Then > list(lo) = med_value > Exit Do > End If > > ' Swap the lo and hi values. > list(lo) = list(hi) > > ' Look up from lo for a value >= med_value. > lo = lo + 1 > Do While list(lo) < med_value > lo = lo + 1 > If lo >= hi Then Exit Do > Loop > If lo >= hi Then > lo = hi > list(hi) = med_value > Exit Do > End If > > ' Swap the lo and hi values. > list(hi) = list(lo) > Loop > > ' Sort the two sublists. > Quicksort list(), min, lo - 1 > Quicksort list(), lo + 1, max >End Sub > >'registry utilities in seperate module > > Option Compare Database >Option Explicit > >Public Const HKEY_CLASSES_ROOT As Long = &H80000000 >Public Const HKEY_CURRENT_USER = &H80000001 >Public Const HKEY_LOCAL_MACHINE As Long = &H80000002 >Public Const HKEY_USERS As Long = &H80000003 >Public Const HKEY_PERFORMANCE_DATA As Long = &H80000004 >Public Const HKEY_CURRENT_CONFIG As Long = &H80000005 >Public Const HKEY_DYN_DATA As Long = &H80000006 > > > > >Const REG_SZ = 1 >Const REG_EXPAND_SZ = 2 >Const REG_BINARY = 3 >Const REG_DWORD = 4 >Const REG_MULTI_SZ = 7 >Const ERROR_MORE_DATA = 234 >Const KEY_READ = &H20019 ' ((READ_CONTROL Or KEY_QUERY_VALUE Or > ' KEY_ENUMERATE_SUB_KEYS Or KEY_NOTIFY) And >(Not > ' SYNCHRONIZE)) >Const REG_OPENED_EXISTING_KEY = &H2 > >Const KEY_WRITE = &H20006 '((STANDARD_RIGHTS_WRITE Or KEY_SET_VALUE Or > ' KEY_CREATE_SUB_KEY) And (Not SYNCHRONIZE)) > > >Private 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 > > >Private Declare Function RegDeleteValue Lib "advapi32.dll" Alias _ > "RegDeleteValueA" (ByVal hKey As Long, ByVal lpValueName As String) >As Long > > > >Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" >(dest As _ > Any, source As Any, ByVal numBytes As Long) > > >Private Declare Function RegEnumKey Lib "advapi32.dll" Alias >"RegEnumKeyA" _ > (ByVal hKey As Long, ByVal dwIndex As Long, ByVal lpName As String, >_ > ByVal cbName As Long) As Long > >Private 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, _ > lpData As Any, lpcbData As Long) As Long > >Private 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 > >Private Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As >Long) As _ > Long > > >Private Declare Function RegCreateKeyEx Lib "advapi32.dll" Alias _ > "RegCreateKeyExA" (ByVal hKey As Long, ByVal lpSubKey As String, _ > ByVal Reserved As Long, ByVal lpClass As Long, ByVal dwOptions As >Long, _ > ByVal samDesired As Long, ByVal lpSecurityAttributes As Long, _ > phkResult As Long, lpdwDisposition As Long) As Long > > >Private 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 > >Private Declare Function RegDeleteKey Lib "advapi32.dll" Alias >"RegDeleteKeyA" _ > (ByVal hKey As Long, ByVal lpSubKey As String) As Long > > > >Sub DeleteRegistryKey(ByVal hKey As Long, ByVal KeyName As String) > RegDeleteKey hKey, KeyName >End Sub > > > > >Function DeleteRegistryValue(ByVal hKey As Long, ByVal KeyName As >String, _ > ByVal ValueName As String) As Boolean > Dim handle As Long > > ' Open the key, exit if not found > If RegOpenKeyEx(hKey, KeyName, 0, KEY_WRITE, handle) Then Exit >Function > > ' Delete the value (returns 0 if success) > DeleteRegistryValue = (RegDeleteValue(handle, ValueName) = 0) > ' Close the handle > RegCloseKey handle >End Function > >Function CheckRegistryKey(ByVal hKey As Long, ByVal KeyName As String) >As _ > Boolean > Dim handle As Long > ' Try to open the key > If RegOpenKeyEx(hKey, KeyName, 0, KEY_READ, handle) = 0 Then > ' The key exists > CheckRegistryKey = True > ' Close it before exiting > RegCloseKey handle > End If >End Function > > >Function CreateRegistryKey(ByVal hKey As Long, ByVal KeyName As String) >As _ > Boolean > Dim handle As Long, disposition As Long > > If RegCreateKeyEx(hKey, KeyName, 0, 0, 0, 0, 0, handle, > disposition) > >Then > Err.Raise 1001, , "Unable to create the registry key" > Else > ' Return True if the key already existed. > CreateRegistryKey = (disposition = REG_OPENED_EXISTING_KEY) > ' Close the key. > RegCloseKey handle > End If >End Function > > >Function EnumRegistryKeys(ByVal hKey As Long, ByVal KeyName As String) >As _ > Collection > Dim handle As Long > Dim length As Long > Dim index As Long > Dim subkeyName As String > > ' initialize the result collection > Set EnumRegistryKeys = New Collection > > ' Open the key, exit if not found > If Len(KeyName) Then > If RegOpenKeyEx(hKey, KeyName, 0, KEY_READ, handle) Then Exit >Function > ' in all case the subsequent functions use hKey > hKey = handle > End If > > Do > ' this is the max length for a key name > length = 260 > subkeyName = Space$(length) > ' get the N-th key, exit the loop if not found > If RegEnumKey(hKey, index, subkeyName, length) Then Exit Do > > ' add to the result collection > subkeyName = Left$(subkeyName, InStr(subkeyName, vbNullChar) - >1) > EnumRegistryKeys.Add subkeyName, subkeyName > ' prepare to query for next key > index = index + 1 > Loop > > ' Close the key, if it was actually opened > If handle Then RegCloseKey handle > >End Function > > >Function EnumRegistryValues(ByVal hKey As Long, ByVal KeyName As >String) > >As _ > Collection > Dim handle As Long > Dim index As Long > Dim valueType As Long > Dim name As String > Dim nameLen As Long > Dim resLong As Long > Dim resString As String > Dim dataLen As Long > Dim valueInfo(0 To 1) As Variant > Dim retVal As Long > > ' initialize the result > Set EnumRegistryValues = New Collection > > ' Open the key, exit if not found. > If Len(KeyName) Then > If RegOpenKeyEx(hKey, KeyName, 0, KEY_READ, handle) Then Exit >Function > ' in all cases, subsequent functions use hKey > hKey = handle > End If > > Do > ' this is the max length for a key name > nameLen = 260 > name = Space$(nameLen) > ' prepare the receiving buffer for the value > dataLen = 4096 > ReDim resBinary(0 To dataLen - 1) As Byte > > ' read the value's name and data > ' exit the loop if not found > retVal = RegEnumValue(hKey, index, name, nameLen, ByVal 0&, >valueType, _ > resBinary(0), dataLen) > > ' enlarge the buffer if you need more space > If retVal = ERROR_MORE_DATA Then > ReDim resBinary(0 To dataLen - 1) As Byte > retVal = RegEnumValue(hKey, index, name, nameLen, ByVal 0&, >_ > valueType, resBinary(0), dataLen) > End If > ' exit the loop if any other error (typically, no more values) > If retVal Then Exit Do > > ' retrieve the value's name > valueInfo(0) = Left$(name, nameLen) > > ' return a value corresponding to the value type > Select Case valueType > Case REG_DWORD > CopyMemory resLong, resBinary(0), 4 > valueInfo(1) = resLong > Case REG_SZ, REG_EXPAND_SZ > ' copy everything but the trailing null char > resString = Space$(dataLen - 1) > CopyMemory ByVal resString, resBinary(0), dataLen - 1 > valueInfo(1) = resString > Case REG_BINARY > ' shrink the buffer if necessary > If dataLen < UBound(resBinary) + 1 Then > ReDim Preserve resBinary(0 To dataLen - 1) As Byte > End If > valueInfo(1) = resBinary() > Case REG_MULTI_SZ > ' copy everything but the 2 trailing null chars > resString = Space$(dataLen - 2) > CopyMemory ByVal resString, resBinary(0), dataLen - 2 > valueInfo(1) = resString > Case Else > ' Unsupported value type - do nothing > End Select > > ' add the array to the result collection > ' the element's key is the value's name > EnumRegistryValues.Add valueInfo, valueInfo(0) > > index = index + 1 > Loop > > ' Close the key, if it was actually opened > If handle Then RegCloseKey handle > >End Function >Function EnumRegistryValuesEx(ByVal hKey As Long, ByVal KeyName As >String) As _ > Collection > Dim handle As Long > Dim index As Long > Dim valueType As Long > Dim name As String > Dim nameLen As Long > Dim resLong As Long > Dim resString As String > Dim dataLen As Long > Dim valueInfo(0 To 2) As Variant > Dim retVal As Long > > ' initialize the result > Set EnumRegistryValuesEx = New Collection > > ' Open the key, exit if not found. > If Len(KeyName) Then > If RegOpenKeyEx(hKey, KeyName, 0, KEY_READ, handle) Then Exit >Function > ' in all cases, subsequent functions use hKey > hKey = handle > End If > > Do > ' this is the max length for a key name > nameLen = 260 > name = Space$(nameLen) > ' prepare the receiving buffer for the value > dataLen = 4096 > ReDim resBinary(0 To dataLen - 1) As Byte > > ' read the value's name and data > ' exit the loop if not found > retVal = RegEnumValue(hKey, index, name, nameLen, ByVal 0&, >valueType, _ > resBinary(0), dataLen) > > ' enlarge the buffer if you need more space > If retVal = ERROR_MORE_DATA Then > ReDim resBinary(0 To dataLen - 1) As Byte > retVal = RegEnumValue(hKey, index, name, nameLen, ByVal 0&, >_ > valueType, resBinary(0), dataLen) > End If > ' exit the loop if any other error (typically, no more values) > If retVal Then Exit Do > > ' retrieve the value's name > valueInfo(0) = Left$(name, nameLen) > > ' return a value corresponding to the value type > Select Case valueType > Case REG_DWORD > CopyMemory resLong, resBinary(0), 4 > valueInfo(1) = resLong > valueInfo(2) = vbLong > Case REG_SZ, REG_EXPAND_SZ > ' copy everything but the trailing null char > resString = Space$(dataLen - 1) > CopyMemory ByVal resString, resBinary(0), dataLen - 1 > valueInfo(1) = resString > valueInfo(2) = vbString > Case REG_BINARY > ' shrink the buffer if necessary > If dataLen < UBound(resBinary) + 1 Then > ReDim Preserve resBinary(0 To dataLen - 1) As Byte > End If > valueInfo(1) = resBinary() > valueInfo(2) = vbArray + vbByte > Case REG_MULTI_SZ > ' copy everything but the 2 trailing null chars > resString = Space$(dataLen - 2) > CopyMemory ByVal resString, resBinary(0), dataLen - 2 > valueInfo(1) = resString > valueInfo(2) = vbString > Case Else > ' Unsupported value type - do nothing > End Select > > ' add the array to the result collection > ' the element's key is the value's name > EnumRegistryValuesEx.Add valueInfo, valueInfo(0) > > index = index + 1 > Loop > > ' Close the key, if it was actually opened > If handle Then RegCloseKey handle > >End Function > > >Function GetRegistryValue(ByVal hKey As Long, ByVal KeyName As String, _ > ByVal ValueName As String, Optional DefaultValue As Variant) As >Variant > Dim handle As Long > Dim resLong As Long > Dim resString As String > Dim resBinary() As Byte > Dim length As Long > Dim retVal As Long > Dim valueType As Long > > ' Prepare the default result > GetRegistryValue = IIf(IsMissing(DefaultValue), Empty, > DefaultValue) > > ' Open the key, exit if not found. > If RegOpenKeyEx(hKey, KeyName, 0, KEY_READ, handle) Then > Exit Function > End If > > ' prepare a 1K receiving resBinary > length = 1024 > ReDim resBinary(0 To length - 1) As Byte > > ' read the registry key > retVal = RegQueryValueEx(handle, ValueName, 0, valueType, >resBinary(0), _ > length) > ' if resBinary was too small, try again > If retVal = ERROR_MORE_DATA Then > ' enlarge the resBinary, and read the value again > ReDim resBinary(0 To length - 1) As Byte > retVal = RegQueryValueEx(handle, ValueName, 0, valueType, >resBinary(0), _ > length) > End If > > ' return a value corresponding to the value type > Select Case valueType > Case REG_DWORD > CopyMemory resLong, resBinary(0), 4 > GetRegistryValue = resLong > Case REG_SZ, REG_EXPAND_SZ > ' copy everything but the trailing null char > resString = Space$(length - 1) > CopyMemory ByVal resString, resBinary(0), length - 1 > GetRegistryValue = resString > Case REG_BINARY > ' resize the result resBinary > If length <> UBound(resBinary) + 1 Then > ReDim Preserve resBinary(0 To length - 1) As Byte > End If > GetRegistryValue = resBinary() > Case REG_MULTI_SZ > ' copy everything but the 2 trailing null chars > resString = Space$(length - 2) > CopyMemory ByVal resString, resBinary(0), length - 2 > GetRegistryValue = resString > Case Else > RegCloseKey handle > Err.Raise 1001, , "Unsupported value type" > End Select > > ' close the registry key > RegCloseKey handle >End Function > > > > >Function SetRegistryValue(ByVal hKey As Long, ByVal KeyName As String, _ > ByVal ValueName As String, value As Variant) As Boolean > Dim handle As Long > Dim lngValue As Long > Dim strValue As String > Dim binValue() As Byte > Dim length As Long > Dim retVal As Long > > ' Open the key, exit if not found > If RegOpenKeyEx(hKey, KeyName, 0, KEY_WRITE, handle) Then > Exit Function > End If > > ' three cases, according to the data type in Value > Select Case VarType(value) > Case vbInteger, vbLong > lngValue = value > retVal = RegSetValueEx(handle, ValueName, 0, REG_DWORD, >lngValue, 4) > Case vbString > strValue = value > retVal = RegSetValueEx(handle, ValueName, 0, REG_SZ, ByVal >strValue, _ > Len(strValue)) > Case vbArray + vbByte > binValue = value > length = UBound(binValue) - LBound(binValue) + 1 > retVal = RegSetValueEx(handle, ValueName, 0, REG_BINARY, _ > binValue(LBound(binValue)), length) > Case Else > RegCloseKey handle > Err.Raise 1001, , "Unsupported value type" > End Select > > ' Close the key and signal success > RegCloseKey handle > ' signal success if the value was written correctly > SetRegistryValue = (retVal = 0) >End Function > > > > > > > -- Marty Connelly Victoria, B.C. Canada _______________________________________________ AccessD mailing list AccessD at databaseadvisors.com http://databaseadvisors.com/mailman/listinfo/accessd Website: http://www.databaseadvisors.com