在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位的注册表了。