如何解決程序/C++Dll的兼容性問題

如何解決程序/C++Dll的兼容性問題

 轉載出處  原文網址   BY Sunyday丶若雪



本文將嘗試解決程序與DLL在不同客戶機上運行存在的兼容性問題

前言

前面的五篇文章已經將程序的核心部分全部搞定,由於我們調用了一些系統API,所以這很有可能導致程序在其他不同的客戶機上無法正確運行。其實關於程序的兼容性提高在之前選擇到底使用何種方法來實現某一功能時已經相當於做過一次了,由於所有的核心功能都是封裝在C++DLL中的,那麼C++DLL兼容性直接決定了程序的兼容性,所以提高C++DLL兼容性成爲了至關重要的問題。

1)先嚐試在目標客戶機試運行

注意:在開發者的電腦上測試是絕對通過的,能在開發者電腦上測試通過不代表客戶機能運行,由於開客戶機不一定有開發者電腦的大量程序運行必要的支持框架和組件,所以先要弄清楚程序需要哪些支持框架、組件、Dll,然後再搞清哪些支持框架是客戶機肯定擁有的,哪些是客戶機不一定擁有的

要在客戶機上測試,那麼什麼樣的客戶機是合理的: 
Windows操作系統,這是必須的 
編寫程序界面的語言是C#,編寫程序核心的語言是C++,兩種語言都需要Microsoft .NET Framework的支持,由於這個程序在編寫當初就沒有想支持XP的意思,所以這兩種語言都選用了Microsoft .NET Framework 4.5版本(XP最高支持到Microsoft .NET Framework 3.0),其實Microsoft .NET Framework 4.5算是客戶機上必有的支持框架了。

大概現在就知道需要這個了,於是打開VM新建一個虛擬機,安裝WIN7,再裝入一個Microsoft .NET Framework 4.5支持框架,把程序拷貝進去,啓動。

這裏寫圖片描述

由於程序啓動不用調用DLL.dll所以程序界面是可以打開的,繼續測試功能,單擊“連接”。

這裏寫圖片描述

明明已經把DLL.dll放到了程序運行目錄下,但它還是提示找不到指定模塊DLL.dll

這個提示並不是找不到DLL.dll,其實是想表明DLL.dll所引用的DLL找不到,那麼必須弄清楚這個DLL.dll還引用了什麼其他DLL

2)查看DLL.dll引用了哪些DLL

用DLL函數查看器打開編寫的DLL 
查看DLL的引用,將DLL的引用信息輸出TXT文件查看

這裏寫圖片描述

這裏顯示一共引用了5個DLL,功能分別是:

系統支持的: 
wlanapi.DLL:管理WLAN的系統DLL 
RASAPI32.DLL:管理撥號的系統DLL 
KERNEL32.DLL:系統內核DLL 
Visual Studio 2015 C++支持的: 
VCRUNTIME140.DLL:Visual Studio 2015 生成的 C++ 應用程序所需的運行時組件。 
api-ms-win-crt-runtime-l1-1-0.dll:Visual Studio 2015 生成的 C++ 應用程序所需的運行時組件。 
注:安裝Visual C++ Redistributable Package就會爲Visual Studio 2015 C++ 生成的 C++ 應用提供運行支持

通過上面的DLL分類大概可知是由於DLL.dll找不到Visual Studio 2015支持的兩個DLL導致的

依據我們的DLL引用DLL時的路徑尋找方法(在上一篇文章中提到過),只要把這兩個DLL放到和DLL.dll相同目錄下應該就OK了。

3)依據引用的DLL名稱嘗試找出被引用的DLL

在C盤搜索VCRUNTIME140.DLL,結果如下:

這裏寫圖片描述

竟然有麼多,這就很尷尬了,怎麼確定它調用的是哪個

沒辦法,只能再上一個軟件procexp64_V16.02(進程查看器),他可以看到所有進程調用的所有DLL以及這些被調用的DLL的位置

在開發者電腦上啓動“閃訊破解”

打開procexp64_V16.02,找到“閃訊破解”,按下Ctrl+D顯示閃訊破解所調用的DLL的信息

這裏寫圖片描述

在這裏只找到了VCRUNTIME140.DLL沒有找到api-ms-win-crt-runtime-l1-1-0.dll;先根據procexp64_V16.02的DLL路徑顯示拷貝VCRUNTIME140.DLL到虛擬機應用程序下;由於沒有找到api-ms-win-crt-runtime-l1-1-0.dll的真實調用路徑,只能是去C盤搜索這個DLL然後隨便拷貝一個過來試試了。

這裏寫圖片描述

現在能確定系統支持的3個DLL和VCRUNTIME140.DLL是沒有問題的,只能嘗試運行程序

這裏寫圖片描述

果然報錯了,這次不是”找不到指定模塊了“而是“試圖加載不正確的程序”,這是由於引用了不正確的DLL導致的,估計就是api-ms-win-crt-runtime-l1-1-0.dll出問題了。但是畢竟C盤有這麼多api-ms-win-crt-runtime-l1-1-0.dll,總不可能都一一拷貝過來嘗試,看來只能另尋他法了。

這裏寫圖片描述

4)使用靜態編譯生成DLL

右鍵點擊DLL項目名,打開DLL項目屬性

這裏寫圖片描述

配置屬性–C/C++–代碼生成–運行庫

這裏寫圖片描述

這裏的運行庫有4個選項:

後面的那個’d’是代表DEBUG版本,沒有’d’的就是RELEASE版本了

多線程MT的程序來說,其連接的是libcmt.lib,該文件屬於C語言運行時庫,整個lib都會連接到PE文件當中。

多線程MD的程序鏈接的卻是類似msvcpXXX.dll,該文件屬於微軟運行時庫,也就是說如果是多線程MD編譯出來的文件運行時都會加載相應版本的運行時庫,當如果找不到運行時庫就會報錯而無法運行,同時如果運行時庫不匹配也會出現各種意料之外的崩潰或者程序根本跑不起來等情況

從上面的說明可以看出由於使用的是MD方式編譯,所以在運行時會調用更多的用於支持VS2015C++應用運行的DLL,爲了減少調用DLL數量,選擇MT編譯。

注:千萬不可以調用DEBUG的DLL,否則加載模塊照常會出錯。

選用MT後重新編譯,用DLL查看器打開新生成的DLL,輸出被引用DLL文件信息

這裏寫圖片描述

發現關於VS2015的兩個DLL都已經消失,只剩下三個系統的DLL

拷貝到虛擬機,嘗試

單擊”連接“按鈕後如果能成功引用DLL中的函數,程序會進行編輯框輸入文本檢驗

這裏寫圖片描述

程序成功的引用了DLL中的函數,進行了編輯框輸入文本檢驗 
同時也發現,新編譯的DLL大小變大了許多

5)使用 多線程MT 方式編譯的弊端

成功運行程序後發現DLL變大了許多,這樣就不是很好了,這是由於多線程MT編譯的時候整個lib都會編譯到DLL文件當中導致的。其實多線程MT編譯不單單是這種缺點:如果是通過多線程MT編譯方式出來的程序,那麼A模塊中申請的內存到B模塊中釋放就會出現問題,這是非常致命的。其實絕大多數軟件都是採用多線程MD方式編譯,如果找到他們目錄很容易發現上面提到的運行時庫。因爲這樣一來編譯出來的文件小,所有運行時庫統一,同時也讓內存管理簡單化,省去了跨模塊內存訪問帶來的各種bug。所以多線程MD還是很好用的,能不用多線程MT就不用。

6)如何才能讓多線程MD方式編譯的程序在客戶機正常運行

在上面在解釋引用DLL各自功能中就提到過,安裝Visual C++ Redistributable Package就會爲Visual Studio 2015 C++ 生成的 C++ 應用提供運行支持,x64和x86最好都裝上,這樣程序就可以在客戶機上運行了

這裏寫圖片描述

這裏寫圖片描述

最後在說兩句

如何提高程序的兼容性

1)對於程序所使用的編程語言的必要運行環境支持必須熟知,比如C#需要安裝Microsoft .NET Framework X.X,C++需要安裝Visual C++ Redistributable for Visual Studio XXXX(x64和x86)

2)要學會使用DLL函數查看器、depends.exe、procexp64_V16.02來查看程序運行所依賴的dll,並不是所有客戶機都有Visual C++ Redistributable for Visual Studio XXXX(x64和x86),把找到的正確的DLL直接加入程序目錄。

3)在程序的安裝程序中添加運行環境檢測,給予沒有必要運行環境的客戶機強制安裝必要的運行環境支持。


發佈了32 篇原創文章 · 獲贊 25 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章