有人说 反射反射,程序员的法宝。这句话一点也没有错。如果能够动态的加载类和方法,就等于彻底的解除了类和类,方法和方法的耦合。
当然,这样编译器就无法帮你检查出其中的错误了,还是有一定的风险的。
总的来说,反射是一位好同志。他可以让程序的扩展变得如此方便,免除了重新编译之苦。
近来在玩C++,被其中的种种细节问题搞得晕头转向。
用LoadLibrary实现动态加载类,花了很多时间在dll的路径问题上。
在传入相对路径时,文件的查找顺序比较诡异,在XP sp2以后首先是系统目录开始搜索,以前是首先从当前目录开始搜索。微软认为当前目录是不安全的。所以如果很不巧你的System32下有一个同名的dll时,会造成dll版本的混乱。
解决这个问题,要改用LoadLibraryEx(path,NULL,LOAD_WITH_ALTERED_SEARCH_PATH);
另一种方法是先调用SetDllDirectory方法,将要设置的目录会优先开始搜索。
以上两种方法是权宜之计,最值得推荐的方法是用绝对路径而不是相对路径。要获得绝对路径就要知道当前程序的目录。问题来了,怎么获得当前目录呢?
我当时是一拍脑袋,用了GetCurrentDirectory方法。用了才发现,得到的路径并不稳定,有时候会得到莫名其妙的路径,甚至在不同电脑上有不同的结果。
正确的解决方法麻烦了许多,要先AfxGetInstanceHandle()得出模块句柄,然后得到当前模块包含路径的全名GetModuleFileName,最后通过字符串操作,去掉最后一个 / 后的内容,才得到当前路径。
解决了这些问题,LoadLibrary路径没问题,得到结果却是0,GetLastError得到126,找不到指定的模块。我和同事一致认为是dll的其他依赖缺失。用depends打开这个dll,所有依赖都没问题啊,Why?
后来我试着把dll和依赖放的满磁盘到处都是,终于找出了问题所在:
我的程序主模块app.exe和要加载的模块 plugins/plgn1.dll不是在同一级目录下,在用depends打开plgn1.dll时,会在当前目录(/plugins/)下寻找其他依赖,这些依赖都在。
而LoadLibrary加载的模块 plugins/plgn1.dll时,他认为的当前路径是相对主模块app.exe来说的,是程序根目录(/)而不是/plugins/,所以就找不到相关依赖,导致plgn1.dll加载失败。
解决方法:SetDllDirectory方法,设置为plgn1.dll所在的绝对路径。