Declare CustomType Library
    Function RegCreateKeyEx& (ByVal hKey As _Offset, Byval lpSubKey As _Offset, Byval Reserved As _Unsigned Long, Byval lpClass As _Offset, Byval dwOptions As _Unsigned Long, Byval samDesired As _Unsigned Long, Byval lpSecurityAttributes As _Offset, Byval phkResult As _Offset, Byval lpdwDisposition As _Offset)
    Function RegOpenKeyEx& (ByVal hKey As _Offset, Byval lpSubKey As _Offset, Byval ulOptions As _Unsigned Long, Byval samDesired As _Unsigned Long, Byval phkResult As _Offset)
    Function RegSetValueEx& (ByVal hKey As _Offset, Byval lpValueName As _Offset, Byval Reserved As _Unsigned Long, Byval dwType As _Unsigned Long, Byval lpData As _Offset, Byval cbData As _Unsigned Long)
    Function RegEnumKeyEx& (ByVal hKey As _Offset, Byval dwIndex As _Unsigned Long, Byval lpName As _Offset, Byval lpcchName As _Offset, Byval lpReserved As _Offset, Byval lpClass As _Offset, Byval lpcchClass As _Offset, Byval lpftLastWriteTime As _Offset)
    Function RegQueryValueEx& (ByVal hKey As _Offset, Byval lpValueName As _Offset, Byval lpReserved As _Offset, Byval lpType As _Offset, Byval lpData As _Offset, Byval lpcbData As _Offset)
    Function RegDeleteKeyEx& (ByVal hKey As _Offset, Byval lpSubKey As _Offset, Byval samdesired As _Unsigned Long, Byval Reserved As _Unsigned Long)
    Sub RegCloseKey (ByVal hKey As _Offset)
End Declare

Declare Dynamic Library "Shlwapi"
    Function SHDeleteKey& Alias "SHDeleteKeyA" (ByVal hkey As _Offset, Byval pszSubKey As _Offset)
End Declare

Declare Dynamic Library "Shell32"
    Function IsUserAnAdmin& ()
    Sub ShellExecute Alias "ShellExecuteA" (ByVal hwnd As _Offset, lpOperation As String, lpFile As String, lpParameters As String, Byval lpDirectory As _Offset, Byval nShowCmd As Long)
End Declare

Sub SelfElevate
    If IsUserAnAdmin = 0 Then
        ShellExecute 0, "runas" + Chr$(0), Command$(0) + Chr$(0), Command$ + Chr$(0), 0, 5
        System
    End If
End Sub

Function CreateRegistryKey%% (hKeyParent As _Offset, subkey As String)
    Const KEY_ALL_ACCESS = &HF003F
    Const REG_OPTION_NON_VOLATILE = &H00000000
    Const ERROR_SUCCESS = 0

    If hKeyParent <> HKEY_CURRENT_USER Then SelfElevate

    Dim As _Unsigned Long dwDisposition
    Dim As Long ret
    Dim As _Offset hKey

    If Right$(subkey, 1) <> Chr$(0) Then subkey = subkey + Chr$(0)

    ret = RegCreateKeyEx(hKeyParent, _Offset(subkey), 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, _Offset(hKey), _Offset(dwDisposition))
    If ret <> ERROR_SUCCESS Then
        CreateRegistryKey = REG_FALSE
    Else
        RegCloseKey hKey
        CreateRegistryKey = REG_TRUE
    End If
End Function

Function DeleteRegistryKey%% (hKeyParent As _Offset, subkey As String)
    Const DELETE = &H00010000
    Const KEY_ENUMERATE_SUB_KEYS = &H0008
    Const KEY_QUERY_VALUE = &H0001
    Const KEY_SET_VALUE = &H0002
    Const ERROR_SUCCESS = 0

    Dim As Long ret
    Dim As _Offset hKey

    If hKeyParent <> HKEY_CURRENT_USER Then SelfElevate

    If Right$(subkey, 1) <> Chr$(0) Then subkey = subkey + Chr$(0)
    If Left$(subkey, 1) <> "\" Then subkey = "\" + subkey

    ret = SHDeleteKey(hKeyParent, _Offset(subkey))
    If ERROR_SUCCESS <> ret Then
        RegCloseKey hKey
        DeleteRegistryKey = REG_FALSE
        Exit Function
    End If
    RegCloseKey hKey
    DeleteRegistryKey = REG_TRUE
End Function

Function WriteREG_DWORD%% (hKeyParent As _Offset, subkey As String, valueName As String, dwdata As _Unsigned Long)
    Const REG_DWORD = 4
    Const STANDARD_RIGHTS_WRITE = &H00020000
    Const KEY_SET_VALUE = &H0002
    Const KEY_CREATE_SUB_KEY = &H0004
    Const SYNCHRONIZE = &H00100000
    Const KEY_WRITE = (STANDARD_RIGHTS_WRITE Or KEY_SET_VALUE Or KEY_CREATE_SUB_KEY) And (Not SYNCHRONIZE)
    Const ERROR_SUCCESS = 0

    If hKeyParent <> HKEY_CURRENT_USER Then SelfElevate

    Dim As Long ret
    Dim As _Offset hKey

    If Right$(valueName, 1) <> Chr$(0) Then valueName = valueName + Chr$(0)
    If Right$(subkey, 1) <> Chr$(0) Then subkey = subkey + Chr$(0)

    ret = RegOpenKeyEx(hKeyParent, _Offset(subkey), 0, KEY_WRITE, _Offset(hKey))

    If ret = ERROR_SUCCESS Then
        If ERROR_SUCCESS <> RegSetValueEx(hKey, _Offset(valueName), 0, REG_DWORD, _Offset(dwdata), Len(dwdata)) Then
            RegCloseKey hKey
            WriteREG_DWORD = REG_FALSE
            Exit Function
        End If
        RegCloseKey hKey
        WriteREG_DWORD = REG_TRUE
    Else
        WriteREG_DWORD = REG_FALSE
    End If
End Function

Function WriteREG_QWORD%% (hKeyParent As _Offset, subkey As String, valueName As String, qdata As _Unsigned _Integer64)
    Const REG_QWORD = 11
    Const STANDARD_RIGHTS_WRITE = &H00020000
    Const KEY_SET_VALUE = &H0002
    Const KEY_CREATE_SUB_KEY = &H0004
    Const SYNCHRONIZE = &H00100000
    Const KEY_WRITE = (STANDARD_RIGHTS_WRITE Or KEY_SET_VALUE Or KEY_CREATE_SUB_KEY) And (Not SYNCHRONIZE)
    Const ERROR_SUCCESS = 0

    If hKeyParent <> HKEY_CURRENT_USER Then SelfElevate

    Dim As Long ret
    Dim As _Offset hKey

    If Right$(valueName, 1) <> Chr$(0) Then valueName = valueName + Chr$(0)
    If Right$(subkey, 1) <> Chr$(0) Then subkey = subkey + Chr$(0)

    ret = RegOpenKeyEx(hKeyParent, _Offset(subkey), 0, KEY_WRITE, _Offset(hKey))

    If ret = ERROR_SUCCESS Then
        If ERROR_SUCCESS <> RegSetValueEx(hKey, _Offset(valueName), 0, REG_QWORD, _Offset(qdata), Len(qdata)) Then
            RegCloseKey hKey
            WriteREG_QWORD = REG_FALSE
            Exit Function
        End If
        RegCloseKey hKey
        WriteREG_QWORD = REG_TRUE
    Else
        WriteREG_QWORD = REG_FALSE
    End If
End Function

Function WriteREG_SZ%% (hKeyParent As _Offset, subkey As String, valueName As String, strData As String)
    Const REG_SZ = 1
    Const STANDARD_RIGHTS_WRITE = &H00020000
    Const KEY_SET_VALUE = &H0002
    Const KEY_CREATE_SUB_KEY = &H0004
    Const SYNCHRONIZE = &H00100000
    Const KEY_WRITE = (STANDARD_RIGHTS_WRITE Or KEY_SET_VALUE Or KEY_CREATE_SUB_KEY) And (Not SYNCHRONIZE)
    Const ERROR_SUCCESS = 0

    If hKeyParent <> HKEY_CURRENT_USER Then SelfElevate

    Dim As Long ret
    Dim As _Offset hKey

    If Right$(strData, 1) <> Chr$(0) Then strData = strData + Chr$(0)
    If Right$(valueName, 1) <> Chr$(0) Then valueName = valueName + Chr$(0)
    If Right$(subkey, 1) <> Chr$(0) Then subkey = subkey + Chr$(0)

    ret = RegOpenKeyEx(hKeyParent, _Offset(subkey), 0, KEY_WRITE, _Offset(hKey))
    If ret = ERROR_SUCCESS Then
        If ERROR_SUCCESS <> RegSetValueEx(hKey, _Offset(valueName), 0, REG_SZ, _Offset(strData), Len(strData)) Then
            RegCloseKey hKey
            WriteREG_SZ = REG_FALSE
            Exit Function
        End If
        RegCloseKey hKey
        WriteREG_SZ = REG_TRUE
    Else
        WriteREG_SZ = REG_FALSE
    End If
End Function

Function ReadREG_DWORD%% (hKeyParent As _Offset, subkey As String, valueName As String, readData As _Unsigned Long)
    'Const STANDARD_RIGHTS_READ = &H00020000
    'Const KEY_QUERY_VALUE = &H0001
    'Const KEY_ENUMERATE_SUB_KEYS = &H0008
    'Const KEY_NOTIFY = &H0010
    Const KEY_READ = &H20019 '(STANDARD_RIGHTS_READ Or KEY_QUERY_VALUE Or KEY_ENUMERATE_SUB_KEYS Or KEY_NOTIFY) And (Not SYNCHRONIZE)
    Const ERROR_SUCCESS = 0

    Dim As Long ret
    Dim As _Offset hkey

    If Right$(valueName, 1) <> Chr$(0) Then valueName = valueName + Chr$(0)
    If Right$(subkey, 1) <> Chr$(0) Then subkey = subkey + Chr$(0)

    ret = RegOpenKeyEx(hKeyParent, _Offset(subkey), 0, KEY_READ, _Offset(hkey))
    If ret = ERROR_SUCCESS Then
        Dim As _Unsigned Long dwdata, length
        length = Len(dwdata)
        ret = RegQueryValueEx(hkey, _Offset(valueName), 0, 0, _Offset(dwdata), _Offset(length))
        If ret = ERROR_SUCCESS Then
            RegCloseKey hkey
            readData = dwdata
            ReadREG_DWORD = REG_TRUE
            Exit Function
        End If
        RegCloseKey hkey
        ReadREG_DWORD = REG_TRUE
    Else
        ReadREG_DWORD = REG_FALSE
    End If
End Function

Function ReadREG_QWORD%% (hKeyParent As _Offset, subkey As String, valueName As String, readData As _Unsigned _Integer64)
    'Const STANDARD_RIGHTS_READ = &H00020000
    'Const KEY_QUERY_VALUE = &H0001
    'Const KEY_ENUMERATE_SUB_KEYS = &H0008
    'Const KEY_NOTIFY = &H0010
    Const KEY_READ = &H20019 '(STANDARD_RIGHTS_READ Or KEY_QUERY_VALUE Or KEY_ENUMERATE_SUB_KEYS Or KEY_NOTIFY) And (Not SYNCHRONIZE)
    Const ERROR_SUCCESS = 0

    Dim As Long ret
    Dim As _Offset hkey

    If Right$(valueName, 1) <> Chr$(0) Then valueName = valueName + Chr$(0)
    If Right$(subkey, 1) <> Chr$(0) Then subkey = subkey + Chr$(0)

    ret = RegOpenKeyEx(hKeyParent, _Offset(subkey), 0, KEY_READ, _Offset(hkey))
    If ret = ERROR_SUCCESS Then
        Dim As _Unsigned _Integer64 qdata
        Dim As _Unsigned Long length
        length = Len(qdata)
        ret = RegQueryValueEx(hkey, _Offset(valueName), 0, 0, _Offset(qdata), _Offset(length))
        If ret = ERROR_SUCCESS Then
            RegCloseKey hkey
            readData = qdata
            ReadREG_QWORD = REG_TRUE
            Exit Function
        End If
        RegCloseKey hkey
        ReadREG_QWORD = REG_TRUE
    Else
        ReadREG_QWORD = REG_FALSE
    End If
End Function

Function ReadREG_SZ%% (hKeyParent As _Offset, subkey As String, valueName As String, readData As String)
    'Const STANDARD_RIGHTS_READ = &H00020000
    'Const KEY_QUERY_VALUE = &H0001
    'Const KEY_ENUMERATE_SUB_KEYS = &H0008
    'Const KEY_NOTIFY = &H0010
    Const KEY_READ = &H20019 '(STANDARD_RIGHTS_READ Or KEY_QUERY_VALUE Or KEY_ENUMERATE_SUB_KEYS Or KEY_NOTIFY) And (Not SYNCHRONIZE)
    Const ERROR_MORE_DATA = 234
    Const ERROR_SUCCESS = 0

    Dim As Long ret
    Dim As _Offset hKey
    Dim As String readBuffer: readBuffer = Space$(32)
    Dim As _Unsigned Long readDataLen: readDataLen = Len(readBuffer)

    If Right$(valueName, 1) <> Chr$(0) Then valueName = valueName + Chr$(0)
    If Right$(subkey, 1) <> Chr$(0) Then subkey = subkey + Chr$(0)

    ret = RegOpenKeyEx(hKeyParent, _Offset(subkey), 0, KEY_READ, _Offset(hKey))
    If ret = ERROR_SUCCESS Then
        ret = RegQueryValueEx(hKey, _Offset(valueName), 0, 0, _Offset(readBuffer), _Offset(readDataLen))
        If ret = ERROR_MORE_DATA Then
            readBuffer = Space$(readDataLen)
            ret = RegQueryValueEx(hKey, _Offset(valueName), 0, 0, _Offset(readBuffer), _Offset(readDataLen))
        End If
        If ret <> ERROR_SUCCESS Then
            RegCloseKey hKey
            ReadREG_SZ = REG_FALSE
            Exit Function
        End If
        readData = readBuffer
        RegCloseKey hKey
        ReadREG_SZ = REG_TRUE
    Else
        ReadREG_SZ = REG_FALSE
    End If
End Function

Function IsInstalled%% (software As String)
    Const HKEY_LOCAL_MACHINE = &H80000002~&
    Const KEY_ALL_ACCESS = &HF003F&
    Const KEY_READ = &H20019&
    Const ERROR_SUCCESS = 0

    Dim As _Offset hUninstKey, hAppKey
    Dim As String sAppKeyName, sSubKey, sDisplayName
    sAppKeyName = Space$(1024): sSubKey = Space$(1024): sDisplayName = Space$(1024)
    Dim As String sRoot
    sRoot = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" + Chr$(0)
    Dim As Long lResult: lResult = ERROR_SUCCESS
    Dim As _Unsigned Long dwType: dwType = KEY_ALL_ACCESS
    Dim As _Unsigned Long dwBufferSize

    If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sRoot), 0, KEY_READ, _Offset(hUninstKey)) <> ERROR_SUCCESS Then
        IsInstalled = REG_FALSE
        Exit Function
    End If
    Dim As _Unsigned Long dwindex
    Do
        sAppKeyName = Space$(1024)
        dwBufferSize = Len(sAppKeyName)
        lResult = RegEnumKeyEx(hUninstKey, dwindex, _Offset(sAppKeyName), _Offset(dwBufferSize), 0, 0, 0, 0)
        If lResult = ERROR_SUCCESS Then
            sSubKey = Mid$(sRoot, 1, InStr(sRoot, Chr$(0)) - 1) + "\" + Mid$(sAppKeyName, 1, InStr(sAppKeyName, Chr$(0)) - 1) + Chr$(0)
            If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sSubKey), 0, KEY_READ, _Offset(hAppKey)) <> ERROR_SUCCESS Then
                RegCloseKey hAppKey
                RegCloseKey hUninstKey
                IsInstalled = REG_FALSE
                Exit Function
            End If
            dwBufferSize = Len(sDisplayName)
            Dim As String displayName: displayName = "DisplayName" + Chr$(0)
            If RegQueryValueEx(hAppKey, _Offset(displayName), 0, _Offset(dwType), _Offset(sDisplayName), _Offset(dwBufferSize)) = ERROR_SUCCESS Then
                If _StriCmp(Mid$(sDisplayName, 1, dwBufferSize - 1), software) = 0 Then
                    RegCloseKey hAppKey
                    RegCloseKey hUninstKey
                    IsInstalled = REG_TRUE
                    Exit Function
                End If
            End If
            RegCloseKey hAppKey
        End If
        dwindex = dwindex + 1
    Loop While lResult = ERROR_SUCCESS
    RegCloseKey hUninstKey
    IsInstalled = IsInstalled64(software)
End Function

Function IsInstalled64%% (software As String)
    Const HKEY_LOCAL_MACHINE = &H80000002~&
    Const KEY_ALL_ACCESS = &HF003F&
    Const KEY_READ = &H20019&
    Const ERROR_SUCCESS = 0

    Dim As _Offset hUninstKey, hAppKey
    Dim As String sAppKeyName, sSubKey, sDisplayName
    sAppKeyName = Space$(1024): sSubKey = Space$(1024): sDisplayName = Space$(1024)
    Dim As String sRoot
    sRoot = "SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" + Chr$(0)
    Dim As Long lResult: lResult = ERROR_SUCCESS
    Dim As _Unsigned Long dwType: dwType = KEY_ALL_ACCESS
    Dim As _Unsigned Long dwBufferSize

    If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sRoot), 0, KEY_READ, _Offset(hUninstKey)) <> ERROR_SUCCESS Then
        IsInstalled64 = REG_FALSE
        Exit Function
    End If
    Dim As _Unsigned Long dwindex
    Do
        sAppKeyName = Space$(1024)
        dwBufferSize = Len(sAppKeyName)
        lResult = RegEnumKeyEx(hUninstKey, dwindex, _Offset(sAppKeyName), _Offset(dwBufferSize), 0, 0, 0, 0)
        If lResult = ERROR_SUCCESS Then
            sSubKey = Mid$(sRoot, 1, InStr(sRoot, Chr$(0)) - 1) + "\" + Mid$(sAppKeyName, 1, InStr(sAppKeyName, Chr$(0)) - 1) + Chr$(0)
            If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sSubKey), 0, KEY_READ, _Offset(hAppKey)) <> ERROR_SUCCESS Then
                RegCloseKey hAppKey
                RegCloseKey hUninstKey
                IsInstalled64 = REG_FALSE
                Exit Function
            End If
            dwBufferSize = Len(sDisplayName)
            Dim As String displayName: displayName = "DisplayName" + Chr$(0)
            If RegQueryValueEx(hAppKey, _Offset(displayName), 0, _Offset(dwType), _Offset(sDisplayName), _Offset(dwBufferSize)) = ERROR_SUCCESS Then
                If _StriCmp(Mid$(sDisplayName, 1, dwBufferSize - 1), software) = 0 Then
                    RegCloseKey hAppKey
                    RegCloseKey hUninstKey
                    IsInstalled64 = REG_TRUE
                    Exit Function
                End If
            End If
            RegCloseKey hAppKey
        End If
        dwindex = dwindex + 1
    Loop While lResult = ERROR_SUCCESS
    RegCloseKey hUninstKey
    IsInstalled64 = REG_FALSE
End Function

Function CheckVersion$ (software As String)
    Const HKEY_LOCAL_MACHINE = &H80000002~&
    Const KEY_ALL_ACCESS = &HF003F&
    Const KEY_READ = &H20019&
    Const ERROR_SUCCESS = 0

    Dim As _Offset hUninstKey, hAppKey
    Dim As String sAppKeyName, sSubKey, sDisplayName
    sAppKeyName = Space$(1024): sSubKey = Space$(1024): sDisplayName = Space$(1024)
    Dim As String sRoot
    sRoot = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" + Chr$(0)
    Dim As Long lResult: lResult = ERROR_SUCCESS
    Dim As _Unsigned Long dwType: dwType = KEY_ALL_ACCESS
    Dim As _Unsigned Long dwBufferSize

    If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sRoot), 0, KEY_READ, _Offset(hUninstKey)) <> ERROR_SUCCESS Then
        CheckVersion = ""
        Exit Function
    End If
    Dim As _Unsigned Long dwindex
    Do
        sAppKeyName = Space$(1024)
        dwBufferSize = Len(sAppKeyName)
        lResult = RegEnumKeyEx(hUninstKey, dwindex, _Offset(sAppKeyName), _Offset(dwBufferSize), 0, 0, 0, 0)
        If lResult = ERROR_SUCCESS Then
            sSubKey = Mid$(sRoot, 1, InStr(sRoot, Chr$(0)) - 1) + "\" + Mid$(sAppKeyName, 1, InStr(sAppKeyName, Chr$(0)) - 1) + Chr$(0)
            If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sSubKey), 0, KEY_READ, _Offset(hAppKey)) <> ERROR_SUCCESS Then
                RegCloseKey hAppKey
                RegCloseKey hUninstKey
                CheckVersion = ""
                Exit Function
            End If
            dwBufferSize = Len(sDisplayName)
            Dim As String displayName: displayName = "DisplayName" + Chr$(0)
            If RegQueryValueEx(hAppKey, _Offset(displayName), 0, _Offset(dwType), _Offset(sDisplayName), _Offset(dwBufferSize)) = ERROR_SUCCESS Then
                If _StriCmp(Mid$(sDisplayName, 1, dwBufferSize - 1), software) = 0 Then
                    Dim As String version: version = Space$(1024)
                    Dim As _Unsigned Long verlen: verlen = Len(version)
                    Dim As String displayversion: displayversion = "DisplayVersion" + Chr$(0)
                    If RegQueryValueEx(hAppKey, _Offset(displayversion), 0, _Offset(dwType), _Offset(version), _Offset(verlen)) = ERROR_SUCCESS Then
                        CheckVersion = Mid$(version, 1, verlen - 1)
                    Else
                        CheckVersion = ""
                    End If
                    RegCloseKey hAppKey
                    RegCloseKey hUninstKey
                    Exit Function
                End If
            End If
            RegCloseKey hAppKey
        End If
        dwindex = dwindex + 1
    Loop While lResult = ERROR_SUCCESS
    RegCloseKey hUninstKey
    CheckVersion = CheckVersion64(software)
End Function

Function CheckVersion64$ (software As String)
    Const HKEY_LOCAL_MACHINE = &H80000002~&
    Const KEY_ALL_ACCESS = &HF003F&
    Const KEY_READ = &H20019&
    Const ERROR_SUCCESS = 0

    Dim As _Offset hUninstKey, hAppKey
    Dim As String sAppKeyName, sSubKey, sDisplayName
    sAppKeyName = Space$(1024): sSubKey = Space$(1024): sDisplayName = Space$(1024)
    Dim As String sRoot
    sRoot = "SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" + Chr$(0)
    Dim As Long lResult: lResult = ERROR_SUCCESS
    Dim As _Unsigned Long dwType: dwType = KEY_ALL_ACCESS
    Dim As _Unsigned Long dwBufferSize

    If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sRoot), 0, KEY_READ, _Offset(hUninstKey)) <> ERROR_SUCCESS Then
        CheckVersion64 = ""
        Exit Function
    End If
    Dim As _Unsigned Long dwindex
    Do
        sAppKeyName = Space$(1024)
        dwBufferSize = Len(sAppKeyName)
        lResult = RegEnumKeyEx(hUninstKey, dwindex, _Offset(sAppKeyName), _Offset(dwBufferSize), 0, 0, 0, 0)
        If lResult = ERROR_SUCCESS Then
            sSubKey = Mid$(sRoot, 1, InStr(sRoot, Chr$(0)) - 1) + "\" + Mid$(sAppKeyName, 1, InStr(sAppKeyName, Chr$(0)) - 1) + Chr$(0)
            If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sSubKey), 0, KEY_READ, _Offset(hAppKey)) <> ERROR_SUCCESS Then
                RegCloseKey hAppKey
                RegCloseKey hUninstKey
                CheckVersion64 = ""
                Exit Function
            End If
            dwBufferSize = Len(sDisplayName)
            Dim As String displayName: displayName = "DisplayName" + Chr$(0)
            If RegQueryValueEx(hAppKey, _Offset(displayName), 0, _Offset(dwType), _Offset(sDisplayName), _Offset(dwBufferSize)) = ERROR_SUCCESS Then
                If _StriCmp(Mid$(sDisplayName, 1, dwBufferSize - 1), software) = 0 Then
                    Dim As String version: version = Space$(1024)
                    Dim As _Unsigned Long verlen: verlen = Len(version)
                    Dim As String displayversion: displayversion = "DisplayVersion" + Chr$(0)
                    If RegQueryValueEx(hAppKey, _Offset(displayversion), 0, _Offset(dwType), _Offset(version), _Offset(verlen)) = ERROR_SUCCESS Then
                        CheckVersion64 = Mid$(version, 1, verlen - 1)
                    Else
                        CheckVersion64 = ""
                    End If
                    RegCloseKey hAppKey
                    RegCloseKey hUninstKey
                    Exit Function
                End If
            End If
            RegCloseKey hAppKey
        End If
        dwindex = dwindex + 1
    Loop While lResult = ERROR_SUCCESS
    RegCloseKey hUninstKey
    CheckVersion64 = ""
End Function

Function GetUninstallString$ (software As String)
    Const HKEY_LOCAL_MACHINE = &H80000002~&
    Const KEY_ALL_ACCESS = &HF003F&
    Const KEY_READ = &H20019&
    Const ERROR_SUCCESS = 0

    Dim As _Offset hUninstKey, hAppKey
    Dim As String sAppKeyName, sSubKey, sDisplayName
    sAppKeyName = Space$(1024): sSubKey = Space$(1024): sDisplayName = Space$(1024)
    Dim As String sRoot
    sRoot = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" + Chr$(0)
    Dim As Long lResult: lResult = ERROR_SUCCESS
    Dim As _Unsigned Long dwType: dwType = KEY_ALL_ACCESS
    Dim As _Unsigned Long dwBufferSize

    If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sRoot), 0, KEY_READ, _Offset(hUninstKey)) <> ERROR_SUCCESS Then
        GetUninstallString = ""
        Exit Function
    End If
    Dim As _Unsigned Long dwindex
    Do
        sAppKeyName = Space$(1024)
        dwBufferSize = Len(sAppKeyName)
        lResult = RegEnumKeyEx(hUninstKey, dwindex, _Offset(sAppKeyName), _Offset(dwBufferSize), 0, 0, 0, 0)
        If lResult = ERROR_SUCCESS Then
            sSubKey = Mid$(sRoot, 1, InStr(sRoot, Chr$(0)) - 1) + "\" + Mid$(sAppKeyName, 1, InStr(sAppKeyName, Chr$(0)) - 1) + Chr$(0)
            If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sSubKey), 0, KEY_READ, _Offset(hAppKey)) <> ERROR_SUCCESS Then
                RegCloseKey hAppKey
                RegCloseKey hUninstKey
                GetUninstallString = ""
                Exit Function
            End If
            dwBufferSize = Len(sDisplayName)
            Dim As String displayName: displayName = "DisplayName" + Chr$(0)
            If RegQueryValueEx(hAppKey, _Offset(displayName), 0, _Offset(dwType), _Offset(sDisplayName), _Offset(dwBufferSize)) = ERROR_SUCCESS Then
                If _StriCmp(Mid$(sDisplayName, 1, dwBufferSize - 1), software) = 0 Then
                    Dim As String uninstall: uninstall = Space$(1024)
                    Dim As _Unsigned Long Lenuninstall: Lenuninstall = Len(uninstall)
                    Dim As String uninstallstring: uninstallstring = "UninstallString" + Chr$(0)
                    If RegQueryValueEx(hAppKey, _Offset(uninstallstring), 0, _Offset(dwType), _Offset(uninstall), _Offset(Lenuninstall)) = ERROR_SUCCESS Then
                        GetUninstallString = Mid$(uninstall, 1, Lenuninstall - 1)
                    Else
                        GetUninstallString = ""
                    End If
                    RegCloseKey hAppKey
                    RegCloseKey hUninstKey
                    Exit Function
                End If
            End If
            RegCloseKey hAppKey
        End If
        dwindex = dwindex + 1
    Loop While lResult = ERROR_SUCCESS
    RegCloseKey hUninstKey
    GetUninstallString = GetUninstallString64(software)
End Function

Function GetUninstallString64$ (software As String)
    Const HKEY_LOCAL_MACHINE = &H80000002~&
    Const KEY_ALL_ACCESS = &HF003F&
    Const KEY_READ = &H20019&
    Const ERROR_SUCCESS = 0

    Dim As _Offset hUninstKey, hAppKey
    Dim As String sAppKeyName, sSubKey, sDisplayName
    sAppKeyName = Space$(1024): sSubKey = Space$(1024): sDisplayName = Space$(1024)
    Dim As String sRoot
    sRoot = "SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" + Chr$(0)
    Dim As Long lResult: lResult = ERROR_SUCCESS
    Dim As _Unsigned Long dwType: dwType = KEY_ALL_ACCESS
    Dim As _Unsigned Long dwBufferSize

    If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sRoot), 0, KEY_READ, _Offset(hUninstKey)) <> ERROR_SUCCESS Then
        GetUninstallString64 = ""
        Exit Function
    End If
    Dim As _Unsigned Long dwindex
    Do
        sAppKeyName = Space$(1024)
        dwBufferSize = Len(sAppKeyName)
        lResult = RegEnumKeyEx(hUninstKey, dwindex, _Offset(sAppKeyName), _Offset(dwBufferSize), 0, 0, 0, 0)
        If lResult = ERROR_SUCCESS Then
            sSubKey = Mid$(sRoot, 1, InStr(sRoot, Chr$(0)) - 1) + "\" + Mid$(sAppKeyName, 1, InStr(sAppKeyName, Chr$(0)) - 1) + Chr$(0)
            If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sSubKey), 0, KEY_READ, _Offset(hAppKey)) <> ERROR_SUCCESS Then
                RegCloseKey hAppKey
                RegCloseKey hUninstKey
                GetUninstallString64 = ""
                Exit Function
            End If
            dwBufferSize = Len(sDisplayName)
            Dim As String displayName: displayName = "DisplayName" + Chr$(0)
            If RegQueryValueEx(hAppKey, _Offset(displayName), 0, _Offset(dwType), _Offset(sDisplayName), _Offset(dwBufferSize)) = ERROR_SUCCESS Then
                If _StriCmp(Mid$(sDisplayName, 1, dwBufferSize - 1), software) = 0 Then
                    Dim As String uninstall: uninstall = Space$(1024)
                    Dim As _Unsigned Long Lenuninstall: Lenuninstall = Len(uninstall)
                    Dim As String uninstallstring: uninstallstring = "UninstallString" + Chr$(0)
                    If RegQueryValueEx(hAppKey, _Offset(uninstallstring), 0, _Offset(dwType), _Offset(uninstall), _Offset(Lenuninstall)) = ERROR_SUCCESS Then
                        GetUninstallString64 = Mid$(uninstall, 1, Lenuninstall - 1)
                    Else
                        GetUninstallString64 = ""
                    End If
                    RegCloseKey hAppKey
                    RegCloseKey hUninstKey
                    Exit Function
                End If
            End If
            RegCloseKey hAppKey
        End If
        dwindex = dwindex + 1
    Loop While lResult = ERROR_SUCCESS
    RegCloseKey hUninstKey
    GetUninstallString64 = ""
End Function

Sub EnumInstalledPrograms
    Const HKEY_LOCAL_MACHINE = &H80000002~&
    Const KEY_ALL_ACCESS = &HF003F&
    Const KEY_READ = &H20019&
    Const ERROR_SUCCESS = 0

    Dim As _Offset hUninstKey, hAppKey
    Dim As String sAppKeyName, sSubKey, sDisplayName
    sAppKeyName = Space$(1024): sSubKey = Space$(1024): sDisplayName = Space$(1024)
    Dim As String sRoot
    sRoot = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" + Chr$(0)
    Dim As Long lResult: lResult = ERROR_SUCCESS
    Dim As _Unsigned Long dwType: dwType = KEY_ALL_ACCESS
    Dim As _Unsigned Long dwBufferSize

    If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sRoot), 0, KEY_READ, _Offset(hUninstKey)) <> ERROR_SUCCESS Then
        Exit Sub
    End If
    Dim As _Unsigned Long dwindex
    Do
        sAppKeyName = Space$(1024)
        dwBufferSize = Len(sAppKeyName)
        lResult = RegEnumKeyEx(hUninstKey, dwindex, _Offset(sAppKeyName), _Offset(dwBufferSize), 0, 0, 0, 0)
        If lResult = ERROR_SUCCESS Then
            sSubKey = Mid$(sRoot, 1, InStr(sRoot, Chr$(0)) - 1) + "\" + Mid$(sAppKeyName, 1, InStr(sAppKeyName, Chr$(0)) - 1) + Chr$(0)
            If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sSubKey), 0, KEY_READ, _Offset(hAppKey)) <> ERROR_SUCCESS Then
                RegCloseKey hAppKey
                RegCloseKey hUninstKey
            End If
            dwBufferSize = Len(sDisplayName)
            Dim As String displayName: displayName = "DisplayName" + Chr$(0)
            If RegQueryValueEx(hAppKey, _Offset(displayName), 0, _Offset(dwType), _Offset(sDisplayName), _Offset(dwBufferSize)) = ERROR_SUCCESS Then
                Print Mid$(sDisplayName, 1, dwBufferSize)
            End If
            RegCloseKey hAppKey
        End If
        dwindex = dwindex + 1
    Loop While lResult = ERROR_SUCCESS
    RegCloseKey hUninstKey
    EnumInstalledPrograms64
End Sub

Sub EnumInstalledPrograms64
    Const HKEY_LOCAL_MACHINE = &H80000002~&
    Const KEY_ALL_ACCESS = &HF003F&
    Const KEY_READ = &H20019&
    Const ERROR_SUCCESS = 0

    Dim As _Offset hUninstKey, hAppKey
    Dim As String sAppKeyName, sSubKey, sDisplayName
    sAppKeyName = Space$(1024): sSubKey = Space$(1024): sDisplayName = Space$(1024)
    Dim As String sRoot
    sRoot = "SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" + Chr$(0)
    Dim As Long lResult: lResult = ERROR_SUCCESS
    Dim As _Unsigned Long dwType: dwType = KEY_ALL_ACCESS
    Dim As _Unsigned Long dwBufferSize

    If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sRoot), 0, KEY_READ, _Offset(hUninstKey)) <> ERROR_SUCCESS Then
        Exit Sub
    End If
    Dim As _Unsigned Long dwindex
    Do
        sAppKeyName = Space$(1024)
        dwBufferSize = Len(sAppKeyName)
        lResult = RegEnumKeyEx(hUninstKey, dwindex, _Offset(sAppKeyName), _Offset(dwBufferSize), 0, 0, 0, 0)
        If lResult = ERROR_SUCCESS Then
            sSubKey = Mid$(sRoot, 1, InStr(sRoot, Chr$(0)) - 1) + "\" + Mid$(sAppKeyName, 1, InStr(sAppKeyName, Chr$(0)) - 1) + Chr$(0)
            If RegOpenKeyEx(HKEY_LOCAL_MACHINE, _Offset(sSubKey), 0, KEY_READ, _Offset(hAppKey)) <> ERROR_SUCCESS Then
                RegCloseKey hAppKey
                RegCloseKey hUninstKey
            End If
            dwBufferSize = Len(sDisplayName)
            Dim As String displayName: displayName = "DisplayName" + Chr$(0)
            If RegQueryValueEx(hAppKey, _Offset(displayName), 0, _Offset(dwType), _Offset(sDisplayName), _Offset(dwBufferSize)) = ERROR_SUCCESS Then
                Print Mid$(sDisplayName, 1, dwBufferSize)
            End If
            RegCloseKey hAppKey
        End If
        dwindex = dwindex + 1
    Loop While lResult = ERROR_SUCCESS
    RegCloseKey hUninstKey
End Sub
