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.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
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.
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
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.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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

      1
      2
      3
      4
      5
      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

      001
      002
      003
      004
      005
      006
      007
      008
      009
      010
      011
      012
      013
      014
      015
      016
      017
      018
      019
      020
      021
      022
      023
      024
      025
      026
      027
      028
      029
      030
      031
      032
      033
      034
      035
      036
      037
      038
      039
      040
      041
      042
      043
      044
      045
      046
      047
      048
      049
      050
      051
      052
      053
      054
      055
      056
      057
      058
      059
      060
      061
      062
      063
      064
      065
      066
      067
      068
      069
      070
      071
      072
      073
      074
      075
      076
      077
      078
      079
      080
      081
      082
      083
      084
      085
      086
      087
      088
      089
      090
      091
      092
      093
      094
      095
      096
      097
      098
      099
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      151
      152
      153
      154
      155
      156
      157
      158
      159
      160
      161
      162
      163
      164
      165
      166
      167
      168
      169
      170
      171
      172
      173
      174
      175
      176
      177
      178
      179
      180
      181
      182
      183
      184
      185
      186
      187
      188
      189
      190
      191
      192
      193
      194
      195
      196
      197
      198
      199
      200
      201
      202
      203
      204
      205
      206
      207
      208
      209
      210
      211
      212
      213
      214
      215
      216
      217
      218
      219
      220
      221
      222
      223
      224
      225
      226
      227
      228
      229
      230
      231
      232
      233
      234
      235
      236
      237
      238
      239
      240
      241
      242
      243
      244
      245
      246
      247
      248
      249
      250
      251
      252
      253
      254
      255
      256
      257
      258
      259
      260
      261
      262
      263
      264
      265
      266
      267
      268
      269
      270
      271
      272
      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

      001
      002
      003
      004
      005
      006
      007
      008
      009
      010
      011
      012
      013
      014
      015
      016
      017
      018
      019
      020
      021
      022
      023
      024
      025
      026
      027
      028
      029
      030
      031
      032
      033
      034
      035
      036
      037
      038
      039
      040
      041
      042
      043
      044
      045
      046
      047
      048
      049
      050
      051
      052
      053
      054
      055
      056
      057
      058
      059
      060
      061
      062
      063
      064
      065
      066
      067
      068
      069
      070
      071
      072
      073
      074
      075
      076
      077
      078
      079
      080
      081
      082
      083
      084
      085
      086
      087
      088
      089
      090
      091
      092
      093
      094
      095
      096
      097
      098
      099
      100
      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:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    // 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

How to post code in comments?