總之,32位程式在64位系統上,只能訪問到一部分註冊表資訊,要想訪問全,簡單的做法就是用64位的程式。 下面是轉來的文章:
【原文地址:http://blog.sina.com.cn/s/blog_592fe54701008d8w.html】
1 簡介
當前電腦系統已經逐漸地從32位轉到64位,XP,2003,VISTA都有64位的版本。從目前而言,32位應用程式還是佔了絕大多數,但是也有部分應用程式既有32位版本,又有64位版本。為了保證32位程式可以順利運行在64位系統上,微軟提供了一套叫WOW64的類比機制。通常把這套系統稱為WOW64。從總體上來說,WOW64是一套基於使用者模式的動態連結程式庫,它可以把32位應用程式的發出的命令翻譯成64位系統可以接受的格式。從中可以大概地看出32位應用程式運行在64位系統上的方式。
當32位應用程式啟動並執行時候,首先會去啟動本地庫載入器(Native Library Loader)。載入器會識別出應用程式是32位的並且用特殊的方式來處理它。載入器會為32位應用程式建立起一個WOW64的類比環境並把控制權交給32位的Ntdll.dll。運行在32位應用程式和64位Ntdll.dll之間的WOW64類比環境會將32位應用程式的指令翻譯成64位Ntdll.dll可以接受的方式,並且它也可以把系統的指令翻譯成32位應用程式可以接受的方式。
2 如何判斷系統是64位
3 檔案系統的轉向
32位進程不能載入64位Dll,64位進程也不可以載入32位Dll。Windows的系統目錄包含了所有安裝的應用程式和它們的Dll檔案,根據我們所述的規則,它應該被分為給64位應用程式的目錄和給32位應用程式的目錄。如果不這樣,我們就無法區分32位和64位的Dll檔案。對於64位應用程式,其檔案通常被放在%windir%\system32和%programfiles%(比如:c:\program files)。對於32位應用程式,其檔案通常在%windir%\syswow64和C:\program files (x86)下面。如果我們用32位程式去訪問%windir%\system32,不管我們用寫入程式碼還是其它的方式,系統都會自動地給我們轉向到%windir%\syswow64下面。這種轉向對於每個32位應用程式預設都是開啟的。但是這種轉向對於我們來說並不總是需要的。那麼我們可以在C#裡面調用相關的API來關閉和開啟這種轉向。常用的函數有3個,Wow64DisableWow64FsRedirection(關閉系統轉向),Wow64RevertWow64FsRedirection(開啟系統轉向),Wow64EnableWow64FsRedirection(開啟系統轉向)。但是Wow64EnableWow64FsRedirection在嵌套使用的時候不可靠,所以通常用上面的Wow64RevertWow64FsRedirection來開啟檔案系統轉向功能。在C#中,我們可以利用DllImport直接調用這兩個函數。但是要注意到的是,在32位的Kernel.dll中是沒有這兩個函數的。那麼在C++中應該使用LoadLibrary來動態載入這兩個函數。否則會因為找不到這兩個函數而無法通過編譯。而且在目前的使用中,發現這兩個函數有一個小小的問題。如果我們在調用了Wow64DisableWow64FsRedirection後去調用Comdlg32.dll的GetOpenFileName函數,是無法調用成功的。但是也得不到Error的值。在C#中可以用如下的代碼關閉和開啟檔案的轉向。
聲明調用規則
[DllImport( "Kernel32.dll", CharSet=CharSet.Auto, SetLastError = true)]
public static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr);
[DllImport( "Kernel32.dll", CharSet=CharSet.Auto, SetLastError = true)]
public static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr);
關閉轉向
Wow64DisableWow64FsRedirection(ref Ptr);
開啟轉向
Wow64RevertWow64FsRedirection(Ptr);
要注意的是,關閉和開啟要成對出現。以免出現混亂的行為。
4 註冊表的轉向
為了防止註冊表鍵衝突,註冊表在某些鍵也分成了兩個部分。一部分是專門給64位系統訪問的,另一部分是專門給32位系統訪問的,放在Wow6432Node下面。當32位程式去訪問某些索引值的時候,和檔案轉向類似,系統也會自動地把程式的訪問轉向到Wow6432Node下面。Wow6432Node這個節點存在於HKEY_LOCAL_MACHINE和HKEY_CURRENT_USER下面。如果我們希望關閉這個轉向的話,可以通過上面的Wow64DisableWow64FsRedirection和RegOpenKeyEx方法辦到。RegOpenEx方法在C#中調用聲明方法如下:
[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern uint RegOpenKeyEx( UIntPtr hKey,string lpSubKey, uint ulOptions,int samDesired,out IntPtr phkResult);
其中需要注意的是samDesired這個參數。這個參數可以取 KEY_ALL_ACCESS, KEY_QUERY_VALUE, KEY_WOW64_64KEY等值(詳情可以查閱MSDN)。當我們已經關閉了檔案系統的轉向,那麼就可以利用:(KEY_QUERY_VALUE | KEY_WOW64_64KEY)來得到註冊表的完整存取。這個地方需要注意的是,在Vista下面,有一些登錄機碼是唯讀,如果用了KEY_ALL_ACCESS這個參數,就會出現“Access is denied” 這個錯誤(ErrorCode = 5)。因此,如果不是要寫入註冊表的話,最好不要使用KEY_ALL_ACCESS。我們可以用如下代碼來完全訪問註冊表。
//use this function transfer the string key name to HKEY handle
private static UIntPtr TransferKeyName(string keyName)
{
UIntPtr HKEY_CLASSES_ROOT = (UIntPtr)0x80000000;
UIntPtr HKEY_CURRENT_USER = (UIntPtr)0x80000001;
UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
UIntPtr HKEY_USERS = (UIntPtr)0x80000003;
UIntPtr HKEY_CURRENT_CONFIG = (UIntPtr)0x80000005;
switch(keyName)
{
case "HKEY_CLASSES_ROOT":
return HKEY_CLASSES_ROOT;
case "HKEY_CURRENT_USER":
return HKEY_CURRENT_USER;
case "HKEY_LOCAL_MACHINE":
return HKEY_LOCAL_MACHINE;
case "HKEY_USERS":
return HKEY_USERS;
case "HKEY_CURRENT_CONFIG":
return HKEY_CURRENT_CONFIG;
}
return HKEY_CLASSES_ROOT;
}
public static bool OpenRegKey(string keyName, string subKeyName)
{
UIntPtr hKey = TransferKeyName(keyName);
UIntPtr phkResult = UIntPtr.Zero;
int KEY_QUERY_VALUE = (0x0001);
int KEY_WOW64_64KEY = (0x0100);
int KEY_ALL_WOW64 = (KEY_QUERY_VALUE | KEY_WOW64_64KEY);
if(Is64bitOS && !IsWow64RedirectionEnabled) //The os is 64 bit and the FileRedirection is closed
{
samDesired = KEY_ALL_WOW64;
}
if(RegOpenKeyEx(hKey, subKeyName,0,samDesired,out phkResult) == 0) //ERROR_SUCCESS=0
{
return true;
}
int errCode = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
return false;
}