x64位windows上程序開發的注意事項
在Windows上麵32位與64位的區別有:
1.指針大小的區別,sizeof(int *)在32bit下麵是4個字節,在64bit下麵是8個字節
2.size_t的區別,size_t在32bit下麵是4個字節的範圍,在64bit下麵是8個字節的範圍
3.地址空間的區別,在32bit下麵,最大地址空間是4GB,在64bit下麵是可以大於4GB的
4.32位程序在64位Windows上運行,是有一個Wow64子係統輔助其運行的,默認情況下,訪問注冊表和某些文件夾是被重定向的
5.指針的區別也意味著Handle的區別
6.唯一支持Windows原始64位編譯的msvc編譯器不支持64bit的內聯匯編,如果要用匯編,需要單獨編譯再link
7.純64bit程序的函數調用方式已經不再區分cdecl和stdcall方式,因為隻有一種了。
8.64bit的程序不再使用esp,而是使用增加的幾個64bit寄存器,因為esp不支持64bit空間的棧
最近的工作涉及到Linux的64位工作,發現當初對32位和64位區別的認識還不夠:
1.long在Windows下麵,不管是32bit還是64bit下,都是4個字節的,但在Linux下麵,32bit下是4字節,在64bit下是8個字節。(long long在64bit下還是8個字節)
2.gcc在64bit下麵,不再支持__attribute((cdecl))__和__attribute((stdcall))__,這點和Windows有點類似,開始以為是gcc的高版本不支持的,後來發現區別在x86和x64
64位下windows的開發建議:
1.避免System.BadImageFormatException
通常,程序員碰到這種情況:“出現未處理的類型異常 ‘System.BadImageFormatException’”。如果你要深究該異常的細節信息,可能會發現係統提示:“試圖加載的程序,格式不正確”。
之所以會出現這樣的問題是因為64位進程試圖加載一個32位組件。雖然你在Windows x64上可以運行64位和32位進程,但是64位代碼和32位代碼不能在相同進程上運行。你的代碼要麼全部是64位,要麼全部是32位。要加載的組件也要符合這一規律。
VS 2005與.NET 2.0為編譯.NET應用程序帶來選擇,將輸入設置為“Any CPU”也具備了可選性。“Any CPU”是默認平台。如果組件以Any CPU作為平台進行編譯,那麼它將依據進程加載的情況以32位或64位方式運行。使用Any CPU,相同的組件可以在64位Windows上以32位或64位方式運行:它不是真正的指定了64位的CPU或操作係統,而是一個調用進程。
為了解決不合格圖像異常的問題,要改變到Any CPU的所有組件的目標平台。如果出於某種原因你無法做到這一點——或許某組件無法提供來源——那麼要將所有組件設置成到達同一平台,可以是x86也可以 是x64。如果你擁有.NET 1.0或1.1組件,最好是用.NET 2.0對其重新進行編譯。如果你不能編譯.NET 1.0或1.1組件,那麼編譯其他代碼,設置為到達x86平台,使之兼容。
2.大小問題
64位和32位Windows之間一個重要的區別是句柄的大小。如果你的代碼中具備任意Windows API調用,那麼你要確保你的說明對於64位Windows是正確的。如果代碼是從VB6升級而來,那麼你不能區分句柄和32位整數的概念,因此你必須尋 找源文件或標頭文件。識別哪些參數和域是句柄,使用這些類型的IntPtr。通常情況下,文件將以INT_PTR或LONG_PTR將其識別或者用名稱隻 是某類句柄,如HWND。用前綴定義的參數,如PTR或LPTR通常是一些指示器,因此需被視為IntPtr或使用ByRef編組。要確定你運行的64位 還是32位,可以在運行時檢查IntPtr.Size的值。
3.COM可以是64位
普遍存在的誤解是認為COM和ActiveX僅限於32位,但是使用VB.NET,你可以使用64位COM和ActiveX控件。 Windows沒有按照64位編譯的控件,但是其中一個值得注意的例外是sysmon.ocx ActiveX 控件,該控件可以讓你創建係統監測圖。
你可以使用Windows.Forms應用程序中的64位ActiveX控件,但是當涉及匯編的時候就存在緩衝。VS當前是32位的應用程序, 它在匯編的時候需要32位的ActiveX控件以便創建運行時可隨時啟用的COM組件包裝。為了在VS中進行編譯,你需要32位的版本。一旦程序被編譯, 就隻需要被選中的平台。
在你沒有32位版本或類似版本的情況下,你可以使用命令行來運行64位工具以便創建一個用於ActiveX控件的Interop程序集。見Tlblmp.exe文件以了解詳情。
4.意識到問題
32位應用程序運行於Windows 64中時,它與模擬器一起運行。模擬器被稱為WOW64,是Windows On Windows64的縮寫,可以讓32位應用程序按照32位操作係統進行查看。WOW64模擬器加載了一個ntdll.dll的x86版本,提供了切入點 和替換程序,還會截取最重要的注冊表和文件係統操作。
WOW64模擬器也暴露出不同的適合32位應用程序的環境型變量。因此,32位應用程序將ProgramFiles環境型變量為 ProgramFiles(x86)。以64位運行的時候,如果你寫出類似MsgBox(Environ(“ProgramFiles”))的代碼,會獲 得"C:\Program Files",如果你32位運行,則獲得"C:\Program Files (x86)"。
模擬器所做的事情與注冊表和係統目錄類似。出於兼容性和性能的考慮,%windir%\System32 文件夾是64位文件夾。也就是說,64位應用程序中不存在任何截取。重新定向的32位操作文件夾默認名為%windir%\SysWOW64。名稱 SysWOW64指明它要被32位模擬器WOW64使用。這或許有些令人困惑。
WOW64之下的注冊表將重定向與反射結合使用。重定向存在於HKEY_LOCAL_MACHINE\SOFTWARE \Wow6432Node等Key之下。至少注冊表中的命名式樣更好。映射是32位進程和64位進程都可以編輯共同Key,如文件關聯。另一方麵講,重定 向是為了確保將32位從64位隔離開。
關鍵是執行不能影響你除非你打算從64位程序中獲取32位程序的詳細信息,反之亦然。通常匯編到同一目標要簡單得多。例如,如果你想使用VS, 將程序鎖定到x86,你不需要擔心文件或注冊表的模擬過程。如果你要以Any CPU運行程序,那麼就取決於它是如何啟動的,或許你要使用重定向,和類似GetSystemWow64Directory的API調用,並且使用 RegOpenKeyEx API,包括KEY_WOW64_32KEY的訪問假象。它可能變成混亂而複雜的測試。這是目前為止對相同平台和鎖定信息最好的匯編方式。
其中筆者偶然發現的一個問題是注冊表反射和Windows Vista UAC的結合。在用於寫入許可的HKLM蜂巢中筆者開放了一個Key,API成功了,但是當筆者向Key寫入時,卻失敗了。應用程序以32位方式運行於 Windows 64上,因此有問題的Key會被映射。筆者浪費了大量時間用於確定所發生的事情,因為注冊表API不會向往常一樣運作。最後,筆者通過往應用程序中包含運 載單使之正常運行。即便requestedExecutionLevel對asInvoker有級別設置,這一漏洞也可以被修複。
UAC提供了注冊表虛擬化,筆者認為WOW64重定向或反射與UAC虛擬化的結合太多了。現在筆者通常會確保應用程序中具備運載單。在VS 2008中,你可以從項目屬性對話框中的程序標簽中獲取運載單。確保你包含了requestedExecutionLevel選項。
5.激活Edit和Continue
雖然,你可以調試64位應用程序,那麼就不能在調試期間使用Edit和Continue。這意味著你不能在調試的時候改變源代碼,相反你要停 止,應用更改,重新編譯並啟動調試。但是你可以用32位程序使用Edit和Continue,即便是在64位Windows上。這是另一種手動構建配置的 示例。
創建一個x86構建配置,並且在開發的時候使用這一配置,如此你就可以使用Edit和Continue。然後將配置切換稱x64或Any CPU用於測試。
使用Windows 32或Windows 64不如VB 8或VB 9中那樣難。使用VS並且構建配置,任務會變得簡單。
最後更新:2017-04-03 14:53:38