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
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
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
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 } } |
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
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 } } |
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" ); } } } } |
- 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
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 > 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) && (numSubKeys > 0))
{
// Create an array to hold the names.
Result =
new
String[numSubKeys];
StringBuilder sb =
new
StringBuilder();
uint
index = 0;
long
writeTime;
while
(index < 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
}
}
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:
// 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 < 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 "<< 40" gave the same result as "<< 8" for any reason. That'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 < 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);
}
}
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.