解決 VisualStudio 2012 偵錯時、找不到工作目錄下的 DLL 的問題

基本上,在使用 Microsoft Visual Studio 開發 Windows 上的 C 應用程式的時候,常常會需要用到其他的函式庫,而在程式執行的時候,也可能會需要用到他們的 DLL 檔。而當程式越寫越大、整個方案(Solution)越來越複雜之後,會用到的 DLL 可能也會越來越多。通常這時候,Heresy 會把所有需要的 DLL 放到一起,方便處理。

像 Heresy 之前在寫 OpenNI 2 的專案設定教學的時候,就有提到相關的設定。

基本上,Windows 要去尋找 DLL 檔的時候,是有一個固定的順序的(參考《Search Path Used by Windows to Locate a DLL》),這個順序是:

  1. 執行檔所在目錄。
    The directory where the executable module for the current process is located.

  2. 目前目錄。
    The current directory.

  3. Windows 系統目錄。
    The Windows system directory. The GetSystemDirectory function retrieves the path of this directory.

  4. Windows 目錄。
    The Windows directory. The GetWindowsDirectory function retrieves the path of this directory.

  5. 系統環境變數 PATH 所列舉的目錄。
    The directories listed in the PATH environment variable.

如果是單一程式,比較簡單的方法,就是把所需要的 DLL 檔,複製到執行檔所在的目錄就可以了(上面的第 1 項)。而如果這個 DLL 會被普遍地使用,那丟到 Windows 的系統目錄(一般都是 C:\Windows\system32)下(上面的第 3 項),就所有程式都找的到了~網路上常常看到有人說下載了 DLL 檔,要丟到 Windows 的 system32 目錄下,其實也就是這個目的。

不過,如果是在開發程式,並不想把 DLL 放到系統目錄下的話(考慮到不同的程式需要的版本衝突等問題),那 Heresy 一般的作法,會是修改專案「組態屬性」(Configuration Properties)裡、「偵錯」(Debugging)的「工作目錄」(working directory)(下圖、英文版),讓對程式進行偵錯(debugging)的時候,在指定的目錄、也就是 DLL 所在的目錄下執行;這樣就可以透過上面的第 2 項,來找到 DLL 檔了。


基本上,「工作目錄」的設定算是 Heresy 最常用的方法之一,在之前的 VisualStudio 裡面,也都可以正常使用。但是,不知道為什麼,到了目前最新版的 VisualStudio 2012,在 Windows 7 底下針對 C 專案進行偵錯,似乎就都會發生「無法找到工作目錄下的 DLL 的問題」了!?也就是說,上面五個去尋找 DLL 的方法,第二個在使用 VisualStudio 偵錯的時候,似乎是失效了?

這個問題基本上也已經有人回報給微軟,回報的紀錄是《Working Directory has no effect!》這篇。而答案則是讓人有點傻眼,他們認為這是 Windows 7 作業系統的問題,而且由於在 Windows 8 上沒問題,所以不打算處理了…(原文:「We have investigated and this appears like it may be a windows bug that was fixed with windows8 as we were no longer able to repro it with the current OS. At this time, we have no plans to workaround the bug for older OSes in a future release」)

Heresy 個人是覺得有點鬼扯啦,畢竟…上一版的 VisualStudio 2010 都還是可以正常使用啊!不過,微軟老大不修,好像也不能怎麼辦就是了…

那解決方法呢?微軟官方有提供四個建議:

  1. 把 DLL 檔放到執行檔所在的目錄
    Change the debuggee so that the dll is dropped next to the exe

  2. 使用 LoadLibrary()、並提供完整的路徑來讀取 DLL 檔
    Changing the debuggee to delay-load the dll explicitly by passing the full path to LoadLibrary()

  3. 把作業系統升級到 Windows 8
    Upgrade the OS from win7 to win8

  4. 修改專案設定的環境變數,讓 PATH 包含 DLL 的所在路徑
    Change the project settings so that the debuggee’s PATH environment variable includes the directory of the dll

基本上,個人覺得最合適的方法,應該是第四個,也就是透過修改專案設定的方法來做,這樣的影響會最小。(至於第三點?不予置評…)

修改方法,基本上就是針對個別的專案,去修改「組態屬性」(Configuration Properties)裡、「偵錯」(Debugging)下的「環境」(Environment),在裡面去額外設定「PATH」這個環境變數,加上 DLL 檔所在的路徑

設定的方法,基本上就是「PATH=目錄路徑」這樣的形式,比如說如果 DLL 檔都在 E:\ 的話,那只要在「環境」裡填入「PATH=E:\」就可以了;這樣的方法,基本上就是讓 VisualStudio 2012 的 debugger 使用上面 DLL 搜尋順序的第五項,來找到程式需要的 DLL 檔了~

而在下方的「合併環境」(Emerge Environment)有勾選的情況下,VisualStudio 在偵錯的時候,會把新設定的環境變數,和現有的(Windows 設定的)做合併,所以不用擔心蓋掉本來的設定,也不用擔心影響到整個系統的設定,算是一個彈性很大的方法。

如果還是想把 DLL 檔都放在「工作目錄」的話,並使用本來「工作路徑」的設定方法來做設定的話,也可以像 Heresy 在上面的截圖一樣,使用內建的巨集「$(LocalDebuggerWorkingDirectory)」,也就是在「環境」那邊輸入「PATH=$(LocalDebuggerWorkingDirectory)」;這樣的話,在修改「工作目錄」的同時,環境變數的 PATH 也就會跟著修改,而不需要改兩個地方了~

發佈留言

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