Access 64-bit key in the Windows Registry through 32-bit application

1

I need to get information about the network to list in an application I'm doing, but I'm having a problem accessing Windows Registry because of project preference.

Path: Right-click on the class, click properties, and then compiler.

Note that under the Target CPU field, you have a CheckBox (32-bit Prefer)

If this option is ticked my code does not work on 64 bit system, however if I disable my application it does not work on the 32 bit machine. If I comment on all procedures that look for values in regedit, the application works on both.

I wonder if I can access the registry key in either 64bit or 32bit.

Follow the code:

  Public Sub ObterTipoDaRede(ByVal NomeConfiguracao As String, ByVal  _
 NomeConfiguracaoDois As String)
    Dim NomeDaRede As String
    Dim regKey
    Dim lDatas As New List(Of KeyValuePair(Of String, DateTime))

    'If Environment.Is64BitOperatingSystem Then

    'Else
    regKey = My.Computer.Registry.LocalMachine.OpenSubKey("SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles")
    'End If

    Try
        For Each SubK In regKey.GetSubKeyNames

            Dim value = My.Computer.Registry.LocalMachine.OpenSubKey("SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles\" + SubK)
            Dim data = My.Computer.Registry.GetValue(value.ToString, "DateLastConnected", Nothing)
            Dim dt As DateTime = ObterDataDoUltimoAcesso(data)

            lDatas.Add(New KeyValuePair(Of String, Date)(SubK, dt))
        Next

        lDatas = lDatas.OrderByDescending(Function(x) x.Value).ToList
        Dim t = lDatas.First
        Dim chave = My.Computer.Registry.LocalMachine.OpenSubKey("SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles\" + t.Key)
        Dim nomeRede As String = My.Computer.Registry.GetValue(chave.ToString, "ProfileName", Nothing)
        Dim tipoRede As String = My.Computer.Registry.GetValue(chave.ToString, "Category", Nothing)

        NomeDaRede = nomeRede
        Select Case tipoRede
            Case 0
                Me.PerfilDaRede = "Publica"
            Case 1
                Me.PerfilDaRede = "Privada"
            Case 2
                Me.PerfilDaRede = "Dominio"
        End Select

        Me.PreencherGriddgvDadosComputador(NomeConfiguracao, NomeDaRede, "Ok")
        Me.PreencherGriddgvDadosComputador(NomeConfiguracaoDois, Me.PerfilDaRede, "Ok")

    Catch ex As Exception
        MsgBox("Teste", vbInformation)
    End Try

End Sub
    
asked by anonymous 14.03.2018 / 21:26

1 answer

2

In the question you said: If this option is ticked my code does not work on 64 bit system, however if I disable my application it does not work on the 32 bit machine.

In fact, if the Target CPU field value is AnyCPU , and Prefer 32-bit If your system is 32-bit, your program will run as 32-bit, if your system is 64-bit, your program will run as 64- bit. But if 32-bit Prefer option is checked, your program will run as 32-bit, even if the system is 64-bit.

The problem is that on 64-bit Windows systems, if your program is 32-bit, it will automatically run on a subsystem called # (32-bit Windows on 64-bit Windows), and in the case of Windows Registry there is something called Registry Redirector , which intercepts calls to Registry and redirects them to the correct location based on the application architecture (32 or 64 bits).

More on the subject in the links below:

  Running 32-bit Applications
link

     

Registry Redirector
link

Today when searching to answer your question, I have discovered that since the .NET Framework 4.0, there is an option in Windows's Registry handling classes that allows access to a 64-bit key through a 32-bit application, that is, an option that temporarily disables the Registry redirector:

  

Method RegistryKey.OpenBaseKey (RegistryHive, RegistryView)
link

     

RegistryView Enumeration - link

     

Members
RegistryView. Default - - > The default view.
RegistryView. Registry32 - > The 32-bit display.
RegistryView. Registry64 - -> The 64-bit view.

     

Comments
In the 64-bit version of Windows, parts of the registry are stored separately for 32-bit and 64-bit applications. There is a 32-bit view for 32-bit applications and a 64-bit view for 64-bit applications.

     

You can specify a record view by using the methods OpenBaseKey and OpenRemoteBaseKey(RegistryHive, String, RegistryView) and the FromHandle property on a RegistryKey object.      

If you request a 64-bit view on a 32-bit operating system, the keys will be returned in the 32-bit view.

Changing your code to use this method, and accessing 64-bit keys even through a 32-bit application:

Imports Microsoft.Win32

' [...]

   Public Sub ObterTipoDaRede(NomeConfiguracao As String, NomeConfiguracaoDois As String)

      Const NomeChaveProfiles = 
         "SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles"

      Dim chaveBase As RegistryKey
      Dim chaveProfiles As RegistryKey
      Dim chaveProfile As RegistryKey
      Dim listaDatas As New List(Of KeyValuePair(Of String, DateTime))

      ' Se você solicitar um modo de exibição de 64 bits em um sistema operacional
      ' de 32 bits, as chaves serão retornadas no modo de exibição de 32 bits.
      chaveBase = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,
                                          RegistryView.Registry64)
      chaveProfiles = chaveBase.OpenSubKey(NomeChaveProfiles)

      For Each nomeChaveProfile In chaveProfiles.GetSubKeyNames
         chaveProfile = chaveBase.OpenSubKey(NomeChaveProfiles & "\" + nomeChaveProfile)
         Dim dataFormatoBinario = chaveProfile.GetValue("DateLastConnected", Nothing)
         Dim dt As DateTime = ObterDataDoUltimoAcesso(dataFormatoBinario)

         listaDatas.Add(New KeyValuePair(Of String, Date)(nomeChaveProfile, dt))
      Next

      listaDatas = listaDatas.OrderByDescending(Function(x) x.Value).ToList()
      Dim primeiroItem = listaDatas.First()
      chaveProfile = chaveBase.OpenSubKey(NomeChaveProfiles & "\" + primeiroItem.Key)
      Dim nomeRede As String = chaveProfile.GetValue("ProfileName", Nothing)
      Dim tipoRede As String = chaveProfile.GetValue("Category", Nothing)

      Select Case tipoRede
         Case 0 : Me.PerfilDaRede = "Publica"
         Case 1 : Me.PerfilDaRede = "Privada"
         Case 2 : Me.PerfilDaRede = "Dominio"
      End Select

   End Sub
    
15.03.2018 / 04:15