做项目的过程中需要读取和修改注册表,操作过程中发现读取的注册的注册表和实际的值不一致。
查阅网上信息了解到,64位操作系统为32位app独立设置了一个目录存放它的注册表项目
计算机\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node
32位如果调用C#自己的函数,则会默认读取32位的注册表,而不会读取64位的注册表。.net4.5之后有办法直接读取。而.net 3.5无法直接读取。只能调用win32api读取
主要用到了是RegOpenKeyEx,RegQueryKeyEx和RegSerKeyEx。
写了一个类可以直接拿去项目里面用。
using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32;
namespace ServiceTest
{
/// <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&Write 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", EntryPoint = "RegSetValueEx")]
public static extern int RegSetValueEx(
int hKey,
string lpValueName,
int lpReserved,
RegistryValueKind lpType,
string lpData,
int len
);
[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 GetRegKey(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_64Key, inPropertyName);
}
public static void SetRegKey64(this RegistryKey inKey, String inPropertyName, String inPropertyValue)
{
string strKey = inKey.ToString();
string regHive = strKey.Split('\\')[0];
string regPath = strKey.Substring(strKey.IndexOf('\\') + 1);
SetRegKey(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_64Key, inPropertyName,inPropertyValue);
}
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 GetRegKey(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_32Key, inPropertyName);
}
public static void SetRegKey32(this RegistryKey inKey, String inPropertyName, String inPropertyValue)
{
string strKey = inKey.ToString();
string regHive = strKey.Split('\\')[0];
string regPath = strKey.Substring(strKey.IndexOf('\\') + 1);
SetRegKey(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_32Key, inPropertyName, inPropertyValue);
}
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 GetRegKeyAsByteArray(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 GetRegKeyAsByteArray(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 GetRegKey(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 void SetRegKey(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName,string inPropertyValue)
{
int hkey = 0;
try
{
uint lResult = RegOpenKeyEx(inHive, inKeyName, 0, (int)RegSAM.AllAccess | (int)in32or64key, out hkey);
if (lResult != 0) return;
RegistryValueKind lpType = RegistryValueKind.String;
RegSetValueEx(hkey, inPropertyName, 0, lpType, inPropertyValue, inPropertyValue.Length);
}
finally
{
if (0 != hkey) RegCloseKey(hkey);
}
}
static public byte[] GetRegKeyAsByteArray(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
}
}
使用方法
RegistryKey localKey = Registry.LocalMachine;
string strName ="";
localKey = localKey.OpenSubKey(@"SOFTWARE\Nokia\Connectivity Server\LinkControl\SCTP");
if (localKey != null)
{
strName = localKey.GetRegKey64("dxtSignIP")
}
localKey.SetRegKey64("dxtSignIP", "10.3.38.1");
下面是对用到的几个函数的参数说明 有兴趣的可以自己看看研究一下
RegOpenKeyEx
LONG RegOpenKeyEx(
HKEY hKey,
LPCTSTR lpSubKey,
DWORD ulOptions,
REGSAM samDesired,
PHKEY phkResult
);
打开一个指定的注册表项,值得注意的是注册表的键值是不区分大小写的。
hKey是主键,可以是预定义的键值,如HKEY_CLASSES_ROOT、HKEY_CURRENT_USER、HKEY_LOCAL_MACHINE、HKEY_USERS 这几个。
lpSubKey是子键,指向一个字符串。当这个字符串为空或这指针为NULL时,他会打开hKey的值。
ulOptions保留。
samDesired是一种权限,如常用的查询权限KEY_QUERY_VALUE,用于创建子键的KEY_CREATE_SUB_KEY,用于写的权限KEY_SET_VALUE等。
phkResult是一个句柄,就像CreateEvent一样,返回了一个打开的注册表键,用完了就用它来关闭。
返回值表示成功或失败,成功则ERROR_SUCCESS,其他则表示出了些问题,在Winerror.h中定义。
RegCloseKey
LONG RegCloseKey(
HKEY hKey
);
用于关闭已经打开(RegOpenKeyEx)的或者创建出来(RegCreateKeyEx)的注册表键值的句柄。
这个操作类似closeHandle。
RegCreateKeyEx
LONG RegCreateKeyEx(
HKEY hKey,
LPCTSTR lpSubKey,
DWORD Reserved,
LPTSTR lpClass,
DWORD dwOptions,
REGSAM samDesired,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
PHKEY phkResult,
LPDWORD lpdwDisposition
);
创建一个注册表键值,如果该值已存在,则类似Open的行为。
hKey与RegOpenKeyEx相似。
lpSubKey是要创建的子键的字符串。该值不可以为NULL,也不可以含有反斜线/,而且是不区分大小写的。
Reserved保留。传入0即可。
lpClass通常设置为NULL。
dwOptions默认设置为REG_OPTION_NON_VOLATILE,另外两个值REG_OPTION_BACKUP_RESTORE和REG_OPTION_VOLATILE有特殊的含义,详细信息见MSDN。
samDesired与RegOpenKeyEx的相应参数含义一样。通常创建一个子键的行为需要Create权限,因为这个函数需要创建子键,但是他并不能设置这个子键的值,需要别的函数帮助。
lpSecurityAttributes是安全级别,传入NULL为默认级别。
phkResult是handle。用于之后的操作。
lpdwDisposition是一个传出参数,它标示了调用该函数是新建了一个子键REG_CREATED_NEW_KEY还是打开了一个原有子键REG_OPENED_EXISTING_KEY。
返回值同样是ERROR_SUCCESS表示成功,其他则表示有问题。
RegSetValueEx
LONG RegSetValueEx(
HKEY hKey,
LPCTSTR lpValueName,
DWORD Reserved,
DWORD dwType,
const BYTE * lpData,
DWORD cbData
);
创建了子键,需要给它赋以特定的值,该函数就是为子键赋值的。
hKey是目标键的handle。
lpValueName是子键名称。
Reserved保留,一般写0。
dwType表示值的类型,常用的有二进制REG_BINARY、DWORD类型REG_DWORD、字符串REG_SZ等。
lpData是值内容。
cbData是值内容的大小,sizeof即可,不过当是字符串的时候,记得加1,来表示结尾符。
RegQueryValueEx
LONG RegQueryValueEx(
HKEY hKey,
LPCTSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData
);
我们要读一个已经打开的键的值的时候,就需要这个函数。
hKey是目标键的handle。
lpValueName是子键名称。
lpReserved保留,一般写0。
lpType是值类型,同RegSetValueEx的类型含义相同。但是他是传出的,这时就有一个小技巧,当我们不知道一个键的值类型时,我们可以用这个参数第一次读出值的类型,后两个参数传入NULL和大小,这时读出了值的类型和值的大小,这样在第二次想确切的读出值的内容的时候,就可以分配恰好可用的空间。
lpData是传出参数,用于读出的数据。
lpcbData是传出参数的长度。