改變DLL目錄延遲加載DLL

西北望長安,可憐無數山

------------------------------------------------------

windows開發中,爲了不想把exe和一堆dll放在一起,勤勞的程序員們使用了很多方法。這裏羅列一下。

  1. 將dll拷貝到windows目錄或system32目錄中。方法可行。 
    挑剔的朋友不想幹了,這不夠綠色。不想“污染”系統盤。
  2. 手動添加系統環境變量。打開“系統”屬性,添加dll目錄到“PATH”系統變量(或用戶變量)。測試方法可行。
    程序員們很善良,不想給用戶增加麻煩。
  3. 把方法2改成簡單自動點。寫一個bat或者再寫簡單exe只做上面的事。註冊一下PATH變量。
    程序員們很善良,不想添加PATH變量,而且覺得再寫一個bat或exe,不是很友好。
  4. 使用顯示加載dll方式,動態加載dll。方法當然可行。
    程序會在需要的時候纔去加載DLL文件,先獲取到DLL文件中相關的函數入口地址,然後轉換執行,執行完之後可以立即釋放掉資源。顯示加載具有更好的靈活性,能更加有效的使用內存,在編寫大型程序時往往使用顯示加載方式(如下)。
    可是這樣要自己實現加載dll、地址類型轉換、卸載dll。好不累人。懶惰的程序員已經習慣了導入lib,include頭文件了。
    typedef int (*test) (int a, int b);
     
    int main(int argc,char *argv[])
    {
    
        HMODULE hDll=LoadLibrary(L"DllTest.dll");
        if(hDll!=NULL)
        {
    
            test sub=(SubFunc)GetProcAddress(hDll,"test");
            ...
            system("pause");
        }
     
        FreeLibrary(hDll);
        
        return 0;
    }

    有沒有一種更爽一點的方式呢?

  5. 程序員嘗試把dll放到別的目錄,在main函數中先調用setDllDirectory修改dll路徑。該方法對於動態加載的dll有效。
    對於隱式加載的dll。程序一開始就報找不到dll,或者直接奔潰退出了。
    隱式調用的情況下似乎程序員沒有更好的方式控制DLL的目錄?

  6. VC++開發中,其實已經提供了一種延遲加載的隱式引用DLL編譯技術。內部原理其實是使用了顯示調用dll的方法。只是編譯器和IDE幫程序員做了很多工作。
    首先要設置VC項目中的連接器-輸入。把引用的dll改爲延遲加載。也不是所有的dll都要寫,很多時候,只需要把入口dll的名稱寫進來就可以了。

 

-------------------------------------------- 驀然回首,那人卻在燈火闌珊處----------------------------------------------------

看起來解決了問題!很多項目能成功跑起來,有些項目缺跑成功。這是爲什麼呢?
深層原因是方法6雖然使用了隱式加載dll的方式,但是其實內部採用的顯示加載(調用LoadLibrary)技術。程序中如果使用了全局變量類型,就會導致發生程序啓動異常。因爲全局變量,在還沒有調用動態加載dll時就已經觸發了。此時的dll還未找到。

因此。我們需要代碼上做一些改動,有時候只需要改動一點點(具體情況具體分析)。將該全局變量,改爲指針類型。在窗口或程序開始的地方。先動態設置臨時PATH變量,或調用setDllDirectory指定dll目錄後,再動態實例化指針對象。
 

//修改PATH臨時變量
SetPrivatePathEnvironment();

//動態加載dll中方法或對象類型。m_Motion爲指針變量
m_Motion = CMotion::CreateCMotion(m_MotionType);

這樣,您的exe就可以脫離一堆dll的包圍。看起來簡潔舒爽。也不需要用戶先執行bat或修改環境變量了。

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