How to read the 64 bit registry from a 32 bit application or vice versa

I found out that I needed to read the 64 bit registry from a 32 bit app today.

Why you might ask?

Well, I need to get the RegisteredOrganization value from HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion and unfortunately Microsoft has a bug where the WOW6432 version of this key always says Microsoft, so a 32 bit application would always return Microsoft as the RegisteredOrganization, regardless of what the user entered when they installed the OS. This is hardly desired.

Note: This is also why all Visual Studio projects created in Windows 7 64 bit have Microsoft in the project’s Assembly Information. Change the WOW6432 version of the RegisteredOrganization and you fix this Visual Studio issue.
Well, turns out C# doesn’t have functionality until .NET 4, so prior to .NET 4, to choose the 64 bit hive when running a 32 bit app, so we have to do use a DLLImport and use RegOpenKeyEx, RegCloseKey, and RegQueryValueEx.

I don’t have this well commented, and it is not very newbie proof, but here are three different ways to do this. Hopefully you can understand one or more of these.

Example 1 – .NET 4 Example

Here is how to do this in .NET 4.

using Microsoft.Win32;

namespace Read64bitRegistryFrom32bitApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string value64 = string.Empty;
            string value32 = string.Empty;

            RegistryKey localKey = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64);
            localKey = localKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
            if (localKey != null)
            {
                value64 = localKey.GetValue("RegisteredOrganization").ToString();
            }
            RegistryKey localKey32 = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry32);
            localKey32 = localKey32.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
            if (localKey32 != null)
            {
                value32 = localKey32.GetValue("RegisteredOrganization").ToString();
            }
        }
    }
}

.NET 3.5 SP1 and Prior

This can also be done in .NET 3.5 and prior but it is not easy.
We have to do use a DLLImport and use RegOpenKeyEx, RegCloseKey, and RegQueryValueEx. Here are some examples.

Example 1 – A console application to read the 64 bit registry from a 32 bit application or vice versa

Here is the code in a simple one file project:
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Read64bitRegistryFrom32bitApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string value64 = GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "RegisteredOrganization");
            Console.WriteLine(value64);
            string value32 = GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "RegisteredOrganization");
            Console.WriteLine(value32);
        }

        public enum RegSAM
        {
            QueryValue = 0x0001,
            SetValue = 0x0002,
            CreateSubKey = 0x0004,
            EnumerateSubKeys = 0x0008,
            Notify = 0x0010,
            CreateLink = 0x0020,
            WOW64_32Key = 0x0200,
            WOW64_64Key = 0x0100,
            WOW64_Res = 0x0300,
            Read = 0x00020019,
            Write = 0x00020006,
            Execute = 0x00020019,
            AllAccess = 0x000f003f
        }

        public static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
        public static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);

        #region Member Variables
        #region Read 64bit Reg from 32bit app
        [DllImport("Advapi32.dll")]
        static extern uint RegOpenKeyEx(
            UIntPtr hKey,
            string lpSubKey,
            uint ulOptions,
            int samDesired,
            out int phkResult);

        [DllImport("Advapi32.dll")]
        static extern uint RegCloseKey(int hKey);

        [DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
        public static extern int RegQueryValueEx(
            int hKey, string lpValueName,
            int lpReserved,
            ref uint lpType,
            System.Text.StringBuilder lpData,
            ref uint lpcbData);
        #endregion
        #endregion

        #region Functions
        static public string GetRegKey64(UIntPtr inHive, String inKeyName, String inPropertyName)
        {
            return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_64Key, inPropertyName);
        }

        static public string GetRegKey32(UIntPtr inHive, String inKeyName, String inPropertyName)
        {
            return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_32Key, inPropertyName);
        }

        static public string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName)
        {
            //UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
            int hkey = 0;

            try
            {
                uint lResult = RegOpenKeyEx(RegHive.HKEY_LOCAL_MACHINE, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
                if (0 != lResult) return null;
                uint lpType = 0;
                uint lpcbData = 1024;
                StringBuilder AgeBuffer = new StringBuilder(1024);
                RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, AgeBuffer, ref lpcbData);
                string Age = AgeBuffer.ToString();
                return Age;
            }
            finally
            {
                if (0 != hkey) RegCloseKey(hkey);
            }
        }
        #endregion
    }
}

Example 2 – A static class to read the 64 bit registry from a 32 bit application or vice versa

Or if you want this in its own separate class, here is a static class you can add to your project.
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Read64bitRegistryFrom32bitApp
{
    public enum RegSAM
    {
        QueryValue = 0x0001,
        SetValue = 0x0002,
        CreateSubKey = 0x0004,
        EnumerateSubKeys = 0x0008,
        Notify = 0x0010,
        CreateLink = 0x0020,
        WOW64_32Key = 0x0200,
        WOW64_64Key = 0x0100,
        WOW64_Res = 0x0300,
        Read = 0x00020019,
        Write = 0x00020006,
        Execute = 0x00020019,
        AllAccess = 0x000f003f
    }

    public static class RegHive
    {
        public static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
        public static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);
    }

    public static class RegistryWOW6432
    {
        #region Member Variables
        #region Read 64bit Reg from 32bit app
        [DllImport("Advapi32.dll")]
        static extern uint RegOpenKeyEx(
            UIntPtr hKey,
            string lpSubKey,
            uint ulOptions,
            int samDesired,
            out int phkResult);

        [DllImport("Advapi32.dll")]
        static extern uint RegCloseKey(int hKey);

        [DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
        public static extern int RegQueryValueEx(
            int hKey, string lpValueName,
            int lpReserved,
            ref uint lpType,
            System.Text.StringBuilder lpData,
            ref uint lpcbData);
        #endregion
        #endregion

        #region Functions
        static public string GetRegKey64(UIntPtr inHive, String inKeyName, String inPropertyName)
        {
            return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_64Key, inPropertyName);
        }

        static public string GetRegKey32(UIntPtr inHive, String inKeyName, String inPropertyName)
        {
            return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_32Key, inPropertyName);
        }

        static public string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName)
        {
            //UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
            int hkey = 0;

            try
            {
                uint lResult = RegOpenKeyEx(RegHive.HKEY_LOCAL_MACHINE, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
                if (0 != lResult) return null;
                uint lpType = 0;
                uint lpcbData = 1024;
                StringBuilder AgeBuffer = new StringBuilder(1024);
                RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, AgeBuffer, ref lpcbData);
                string Age = AgeBuffer.ToString();
                return Age;
            }
            finally
            {
                if (0 != hkey) RegCloseKey(hkey);
            }
        }
        #endregion

        #region Enums
        #endregion
    }
}
Here is an example of using this class.
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Read64bitRegistryFrom32bitApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string value64 = RegistryWOW6432.GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "RegisteredOrganization");
            string value32 = RegistryWOW6432.GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "RegisteredOrganization");
        }
    }
}

Example 3 – Adding extension methods to the managed RegistryKey object that read the 64 bit registry from a 32 bit application or vice versa

You know what else is a cool idea? Making it an extension class to the normal managed registry C# code. So you can create a regular managed RegistryKey and then just call an extension function off it.
using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32;

namespace Read64bitRegistryFrom32bitApp
{
    /// <summary>
    /// An extension class to allow a registry key to allow it to get the
    /// registry in the 32 bit (Wow6432Node) or 64 bit regular registry key
    /// </summary>
    public static class RegistryWOW6432
    {
        #region Member Variables
        #region Read 64bit Reg from 32bit app
        public static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
        public static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);

        [DllImport("Advapi32.dll")]
        static extern uint RegOpenKeyEx(
            UIntPtr hKey,
            string lpSubKey,
            uint ulOptions,
            int samDesired,
            out int phkResult);

        [DllImport("Advapi32.dll")]
        static extern uint RegCloseKey(int hKey);

        [DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
        public static extern int RegQueryValueEx(
            int hKey, 
            string lpValueName,
            int lpReserved,
            ref RegistryValueKind lpType,
            StringBuilder lpData,
            ref uint lpcbData);

        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "RegQueryValueEx")]
        private static extern int RegQueryValueEx(
            int hKey,
            string lpValueName,
            int lpReserved,
            ref RegistryValueKind lpType,
            [Out] byte[] lpData,
            ref uint lpcbData);
        #endregion
        #endregion

        #region Functions
        public static string GetRegKey64(this RegistryKey inKey, String inPropertyName)
        {
            string strKey = inKey.ToString();
            string regHive = strKey.Split('\\')[0];
            string regPath = strKey.Substring(strKey.IndexOf('\\') + 1);
            return GetRegKey64(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_64Key, inPropertyName);
        }

        public static string GetRegKey32(this RegistryKey inKey, String inPropertyName)
        {
            string strKey = inKey.ToString();
            string regHive = strKey.Split('\\')[0];
            string regPath = strKey.Substring(strKey.IndexOf('\\') + 1);
            return GetRegKey64(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_32Key, inPropertyName);
        }

        public static byte[] GetRegKey64AsByteArray(this RegistryKey inKey, String inPropertyName)
        {
            string strKey = inKey.ToString();
            string regHive = strKey.Split('\\')[0];
            string regPath = strKey.Substring(strKey.IndexOf('\\') + 1);
            return GetRegKey64AsByteArray(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_64Key, inPropertyName);
        }

        public static byte[] GetRegKey32AsByteArray(this RegistryKey inKey, String inPropertyName)
        {
            string strKey = inKey.ToString();
            string regHive = strKey.Split('\\')[0];
            string regPath = strKey.Substring(strKey.IndexOf('\\') + 1);
            return GetRegKey64AsByteArray(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_32Key, inPropertyName);
        }

        private static UIntPtr GetRegHiveFromString(string inString)
        {
            if (inString == "HKEY_LOCAL_MACHINE")
                return HKEY_LOCAL_MACHINE;
            if (inString == "HKEY_CURRENT_USER")
                return HKEY_CURRENT_USER;
            return UIntPtr.Zero;
        }

        static public string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName)
        {
            //UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
            int hkey = 0;

            try
            {
                uint lResult = RegOpenKeyEx(inHive, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
                if (0 != lResult) return null;
                RegistryValueKind lpType = 0;
                uint lpcbData = 1024;
                StringBuilder strBuffer = new StringBuilder(1024);
                RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, strBuffer, ref lpcbData);
                string value = strBuffer.ToString();
                return value;
            }
            finally
            {
                if (0 != hkey) RegCloseKey(hkey);
            }
        }

        static public byte[] GetRegKey64AsByteArray(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName)
        {
            int hkey = 0;

            try
            {
                uint lResult = RegOpenKeyEx(inHive, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
                if (0 != lResult) return null;
                RegistryValueKind lpType = 0;
                uint lpcbData = 2048;

                // Just make a big buffer the first time
                byte[] byteBuffer = new byte[1000];
                // The first time, get the real size
                RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, byteBuffer, ref lpcbData);
                // Now create a correctly sized buffer
                byteBuffer = new byte[lpcbData];
                // now get the real value
                RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, byteBuffer, ref lpcbData);

                return byteBuffer;
            }
            finally
            {
                if (0 != hkey) RegCloseKey(hkey);
            }
        }
        #endregion

        #region Enums
        public enum RegSAM
        {
            QueryValue = 0x0001,
            SetValue = 0x0002,
            CreateSubKey = 0x0004,
            EnumerateSubKeys = 0x0008,
            Notify = 0x0010,
            CreateLink = 0x0020,
            WOW64_32Key = 0x0200,
            WOW64_64Key = 0x0100,
            WOW64_Res = 0x0300,
            Read = 0x00020019,
            Write = 0x00020006,
            Execute = 0x00020019,
            AllAccess = 0x000f003f
        }
        #endregion
    }
}
Here is an example of using these extension functions.
using Microsoft.Win32;

namespace Read64bitRegistryFrom32bitApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string value64 = string.Empty;
            string value32 = string.Empty;

            byte[] byteValue64 = new byte[1024];
            byte[] byteValue32 = new byte[1024];
            RegistryKey localKey = Registry.LocalMachine;
            
            localKey = localKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
            if (localKey != null)
            {
                value32 = localKey.GetRegKey32("RegisteredOrganization");
                value64 = localKey.GetRegKey64("RegisteredOrganization");

                // byteValue32 = localKey.GetRegKey32AsByteArray("DigitalProductId"); // Key doesn't exist by default in 32 bit
                byteValue64 = localKey.GetRegKey64AsByteArray("DigitalProductId");
            }
        }
    }
}
If anything is confusing please comment.
Resources:
  • RegOpenKeyEx Function – http://msdn.microsoft.com/en-us/library/ms724897%28v=VS.85%29.aspx
  • RegQueryValueEx Function – http://msdn.microsoft.com/en-us/library/ms724911%28VS.85%29.aspx
  • http://www.pinvoke.net/default.aspx/advapi32/RegQueryValueEx.html
  • http://www.pinvoke.net/default.aspx/advapi32/RegOpenKeyEx.html
  • http://www.pinvoke.net/default.aspx/advapi32/RegCreateKeyEx.html
  • http://www.pinvoke.net/default.aspx/advapi32/RegCloseKey.html
  • http://stackoverflow.com/questions/1470770/accessing-registry-using-net
  • http://connect.microsoft.com/VisualStudio/feedback/details/400597/registeredorganization-reg-key-on-x64-vista-7

Copyright ® Rhyous.com – Linking to this post is allowed without permission and as many as ten lines of this page can be used along with this link. Any other use of this page is allowed only by permission of Rhyous.com.

50 Comments

  1. สล็อต

    Rhyous » Blog Archive » How to read the 64 bit registry from a 32 bit application or vice versa

  2. safari heat slot game free

    Rhyous » Blog Archive » How to read the 64 bit registry from a 32 bit application or vice versa

  3. 918Kiss panda

    Rhyous » Blog Archive » How to read the 64 bit registry from a 32 bit application or vice versa

  4. www23.tok2.com

    Rhyous » Blog Archive » How to read the 64 bit registry from a 32 bit application or vice versa

  5. Brian W says:

    Thanks for the article! Out of curiosity, how did you figure out the registry memory offsets for the 2 constants: HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER?

  6. Vincent says:

    I'm extending your code for Microsoft Office which is stored in HKLM\SOFTWARE\Microsoft\Office\{0}.0\Registration\
    and I need to retrieve all values using : localKey.GetSubKeyNames();

    but I think we must change this code to read from 32 or 64 registry ?

    Vincent

    • Hi,

      here's the code using exemple 3 :

      Main call

       string[] Result3 = RegistryUtility.GetKeyNames32(RegistryConst.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability");
       string[] Result4 = RegistryUtility.GetKeyNames64(RegistryConst.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability");
      
       string[] Result = RegistryUtility.GetValueNames32(RegistryConst.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run");
       string[] Result2 = RegistryUtility.GetValueNames64(RegistryConst.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run");
      

      RegistryUtility.cs

      using Microsoft.Win32;
      using System;
      using System.Collections.Specialized;
      using System.Text;
      
      namespace Nolme.Win32
      {
          /// 
          /// 
          /// 
          public sealed class RegistryUtility
          {
              private RegistryUtility() {  }
      
              #region Enums
              public enum RegSAM
              {
                  QueryValue = 0x0001,
                  SetValue = 0x0002,
                  CreateSubKey = 0x0004,
                  EnumerateSubKeys = 0x0008,
                  Notify = 0x0010,
                  CreateLink = 0x0020,
                  WOW64_32Key = 0x0200,
                  WOW64_64Key = 0x0100,
                  WOW64_Res = 0x0300,
                  Read = 0x00020019,
                  Write = 0x00020006,
                  Execute = 0x00020019,
                  AllAccess = 0x000f003f
              }
              #endregion
      
              #region Functions
              public static string GetRegKey64(RegistryKey inKey, String inPropertyName)
              {
                  string strKey = inKey.ToString();
                  string regHive = strKey.Split('\\')[0];
                  string regPath = strKey.Substring(strKey.IndexOf('\\') + 1);
                  return GetRegKey64(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_64Key, inPropertyName);
              }
      
              public static string GetRegKey32(RegistryKey inKey, String inPropertyName)
              {
                  string strKey = inKey.ToString();
                  string regHive = strKey.Split('\\')[0];
                  string regPath = strKey.Substring(strKey.IndexOf('\\') + 1);
                  return GetRegKey64(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_32Key, inPropertyName);
              }
      
              public static byte[] GetRegKey64AsByteArray(RegistryKey inKey, String inPropertyName)
              {
                  string strKey = inKey.ToString();
                  string regHive = strKey.Split('\\')[0];
                  string regPath = strKey.Substring(strKey.IndexOf('\\') + 1);
                  return GetRegKey64AsByteArray(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_64Key, inPropertyName);
              }
      
              public static byte[] GetRegKey32AsByteArray(RegistryKey inKey, String inPropertyName)
              {
                  string strKey = inKey.ToString();
                  string regHive = strKey.Split('\\')[0];
                  string regPath = strKey.Substring(strKey.IndexOf('\\') + 1);
                  return GetRegKey64AsByteArray(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_32Key, inPropertyName);
              }
      
              private static UIntPtr GetRegHiveFromString(string inString)
              {
                  if (inString == "HKEY_LOCAL_MACHINE")
                      return RegistryConst.HKEY_LOCAL_MACHINE;
                  if (inString == "HKEY_CURRENT_USER")
                      return RegistryConst.HKEY_CURRENT_USER;
                  return UIntPtr.Zero;
              }
      
              static public string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName)
              {
                  int hkey = 0;
      
                  try
                  {
                      uint lResult = RegistryNativeMethods.RegOpenKeyEx(inHive, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
                      if (0 != lResult) return null;
                      RegistryValueKind lpType = 0;
                      uint lpcbData = 1024;
                      StringBuilder strBuffer = new StringBuilder(1024);
                      RegistryNativeMethods.RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, strBuffer, ref lpcbData);
                      string value = strBuffer.ToString();
                      return value;
                  }
                  finally
                  {
                      if (0 != hkey)
                          RegistryNativeMethods.RegCloseKey(hkey);
                  }
              }
      
              static public byte[] GetRegKey64AsByteArray(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName)
              {
                  int hkey = 0;
      
                  try
                  {
                      uint lResult = RegistryNativeMethods.RegOpenKeyEx(inHive, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
                      if (0 != lResult) 
                          return null;
                      RegistryValueKind lpType = 0;
                      uint lpcbData = 2048;
      
                      // Just make a big buffer the first time
                      byte[] byteBuffer = new byte[1000];
                      // The first time, get the real size
                      RegistryNativeMethods.RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, byteBuffer, ref lpcbData);
                      // Now create a correctly sized buffer
                      byteBuffer = new byte[lpcbData];
                      // now get the real value
                      RegistryNativeMethods.RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, byteBuffer, ref lpcbData);
      
                      return byteBuffer;
                  }
                  finally
                  {
                      if (0 != hkey)
                          RegistryNativeMethods.RegCloseKey(hkey);
                  }
              }
      
      
              static public string[] GetValueNames32(UIntPtr inHive, String inKeyName)
              {
                  return GetValueNames(inHive, inKeyName, RegSAM.WOW64_32Key);
              }
      
              static public string[] GetValueNames64(UIntPtr inHive, String inKeyName)
              {
                  return GetValueNames(inHive, inKeyName, RegSAM.WOW64_64Key);
              }
      
              /// 
              /// 
              /// 
              /// 
              /// 
              /// 
              /// 
              static public string[] GetValueNames(UIntPtr inHive, String inKeyName, RegSAM in32or64key)
              {
                  long lResult = 0;
                  int hkey = 0;
                  string[] Result = null;
      
                  try
                  {
                      lResult = RegistryNativeMethods.RegOpenKeyEx(inHive, inKeyName, 0, (int)RegistryUtility.RegSAM.QueryValue | (int)in32or64key | (int)RegistryUtility.RegSAM.Read, out hkey);
                      if (RegistryConst.ERROR_SUCCESS == lResult)
                      {
      
                          uint MAX_REG_KEYNAME_SIZE = 256;
                          uint i = 0;
                          uint NameSize = 0;
                          StringCollection sc = new StringCollection();
                          StringBuilder sb = new StringBuilder();
                          
                          do
                          {
                              NameSize = MAX_REG_KEYNAME_SIZE + 1;
                              lResult = RegistryNativeMethods.RegEnumValue(hkey, i, sb, ref NameSize, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
                              if (lResult != RegistryConst.ERROR_SUCCESS)
                              {
                                  break; // TODO: might not be correct. Was : Exit Do
                              }
                              sc.Add(sb.ToString());
                              i += 1;
                          } while (true);
      
                          if (sc.Count &gt; 0)
                          {
                              Result = new string[sc.Count];
                              sc.CopyTo(Result, 0);
                          }
                      }
                  }
                  finally
                  {
                      if (0 != hkey)
                      {
                          lResult = RegistryNativeMethods.RegCloseKey(hkey);
                          if (lResult != RegistryConst.ERROR_SUCCESS)
                          {
                              // TODO : closing error to manage
                          }
                      }
                  }
                  return Result;
              }
      
      
              static public string[] GetKeyNames32(UIntPtr inHive, String inKeyName)
              {
                  return GetKeyNames(inHive, inKeyName, RegSAM.WOW64_32Key);
              }
      
              static public string[] GetKeyNames64(UIntPtr inHive, String inKeyName)
              {
                  return GetKeyNames(inHive, inKeyName, RegSAM.WOW64_64Key);
              }
      
              /// 
              /// 
              /// 
              /// 
              /// 
              /// 
              /// 
              static public string[] GetKeyNames(UIntPtr inHive, String inKeyName, RegSAM in32or64key)
              {
                  long lResult = 0;
                  string[] Result = null;
                  int hkey = 0;
      
                  try
                  {
                      lResult = RegistryNativeMethods.RegOpenKeyEx(inHive, inKeyName, 0, (int)RegistryUtility.RegSAM.QueryValue | (int)in32or64key | (int)RegistryUtility.RegSAM.Read, out hkey);
                      if (RegistryConst.ERROR_SUCCESS == lResult)
                      {
                          // Get the number of subkey names under the key.
                          uint numSubKeys; // Number of subkeys
                          uint numValues;  // Number of values
                          lResult = RegistryNativeMethods.RegQueryInfoKey(hkey, null, IntPtr.Zero, IntPtr.Zero, out numSubKeys, IntPtr.Zero, IntPtr.Zero, out numValues, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
      
                          if ((RegistryConst.ERROR_SUCCESS == lResult) &amp;&amp; (numSubKeys &gt; 0))
                          {
                              // Create an array to hold the names.
                              Result = new String[numSubKeys];
                              StringBuilder sb = new StringBuilder();
                              uint index = 0;
                              long writeTime;
                              while (index &lt; numSubKeys)
                              {
                                  sb = new StringBuilder();
                                  uint MAX_REG_KEY_SIZE = 1024;       // This value is changed after function call. So we must init it at each time
                              
                                  lResult = RegistryNativeMethods.RegEnumKeyEx(hkey, index, sb, ref MAX_REG_KEY_SIZE, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, out writeTime);
                                  if (RegistryConst.ERROR_SUCCESS == lResult)
                                  {
                                      Result[(int)(index++)] = sb.ToString();
      
                                  }
                                  else
                                  {
                                      break;
                                  }
                              }
                          }
                      }
                  }
                  finally
                  {
                      if (0 != hkey)
                      {
                          lResult = RegistryNativeMethods.RegCloseKey(hkey);
                          if (lResult != RegistryConst.ERROR_SUCCESS)
                          {
                              // TODO : closing error to manage
                          }
                      }
                  }
                  return Result;
              }
              #endregion
          }
      }
      

      RegistryNativeMethods.cs

      using Microsoft.Win32;
      using System;
      using System.Collections.Generic;
      using System.Runtime.InteropServices;
      using System.Text;
      
      namespace Nolme.Win32
      {
          /// 
          /// Registry specific constants
          /// 
          public sealed class RegistryConst
          {
              private RegistryConst() { }
      
              #region Member Variables
              public static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
              public static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);
      
              internal static int ERROR_SUCCESS = 0;
              #endregion
          }
      
          /// 
          /// Win32 native methods for Registry access
          /// 
          internal sealed class RegistryNativeMethods
          {
              private RegistryNativeMethods() { }
      
              #region Read 64bit Reg from 32bit app
              [DllImport("Advapi32.dll")]
              internal static extern uint RegOpenKeyEx(
                  UIntPtr hKey,
                  string lpSubKey,
                  uint ulOptions,
                  int samDesired,
                  out int phkResult);
      
              [DllImport("Advapi32.dll")]
              internal static extern uint RegCloseKey(int hKey);
      
              [DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
              internal static extern int RegQueryValueEx(
                  int hKey,
                  string lpValueName,
                  int lpReserved,
                  ref RegistryValueKind lpType,
                  StringBuilder lpData,
                  ref uint lpcbData);
      
              [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "RegQueryValueEx")]
              internal static extern int RegQueryValueEx(
                  int hKey,
                  string lpValueName,
                  int lpReserved,
                  ref RegistryValueKind lpType,
                  [Out] byte[] lpData,
                  ref uint lpcbData);
      
              [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "RegEnumValue")]
              internal static extern uint RegEnumValue(
                    int hKey,
                    uint dwIndex,
                    StringBuilder lpValueName,
                    ref uint lpcValueName,
                    IntPtr lpReserved,
                    IntPtr lpType,
                    IntPtr lpData,
                    IntPtr lpcbData);
      
              [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "RegEnumKeyEx")]
              internal static extern int RegEnumKeyEx(
                  int hKey,
                  uint index,
                  StringBuilder lpName,
                  ref uint lpcbName,
                  IntPtr reserved,
                  IntPtr lpClass,
                  IntPtr lpcbClass,
                  out long lpftLastWriteTime);
      
              [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
              internal static extern int RegQueryInfoKey(
                  int hkey,
                  StringBuilder lpClass,
                  IntPtr lpcbClass,
                  IntPtr lpReserved,
                  out uint lpcSubKeys,
                  IntPtr lpcbMaxSubKeyLen,
                  IntPtr lpcbMaxClassLen,
                  out uint lpcValues,
                  IntPtr lpcbMaxValueNameLen,
                  IntPtr lpcbMaxValueLen,
                  IntPtr lpcbSecurityDescriptor,
                  IntPtr lpftLastWriteTime
              );
              #endregion
          }
      }
      
  7. selim says:

    Hi Rhyous

    Thank you very very much for this code. You saved me ^^

    What a relief

  8. anonymouse says:

    I think there is a typo in example 2, line 73:
    uint lResult = RegOpenKeyEx(RegHive.HKEY_LOCAL_MACHINE, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);

    which should be:?
    uint lResult = RegOpenKeyEx(inHive, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);

  9. ThielHater says:

    I also had some trouble to read DWORD/QWORD values from registry using the 2nd example, it just didn't work with the original code. So I mixed up GetRegKey64() from the 3rd and 2nd example, which led me to:

    // Copied from 3rd example
    [DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
    public static extern int RegQueryValueEx(int hKey, string lpValueName, int lpReserved, ref RegistryValueKind lpType, StringBuilder lpData, ref uint lpcbData);
    
    static private string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName)
    {
        int hkey = 0;
        try
        {
            uint lResult = RegOpenKeyEx(inHive, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
            if (0 != lResult) return null;
            RegistryValueKind lpType = 0;
            uint lpcbData = 1024;
            StringBuilder strBuffer = new StringBuilder(1024);
            RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, strBuffer, ref lpcbData);
            if (lpType == RegistryValueKind.DWord)
            {                 
                byte[] reg = Encoding.ASCII.GetBytes(strBuffer.ToString());
                byte[] bytes = {0, 0, 0, 0};
                for (int i = 0; i &lt; reg.Length; i++)
                    bytes[i] = reg[i];
                return BitConverter.ToUInt32(bytes, 0).ToString();
            }
            else if (lpType == RegistryValueKind.QWord)
            {
                /*
                  - Theoretically this could be done by bit shifting and masking the char[] values of strBuff into ulong,
                    but shifting &quot;&lt;&lt; 40&quot; gave the same result as &quot;&lt;&lt; 8&quot; for any reason. That&#039;s why I used BitConverter!
                  - BitConverter requires a byte[] size of 4/8, otherwise an exception is thrown.
                */
                byte[] reg = Encoding.ASCII.GetBytes(strBuffer.ToString());
                byte[] bytes = { 0, 0, 0, 0, 0, 0, 0, 0 };
                for (int i = 0; i &lt; reg.Length; i++)
                    bytes[i] = reg[i];
                return BitConverter.ToUInt64(bytes, 0).ToString();
            }
            else if ((lpType == RegistryValueKind.String) || (lpType == RegistryValueKind.ExpandString)) // REG_MULTI_SZ is not read correctly from registry
            {
                return strBuffer.ToString();
            }
            else
            {
                return String.Empty;
            }
        }
        finally
        {
            if (hkey != 0) RegCloseKey(hkey);
        }
    }
    
  10. Lambertar says:

    Thanx a lot ! You're a life saver !

  11. Michael says:

    Hi

    For some reason RegOpenKeyEx, with the WOW64_32Key as a parameter, is not working.

    I am running in debug on SharpDevelop, which requires 32bit exe. No matter what I do, I am getting the 64bit registry!

    Very strange! I am new to C# but very familiar with the registry and 64/32bit processes!

    I can only imagine that 32bit C# binaries are using the 64bit framework, and have hence arrived at a position where KEY_WOW64_32KEY is utterly ignored!?

  12. sandeep says:

    Any idea how will we do this in a java program?
    I have a 32bit java application that runs on 64bit windows.
    I don't want to use C/C++ libraries.

  13. GroovyB says:

    Nice job!
    Only a question: how can I do the same job but for remote registry ?

    Thanks.

  14. create an android app says:

    I know this if off topic but I'm looking into starting my own blog and was wondering what all is required to get setup? I'm
    assuming having a blog like yours would cost a pretty penny?
    I'm not very web savvy so I'm not 100% sure. Any recommendations or advice would be greatly appreciated. Kudos

  15. RohitP says:

    I am not able to get Dword value any idea

    • NinR says:

      int iData;
      bool success = Int32.TryParse(sData, out iData);
      if (success == true)
      {
      regKey.SetValue(sName, iData);
      }
      else
      {
      sData = sData.Substring(2);
      iData = int.Parse(sData, System.Globalization.NumberStyles.HexNumber);
      regKey.SetValue(sName, iData);
      }

  16. [...] How to read the 64 bit registry from a 32 bit application or vice versa | Rhyous. Share this:TwitterFacebookLike this:LikeBe the first to like this. By Bri-Tri • Posted in .NET Programming • Tagged 32bit, 64bit, C#, registry, windows7 0 [...]

  17. [...] option is to implement a solution like what’s described here. You can add logic to your application to determine whether the OS is 32 or 64 bit and access the [...]

  18. evhenious says:

    Thanx a lot, CodeKnight. Good examples, nice explanation. I thought that I've been killed by that f*cking registry, but horror is over) thanx again!

  19. AlanB says:

    Nice job, you just saved me several hours of work. Clear explanation and examples.

  20. Rudson Kiyoshi S. Carvalho says:

    Congrats!

  21. Carlo says:

    I translate the first examples for vb.net, it' good!!
    Best Regards

  22. Deploying an application for any cpu. Reading HKLM registry | PHP Developer Resource says:

    [...] You may have missed this link: https://www.rhyous.com/2011/01/24/how-read-the-64-bit-registry-from-a-32-bit-application-or-vice-vers... [...]

  23. Eduardo says:

    I'm trying to get value from a REG_DWORD key. I tried to change your code to return long value, but without success.
    For the moment, i'm using the GetRegKey64AsByteArray method and return only the first byte, which gives me the correct value.
    Got a better idea on returning int values ? Thanks

  24. Eduardo says:

    Extension Methods don't work well on .NET 2.0, so you need to hack in order to make it work.
    Anyway, great article, thanks for posting!

  25. emil says:

    Hi,

    thank you for sharing this code. I am rather new to .net and c# and it helps me quite a bit when I can see an example from someone that knows what they are doing.

    Do you mind sharing how you would extend RegistryKey.GetValueNames() (which returns a String[]) in your example 3? Possibly with GetValueNames32() and GetValueNames64().

    Thank you
    emil

  26. Qambar Raza says:

    Hi,

    I am unable to read byte[] digital product ids from registry using this class. That is because i assume your class is returning string. I am using your example 3.

    Can you help me with the amendments ?

    Thanks.

    • Rhyous says:

      I am not sure what you mean by "byte[] digital product ids" as there is not a registry key type of "byte[]" that I know of. Perhaps you are getting a binary key and converting it to byte?

      Export a registry key with the example you want to pull and I will try to look at it.

      • Qambar Raza says:

        Yes, its a binary value REG_BINARY you guessed it right. I am trying to convert it to byte. But when i do so it says you cannot convert System.String to System.Byte[]. I am doing explicit casting.

        You can test it yourself on the following registry path:

        SOFTWARE\Microsoft\Windows NT\CurrentVersion\

        Value Name : DigitalProductId
        Value Date : REG_BINARY 24bit encoded.

        My guess is GetRegKey64() and GetRegKey32() are both returning String data so we cannot convert it to byte[]. I tried to change the return types to object but it didn't work either.

        Do you have any suggestions ?

  27. Garry@TriSys says:

    I expected that the write code would work also:
    Dim localKey As Microsoft.Win32.RegistryKey = Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, Microsoft.Win32.RegistryView.Registry64)
    localKey = localKey.OpenSubKey(RegistryLocationKey)
    If localKey IsNot Nothing Then
    localKey.SetValue(sValueName, sValue, Microsoft.Win32.RegistryValueKind.String)
    End If
    Dim localKey32 As Microsoft.Win32.RegistryKey = Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, Microsoft.Win32.RegistryView.Registry32)
    localKey32 = localKey32.OpenSubKey(RegistryLocationKey)
    If localKey32 IsNot Nothing Then
    localKey.SetValue(sValueName, sValue, Microsoft.Win32.RegistryValueKind.String)
    End If

    But it does not as Windows complains. Any ideas?

  28. Bishnu says:

    it was very helpful...
    Thanks.

  29. [...] How read the 64 bit registry from a 32 bit application or vice versa Posted on July 12, 2011 by mytechconnect https://www.rhyous.com/2011/01/24/how-read-the-64-bit-registry-from-a-32-bit-application-or-vice-vers... [...]

  30. Mohan says:

    Rhyous! Thanks for the code. I have been searching for an example like your example 1. You saved my time.

  31. Chris Motter says:

    In example #2 your last GetRegKey64() method accepts a parameter called inHive but this is not used in the method; in fact it's hard-coded to only allow LOCAL_MACHINE. It appears that it's just a leftover from debugging and that it should actually make use of the RegHive class above.

    At first glance I'm guessing that you can just remove the hard-coded reference and replace it with the inHive parameter to fix this.

  32. Matt says:

    A bit help to get me started thanks

  33. Marcin says:

    Nice, helped me a lot. Thanks!

  34. Sparky says:

    In example 3, lines 41 and 49 include the this keyword. Is it necessary to include those? Thanks.

Leave a Reply to ThielHater

How to post code in comments?