Windows 64Bit移植心得

下半年公司有一個Windows下64Bit移植的項目,已經厭倦之前百無聊賴的維護工作的我,有幸接到了這項工作。廢話不多說,接下來談談Windows下64Bit移植的心得。

 

項目特點: Visual Studio 2005 (包括MFC應用程序以及Win32 DLL) + WDK7000 (驅動程序) 環境

 

移植基本步驟:

1. 調整項目文件目錄結構

    心得1: 調整目錄結構的原因是同時支持64Bit和32Bit的編譯,這時候可能對應的要修改很多腳本來應對這些目錄的變化。

2. 追加64Bit編譯配置項,調整編譯環境

    心得1: 對於VC項目,記得在追加了x64編譯選項的時候,追加_WIN64的宏定義。 按照MSDN的說法,_WIN64和_AMD64_對於64Bit編譯環境應該是默認存在的,而且_WIN32宏並不需要去掉。 (因爲像RC文件也許要這樣的宏,直接在Visual Studio中一個一個添加實在會把人累死,建議可以通過腳本修改)

 

    心得2: 對於使用WDK環境,如果支持從XP到Win7的多個操作系統,一定要注意NTDDI_VERSION, _NT_TARGET_VERSION, _WIN32_WINNT的指定(否則可能編出來的DLL壓根不能用)。 32Bit項目支持一些較早的系統(如Win2000),顯然64Bit項目應該是與時俱進的。

 

    心得3: 記得WinSXS與DLL Hell的事情,一定要檢查manifest文件,或者linker聲明中對於系統特定版本DLL的依賴關係。32Bit項目下可能支持了特定版本的DLL(比如6.0的comctl32.dll)。 64Bit也一定要支持。

 

    心得4: 如果整個項目(VS+WDK)由統一的腳本控制編譯,一定要注意編譯器,鏈接器的路徑衝突問題(防止用VS2005的編譯工具去編WDK的代碼)。 還有就是一些lib文件引用的衝突問題。控制好各種PATH環境變量很重要。

 

    心得5: 不要相信VS的版本移植所執行的conversion。如果從VS2003升級到VS2005, 記得檢查一下配置中有哪些配置被弄丟了。比如對manifest文件的依賴

3. 修改部分代碼,或者重寫部分代碼

    其實這裏本應是64Bit移植的重頭戲,如果之前的代碼寫的好的話, 這裏基本不用什麼大的調整了。可是大部分年代久遠的系統,多半在產生之初都沒有考慮過64Bit系統,可能那個時候amd64還沒有, ia64又太激進。 代碼中存在着各種稀奇古怪的bomb,一定要掃乾淨。

 

   心得6: 類型,類型, 還是類型

  數據類型的擴展可謂是64Bit系統與32Bit系統最大的不同,數據尋址範圍增大到64位長度,指針類型擴展到64位長度,數據結構變成8字節對齊,位操作的變量很可能需要應對高32位的擴展。因此,類型,特別是各種數據類型的長度應該是bomb最密集的區域。

 

    應對這些問題,有以下幾種實踐中好用的方法:

    1. 重視編譯過程中產生的warning。現在的編譯器都很強大,對於類型及長度發生的變化,它是最直接的反應。

    2. 除了編譯器,可以使用靜態代碼分析工具。

    3. 一定要檢查每一處強制類型轉換,"每一處"聽起來有點可怕。可以通過正則表達式將這些強制類型轉換都找出來。

    4. 在Windows系統中,特別要注意DWORD類型,WPARAM, LPARAM, LRESULT, size_t等, 以及各種PTR結尾的類型。 因爲32Bit系

        統中,他們很可能都用來保存指針或者範圍。

 

   心得7: 與長度有關的函數

   一定要小心這些與長度相關的函數,文件長度,數組長度,內存範圍, 這些東西從2^32次方的訪問範圍,增大到了2^64次方的範圍,一個不小心,溢出就等着你。

  

   心得8: 如果能回到過去

   如果回到32Bit項目編碼的一開始,你必須要記住以下幾件事情,否則噩夢會伴隨着你的:

      

      1. 函數聲明,定義一定要匹配。 特別是C代碼,編譯器有時候對是檢查不錯來這種事情的。

      2. 儘量不要用強制類型轉換,也不要圖方便用一些被typedef或者#define出來的同類型不同名的類型聲明。

           不要隨便使用你認爲的類型相同類型名,應該好好閱讀系統建議你應該使用的類型名。也就是針對特定的場合,使用特定的類型名。

      

           表示長度的時候,儘量使用size_t

           表示指針操作的時候,儘量使用ptrdiff_t

           LPARAM, WPARAM 不要用DWORD取代

           LRESULT以及各種PTR結尾的類型不要用int或者unsigned int取代

           指針不要存在DWORD變量中

           。。。。。。

      

      3. 要注意數據接口,特別是保存或者度入的數據。

           因爲程序導出和讀入的數據有可能需要在32Bit和64Bit系統上共享。因此,到出的數據中,儘量不要使用長度發生變化的類型。對於數

           據存取,最好限定在BYTE, WORD, DWORD, QWORD這些固定的數據類型上。

4. 進行系統以及應用程序兼容性測試

    移植有時候會有一些不那麼顯而易見得問題產生,特別是Windows系統之間也有許多差異。步驟3中的動作,基本上是移植中的已知問題,但是還有許多未知的潛在不兼容性存在。而這些,是在設計之出很難考慮到的。所以兼容性測試是必須要做的,而且是大規模的迴歸測試。

    儘管如此大規模的全面測試,這裏我已經有一些應該牢記的兼容性問題,

   

   心得9: 子進程與權限提升

    WinExec, CreateProcess函數與ShellExecute函數都是用來創建子進程的函數。根據微軟官方的說法,WinExec, CreateProcess函數並不支持子進程的權限提升。在Vista以後的系統中,用這兩個底層函數創建安裝程序進程將導致無法安裝(沒有權限)。 而ShellExecute被是較爲高層的用戶函數,它是支持權限提升的。 雖然微軟這麼說,但實際上這隻發生在64Bit系統上。(可能默認情況下32Bit已經被修整了) 。 因爲實際上32Bit下WinExec, CreateProcess仍然可以提升權限,這可能導致這個問題被忽視。

 

    心得10: ToolTipInfo結構體大小與comctl32.dll版本

    奇怪的問題,ToolTipInfo結構體大小必須剪掉一個指針的長度,才能在多數64Bit系統中正常運作。

 

    心得11: MFC中的OnCancel事件與OnQueryCancel事件

    兩者的用法有區別,但32Bit下有人把它們隨意的使用。結果,64Bit下會發生你把電腦砸了也想不到的現象發生。

 

以上就是這半年來在64Bit移植上的心得。暫時想到這麼多,還比較凌亂,以後慢慢整理吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章