'===========================================================================
' Subject: WRAPPER FOR WIN9X REGISTRY API     Date: 05-13-00 (15:32)       
'  Author: Jeremiah Hyde                      Code: VB5                    
'  Origin: fishoffire@yahoo.com             Packet: VBWIN.ABC
'===========================================================================
Attribute VB_Name = "Registry"
'PPPPPP
'PP  PP
'PP  PP  rr rrr   oooo    ggg gg  rr rrr   aaaa   mm  mm    eeee   rr rrr   zzzzzz
'PPPPP    rrr rr oo  oo  gg  gg    rrr rr     aa  mmmmmmm  ee  ee   rrr rr  z  zz
'PP       rr  rr oo  oo  gg  gg    rr  rr  aaaaa  mmmmmmm  eeeeee   rr  rr    zz
'PP       rr     oo  oo   ggggg    rr     aa  aa  mm m mm  ee       rr       zz  z
'PP      rrrr     oooo       gg   rrrr     aaaaa  mm   mm   eeee   rrrr     zzzzzz
'                         ggggg                               (  /\__________/\  )
'   ###########                                                \(^ @___..___@ ^)/
'   # ___ ___ #   RRRRR            lll            !!   !!       /\ (\/\/\/\/) /\
'   { (0) (0) }   RR  RR            ll           !!!! !!!!     /  \(/\/\/\/\)/  \
'   |    P    |   RR  RR  uu  uu    ll   zzzzzz  !!!! !!!!   -(    """"""""""    )
'    \ \___/ /    RRRRR   uu  uu    ll   z  zz   !!!! !!!!    \      _____      /
'      \___/      RR RR   uu  uu    ll     zz     !!   !!     (     /(   )\     )
'  Jeremiah "BJ"  RR  RR  uu  uu    ll    zz  z               _)   (_V) (V_)   (_
'      Hyde       RR  RR   uuu uu  llll  zzzzzz   !!   !!    (V)(V)(V)   (V)(V)(V)
'                                                         My dog Smokey(Brainless Mutt)
'
' This code released under the GNU General Public License. This means you can use it,
' compile it, pass it around, modify it, WHATEVER! However, if you do this, I will
' expect notification and a copy of whatever you've done, unless it's a virus, or
' breaking into the CIA, etc. Also, there should be a prominent display in the program,
' visible to users, stating that I am responsible for that part of the program.
'                                                    Jeremiah "BJ" Hyde
' E-Mail me at: fishoffire@yahoo.com               fishoffire Industries:
'Visit me at: www.geocities.com/fishoffire/           Your source for
'                                                    EVERYTHING QBasic
'Note:
' This code has been tested on one machine(An AMD K6-266, 32MB RAM, 4.2GB HD, 15"
' PnP Monitor, Win95 DOS Box), and has run correctly there. However, no guarantee,
' warranty, or other declaration of safety, etc. is offered. If your computer system
' is taken over by smurfs, or the PROM is zapped, or anything else of a detrimental
' nature happens to your system as a result of this code, I am not responsible for
' it. The full burden of blame rests on your shoulders. (Of course, if something
' GOOD happens to your computer as a result of this code, well, obviously, I did it!)

' This module is a wrapper for the Win9x Registry API. Most of the time, you can
' safely use this as a "black box," without even understanding it. However, I think
' the code is clear enough to expand, if you want. If this code is too difficult to
' use, then try to find my EasyReg.bas, which provides Drop-In replacements for VB's
' native registry support(Should be in the same place you got this from).
Option Explicit
Public Enum HKEY_BASE
    [_hkMin] = &H80000000
    HKEY_CLASSES_ROOT = &H80000000
    HKEY_CURRENT_USER = &H80000001
    HKEY_LOCAL_MACHINE = &H80000002
    HKEY_USERS = &H80000003
    HKEY_PERFORMANCE_DATA = &H80000004
    HKEY_CURRENT_CONFIG = &H80000005
    HKEY_DYN_DATA = &H80000006
    [_hkMax] = &H80000006
End Enum
Private Const ERROR_SUCCESS = 0&

Private Const REG_SZ = 1
Private Const REG_DWORD = 4

Global Const regError = 4096
Global Const regCloseKeyErr = regError + 1
Global Const regCreateKeyErr = regError + 2
Global Const regDeleteKeyErr = regError + 3
Global Const regEnumKeyErr = regError + 4
Global Const regOpenKeyErr = regError + 5
Global Const regQueryStringValueErr = regError + 6
Global Const regQueryNumericValueErr = regError + 7
Global Const regSetStringValueErr = regError + 8
Global Const regSetNumericValueErr = regError + 9

Private Declare Function OSRegCloseKey Lib "advapi32" Alias "RegCloseKey" (ByVal HKEY As Long) As Long
Private Declare Function OSRegCreateKey Lib "advapi32" Alias "RegCreateKeyA" (ByVal HKEY As Long, ByVal lpszSubKey As String, phkResult As Long) As Long
Private Declare Function OSRegDeleteKey Lib "advapi32" Alias "RegDeleteKeyA" (ByVal HKEY As Long, ByVal lpszSubKey As String) As Long
Private Declare Function OSRegEnumKey Lib "advapi32" Alias "RegEnumKeyA" (ByVal HKEY As Long, ByVal iSubKey As Long, ByVal lpszName As String, ByVal cchName As Long) As Long
Private Declare Function OSRegOpenKey Lib "advapi32" Alias "RegOpenKeyA" (ByVal HKEY As Long, ByVal lpszSubKey As String, phkResult As Long) As Long
Private Declare Function OSRegQueryValueEx Lib "advapi32" Alias "RegQueryValueExA" (ByVal HKEY As Long, ByVal lpszValueName As String, ByVal dwReserved As Long, lpdwType As Long, lpbData As Any, cbData As Long) As Long
Private Declare Function OSRegSetValueEx Lib "advapi32" Alias "RegSetValueExA" (ByVal HKEY As Long, ByVal lpszValueName As String, ByVal dwReserved As Long, ByVal fdwType As Long, lpbData As Any, ByVal cbData As Long) As Long

Public Sub RegCloseKey(ByVal hOpenKey As Long)
' Closes an open registry key.
    If OSRegCloseKey(hOpenKey) = ERROR_SUCCESS Then
        ' We succeeded, nothing more to do
    Else
        ' We failed, throw an error
        Err.Raise regCloseKeyErr, , "Unable to close key. RegCloseKey failed."
    End If
End Sub

Public Function RegCreateKey(ByVal hKeyRoot As Long, ByVal lpszSubKey As String) As Long
' Opens (creates if already exists) a key in the system registry.
' Returns the handle of the opened or created key
    Dim phkResult As Long
    If OSRegCreateKey(hKeyRoot, lpszSubKey, phkResult) = ERROR_SUCCESS Then
        ' Successfully created key, return hKey
        RegCreateKey = phkResult
    Else
        ' There was an error, throw it
        Err.Raise regCreateKeyErr, , "Unable to create(or open) key """ & lpszSubKey & """. RegCreateKey failed."
    End If
End Function

Public Sub RegDeleteKey(ByVal hKeyRoot As Long, ByVal lpszSubKey As String)
' Deletes an existing key in the system registry.
' Must recursively delete from key passed through
' all subkeys to handle WinNT.
    Dim hOpenKey As Long, iIndex As Long, strSubKey As String
    hOpenKey = RegOpenKey(hKeyRoot, lpszSubKey)
    iIndex = 0
    Do
        On Error Resume Next: Err.Clear
        strSubKey = RegEnumKey(hOpenKey, iIndex)
        If Err Then Exit Do ' End of keys to delete
        iIndex = iIndex + 1
        RegDeleteKey hKeyRoot, lpszSubKey & "\" & strSubKey
    Loop
    RegCloseKey hOpenKey
    If OSRegDeleteKey(hKeyRoot, lpszSubKey) = ERROR_SUCCESS Then
        ' We succeeded, nothing more to do
    Else
        ' We failed, throw an error
        Err.Raise regDeleteKeyErr, , "Unable to delete key " & GetRootHKEYString(hKeyRoot) & "\" & lpszSubKey & ". RegDeleteKey failed."
    End If
End Sub

Public Function RegEnumKey(ByVal hOpenKey As Long, ByVal i As Long) As String
' Enumerates through the subkeys of an open registry
' key (returns the "i"th subkey of hkey, if it exists)
    Dim strResult As String
    
    strResult = Space(300)
    If OSRegEnumKey(hOpenKey, i, strResult, Len(strResult)) = ERROR_SUCCESS Then
        ' Yup, that key index exists
        RegEnumKey = StripTerminator(strResult)
    Else
        ' Nope, throw an error
        Err.Raise regEnumKeyErr, , "Could not find subkey with index of " & i & ". RegEnumKey failed."
    End If
End Function

Public Function RegOpenKey(ByVal hKeyRoot As Long, ByVal lpszSubKey As String) As Long
' Opens an existing key in the system registry.
    Dim phkResult As Long
    If OSRegOpenKey(hKeyRoot, lpszSubKey, phkResult) = ERROR_SUCCESS Then
        ' We succeeded! Throw a party!!! And, return the hKey
        RegOpenKey = phkResult
    Else
        ' We failed! Throw an error!!!
        Err.Raise regOpenKeyErr, , "Unable to open key """ & GetRootHKEYString(hKeyRoot) & "\" & lpszSubKey & """. RegOpenKey failed."
    End If
End Function

Public Function RegQueryStringValue(ByVal hOpenKey As Long, ByVal strValueName As String) As String
' Retrieves the string data for a named
' (strValueName = name) or unnamed (strValueName = "")
' value within a registry key.  If the named value
' exists, but its data is not a string, this function
' fails.
    Dim lValueType As Long
    Dim strBuf As String
    Dim lDataBufSize As Long
    
    ' Get length/data type
    If OSRegQueryValueEx(hOpenKey, strValueName, 0&, lValueType, ByVal 0&, lDataBufSize) = ERROR_SUCCESS Then
        If lValueType = REG_SZ Then
            strBuf = String(lDataBufSize, " ")
            If OSRegQueryValueEx(hOpenKey, strValueName, 0&, 0&, ByVal strBuf, lDataBufSize) = ERROR_SUCCESS Then
                RegQueryStringValue = StripTerminator(strBuf)
            Else
                Err.Raise regQueryStringValueErr, , "Could not retrieve data for key """ & strValueName & """. RegQueryValueEx failed."
            End If
        Else
            Err.Raise regQueryStringValueErr, , "RegQueryStringValue cannot retrieve non-string data. """ & strValueName & """ is non-string data."
        End If
    Else
        Err.Raise regQueryStringValueErr, , "Could not determine data type/size for key """ & strValueName & """. RegQueryValueEx failed."
    End If
End Function

Public Function RegQueryNumericValue(ByVal hOpenKey As Long, ByVal strValueName As String) As Long
' Retrieves the integer data for a named
' (strValueName = name) or unnamed (strValueName = "")
' value within a registry key.  If the named value
' exists, but its data is not a REG_DWORD, this function
' fails.
    Dim lResult As Long
    Dim lValueType As Long
    Dim lBuf As Long
    Dim lDataBufSize As Long
    
    ' Get length/data type
    lDataBufSize = 4
    If OSRegQueryValueEx(hOpenKey, strValueName, 0&, lValueType, lBuf, lDataBufSize) = ERROR_SUCCESS Then
        If lValueType = REG_DWORD Then
            RegQueryNumericValue = lBuf
        Else
            Err.Raise regQueryNumericValueErr, , "RegQueryNumericValue cannot return data that is not of REG_DWORD(&H" & Hex(REG_DWORD) & "&) type. """ & strValueName & """ is not of REG_DWORD type."
        End If
    Else
        Err.Raise regQueryNumericValueErr, , "Could not retrieve data for """ & strValueName & """. RegQueryValueEx failed."
    End If
End Function

Public Sub RegSetStringValue(ByVal hOpenKey As Long, ByVal strValueName As String, ByVal strValueData As String)
' Associates a named (strValueName = name) or unnamed (strValueName = "")
'   value with a registry key.
    If OSRegSetValueEx(hOpenKey, strValueName, 0&, REG_SZ, ByVal strValueData, Len(strValueData) + 1) = ERROR_SUCCESS Then
        ' We succeeded, do nothing
    Else
        ' We failed, throw an error(no, I did not say tantrum!)
        Err.Raise regSetStringValueErr, , "Unable to set """ & strValueName & """ to the value """ & strValueData & """. RegSetValueEx failed."
    End If
End Sub

Public Sub RegSetNumericValue(ByVal hOpenKey As Long, ByVal strValueName As String, ByVal lValueData As Long)
' Associates a named (strValueName = name) or unnamed (strValueName = "")
'   value with a registry key.
    If OSRegSetValueEx(hOpenKey, strValueName, 0&, REG_DWORD, lValueData, 4) = ERROR_SUCCESS Then
        ' We succeeded, do nothing
    Else
        ' We failed, throw an error
        Err.Raise regSetNumericValueErr, , "Unable to set """ & strValueName & """ to the value " & lValueData & ". RegSetValueEx failed."
    End If
End Sub

Private Function GetRootHKEYString(ByVal HKEY As Long) As String
'Given a root HKEY, return the text string representing that
'key, or else return "".
    Select Case HKEY
        Case HKEY_CLASSES_ROOT
            GetRootHKEYString = "HKEY_CLASSES_ROOT"
        Case HKEY_CURRENT_USER
            GetRootHKEYString = "HKEY_CURRENT_USER"
        Case HKEY_LOCAL_MACHINE
            GetRootHKEYString = "HKEY_LOCAL_MACHINE"
        Case HKEY_USERS
            GetRootHKEYString = "HKEY_USERS"
    End Select
End Function

Private Function GetRootHKEYVal(ByVal HKEY As String) As Long
' Given a string root HKEY, return the long
' HKEY value(used for Reg calls) for it. If
' not found, return -1. Allows abbreviations
' for ease of use.
Select Case LCase(Trim(HKEY))
    Case "hkey_classes_root", "hkcr"
        GetRootHKEYVal = HKEY_CLASSES_ROOT
    Case "hkey_current_user", "hkcu"
        GetRootHKEYVal = HKEY_CURRENT_USER
    Case "hkey_local_machine", "hklm"
        GetRootHKEYVal = HKEY_LOCAL_MACHINE
    Case "hkey_users", "hku"
        GetRootHKEYVal = HKEY_USERS
End Select
End Function

Private Function StripTerminator(ByVal strString As String) As String
' Returns a string without any zero terminator.  Typically,
' this was a string returned by a Windows API call.
    Dim intZeroPos As Integer

    intZeroPos = InStr(strString, Chr$(0))
    If intZeroPos > 0 Then
        StripTerminator = Left$(strString, intZeroPos - 1)
    Else
        StripTerminator = strString
    End If
End Function

Private Function Parse(Pos As Long, Work As String, Delimit As String) As String
' Splits a string into chunks, delimited by Delimit, and returns the requested one.
If InStr(Work, Delimit) > 0 Then
    If Pos = 0 Then
        Parse = Mid(Work, 1, InStr(Work, Delimit) - 1)
    ElseIf Pos <> 0 Then
        Dim sTemp As String
        sTemp = Mid(Work, InStr(Work, Delimit) + Len(Delimit))
        Parse = Parse(Pos - 1, sTemp, Delimit)
    End If
Else
    Parse = Work
End If
End Function
