动态链接库(DLL)总结
以前的学习笔记,记录库的一点学习心得。主要是Windows下的静态库和动态链接库,动态链接库只写了关于非MFC的DLL,比较初级,适合和我一样的新手看看。有不对的地方请指出,有疏漏的地方请补充,如果您比较闲的话,呵呵,感激不尽。
一:静态链接库
静态库(static library)将函数和数据编译进一个二进制文件,通常可以命名为*.lib,编译器在链接过程中,将这些二进制数据复制出来,并与调用库的其他模块数据组合在一起,形成最终的可执行文件,等以后使用这个可执行文件时,就不需要这个静态库的支持了。
1 在Windows下静态库的创建和使用
在vs2010新建一个win32静态库工程,添加两个文件。
extern int gVar;
extern int add(int lhs, int rhs);//extern可以省略,因为函数默认作用域是extern
class T
{
public:
T();
T(int x, int y);
int add();
private:
int a;
int b;
};
#include "../dllTest/staticLib.h"
int gVar = ;
int add(int lhs, int rhs)
{
return lhs + rhs;
} T::T():a(),b() {}
T::T(int x, int y):a(x),b(y) {}
int T::add()
{
return a+b;
}
我们在库中声明了一个变量,一个函数,和一个类。然后build会生成一个staticlib.lib文件。为了测试这个库文件,我们新建一个win32控制台测试工程Test,在main函数中调用库,有两种方式:第一,你可以使用指令#pragma comment(lib,”staticlib.lib”),第二,可以在工程属性里面添加库及其路径,这里我们可以把前面静态库工程中的staticLib.h和staticlib.lib拷贝到Test工程目录下,然后选择:Property/Linker/General/Additional Library Directories,把staticlib.lib所在目录添加进来;再选择Linker/Input/Additional Dependencies,把库staticlib.lib加进去就可以了。这里我们用第一种方式加入库,代码如下:
#include <iostream>
#include "staticLib.h"
#pragma comment(lib,"Debug/staticlib.lib") int main(int argc, char *argv[])
{
T t(,);
std::cout<<gVar<<std::endl;
std::cout<<add(,)<<std::endl;
std::cout<<t.add()<<std::endl;
}
输出结果:
10
3
3
二:动态链接库
故名思义,动态链接库只有在需要的时候才会调用,所以相比静态链接库来说,有效减少程序运行时占用的内存空间。我们先创建一个dll,工程名为:dlllib。新建两个文件:dllLibDeclare.h和dllLibImp.cpp。代码如下:
#ifndef _dlllibdeclare_h_
#define _dlllibdeclare_h_ #ifdef DLL_API
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif DLL_API int gVar;
DLL_API int add(int lhs, int rhs);
class DLL_API T
{
public:
T();
T(int x, int y);
int add();
private:
int a;
int b;
};
#endif
实现文件:
#include "dlllibdeclare.h"
#define DLL_API
int gVar = ; int add(int lhs, int rhs)
{
return lhs + rhs;
} T::T():a(),b() {}
T::T(int x, int y):a(x),b(y) {}
int T::add()
{
return a+b;
}
编译之后,会生成一个dlllib.lib文件和一个dlllib.dll文件(此文件虽然也是以.lib结尾,但与上面提到的静态链接库还是有很大差别的,套用一句广告词,不是所有的lib都叫静态库)。这个文件只是包含了相应的dll的接口说明,并不包含实际的代码,从文件大小就可以看出。头文件里面定义了DLL_API这个宏,是为了方便以后调用这个dll的时候,直接利用此头文件,而不用再次声明我们导出的这些数据单元(因为没有预定义DLL_API这个宏的时候是导入)。说白了,就是方便多个工程重复利用。我们用vs2010自带的工具dumpbin查看dll里面导出的内容是什么?选择tool/visual studio command prompt,在命令行窗口输入如下命令:
我们可以看到,导出了5个单元,对应这类T的构造函数,拷贝构造函数,类的add成员函数,还有add函数和gVar整型变量。其中由于有2个同名的add函数,不太好辨认到底哪个是类的成员,哪一个是独立的类外的函数?不要紧,我们只要导出函数声明和最终的dll输出名之间的映射关系文件就ok了。在工程dlllib的properties/Linker/Debugging里面设置输出map信息就可以查看了:
在Debug模式下重新编译dlllib,会生成map.txt文件,打开这个文件,在文件最后可以看到如下内容:
这里清楚的指明了函数的对应关系。好了,下面我们调用这个dll做一下测试,新建一个工程:dllTest。代码如下:
#pragma comment(lib,"Debug/dlllib.lib")
__declspec(dllimport) int __stdcall add(int lhs, int rhs);
int __declspec(dllimport) gVar;
class __declspec(dllimport) T
{
public:
T();
T(int x, int y);
int add();
private:
int a;
int b;
};
int main(int argc, char *argv[])
{
T t(,);
std::cout<<gVar<<std::endl;
std::cout<<add(,)<<std::endl;
std::cout<<t.add()<<std::endl;
}
这里我没有用#include “dllLibDeclare.h”,而是自己声明了dll中的函数和数据,主要是为了说明__stdcall的问题,这个小地方折磨了我很久,所以拿出来强调一下。注意没有,我在声明外部add函数的时候,指明了函数的调用方式是__stdcall,如果没有这个,编译会报链接错误的。因为,在win32中,dll的调用方式默认是WINAPI(也就是__stdcall)的,而对于一般的c/c++工程,函数调用方式是__cdecl的,这两者的差别在于:__stdcall方式与__cdecl对函数名最终生成符号的方式不同,若采用C编译方式(在c++中需将函数声明为extern “C”),__stdcall调用约定在输出函数名前面加下划线,后面加”@”符号和参数的字节数,形如_functionname@number;而__cdecl调用约定仅在输出函数名前面加下划线,行如_functionname。而对于C++编译方式,这两者的差别与C的又会有区别,详见:http://baike.baidu.com/view/1276580.htm
所以,我们把握一个原则,前后对应。为了防止自己声明时的调用类型与dll原型不一致,我们调用时,最好以包含同一个头文件的方式进行声明,而且为了便于被其它语言程序调用,约定调用方式为__stdcall。新的”dllLibDeclare.h”中,我们这样写:
DLL_API int __stdcall add(int lhs, int rhs);
而调用dll时,包含这个头文件即可:
#include "dlllib/dlllibdeclare.h"
#pragma comment(lib,"Debug/dlllib.lib")
模块定义文件:上面的dll中我们利用__declspec(dllimport)指明导出的数据单元,其实也可以利用模块里定义导出数据。我们新建一个文件”set.def”,可以在工程中新建,也可以手动在别处新建。手动新建的可以通过在properties/Linker/Input中设定,如下图:
采用模块定义这种方式时,Def文件应该是不支持类的导出(有待考证),我们只导出一个变量和函数:
int gVar = ; int __stdcall add(int lhs, int rhs) { return lhs + rhs; }
Def的内容为:
;set dll
LIBRARY dlllib
EXPORTS
add @
gVar DATA
其中以分号开头的行代表注释,且不能与其它内容同行。LIBRARY指明要输出的库的名称,EXPROTS下面是具体要输出的数据单元,add @1表示输出的add函数的序号是1,这个序号在显示调用dll的时候用的上,gVar DATA表示输出一个全局变量。下面我们就给出隐式调用这个dll的测试代码:
#include <iostream>
#pragma comment(lib,"Debug/dlllib.lib")
extern _declspec(dllimport) int gVar;
extern _declspec(dllimport) int __stdcall add(int lhs, int rhs);
int main(int argc, char *argv[])
{
std::cout<<gVar<<std::endl;
std::cout<<add(,)<<std::endl;
gVar = ;
std::cout<<gVar<<std::endl;
}
也可以显示调用:
#include <iostream>
#include <windows.h>
Int main(int argc, char *argv[])
{
HMODULE hin;
char gvar[] = "gVar";
char add[] = "add";
typedef int (__stdcall *padd)(int, int);//don't forget to set __stdcall
hin = LoadLibrary(L"Debug/dlllib.dll");
if(NULL == hin) {
std::cout<<"can't load the dll file!"<<std::endl;
return ;
}
padd addfunc = (padd)GetProcAddress(hin,MAKEINTRESOURCEA() /*add*/ /*"add"*/);//three different way to find the function
int *pvar = (int*)GetProcAddress(hin,gvar);
std::cout<<addfunc(,)<<std::endl;
std::cout<<*pvar<<std::endl;
FreeLibrary(hin);
}
Ok,Windows下面的非mfc dll就是这样的。这样的dll也可以被其他语言调用,这里给一个在perl里面调用的例子:
perl调用dll的例子:
use strict;
use Win32::API;
my $dllPath = "./dlllib.dll";
my $func = new Win32::API($dllPath,"int __stdcall add(int lhs, int rhs)");
if(not defined $func)
{
die"can't import api\n";
}
my $sum = ;
$sum = $func->Call(,);
print "$sum\n";
好吧,先写到这里,以后写篇Linux下的库学习心得。
动态链接库(DLL)总结的更多相关文章
- 编译可供C#调用的C/C++动态链接库dll文件
编译可供C#调用的C/C++动态链接库dll文件,C语言控制台应用程序,探索生成dll过程 由于项目需求,需要公司另一个团队提供相关算法支持,是用C语言编译好的dll库提供给我们进行调用. 但是拿到d ...
- VC++动态链接库(DLL)编程深入浅出(zz)
VC++动态链接库(DLL)编程深入浅出(zz) 1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用 ...
- VS2010编写动态链接库DLL及单元测试用例,调用DLL测试正确性
转自:http://blog.csdn.net/testcs_dn/article/details/27237509 本文将创建一个简单的动态链接库,并编写一个控制台应用程序使用该动态链接库,该动态链 ...
- 无法加载 DLL“rasapi32.dll”: 动态链接库(DLL)初始化例程失败。
无法加载 DLL“rasapi32.dll”: 动态链接库(DLL)初始化例程失败. 在Asp.Net项目中使用WebClient或HttpWebRequest时出现以上错误 解决方案:把以下代码放在 ...
- delphi 2010 动态链接库DLL断点调试
DELPHI 2010 动态链接库DLL断点调试 马根峰 (广东联合电子服务股份有限公司,广州 510300) 摘要:本文详细介绍了Delphi 2010中的动态链接库DLL断点调试技术 关键词:DE ...
- 动态链接库 DLL
动态链接库DLL 不使用时不会有任何作用,只有在其他模块调用动态链接库中的函数时,它才发挥作用. 一.静态库与动态库 1.静态库 函数和数据被编译进一个二进制文件(.LIB),编译时,会将其组合起来创 ...
- MinGW gcc 生成动态链接库 dll 的一些问题汇总 (补充)
我以前写过一个小短文,介绍MinGW gcc 生成动态链接库 dll 的一些问题.当时写的并不全面.近期又遇到写新的问题.这里记录一下,做个补充. 通常情况下,dll 中的函数假设採用 _stdcal ...
- 动态链接库dll,静态链接库lib, 导入库lib
转载地址:http://www.cnblogs.com/chio/archive/2008/08/05/1261296.html 目前以lib后缀的库有两种,一种为静态链接库(Static Libar ...
- 动态链接库dll的 静态加载 与 动态加载
dll 两种链接方式 : 动态链接和静态链接(链接亦称加载) 动态链接是指在生成可执行文件时不将所有程序用到的函数链接到一个文件,因为有许多函数在操作系统带的dll文件中,当程序运行时直接从操作系统 ...
- VS2010编写动态链接库DLL和单元测试,转让DLL测试的正确性
本文将创建一个简单的动态库-link,谱写控制台应用程序使用该动态链接库,该动态链接库为"JAVA调用动态链接库DLL之JNative学习"中使用的DLL,仅仅是项目及文件名不同. ...
随机推荐
- JavaScript基础学习篇
1.alert消息弹出框 alert(字符串或变量); 消息对话框通常可以用于调试程序. 与document.write 相似. 2.确认:confirm消息对话框 confirm(弹出时要显示的文本 ...
- osg中遇到的问题
osg中遇到的问题 今天写程序的时候, 需要把键盘和鼠标消息转发出来, 就直接写了接口用signal丢出来了. 程序写的很多, 测试的时候却崩溃了.... 在场景中拖拽鼠标左键的时候, 会发现在扔出鼠 ...
- .net后台获取HTML中select元素选中的值
前台: <select id="Province" name="Province" class="select"></se ...
- ListView的HeaderView和Footer
HeaderView介绍 HeaderView用法 属性中添加 ListView中属性listHeader和overScrollHeader区别: android:overScrollHeader=& ...
- Qt Load and Save Image Dialog 加载图片对话框
在Qt中,我们想要通过对话框来打开某一个图片,可以通过使用QFileDialog来快速实现,参见以下代码: QString fileName = QFileDialog::getOpenFileNam ...
- jQuery的常用事件
1.$(document).ready() $(document).ready()是jQuery中响应JavaScript内置的onload事件并执行任务的一种典型方式.它和onload具有类似的效果 ...
- ie上 CSS3114: @font-face 未能完成 OpenType 嵌入权限检查。(包括图标无法显示)
转自:http://blog.csdn.net/shore_w/article/details/8976188 @font-face是CSS3中的一个模块, 它主要是把自己定义的Web字体嵌入到网页中 ...
- bzoj1857: [Scoi2010]传送带--三分套三分
三分套三分模板 貌似只要是单峰函数就可以用三分求解 #include<stdio.h> #include<string.h> #include<algorithm> ...
- Web前端开发基础 第二天(各类标签)
认识标签(第二部分): <ul> <li>信息</li> <li>信息</li> ...... </ul> <ol> ...
- 关于Java擦除特性
package thinkingInJava; /* * 模拟擦除 */ public class SimpleHolder { private Object obj ; public void se ...