动态链接库.docx
- 文档编号:7254629
- 上传时间:2023-01-22
- 格式:DOCX
- 页数:13
- 大小:44.84KB
动态链接库.docx
《动态链接库.docx》由会员分享,可在线阅读,更多相关《动态链接库.docx(13页珍藏版)》请在冰豆网上搜索。
动态链接库
动态链接库
1.隐式链接
新建一个工程,选择Win32Dynamic-LinkLibrary,取名Dll1,选择一个空的动态链接库工程,然后新建一个文件名为Dll1的C++源文件,编辑:
_declspec(dllexport) int add(int a,int b) //加法
{
return a+b;
}
_declspec(dllexport) int subtract(int a,int b) //减法
{
return a-b;
}
编译,生成动态链接库文件:
Dll1.dll
2.查看dll文件的导出信息
打开cmd,进入到:
D:
\>cdD:
\cprograms\C_WORKSPACE\Dll1\Debug
然后:
D:
\cprograms\C_WORKSPACE\Dll1\Debug>dumpbin/exportsDll1.dll
输出如下信息:
FileType:
DLL
SectioncontainsthefollowingexportsforDll1.dll
0characteristics
4DBBFCA6timedatestampSatApr3020:
12:
222011
0.00version
1ordinalbase
2numberoffunctions
2numberofnames
ordinalhintRVAname
100000100A?
add@@YAHHH@Z
2100001005?
subtract@@YAHHH@Z
Summary
7000.data
1000.idata
3000.rdata
2000.reloc
2A000.text
3.调用动态链接库
新建一个基于对话框的MFC应用程序,取名DllTest,并在对话框资源中添加两个按钮(id:
IDC_BTN_ADD,标题:
add)和(id:
IDC_BTN_SUBTRACT,标题:
subtract),并双击分别添加消息响应函数,编辑:
#pragma comment (lib,"Dll1.lib") //加载库引用文件
extern int add(int a,int b);//声明一下,表明这函数是在外部定义的
extern int subtract(int a,int b);
void CDllTestDlg:
:
OnBtnAdd()
{
CString str;
str.Format("5+3=%d",add(5,3));
MessageBox(str);
}
void CDllTestDlg:
:
OnBtnSubtract()
{
CString str;
str.Format("5-3=%d",subtract(5,3));
MessageBox(str);
}
将上一步生成的Dll1.lib文件拷贝到这个工程目录下,并在DllTestDlg.cpp中声明:
#pragma comment (lib,"Dll1.lib") //加载库引用文件
运行。
OK!
4.查看可执行文件(或dll)的输入信息
方式一
Cmd中输入:
D:
\cprograms\C_WORKSPACE\DllTest\Debug>dumpbin/importsDllTest.exe
方式二
利用microsoftvisualstudio6.0的工具depends可以查看可执行文件、动态连接库等二进制文件的输入输出信息。
如下图:
5.用_declspec(dllimport)表明从dll中引入函数
修改DllTestDlg.cpp中的:
#pragma comment (lib,"Dll1.lib") //加载库引用文件
//extern int add(int a,int b);//声明一下,表明这函数是在外部定义的
//extern int subtract(int a,int b);
_declspec(dllimport) int add(int a,int b);//指示导入动态链接库中的函数
_declspec(dllimport) int subtract(int a,int b);//告诉编译器这两函数是从Dll1.lib中引入的
6.在动态链接库工程中增加头文件
打开Dll1动态链接库工程,在工程中新建一个C/C++HeadFiles,取名叫:
Dll1,编辑:
_declspec(dllimport) int add(int a,int b);//指示导入动态链接库中的函数
_declspec(dllimport) int subtract(int a,int b);//告诉编译器这两函数是从Dll1.lib中引
并在DllTestDlg.cpp当中包含头文件:
#include "..\Dll1\Dll1.h" //包含动态链接库的头文件
7.使dll既可以被自身引用也可以被外部引用
在Dll1.h中编辑:
//Dll1.h
#ifdef DLL1_API
#else
#define DLL1_API _declspec(dllimport)
#endif
DLL1_API int add(int a,int b);//指示导入动态链接库中的函数
DLL1_API int subtract(int a,int b);//告诉编译器这两函数是从Dll1.
在dll1.cpp中编辑:
//dll1.cpp
#define DLL1_API _declspec(dllexport)
#include "Dll1.h"
_declspec(dllexport) int add(int a,int b) //加法
{
return a+b;
}
_declspec(dllexport) int subtract(int a,int b) //减法
{
return a-b;
}
8.在dll中导出类
在Dll1.h中添加:
class DLL1_API Point //Dll1_API是宏定义,用于导出类
{
public:
void output(int x,int y);
};
在dll1.cpp中编辑:
#include
#include
.........
.........
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);//将要输出的字符串打印到buf中
TextOut(hdc,0,0,buf,strlen(buf));
ReleaseDC(hwnd,hdc);
}
编译,并将生成的dll与lib文件复制到DllTest工程目录下。
并在测试程序中的对话框资源上添加一个按钮(id:
IDC_BTN_OUTPUT,Caption:
output),并添加消息响应函数,编辑:
void CDllTestDlg:
:
OnBtnOutput()
{
Point pt;
pt.output(5,3);//输出
}
运行,ok!
导出类中的指定的成员函数
在Dll1.h中编辑:
class /*DLL1_API*/ Point //Dll1_API是宏定义,用于导出类
{
public:
DLL1_API void output(int x,int y);//导出
void test();
};
在Dll1.cpp中编辑:
void Point:
:
test() //实现
{
}
9.修改dll的兼容性
对于其它的C++编译器生成的dll访问客户端,要使用用VC++生成的dll。
在Dll1.h中编辑:
#ifdef DLL1_API
#else
#define DLL1_API extern "C" _declspec(dllimport)
#endif
注释掉:
//class /*DLL1_API*/ Point //Dll1_API是宏定义,用于导出类
/*{
public:
DLL1_API void output(int x,int y);//导出
void test();
};
*/
在dll1.cpp中编辑:
#include
#include
#define DLL1_API extern "C" _declspec(dllexport)
#include "Dll1.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);//将要输出的字符串打印到buf中
TextOut(hdc,0,0,buf,strlen(buf));
ReleaseDC(hwnd,hdc);
}
void Point:
:
test()
{
}
*/
注意:
extern“C”,就不能在导出类中的成员函数,同样在类外边的函数,如果用_stdcall调用约定,那么导出的函数名仍然会发生变化,因为_stdcall的调用约定不同于C的调用约定,所以即使用了extern“C”指明了调用约定,在加了_stdcall的函数上,编译时仍然会改变函数的名字。
示例,如可以这样修改:
在Dll1.h中,
DLL1_API int _stdcall add(int a,int b);//指示导入动态链接库中的函数
DLL1_API int _stdcall subtract(int a,int b);//告诉编译器这两函数是从Dll1.lib中引
在DLL1_API中
DLL1_API int _stdcall add(int a,int b) //加法
{
return a+b;
}
DLL1_API int _stdcall subtract(int a,int b) //减法
{
return a-b;
}
编译生成dll后,用dumpbin/exportsDll1.dll测试可以发现Dll1.dll中的两个函数的名字被改成了,如下:
_add@8和_substract@8,其中8表示这个中的参数所占用的字节数。
10.利用模块定义文件(def)解决函数名字改变的问题
新建一个工程,选择Win32Dynamic-LinkLibrary,取名Dll2,选择一个空的动态链接库工程,然后新建一个文件名为Dll2的C++源文件,编辑:
int add(int a,int b)
{
return a+b;
}
int subtract(int a,int b)
{
return a-b;
}
然后在这个工程目录下,新建一个文本文件,并将其名字改成Dll2.def,接着在Dll2工程中选择Project->addtoproject->files…,将Dll2.def文件添加到工程,编辑:
#指定动态链接库的内部名称
LIBRARYDll2
#表示在动态链接库在要导出的函数
EXPORTS
add
subtract
即使这样改变也没关系,如下:
int _stdcall add(int a,int b)
{
return a+b;
}
int _stdcall subtract(int a,int b)
{
return a-b;
}
编译,用dumpbin/exportsDll2.dll测试,可以看到函数名是add和subtract,可见编译后导出的函数名也没有改变。
但要注意,相应的测试程中也要改成_stdcall方式访问。
11.动态加载一个名字不变的动态链接库
在在DllTest.cpp中首先注释掉:
//#include "..\Dll1\Dll1.h" //包含动态链接库的头文件
再编辑:
//#pragma comment (lib,"Dll1.lib") //加载库引用文件
//extern int add(int a,int b);//声明一下,表明这函数是在外部定义的
//extern int subtract(int a,int b);
//_declspec(dllimport) int add(int a,int b);//指示导入动态链接库中的函数
//_declspec(dllimport) int subtract(int a,int b);//告诉编译器这两函数是从Dll1.lib中引入的
void CDllTestDlg:
:
OnBtnAdd()
{
HINSTANCE hInst;
hInst=LoadLibrary("Dll2.dll");//动态加载动态链接库
typedef int (/*_stdcall*/*ADDPROC)(int a,int b);//定义一个表示有两个参数的函数指针类型
ADDPROC Add=(ADDPROC)GetProcAddress(hInst,"add");//用来接收由GetProcAddress返回的dll导出函数的地址
//获得动态链接库导出函数的地址
if(!
Add)
{
MessageBox("获取add函数地址失败");
return;
}
CString str;
str.Format("5-3=%d",Add(5,3));
MessageBox(str);
}
void CDllTestDlg:
:
OnBtnSubtract()
{
HINSTANCE hInst;
hInst=LoadLibrary("Dll2.dll");//动态加载动态链接库
typedef int (/*_stdcall*/*ADDPROC)(int a,int b);//定义一个表示有两个参数的函数指针类型
ADDPROC Subtract=(ADDPROC)GetProcAddress(hInst,"subtract");//用来接收由GetProcAddress返回的dll导出函数的地址
//获得动态链接库导出函数的地址
if(!
Subtract)
{
MessageBox("获取subtract函数地址失败");
return;
}
CString str;
str.Format("5-3=%d",Subtract(5,3));
MessageBox(str);
}
void CDllTestDlg:
:
OnBtnOutput()
{
}
并将Dll2.dll拷贝到DllTest工程目录下,编译运行,OK!
12.动态加载名字改变的dll
新建一个工程,选择Win32Dynamic-LinkLibrary,取名Dll3,选择一个空的动态链接库工程,然后新建一个文件名为Dll3的C++源文件,编辑:
_declspec(dllexport) int add(int a,int b)
{
return a+b;
}
_declspec(dllexport) int subtract(int a,int b)
{
return a-b;
}
编译后,将Dll3.dll文件拷贝与DllTest工程目录下,然后对DllTest修改,如下:
void CDllTestDlg:
:
OnBtnAdd()
{
HINSTANCE hInst;
//hInst=LoadLibrary("Dll2.dll");//动态加载动态链接库
hInst=LoadLibrary("Dll3.dll");
typedef int (/*_stdcall*/ *ADDPROC)(int a,int b);//定义一个表示有两个参数的函数指针类型
//ADDPROC Add=(ADDPROC)GetProcAddress(hInst,"add");//用来接收由GetProcAddress返回的dll导出函数的地址
//获得动态链接库导出函数的地址
//ADDPROC Add=(ADDPROC)GetProcAddress(hInst,"?
add@@YAHHH@Z");
ADDPROC Add=(ADDPROC)GetProcAddress(hInst,MAKEINTRESOURCE
(1));
if(!
Add)
{
MessageBox("获取add函数地址失败");
return;
}
CString str;
str.Format("5-3=%d",Add(5,3));
MessageBox(str);
FreeLibrary(hInst);//释放动态链接库
}
void CDllTestDlg:
:
OnBtnSubtract()
{
HINSTANCE hInst;
//hInst=LoadLibrary("Dll2.dll");//动态加载动态链接库
hInst=LoadLibrary("Dll3.dll");
typedef int (/*_stdcall*/ *ADDPROC)(int a,int b);//定义一个表示有两个参数的函数指针类型
//ADDPROC Subtract=(ADDPROC)GetProcAddress(hInst,"subtract");//用来接收由GetProcAddress返回的dll导出函数的地址
//获得动态链接库导出函数的地址
//ADDPROC Subtract=(ADDPROC)GetProcAddress(hInst,"?
subtract@@YAHHH@Z");
ADDPROC Subtract=(ADDPROC)GetProcAddress(hInst,MAKEINTRESOURCE
(2));
if(!
Subtract)
{
MessageBox("获取subtract函数地址失败");
return;
}
CString str;
str.Format("5-3=%d",Subtract(5,3));
MessageBox(str);
FreeLibrary(hInst);//释放动态链接库
}
编译运行,OK!
!
13.DllMain函数
DllMain函数指动态链接库的入口函数
DllMain
TheDllMainfunctionisanoptionalentrypointintoadynamic-linklibrary(DLL).Ifthefunctionisused,itiscalledbythesystemwhenprocessesandthreadsareinitializedandterminated,oruponcallstotheLoadLibraryandFreeLibraryfunctions.
DllMainisaplaceholderforthelibrary-definedfunctionname.EarlierversionsoftheSDKdocumentationusedDllEntryPointastheentry-pointfunctionname.YoumustspecifytheactualnameyouusewhenyoubuildyourDLL.Formoreinformation,seethedocumentationincludedwithyourdevelopmenttools.
BOOLWINAPIDllMain(
HINSTANCEhinstDLL,//handletotheDLLmodule
DWORDfdwReason,//reasonforcallingfunction
LPVOIDlpvReserved//reserved
);
Parameters
hinstDLL
[in]HandletotheDLLmodule.ThevalueisthebaseaddressoftheDLL.TheHINSTANCEofaDLListhesameastheHMODULEoftheDLL,sohinstDLLcanbeusedincallstofunctionsthatrequireamodulehandle.
fdwReason
[in]SpecifiesaflagindicatingwhytheDLLentry-pointfunctionisbeingcalled.Thisparametercanbeoneofthefollowingvalues.
Value
Meaning
DLL_PROCESS_ATTACH
IndicatesthattheDLLisbeingloadedintothevirtualaddressspaceofthecurrentprocessasaresultoftheprocessst
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 动态 链接