QT編譯好的檔案無法執行的一種解決方案

狀況: 利用QT Creator搭配MinGW寫好編譯好的程式,在自己的電腦可以順利執行,移到別的電腦卻不能動,出現 Microsoft Visual C++ Runtime Library的視窗如下:

1 (2)

 

尋找了n篇網頁之後,終於在這篇找到解決方式:

http://stackoverflow.com/questions/16022967/run-exe-without-qt

大概是我關鍵字下的不好,所以沒有第一時間找到這篇。

首先先來講背景,我用的是QT5.1與MinGW,而利用QT編譯出來的執行檔是屬於動態編譯,也就是執行檔本身很小,許多功能都是在DLL中執行,如果要改成靜態,要將QT一起編譯,工程有點浩大,下次做完再來說心得。

所以,如果單獨一個執行檔要執行時,首先會跳出來說找不到Qt5Core.dll,再來是icudt51.dll之類的,當我把一個一個它所需要的DLL跟執行檔放一起之後,竟然出現了上面 的錯訊視窗。在有安裝QT5的電腦中,不會出現那個錯誤,把DLL放好就沒事。

首先,既然畫面都說了是Microsoft Visual C++ Runtime Library的問題,很自然的我就安裝了 Visual C++ redistribution可轉散發套件(在這裡),從2005版、2008版、2008 SP1版裝到2010版都沒用!

在這篇(http://qt-project.org/forums/viewthread/29542/P15)提到了他也有同樣問題,但是他在修正程式碼內容之後就解決了,我試著做類似的事,調整原始碼,沒有用。

許多文章都提到是DLL的問題,我一種一種的試,最後把mingw的bin中所有的dll一口氣複製過去,還是不行。

試了dependency walker 2.2,它說我缺了MSJAVA.DLL,我根本沒用到JAVA啊…硬著頭皮找來檔案複製過去,什麼錯誤訊息都沒有了,結果還是同樣的錯誤視窗….

dependency walker有個功能是profiler,可以顯示程式執行中所有的DLL呼叫記錄,於是我在兩台電腦執行,一台是正常的,一台是一直錯誤的,發現在下面的訊息之後就會掛掉:

00:00:07.797: GetProcAddress(0x73640000 [c:\winnt\system32\MSCTFIME.IME], “ImeGetImeMenuItems”) called from “c:\winnt\system32\IMM32.DLL” at address 0x76307354 and returned NULL by thread 1. Error: w{C (127).
00:00:07.797: GetProcAddress(0x73640000 [c:\winnt\system32\MSCTFIME.IME], “CtfImeInquireExW”) called from “c:\winnt\system32\IMM32.DLL” at address 0x76307394 and returned 0x73659548 by thread 1.
00:00:07.797: GetProcAddress(0x73640000 [c:\winnt\system32\MSCTFIME.IME], “CtfImeSelectEx”) called from “c:\winnt\system32\IMM32.DLL” at address 0x763073A8 and returned 0x736592C5 by thread 1.
00:00:07.797: GetProcAddress(0x73640000 [c:\winnt\system32\MSCTFIME.IME], “CtfImeEscapeEx”) called from “c:\winnt\system32\IMM32.DLL” at address 0x763073BC and returned 0x736596FE by thread 1.
00:00:07.797: GetProcAddress(0x73640000 [c:\winnt\system32\MSCTFIME.IME], “CtfImeGetGuidAtom”) called from “c:\winnt\system32\IMM32.DLL” at address 0x763073D0 and returned 0x73659737 by thread 1.
00:00:07.813: GetProcAddress(0x73640000 [c:\winnt\system32\MSCTFIME.IME], “CtfImeIsGuidMapEnable”) called from “c:\winnt\system32\IMM32.DLL” at address 0x763073E4 and returned 0x7365931A by thread 1.
00:00:07.828: GetProcAddress(0x7C920000 [c:\winnt\system32\NTDLL.DLL], “RtlDllShutdownInProgress”) called from “c:\winnt\system32\MSCTF.DLL” at address 0x746BFA60 and returned 0x7C9336B0 by thread 1.

最後一個其實就是呼叫行程中止,比對兩台電腦的記錄,發現正常的狀況是會在這裡去執行一個對 ole32.dll 的呼叫,再比對,發現兩台電腦的windows系統 system32 目錄中,ole32.dll 的版本不同,可以正常執行的那一台版本較新,此時心花怒放,抓到了!!兇手就是你!!

先到 system32\dllcache 中,把 ole32.dll 改名為 ole32.dll.bak,再去 system32 目錄把ole32.dll 改名為 ole32.dll.bak,再把新版本的 ole32.dll 複製過去。如果 dllcache 裡面的東西不先改,windows的保護機制會把ole32.dll 還原,所以 dllcache 要先處理。

興沖沖的啟動程式,又是熟悉的畫面跳出來跟我say hello,被耍了….

http://stackoverflow.com/questions/16022967/run-exe-without-qt 所提到的解決方案是這樣:

先複製mingw目錄中所需要的DLL檔,但是5.1的目錄結構跟他示範的5.0.2不太相同,就是mingw這個目錄下是沒東西的,DLL檔是在bin裡面。

這一步我早就做了。

重點在第二步,到mingw的目錄中,有個 plugins 的子目錄,plugins 子目錄中,有個叫 platforms 的子目錄,裡面有幾個檔案:

qminimal.dll
qminimald.dll
qoffscreen.dll
qoffscreend.dll
qwindows.dll
qwindowsd.dll

並不是要你把這些檔案複製過去,這才是奧妙的地方,他能發現這一點,真是了不起。我們要做的是,把整個 platforms 子目錄,複製到你的執行檔所在目錄中

在網頁中提到,需要的檔案是qminimal.dll,但我實驗發現我需要的是 qwindows.dll。不確定的話就乾脆全部複製過去吧。

所以你的執行檔(假設叫做app.exe)的目錄結構會是這樣:

c:\dir\app.exe
c:\dir\Qt5Core.dll (跟其它需要的DLL檔)
c:\dir\platforms\qminimal.dll (或是 qwindows.dll 或其它DLL檔)

所以重點就是要有 platforms 這個目錄,還不能改名喔,你可以改成 platformsA 試試,熟悉的錯誤視窗立馬跳出來煩死你。

即使將 qminimal.dll ,以我的例子就是將 qwindows.dll ,跟執行檔擺在一起,一樣會出現錯誤,目錄結構一定要一樣才行,有夠神奇。

以上就是試了n個小時的心得。

 

Leave a Reply

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *