改变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或修改环境变量了。

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