动态链接库:我们经常把常用的代码制作成一个可执行模块供其他可执行文件调用,这样的模块称为链接库,分为动态链接库和静态链接库。

对于静态链接库,LIB包含具体实现代码且会被包含进EXE中,导致文件过大,浪费磁盘和内存;

对于动态链接库,DLL不必被包含在最终的EXE中,EXE执行时可以动态地装载和卸载DLL文件。

导出函数

将函数声明为导出函数有两种方式:

1、 在函数声明上加上_declspec(dllexport):

如:extern "C" int__declspec(dllexport)add(int x, int y);

2、 在.def文件中声明:如:

; lib.def : 导出DLL函数

LIBRARY dllTest(dll名称可忽略,但需要和生成的名称一致)

EXPORTS

Add @ 1

以”;”开始的为注释行,上述例子表示:生成名为“dllTest”的动态链接库,导出其中的add函数,序号为1。该序号在函数调用时起作用:GetProcAddress ( hDll, MAKEINTRESOURCE ( n ))返回 def定义的第n个函数地址。

DLL调用

使用动态链接库的时,往往提供两个文件:引入库文件(LIB)和动态链接库(DLL)。引入库文件(LIB)包含动态连接库(DLL)所有导出的函数和变量的符号名和地址,动态连接库(DLL)包含实际的函数和数据。调用方式分为动态调用(显式链接)和静态调用(隐式链接)。

1、 静态调用(隐式链接)

由编译系统完成对DLL的加载和卸载。共需两步操作:

告诉编译器与DLL相对应的LIB文件所在的路径及文件名,如#pragma comment (lib,"dllTest.lib") ;

声明导入函数,如:extern "C" __declspec(dllimport)add(int x,int y)(若有导出函数声明的头文件可直接包含该.h文件);

2、 动态调用(显示链接)

使用Win32 API 函数LoadLibrary、GetProcAddress、FreeLibrary实现"DLL加载-DLL函数地址获取-DLL释放”。这种方法不需要LIB文件,只需要DLL文件即可,显式链接速度更快且更加灵活。

关于DLL放置路径:

使用显式链接,在函数LoadLibrary的参数中可以指定DLL文件的完整路径;如果不指定路径,或者进行隐式链接,Windows将遵循下面的搜索顺序来定位DLL:

(1)包含EXE文件的目录

(2)工程目录

(3)Windows系统目录

(4)Windows目录

(5)列在Path环境变量中的一系列目录

例:

1、 生成DLL

创建Win32控制台的DLL项目MyDll,新建mydll.h和mydll.cpp,源码如下:

  1. //mydll.h文件
  2. #ifndef _MYDLL_H
  3. #define _MYDLL_H
  4. extern "C" int __declspec(dllexport)add(int x, int y);
  5. #endif
  1. //mydll.cpp文件
  2. #include "mydll.h"
  3. int add(int x, int y)
  4. {
  5. return x + y;
  6. }

编译(F7)生成MyDll.lib和MyDll.dll。(extern "C"指定导出函数为c链接,避免C/C++命名规则不同导致的函数名不一致)

2、 调用DLL

创建Win32控制台项目,新建test.cpp文件,源码如下:

动态调用:(将MyDll.dll拷贝至工程目录)

  1. #include <stdio.h>
  2. #include <windows.h>
  3. typedef int(*lpAddFun)(int, int); //宏定义函数指针类型
  4. int main(int argc, char *argv[])
  5. {
  6. HINSTANCE hDll = LoadLibrary("MyDll.dll");//加载DLL
  7. if (hDll != NULL)
  8. {
  9. lpAddFun addFun = (lpAddFun)GetProcAddress(hDll, "add");//获取函数地址
  10. if (addFun != NULL)
  11. {
  12. int result = addFun(2, 3);
  13. printf("%d", result);
  14. }
  15. FreeLibrary(hDll);//卸载DLL
  16. }
  17. return 0;
  18. }

静态调用:(将MyDll.dll和MyDll.lib拷贝至工程目录)

  1. #pragma comment(lib,"MyDll.lib")
  2. extern "C" __declspec(dllimport) int add(int x,int y);
  3. #include <stdio.h>
  4. int main(int argc, char* argv[])
  5. {
  6. int result = add(2,3);
  7. printf("%d",result);
  8. return 0;
  9. }

有时DLL导出函数若很多,在静态调用时,为了避免逐个写出extern "C"__declspec(dllimport) function(),可以直接包含DLL头文件(若有的话)。对于DLL制作者来说,需要实现头文件中函数是导入还是导出的自动转换,这时可通过定义宏实现。在DLL工程中头文件作用为导出声明,在应用工程中该头文件为导出声明。这时,DLL工程MyDll源码如下:

  1. //mydll.h文件
  2. #ifndef _MYDLL_H
  3. #define _MYDLL_H
  4. #ifdef MYDLL_EXPORT
  5. #define MYDLL_API __declspec(dllexport)
  6. #else
  7. #define MYDLL_API __declspec(dllimport)
  8. #endif
  9. extern "C" MYDLL_API int add(int x, int y);
  10. #endif
  1. // mydll.cpp文件
  2. #define MYDLL_EXPORT //只在DLL实现中定义此符号
  3. #include "mydll.h"
  4. int add(int x, int y)
  5. {
  6. return x + y;
  7. }

静态调用:(将MyDll.dll,MyDll.lib, mydll.h拷贝至工程目录)

  1. #pragma comment(lib,"MyDll.lib")
  2. #include"mydll.h"
  3. #include <stdio.h>
  4. int main(int argc, char* argv[])
  5. {
  6. int result = add(2,3);
  7. printf("%d",result);
  8. return 0;
  9. }

参考:

http://www.cnblogs.com/chio/archive/2007/11/03/948480.html#undefined

http://www.cnblogs.com/fangyukuan/archive/2010/06/20/1761464.html

http://www.cppblog.com/amazon/archive/2009/09/04/95318.html

版权声明:本文为博主原创文章,未经博主允许不得转载。

动态链接库(DLL) 分类: c/c++ 2015-01-04 23:30 423人阅读 评论(0) 收藏的更多相关文章

  1. HDU2680 Choose the best route 最短路 分类: ACM 2015-03-18 23:30 37人阅读 评论(0) 收藏

    Choose the best route Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  2. android开发之调试技巧 分类: android 学习笔记 2015-07-18 21:30 140人阅读 评论(0) 收藏

    我们都知道,android的调试打了断点之后运行时要使用debug as->android application 但是这样的运行效率非常低,那么我们有没有快速的方法呢? 当然有. 我们打完断点 ...

  3. HDU 1272 小希的迷宫(并查集) 分类: 并查集 2015-07-07 23:38 2人阅读 评论(0) 收藏

    Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就 ...

  4. MS SQL数据批量备份还原(适用于MS SQL 2005+) 分类: SQL Server 数据库 2015-03-10 14:32 103人阅读 评论(0) 收藏

    我们知道通过Sql代理,可以实现数据库的定时备份功能:当数据库里的数据库很多时,备份一个数据库需要建立对应的定时作业,相对来说比较麻烦: 还好,微软自带的osql工具,比较实用,通过在命令行里里输入命 ...

  5. NYOJ-289 苹果 289 AC(01背包) 分类: NYOJ 2014-01-01 21:30 178人阅读 评论(0) 收藏

    #include<stdio.h> #include<string.h> #define max(x,y) x>y?x:y struct apple { int c; i ...

  6. ubuntu14.04使用root用户登录桌面 分类: 学习笔记 linux ubuntu 2015-07-05 10:30 199人阅读 评论(0) 收藏

    ubuntu安装好之后,默认是不能用root用户登录桌面的,只能使用普通用户或者访客登录.怎样开启root用户登录桌面呢? 先用普通用户登录,然后切换到root用户,然后执行如下命令: vi /usr ...

  7. Matlab调用C程序 分类: Matlab c/c++ 2015-01-06 19:18 464人阅读 评论(0) 收藏

    Matlab是矩阵语言,如果运算可以用矩阵实现,其运算速度非常快.但若运算中涉及到大量循环,Matlab的速度令人难以忍受的.当必须使用for循环且找不到对应的矩阵运算来等效时,可以将耗时长的函数用C ...

  8. Mahout快速入门教程 分类: B10_计算机基础 2015-03-07 16:20 508人阅读 评论(0) 收藏

    Mahout 是一个很强大的数据挖掘工具,是一个分布式机器学习算法的集合,包括:被称为Taste的分布式协同过滤的实现.分类.聚类等.Mahout最大的优点就是基于hadoop实现,把很多以前运行于单 ...

  9. 各种排序算法的分析及java实现 分类: B10_计算机基础 2015-02-03 20:09 186人阅读 评论(0) 收藏

    转载自:http://www.cnblogs.com/liuling/p/2013-7-24-01.html 另可参考:http://gengning938.blog.163.com/blog/sta ...

随机推荐

  1. &quot;undefined reference to strptime&quot;之自己定义strptime函数

    简单介绍   strptime()函数可以依照特定时间格式将字符串转换为时间类型.简单点说可以将字符串时间转化为时间戳. 这个函数包括在time.h头文件里,在Unix或者类Unix系统中,我们会常常 ...

  2. Reload file in vim

    68down voteaccepted Give this a try: :e From :h :e: Edit the current file. This is useful to re-edit ...

  3. Ansible 详细用法说明(二)

    setup:获取指定主机的facts. ===================================facts就是变量,内建变量 .每个主机的各种信息,cpu颗数.内存大小等.会存在fact ...

  4. jquery 动态添加,降低input表单的方法

    html代码例如以下 <html> <tr><button style="margin-left:10px" class="add_fiel ...

  5. Spring之IOC篇章具体解释

    专题一   IOC 1.接口以及面向接口编程 a.结构设计中,分清层次以及调用关系,每层仅仅向外(或者上层)提供一组功能接口,各层间仅依赖接口而非实现类这样做的优点是,接口实现的变动不影响各层间的调用 ...

  6. Wi-Fi无线网络(WPA2加密)快速破解 ——某公司无线设备安全隐患报告

    Wi-Fi无线网络(WPA2加密)快速破解 --某公司无线设备安全隐患报告 评估人:阿牛 2013年12月12日 文件夹 一. 导言 2 二. 背景 2 三. 无线产品应当採取的安全策略 3 四. 存 ...

  7. 2015/12/25 ① 图灵测试 ② 安装jdk出现的问题 ③ 配置环境变量

    ①图灵测试 1,解释 图灵测试一词来源于计算机科学和密码学的先驱阿兰·麦席森·图灵写于1950年的一篇论文<计算机器与智能>.阿兰·麦席森·图灵1950年设计出这个测试,其内容是,如果电脑 ...

  8. Tomcat 安装错误

    安装tomcat时,遇到"failed to install tomcat6 service check your settings and permissions"的问题 安装时 ...

  9. PR 修改保存的增强 ME_UPDATE_REQUISITION

    FUNCTION me_update_requisition."""""""""""&qu ...

  10. java语法基础(四)

    继承 继承概述 继承是面向对象语言的三大基本特性(封装,继承,多态)之一. 一个类可以继承另外一个类,继承的类称为子类(也可以叫派生类),被继承的类称为父类(或者也叫基类,超类). 通过继承,子类可以 ...