Search code examples
.netregistrywmi

How can I remotely query Registry using WMI from a 32-bit application?


I need to remotely collect the data about installed software on a device from these 2 locations:

  • HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\
  • HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\

For that I am using WMI class StdRegProv. Application which collects the data needs to be 32-bit.

The problem is that I recive only the data from Wow6432Node and it is doubled. E.g. If there are 3 records in 64-bit part and 5 records in 32-bit part I will receive 10 records (5 unique) in total.

How can I stop WMI from doing the redirection?


Solution

  • VB not C# but this worked for me and is coded to work whether your app is running as a 32 bit process or as a 64 bit process. The magic bit is the IF statement around line 8 - IntPtr.Size will only be 4 if your process is a 32 bit process.

       Public Function GetSettingEx(PredefinedKey As PredefinedKeyEnum, Section As String, Key As String, Default_Renamed As String, sComputerName As String, Optional b64Bit As Boolean = False) As String
           Try
               Dim options As New ConnectionOptions()
               options.Impersonation = ImpersonationLevel.Impersonate
    
               Dim scope As New ManagementScope("\\" & sComputerName & "\root\default", options)
    
               If IntPtr.Size = 4 Then
                   scope.Options.Context.Add("__ProviderArchitecture", 64)
                   scope.Options.Context.Add("__RequiredArchitecture", True)
               End If
    
               scope.Connect()
    
               Dim regclass As New ManagementClass(scope, New ManagementPath("StdRegProv"), Nothing)
    
               Dim hDefKey As UInteger = MapPredefinedKeyToWMI(PredefinedKey)
    
               Dim methodParams As ManagementBaseObject = regclass.GetMethodParameters("EnumValues")
               methodParams("hDefKey") = hDefKey
               methodParams("sSubKeyName") = Section
    
               Dim outParams As ManagementBaseObject = regclass.InvokeMethod("EnumValues", methodParams, Nothing)
    
               If CUInt(outParams("ReturnValue")) = 0 Then
                   Dim valueNames As String() = DirectCast(outParams.Properties("sNames").Value, String())
                   Dim valueTypes As Integer() = DirectCast(outParams.Properties("Types").Value, Integer())
    
                   If valueNames Is Nothing Then
                       Return ""
                   End If
    
                   For i As Integer = 0 To valueNames.Length - 1
                       Dim name As String = valueNames(i)
                       If name = Key Then
                           Dim regtype As RegistryTypes = CType(valueTypes(i), RegistryTypes)
    
                           Select Case regtype
                               Case RegistryTypes.REG_SZ, RegistryTypes.REG_EXPAND_SZ
                                   Dim methodParamssz As ManagementBaseObject = regclass.GetMethodParameters("GetStringValue")
                                   methodParamssz("hDefKey") = hDefKey
                                   methodParamssz("sSubKeyName") = Section
                                   methodParamssz("sValueName") = Key
    
                                   Dim outParamssz As ManagementBaseObject = regclass.InvokeMethod("GetStringValue", methodParamssz, Nothing)
    
                                   Dim value As Object = outParamssz.Properties("sValue").Value
                                   Return CStr(value)
    
    
                               Case RegistryTypes.REG_MULTI_SZ
                                   Dim methodParamssz As ManagementBaseObject = regclass.GetMethodParameters("GetMultiStringValue")
                                   methodParamssz("hDefKey") = hDefKey
                                   methodParamssz("sSubKeyName") = Section
                                   methodParamssz("sValueName") = Key
    
                                   Dim outParamssz As ManagementBaseObject = regclass.InvokeMethod("GetMultiStringValue", methodParamssz, Nothing)
    
                                   Dim value As Object = outParamssz.Properties("sValue").Value
                                   Return String.Join(",", DirectCast(value, String()))
    
                               Case RegistryTypes.REG_DWORD
                                   Dim methodParamsdword As ManagementBaseObject = regclass.GetMethodParameters("GetDWORDValue")
                                   methodParamsdword("hDefKey") = hDefKey
                                   methodParamsdword("sSubKeyName") = Section
                                   methodParamsdword("sValueName") = Key
    
                                   Dim outParamsdword As ManagementBaseObject = regclass.InvokeMethod("GetDWORDValue", methodParamsdword, Nothing)
    
                                   Dim value As Object = outParamsdword.Properties("uValue").Value
                                   Return CStr(value)
    
                               Case RegistryTypes.REG_QWORD
                                   Dim methodParamsqword As ManagementBaseObject = regclass.GetMethodParameters("GetQWORDValue")
                                   methodParamsqword("hDefKey") = hDefKey
                                   methodParamsqword("sSubKeyName") = Section
                                   methodParamsqword("sValueName") = Key
    
                                   Dim outParamsqword As ManagementBaseObject = regclass.InvokeMethod("GetQWORDValue", methodParamsqword, Nothing)
    
                                   Dim value As Object = outParamsqword.Properties("uValue").Value
                                   Return CStr(value)
    
                               Case RegistryTypes.REG_BINARY
                                   Dim methodParamsbinary As ManagementBaseObject = regclass.GetMethodParameters("GetBinaryValue")
                                   methodParamsbinary("hDefKey") = hDefKey
                                   methodParamsbinary("sSubKeyName") = Section
                                   methodParamsbinary("sValueName") = Key
    
                                   Dim outParamsbinary As ManagementBaseObject = regclass.InvokeMethod("GetBinaryValue", methodParamsbinary, Nothing)
    
                                   Dim value As Object = outParamsbinary.Properties("uValue").Value
                                   Return BitConverter.ToString(DirectCast(value, Byte()))
    
                               Case Else
                                   Throw New Exception("Unknown registry type : " & regtype.ToString)
                           End Select
                       End If
                   Next
               End If
    
    
               Return Default_Renamed
           Catch ex As Exception
               Return Default_Renamed
           End Try
       End Function
    
    
    
    Public Enum PredefinedKeyEnum
        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
    End Enum
    
        Private Function MapPredefinedKeyToWMI(PredefinedKey As PredefinedKeyEnum) As UInteger
    
            Dim ret As UInteger
    
            Select Case PredefinedKey
                Case PredefinedKeyEnum.HKEY_CLASSES_ROOT
                    ret = 2147483648 ' &H80000000
                Case PredefinedKeyEnum.HKEY_CURRENT_USER
                    ret = 2147483649 ' &H80000001
                Case PredefinedKeyEnum.HKEY_LOCAL_MACHINE
                    ret = 2147483650 ' &H80000002
                Case PredefinedKeyEnum.HKEY_USERS
                    ret = 2147483651 ' &H80000003
                Case PredefinedKeyEnum.HKEY_PERFORMANCE_DATA
                    ret = 2147483652 ' &H80000004
                Case PredefinedKeyEnum.HKEY_CURRENT_CONFIG
                    ret = 2147483653 ' &H80000005
                Case PredefinedKeyEnum.HKEY_DYN_DATA
                    ret = 2147483654 ' &H80000006
                Case Else
                    Throw New ArgumentException("Invalid predefinedKey")
            End Select
    
            Return ret
    
        End Function