2010年9月9日 星期四

軟體缺少 d3dx9_xx.dll 的問題

DirectX 在版本轉換時真的是個麻煩的東西,曾經發生一個狀況,將原本正常的專案由 VS2003 轉至 2008 以後,原本利用 VS2003 包出來正常的檔案,改用 VS2008 編以後自已用起來正常,給其他人用卻出問題,在其他台執行時跳出缺少 d3dx9_41.dll 的錯誤。

原因無他,就是因為程序員自己有裝 DirectX SDK 而其他人沒有,這時候直覺就是將 d3dx9_41.dll 包進安裝檔中即可解決,但這有著作權的法律問題,畢竟 d3dx9_41.dll 不是我們自己的產品,嚐試向下轉換較低版本的 DX SDK 反而變成缺少 d3dx9_34.dll、d3dx_27.dll,後面的數字隨版本愈低就愈小,這似乎代表這些 dll 是同樣的東西,只是不同的 DX SDK 鏈結不同的 dll 版本,令人轉了個方向思考,為何在 VS2003 編譯時不需使用到 d3dx9_xx.dll呢?

原來 DirectX 9 的鏈結方式曾經在 December 2004 這個版本之後做過大異動,在 December 2004(含) 以前的版本是使用靜態鏈結的方式使用 d3dx9.lib,這會使得執行檔將所使用到的 d3d function 全部被 copy 一份包進去,造成執行檔變肥的現像。

所以在 December 2004 以後的版本也是使用 d3dx9.lib,但變成只是一個中介點,這之後的d3dx9.lib做的事是去使用它自己版本所需要的 d3dx9_xx.dll,xx 是一個數字,依各版本會鏈結到不相同版本的 dll,例如 2009 年 3 月份的 DX 9 SDK 就是鏈結 d3dx9_41.dll,這麼改是為了利用動態鏈結的優點讓主執行檔不會變太大,缺點就是動態鏈結的時間與用戶可能沒有足夠 dll 的風險。

解法有幾個,最簡單的方式就是將 dll 包進安裝檔並於安裝時註冊到用戶 system32 資料夾內,但這可能有前面提的法律問題。

也可以在安裝過程中檢查用戶是否有安裝足夠版本的 DirectX Runtime Library,若沒有安裝就導到微軟下載頁請用戶先裝 DirectX,但是 DirectX Runtime Library 似乎要 95MB 以上,若你寫的是大型軟件例如 1.5GB 的 3D Online Game,要求用戶裝還蠻合理的若是個 3、4MB 的小軟件,要求用戶先裝 95MB 的 DX 套件似乎有點怪。

再不然就是若沒有非要用新版 Visual Studio 不可,就回到 VS2003 去編譯程式。

最乾淨的方法就是確認自己的程式中是否有用到 December 2004 以後才有的功能,若沒有用到就不要在程式庫參考目錄中指定更新的版本目錄。

若你的 Visual Studio 比較新,或因為專案的關係一定要使用新的 DX SDK,例如必須使用 2009 年的 Direct Show 之類的,所以必須參考新的目錄,這時也不必去硬是修改專案目錄設定,只要確定專案在 D3D 的部份沒有用到新版本,即可將 d3dx9.lib 寫死絕對 December 2004(含) 以前的路徑,例如 VS2008 在
"專案屬性頁 / 組態屬性 / 連結器/輸入 / 其他相依性"
寫入 "C:\Program Files\[December 2004(含)以前]\Lib\x86\d3dx9.dll" 這樣就可以確定使用的是不需呼叫 dll 的 d3dx9.lib 來編譯,而其他的部份還是依造專案目錄所指定的新版本 Lib 目錄。

另外,有時候若寫入絕對路徑或在更改 DX SDK 版本時,Build 程式會發生無法開啟檔案 libcp.lib 的錯誤,這種情況只要將 libcp.lib 忽略就行了,例如 VS2008 即是在這裡指定
"專案屬性頁 / 組態屬性 / 連結器/輸入 / 忽略特定程式庫"
忽略這個 libcp.lib 通常不會有什麼不良反應,這純粹是 Visual Studio 版本的 bug。

2 則留言:

  1. 测试了下,最後一個支持靜態鏈結應該是 December 2004 版本

    回覆刪除