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中的符号。
上一篇: 娘胎里就懒
下一篇: ansible批量修改用户密码
推荐阅读
-
Windows10系统C盘的cmak文件夹删除的方法
-
Windows下Python使用Pandas模块操作Excel文件的教程
-
Windows下MySQL5.6查找my.ini配置文件的方法
-
Windows本地环境和Linux腾讯云服务器之间传输文件的方法
-
win10系统中Windows Defender自动删除下载的文件该怎么解决?
-
windows下编辑的文件传到Linux后会出现^M怎么办?
-
win8.1系统丢失msvcr71.dll文件的解决方法
-
Windows系统中使用C#读取文本文件内容的小示例
-
xshell—实现Linux与Windows之间的文件传递
-
C#中调用DLL时未能加载文件或程序集错误的处理方法(详解)