第19章dll
1
动态链接库
自从微软推出第一个版本的Windows操作系统以来,动态链接库(DLL)一直是Windows操作系统的基础。
动态链接库通常都不能直接运行,也不能接收消息。它们是一些独立的文件,其中包含能被可执行程序或其它DLL调用来完成某项工作的函数。只有在其它模块调用动态链接库中的函数时,它才发挥作用。
Windows API中的所有函数都包含在DLL中。其中有3个最重要的DLL,Kernel32.dll,它包含用于管理内存、进程和线程的各个函数;User32.dll,它包含用于执行用户界面任务(如窗口的创建和消息的传送)的各个函数;GDI32.dll,它包含用于画图和显示文本的各个函数。
静态库和动态库
静态库:函数和数据被编译进一个 二进制文件(通常扩展名为.LIB)。在使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其它模块组合起来创建最终的可执行文件(.EXE文件)。
在使用动态库的时候,往往提供两个文件:一个引入库和一个DLL。引入库包含被DLL导出的函数和变量的符号名,DLL包含实际的函数和数据。在编译链接可执行文件时,只需要链接引入库,DLL中的函数代码和数据并不复制到可执行文件中,在运行的时候,再去加载DLL,访问DLL中导出的函数。
2
使用动态链接库的好处
可以采用多种编程语言来编写。
增强产品的功能。
提供二次开发的平台。
简化项目管理。
可以节省磁盘空间和内存。
有助于资源的共享。
有助于实现应用程序的本地化。
动态链接库被多个进程访问
动态链接库加载的两种方式
隐式链接
显示加载
/*example1*/
int add(int a,int b)
{
return(a+b);
}
int subtract(int a,int b)
{
return(a-b);
}
output:
dll1.dll
需要导出才可以使用
dumpbin命令查看
*******dumpbin.exe
*******vcvars32.bat
dumpbin -exports dll1.dll
/*example2*/
_declspec(dllexport)int add(int a,int b)
{
return(a+b);
}
_declspec(dllexport)int subtract(int a,int b)
{
return(a-b);
}
output:
dll1.lib dll1.exp
dll1.dll
dumpbin -export dll1.dll
3
/*example3*/
使用example2的dll文件
使用:
extern int add(int a,int b);
extern int subtract(int a,int b);
CString str;
str.Format("5+3=%d",add(5,3));
MessageBox(str);
CString str;
str.Format("5-3=%d",subtract(5,3));
MessageBox(str);
链接出错
dll1.lib考到debug目录,并且设置链接选项
link object/library module: add dll1.lib
dumpbin -import test.exe
查看可执行文件用到的 dll文件
链接ok,运行出错,找不到dll文件
拷贝dll考到目录
dumpbin -imports dll1.exe
查看输入信息
dll文件依赖工具depends
open dll1.exe
/*example4*/
使用example2的dll文件
使用:
_declspec(dllexport)int add(int a,int b);
_declspec(dllexport)int subtract(int a,int b);
4
/*example4*/
dll1.dll
增加头文件,内容如下
_declspec(dllimport) int add(int a,int b);
_declspec(dllimport) int subtract(int a,int b);
测试文件
增加头文件
#inlclude"../dll1.h"
删除声明
_declspec(dllimport) int add(int a,int b);
_declspec(dllimport) int subtract(int a,int b);
头文件改造
/*example5*/
dll.h
#ifdef DLL1_API
#else
#define DLL1_API _declspec(dllimport)
#endif
DLL1_API int add(int a,int b);
DLL1_API int substract(int a,int b);
dll.cpp
#define DLL1_API _declspec(dllexport)
#include "dll.h"
int add(int a,int b);
int subtract(int a,int b);
导出类的全部函数
/*example6*/
.h
class DLL1_API Point
{
public:/*important*/
void output(int x,int y);
};
.cpp
#include window.h
#include stdio.h
void Point::output(int x,int y)
{
HWND hwnd=GetForegroundWindow();
HDC hdc=GetDc(hwnd);
char buf[20];
memset(buf,0,20);
sprintf(buf,"x=%d,y=%d",x,y);
Textout(hdc,0,0,buf,strlen(buf));
ReleaseDC(hwnd,hdc);
}
Point pt;
pt.output(5,4);
导出类的一个函数
/*example7*/
.h
class /*DLL1_API*/ Point
{
public:/*important*/
DLL1_API void output(int x,int y);
voit test();
};
void Point::test()
{
}
56
名称改变
如果想名称不改变
/*example8*/
dll.h
#ifdef DLL1_API
#else
#define DLL1_API extern "C" _declspec(dllimport)
#endif
缺点不能导出类的成员函数,智能全局函数
调用方式改变,命名也会改变,即使使用 extern "C",比如stdcall
/*example9*/
def文件,统一命名
动态加载动态链接库
HINSTANCE hInst;
hInst=LoadLibrary("dll1.dll");
typedef int(*ADDPROC)(int a,int b);
ADDPROC Add=(ADDPROC)GetProcAddress(hInst,"add");
if(!Add)
{
MessageBox("error");
return;
}
CString str;
str.Format("5+3=%d",add(5,3));
MessageBox(str);
调用方式需要一直dll和调用它的函数
动态加载动态链接库看不到其输出信息
dumpbin -imports dll1.exe
名称改变
7
通过序号访问函数
DllMain
FreeLibrary
文章评论(0条评论)
登录后参与讨论