windows dll的def文件
dll(testcase_1.dll )源码:myfun.h
#pragma once #ifdef testcase_1_exports #define my_api __declspec(dllexport) #else #define my_api __declspec(dllimport) #endif #include <iostream> #include <string> namespace apicore { class my_api exportinterface { public: virtual void foo() = 0; }; extern "c" my_api exportinterface* getinstance(); #ifdef testcase_1_exports class exportclass :public exportinterface { private: std::string m_str; public: void foo(); }; #endif };
mufun.cpp
#include <iostream> #include "myfun.h" //#include "myfun2.h" using namespace std; namespace apicore { extern "c" my_api exportinterface* getinstance() { //apicore2::printinfo(); static exportclass ec; return &ec; } void exportclass::foo() { cout << "hi, i'm exportclass::foo" << endl; } }
可执行文件(alltest.exe)源码:
main.cpp
#include <iostream> //#include "..\\testcase_1\\myfun.h" //#pragma comment(lib, "..\\debug\\testcase_1.lib") #include <windows.h> #include "myfun.h" int main(int argc, char *argv[]) { //// 动态加载dll,不需要lib文件, //hinstance handle = getmodulehandle("testcase_1.dll"); // //if (handle == null) //{ // handle = loadlibrary("testcase_1.dll"); // typedef apicore::exportinterface* (*funtype)() ; // funtype fun = (funtype)getprocaddress(handle, "getinstance"); // if (fun) // { // fun()->foo(); // } // freelibrary(handle); //} // 静态加载调用,无法使用def文件,因为静态加载用的是lib文件 apicore::getinstance()->foo(); getchar(); return 0; }
如果都使用默认配置编译,只要设置好可执行文件的头文件包含目录(myfun.h所在目录),导入对应的lib(testcase_1.dll.lib)文件,然后把testcase_1.dll.dll放到alltest.exe同一目录。程序便可以正常运行。
那么def文件有什么用呢?
我们先改变一下testcase_1.dll的项目属性,调用约定由__cdecl改为__fastcall,可执行文件alltest.exe保持__cdecl调用约定不变
这个时候再次编译dll,生产成功
再重新编译生产可执行文件alltest.exe,编译失败,说找不到我们要使用的dll中的函数符号。
这是因为上面改了dll调用约定,而exe没有改。我们可以吧exe和dll的调用约定改成一样的,就没问题了。
这里我介绍另一种方法,就是使用我们的def文件。我们在testcase_1.dll这个项目中新添加一个def文件,
叫做sourc.def。内容如下
library "testcase_1.lib" exports getinstance
exports下的getinstance告诉编译器要导出的符号是getinstance,而是其他的,比如@getinstance@0,然后修改
项目属性如下:
再重新编译生产testcase_1.dll。这时候我们再次编译可执行文件,发现还是找不到符号,编译不通过。然后我们对可执行文件alltest.exe的代码做一点修改,
把dll加载有静态加载改为动态加载。修改main.cpp如下
#include <iostream> //#include "..\\testcase_1\\myfun.h" //#pragma comment(lib, "..\\debug\\testcase_1.lib") #include <windows.h> #include "myfun.h" int main(int argc, char *argv[]) { // 动态加载dll,不需要lib文件, hinstance handle = getmodulehandle("testcase_1.dll"); if (handle == null) { handle = loadlibrary("testcase_1.dll"); typedef apicore::exportinterface* (*funtype)() ; funtype fun = (funtype)getprocaddress(handle, "getinstance"); if (fun) { fun()->foo(); } freelibrary(handle); } //// 静态加载调用,无法使用def文件,因为静态加载用的是lib文件 //apicore::getinstance()->foo(); getchar(); return 0; }
然后重新编译运行,就可以了
总结
def文件可以用于当dll的调用约定(__fastcall),与宿主(本例的alltest.exe)程序的调用约定不一致时(__cdecl),导致可执行文件在
使用dll时的链接出错。不过要注意的是,def文件从实验来看,只会影响dll中的输出符号,而不会影响lib中的输出符号。这也是为什么
我们不能再使用静态加载的方式,而要改为动态加载的方式。因为动态加载只使用dll,而静态加载链接时使用的是lib中的符号。
上一篇: 金山毒霸残余讯息怎么清理?
下一篇: 百度杀毒彻底卸载删除的技巧
推荐阅读
-
mysql 5.7 zip 文件在 windows下的安装教程详解
-
解析Java和Eclipse中加载本地库(.dll文件)的详细说明
-
C#使用ICSharpCode.SharpZipLib.dll进行文件的压缩与解压功能
-
VS2010中lib与dll文件的生成与使用方法
-
Visual Studio中根据系统区分引用64位、32位DLL动态库文件的配置方法
-
C#中实现在32位、64位系统下自动切换不同的SQLite dll文件
-
C# 编译生成dll文件供程序调用的两种方法
-
C#使用反射(Reflect)获取dll文件中的类型并调用方法
-
XP系统删除Windows Search和searchindexer.exe文件的方法
-
将ocx文件转换成C#程序引用的DLL文件的办法