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.