天天看點

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并且建構配置,任務會變得簡單。