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
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
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
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 } }
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
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 } }
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"); } } } }
- 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.
สล็อต
Rhyous » Blog Archive » How to read the 64 bit registry from a 32 bit application or vice versa
safari heat slot game free
Rhyous » Blog Archive » How to read the 64 bit registry from a 32 bit application or vice versa
918Kiss panda
Rhyous » Blog Archive » How to read the 64 bit registry from a 32 bit application or vice versa
www23.tok2.com
Rhyous » Blog Archive » How to read the 64 bit registry from a 32 bit application or vice versa
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?
I don't think I did. I think I found them in one of the articles I linked for resource.
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
RegistryUtility.cs
RegistryNativeMethods.cs
Hi Rhyous
Thank you very very much for this code. You saved me ^^
What a relief
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);
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:
Awesome!
Thanx a lot ! You're a life saver !
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!?
Ok just discovered this only happens for HKCU. HKLM is behaving normally.
For now, I only need HKLM. Crikey. Complicated 🙂
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.
I don't know if Java has this ability.
Nice job!
Only a question: how can I do the same job but for remote registry ?
Thanks.
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
I am not able to get Dword value any idea
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);
}
thx !
[...] 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 [...]
[...] 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 [...]
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!
Nice job, you just saved me several hours of work. Clear explanation and examples.
Congrats!
I translate the first examples for vb.net, it' good!!
Best Regards
That would be great if you port it to vb.net.
Carlo,
I would love to get a copy of your vb.net version of the code. Would you please email me a copy?
Thanks for blazing the trail.
Larry George
[...] 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... [...]
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
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!
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
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.
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.
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 ?
I updated the post, give it a try.
Amazing !! Its working like a charm.
Thanks alot mate !! 😀
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?
it was very helpful...
Thanks.
[...] 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... [...]
Rhyous! Thanks for the code. I have been searching for an example like your example 1. You saved my time.
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.
I think your right. I am sure I meant to make it dynamic.
A bit help to get me started thanks
Nice, helped me a lot. Thanks!
In example 3, lines 41 and 49 include the this keyword. Is it necessary to include those? Thanks.
For example 3, YES! That is how extension classes work.