Windows下调用C++动态库,即dll文件有两种方式:隐式调用和显式调用。如下以VS2013为编译环境说明。假若有一个项目TestDLL,产生的可执行文件名为TestDLL.exe,在这个工程中调用mydll.dll,mydll.dll对应的.lib文件名为mydll.lib。
一 隐式调用
这种调用方式须要编译动态库时用到的头文件、静态库文件(.lib),动态库文件(.dll)。
这里的.lib文件只包含一些索引,即.dll文件中导出的变量或函数的符号名和可选的标识号,不包含具体的代码实现,具体的代码实现都在.dll文件中, 应用程序中对函数或变量的调用与.lib文件中的符号相匹配,这些符号或标识号被写入最终的可执行文件中,可执行文件运行时,就按照这些符号或标识号到.dll中寻找定义。.lib文件中也包含了对应的.dll文件名,但不是彻底路径,连接程序会把这个.dll文件名写到可执行文件中,当应用程序运行过程当中须要加载.dll文件时, windows根据这些信息发现并加载.dll, 而后经过符号名或标识符实现对dll函数的动态连接。全部被应用程序调用的.dll文件都会在应用程序加载时被加载到内存中。
若是要完成源代码的编译,只须要.lib文件就能够了;若是要使可执行文件运行起来,只要有.dll文件就能够了,在编译和测试阶段,这两个文件最好都有。
隐式调用步骤以下:
1 将编译mydll.dll时用到的头文件拷贝到TestDLL的项目目录下,保证TestDLL项目在编译时能够找到这些头文件。
在VS2013中,右键点击项目->Properties->Configuration Properties->VC++ Directories->Include Directories,而后将头文件的路径添加到项目配置中。
2 将mydll.lib的文件路径添加到TestDLL项目的依赖库路径下,保证TestDLL项目在编译时可以找到这个mydll.lib。
在VS2013中,右键点击项目->Properties->Configuration Properties->VC++ Directories->Library Directories,而后将mydll.lib的文件路径添加到项目配置中。
3 将mydll.lib文件添加到TestDLL项目的附加依赖中,告诉程序要使用mydll.lib。
在VS2013中,右键点击项目->Properties->Configuration Properties->Linker->Input->Additional Dependencies, 将mydll.lib添加进去。
4 将要用到的mydll.dll文件拷贝到可执行文件所在的目录,即TestDLL.exe所在的目录,或系统环境变量配置的目录中(系统环境变量配置可到网上查找),保证TestDLL.exe运行时可以找到mydll.dll。
在TestDLL项目中,须要用到mydll.dll的地方,包含相应的头文件之后,就可使用mydll.dll中定义的变量或函数了。
二 显示调用
这种方式不须要头文件,也不须要相应的.lib文件,只要.dll文件就能够了。
这种方式在应用程序编译前并不知道会调用哪些.dll文件,在运行过程当中才肯定,运行过程当中,应用程序调用系统函数,在须要的时候加载.dll文件,而后获取指定变量的址或指定函数的入口地址后,就可使用变量或进行函数调用了。
显示式调用步骤以下:
1 调用系统函数LoadLibraryEx加载mydll.dll。示例代码片断:windows
string dllPath = "D:\\Project\\lib\\mydll.dll"; //mydll.dll的路径 TCHAR dynLibPath[MAX_PATH_LEN]; //若是使用的是ANSI字符集,这一步不须要 swprintf(dynLibPath, MAX_PATH_LEN, L"%S", dllPath.c_str()); //若是使用的是ANSI字符集,这一步不须要 //若是使用的是ANSI字符集,LoadLibraryEx的第一个参数,直接使用dllPath.c_str(),即ANSI字符串便可。 HMODULE dllHandler = LoadLibraryEx(dynLibPath, NULL, DONT_RESOLVE_DLL_REFERENCES); if(dllHandler) { cout << "Load mydll.dll successfully!" << endl; } else { cout << "Load mydll.dll failed!" << endl; }
2 调用系统函数GetProcAddress获取变量或函数的地址。示例代码片断:函数
FARPROC pFun = NULL; pFun = GetProcAddress(dllHandler, "TestFun"); //TestFun是mydll.dll中导出的函数 pFun(); //调用TestFun FARPROC pVar = NULL; pVar = GetProcAddress(dllHandler, "TestVar"); //TestVar是mydll.dll中导出的整型变量 int num = *(int*)pVar; //将pVar转换成整形 cout<<num<<endl; //打印TestVar的值
注意: 有时候,dll中肯定有相应的函数,调用GetProcAddress却返回NULL,例如: mydll.dll中肯定导出了函数“ AnotherTestFun",在Dependency Walker下看到相应的函数名为?AnotherTestFun@3HA,调用GetProcAddress(dllHandler, "AnotherTestFun")始终返回NULL;
而调用GetProcAddress(dllHandler, "?AnotherTestFun@3HA")却能够返回有效地址值。
像这种状况,多是由于在定义AnotherTestFun函数中,函数声明前忘了加 extern "C"。
若是没有加extern "C",编译器在编译AnotherTestFun这个函数时,会按照C++的规则翻译这个函数名,便可能把函数名字改掉,例如改为上面的"?AnotherTestFun@3HA",具体改为什么样的名字视编译器而定,这样一来,以TestDLL项目中再以"AnotherTestFun"为参数获取该函数的地址,确定会失败。
若是加上了extern "C",则是告诉编译器在编译函数时按照C语言的规则去翻译相应的函数名,即“请保持函数名称,不要生成中间函数名"。测试