在64位Windows中运行32位应用程序的时候,Windows会使用WoW(Windows on Windows)模式来运行它。简单来说,WoW模式是一个运行在64位Windows中的32位Windows的虚拟机,对于32位应用程序来说,它仍然会以为自己运行在32位的Windows当中,它所加载的系统文件、所访问的注册表,也都是32位的版本。不过在64位Windows中,提供了一种方法,可以让32位的应用程序,访问64位的注册表。
.Net Framework 4及以后版本
在.Net 4中,我们可以使用RegistryView枚举来指定打开的64位的注册表,还是32位的注册表。比如下面的C#代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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(); } |
不难发现,当OpenBaseKey的时候,传入RegistryView.Registry64即可以访问64位的注册表。需要注意的是,在纯32位的Windows中,由于没有64位注册表,这个参数将不起作用,最终打开的还是32位注册表。由于RegistryView和OpenBaseKey是.Net中的新增API,所以C#、VB.Net、PowerShell都可以用这种方式来访问。
Windows API
在Windows API中,可以通过调用RegOpenKeyEx并传入KEY_WOW64_64KEY来达到相同的效果。代码如下:
1 2 3 4 5 6 7 8 9 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 | 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 { [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); 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); } } } |
1 2 | 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"); |
上述代码是在C#中通过P/Invoke来调用Windows API,适用于.Net 3.5及之前版本,C++中的调用方法类似。
Windows Management Instrumentation (WMI)
WMI是一种标准化的Windows资源的访问方式,使用WMI也可以访问注册表。可以使用__ProviderArchitecture参数指定所需要的平台:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | strComputer = "." Const HKLM = &h80000002 Set objCtx = CreateObject("WbemScripting.SWbemNamedValueSet") objCtx.Add "__ProviderArchitecture", 32 objCtx.Add "__RequiredArchitecture", TRUE Set objLocator = CreateObject("Wbemscripting.SWbemLocator") Set objServices = objLocator.ConnectServer("","root\default","","",,,,objCtx) Set objStdRegProv = objServices.Get("StdRegProv") ' Use ExecMethod to call the GetStringValue method Set Inparams = objStdRegProv.Methods_("GetStringValue").Inparameters Inparams.Hdefkey = HKLM Inparams.Ssubkeyname = "SOFTWARE\Microsoft\Windows NT\CurrentVersion" Inparams.Svaluename = "RegisteredOrganization" set Outparams = objStdRegProv.ExecMethod_("GetStringValue", Inparams,,objCtx) 'Show output parameters object and the registry value HKLM\SOFTWARE\ WScript.Echo Outparams.GetObjectText_ WScript.Echo "WMI Logging is set to " & Outparams.SValue |
WMI可以被多数语言使用,如VBScript、C++,C#也是可以的。
于是,几乎使用任何语言写出来的32位应用程序,都可以在64位Windows上访问64位的注册表了。