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() = ;
}; 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 ;
}

如果都使用默认配置编译,只要设置好可执行文件的头文件包含目录(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 ;
}

然后重新编译运行,就可以了

总结

def文件可以用于当dll的调用约定(__fastcall),与宿主(本例的alltest.exe)程序的调用约定不一致时(__cdecl),导致可执行文件在

使用dll时的链接出错。不过要注意的是,def文件从实验来看,只会影响dll中的输出符号,而不会影响lib中的输出符号。这也是为什么

我们不能再使用静态加载的方式,而要改为动态加载的方式。因为动态加载只使用dll,而静态加载链接时使用的是lib中的符号。

windows dll的def文件的更多相关文章

  1. 通过dll或def文件提取lib导入库文件

    很多时候第三方库或其他项目提供的库多数会以动态库的形式提供dll以及相应的lib导入库.头文件,不过也有的只是提供dll和头文件,或者也提供了def模块定义(用于导出函数)文件,此时若使用将不得不调用 ...

  2. 简单了解 DLL中, .def 文件及C#调用C++方法

    DLL中导出函数的声明有两种方式: 1.在函数声明中加上__declspec(dllexport) //以下内容为 .h 文件中的内容 //向外界提供的端口 extern"C" _ ...

  3. VS制作dll、def文件的使用、dll加入工程使用

    1.VS新建工程,在选项的时候,选择dll和空项目,保持干净的dll库: 创建完以后,添加头文件以及源文件. 2.将外部模块使用的接口导出: (1)函数导出: __declspec(dllexport ...

  4. 使用Def文件导出Dll文件

    模块定义 (.def) 文件是包含一个或多个描述 DLL 各种属性的 Module 语句的文本文件.如果不使用 __declspec(dllexport) 关键字导出 DLL 的函数,则 DLL 需要 ...

  5. 由动态库文件dll生成lib库文件(手动生成.def文件,然后使用lib命令编译,非常牛),同理可使用dll生成.a库文件

    本文基于OpenBlas的编译和安装,来说明如何从一个dll文件生成lib库文件. 参考OpenBlas的说明“Howto generate import library for MingW”,和Mi ...

  6. DLL动态链接库导出函数方法 -- 动态导出(.def文件导出)

    简介 动态链接库最大的优势在于可以提供给其他应用程序共享的资源,最小化应用程序代码的复杂度,其中一个十分重要的功能就是dll可以导出封装函数的功能.导出函数有两种主要方式,分别是静态导入和动态导入,本 ...

  7. DLL中导出函数的两种方式(dllexport与.def文件)

    DLL中导出函数的声明有两种方式: 一种方式是:在函数声明中加上__declspec(dllexport): 另外一种方式是:采用模块定义(.def)文件声明,(.def)文件为链接器提供了有关被链接 ...

  8. (转)DLL中导出函数的两种方式(dllexport与.def文件)

    DLL中导出函数的两种方式(dllexport与.def文件)http://www.cnblogs.com/enterBeijingThreetimes/archive/2010/08/04/1792 ...

  9. DLL DEF文件编写方法 VC++ 调用、调试DLL的方法 显式(静态)调用、隐式(动态)调用

    DLL 文件编写方法: 1.建立DLL工程 2.声明.定义要导出的函数 BOOL WINAPI InitDlg( HWND hTabctrl,TShareMem* pTshare,CRect* prc ...

随机推荐

  1. 数据库连接池dbcp和c3po的区别

    1 DBCP   DBCP是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件. 2.C3P0 是一个开放源代码的JDBC连接池,它在lib目录中与Hibernate ...

  2. ngnix 是什么

    Nginx系列(一)--nginx是什么? 发表于2015/7/1 7:57:58  14347人阅读 分类: Nginx Java 一.介绍 Nginx是一个高性能的HTTP和反向代理服务器,也是一 ...

  3. 【阿里聚安全·安全周刊】Python库现后门 可窃取用户SSH信息|Facebook再曝300万用户数据泄露

    本周七个关键词:Python库现后门丨Facebook再曝数据泄露丨加密协议被曝严重漏洞丨英国报摊将出售"色情通行证"丨HTTPS的绿色锁图标丨机器学习和预测应用的API丨Ecli ...

  4. Centos7 下 tty2等文字窗口的中文乱码问题分析

    在使用 tty 的时候遇到了一个事情,那就是主文件夹下面的中文文件是乱码: [备注]tty 是 通过 CTRL + ALT +F2~F6  获得的,  这与桌面系统中的终端不是一个概念,  望看到这篇 ...

  5. JAVA PERSISTENCE API (JPA)

    13.2.1. About JPA The Java Persistence API (JPA) is the standard for using persistence in Java proje ...

  6. 第二天 Java语言基础

    一.如何定义Java中的类 Java代码都定义在类中,类由class来定义,区分public class和class: 二.main方法的作用 main方法是程序的入口:保证程序的独立运行:被JVM调 ...

  7. Reactor和Proactor模式

    在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操作.同步和异步 同步和异步是针对应用程序和内 ...

  8. api_request.go

    && !strings.HasPrefix(endpoint, "https") {             endpoint, err = httpsEndpoi ...

  9. BZOJ_2734_[HNOI2012]集合选数_构造+状压DP

    BZOJ_2734_[HNOI2012]集合选数_构造+状压DP 题意:<集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x ...

  10. ./configure、make、make install

    这些都是典型的使用GNU的AUTOCONF和AUTOMAKE产生的程序的安装步骤 一.基本信息 1../configure 是用来检测你的安装平台的目标特征的.比如它会检测你是不是有CC或GCC,并不 ...