转载:https://www.cnblogs.com/chengbing2011/p/4084125.html

__declspec(dllimport)和__declspec(dllexport)经常是成对的,在动态链接库中__declspec(dllexport)导出dll中的成员,__declspec(dllimport)导入外部dll中的成员。

但是有时候不使用dllimport和dllexport也能实现个基本的导出导入功能, 它们具有的功能如下:

1.dllimport/dllexport可以导入或者导出动态链接库中的全局变量,当然是用extern也可以实现同样的功能;

2.dllimport/dllexport的作用主要体现在导出类的静态成员方面,如果不使用它们,无法在正常是用外部dll中类的静态成员函数;

3.隐式使用dll时,不加dllimport/dllexport也是可以,使用上没什么区别,只是在生成的二进制代码上稍微有点效率损失;

4.使用dllimport/dllexport还可以体现编程语言的对称美。

以下是一个Demo实例:

创建win的dll项目空项目名为DllExport

====================================.h文件如下[DllExport.h]:================================================

#ifdef DLLEXPORT_EXPORTS
#define DLLEXPORT_API __declspec(dllexport)
#else
#define DLLEXPORT_API __declspec(dllimport)
#endif // class从dll中导出Demo
class DLLEXPORT_API CDllExport {
public: CDllExport(void);
}; //变量从dll中导出Demo
extern DLLEXPORT_API int nDllExport; //函数从dll中导出Demo
DLLEXPORT_API int fnDllExport(void);

====================================.cpp文件如下[DllExport.cpp]:==============================================

#include "DllExport.h"

// 变量从Dll中导出Demo
DLLEXPORT_API int nDllExport=0; // 函数从Dll中导出Demo
DLLEXPORT_API int fnDllExport(void) { return 42; } // 类从Dll中导出Demo,以下为导出类的构造函数
CDllExport::CDllExport() { return; }

创建win的exe项目名为DemoEntry

====================================调用文件如下[DemoEntry.cpp]:=============================================

#include"DllExport.h"
#include<iostream> int _tmain(int argc, _TCHAR* argv[])
{
int returncnt= fnDllExport();
std::cout<<returncnt<<std::endl;
system("pause");
return 0; }

====================================================================================================

调用Dll过程编译器设置如下:

同样,使用.def文件也可以导出dll中的函数供外部调用,关于.def的使用如下:

1.LIBRARY语句说明.def文件相应的DLL;

2.EXPORTS语句后列出要导出函数的名称。可以在.def文件中的导出函数名后加@n,表示要导出函数的序号为n(在进行函数调用时,这个序号将发挥其作用);

3.def文件中的注释由每个注释行开始处的分号 (;) 指定,且注释不能与语句共享一行

以下是使用.def 文件导出DLL的Demo实例:

====================================.cpp文件如下[APIExport.cpp]:=============================================

int nTest=1;//全局变量  

int AddAndMulti(int a,int b)
{
return (a+b)*nTest;
} int _stdcall SubAndMulti(int a,int b)
{
return (a-b)*nTest;
} int _cdecl Multiply(int a,int b)
{
return a*b;
}

====================================.def文件如下[DllExport.def]:==============================================

LIBRARY   DllExport_def
EXPORTS
AddAndMulti @3
SubAndMulti @5
Multiply @1
nTest DATA

====================================.cpp调用代码[DllLoadEntry.cpp]:============================================

// DllLoadEntry.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <iostream> using namespace std; //引用dll中的全局变量
extern int _declspec(dllimport) nTest; //声明函数,需与Dll中的函数定义一致(包括其函数调用修饰词)
int AddAndMulti(int a,int b); int _stdcall SubAndMulti(int a,int b); int _cdecl Multiply(int a,int b); //#pragma comment(lib,"DllExport_def.lib")
int _tmain(int argc, _TCHAR* argv[])
{
nTest=2; cout<<AddAndMulti(1,2)<<endl;
cout<<SubAndMulti(3,4)<<endl;
cout<<Multiply(4,5)<<endl; system("pause"); return 0;
}

====================================================================================================

编译环境设置如下:

 

当然也可以在代码中添加 #pragma comment(lib,"DllExport_def.lib")实现同样的效果,DLL和调用的exe在同一个目录下。

def和__declspec的使用区别:

VC++编译器会对__declspec导出的函数进行一定的变化,如下:__declspec(dllexport) int __stdcall Add()会转换为Add@0(),对于外部调用程序也是VC++时,只需要将编译产生的lib文件提供给调用者即可,而如果提供给语言程序调用,就不是那么方便了。此时,使用.def文件就可以让编译器不会对导出的函数名称进行修改。

最新文章

  1. Python标准模块--ContextManager
  2. ASP.NET Aries JSAPI 文档说明:AR.Utility
  3. Android之mtklog分析
  4. java中static 和 final 的一些使用规则
  5. LeetCode----66. Plus One(Java)
  6. shell 实现word count
  7. updatepanel刷新后重新加载js脚本问题
  8. for 迭代器遍历list map
  9. Cocos2d-x3.3它DrawPrimitivesTest分析
  10. Spring Bean 生命周期
  11. CentOS_5.6下使用cmake编译MySQL_5.5.11教程
  12. 为程序启用 守护进程-- supervisior
  13. java中Map.Entry的使用方法
  14. Day033--Python--进程
  15. GoldenGate 12.3 MA架构介绍系列(5) - 静默安装
  16. 【BZOJ2227】[ZJOI2011]看电影(组合数学,高精度)
  17. Database学习 - mysql 连接数据库 库操作
  18. JQuery中Ajax的Post提交在IE下中文乱码的解决方法
  19. Android Jackson 概述
  20. WPF对象级资源的定义与查找

热门文章

  1. RabbitMQ入门指南
  2. Laravel ServiceProvider注册过程及简单使用
  3. kotlin 作用域函数 : let、run、with、apply、 also、takeIf、takeUnless
  4. idea vue文件设置tab为四个空格
  5. 基于模板特化的Lua自动绑定系统
  6. python-opencv 图像捕捉多个不规则轮廓,与轮廓内接区域(圆/矩形)思路-持续更新编辑中(会附上详细的思路解释和图片)
  7. Avtiviti工作流规范 BPM与BPMN
  8. HTTP走私
  9. MySQL For Linux(CentOS/Ubuntu/Debian/Fedora/Arch)一键安装脚本(5.1-8.0)
  10. 我的Python自学之路-001 列表的知识