定义:
动态链接库(dll)是一个包含可由多个程序同时使用的代码和数据的库。动态链接库不能直接运行,也不能接收消息。它们是一些独立的文件,其中包含能被可执行程序或其它DLL调用来完成某项工作的函数或是数据
一、创建动态链接库
1、新建一个名为DllOne的win32工程,并设置Application type为DLL,创建一个DLL工程。
2、添加如下三个文件
DllMain.cpp
#include<windows.h>
//DllMain函数在DLL被加载和卸载时被调用,在单个线程启动和终止时,DllMain
//函数也被调用。参数ul_reason_for_call指明了调用DllMain的原因。
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
DllOne.h
#include<string>
using namespace std;
//DLLONE_EXPORTS定义在工程属性的command line中。
//数据或者函数需要被导出时,则要在其定义前加上__declspec(dllexport)。这里用了宏定义来简化编码。
#ifdef DLLONE_EXPORTS
#define DLLONE_API __declspec(dllexport)
#else
#define DLLONE_API __declspec(dllimport)
#endif
#define EXTERN_C extern "C" //使该dll能被c语言程序调用
class DLLONE_API CFirstDll
{
public:
CFirstDll()
{
m_spDllName = new string("");
}
~CFirstDll()
{
delete m_spDllName;
}
void SetDllName(const string &sName);
void PrintDllName();
private:
//如果定义的是一个string变量,则在其他程序中
//调用定义这个类的对象时,会提示这个string变量是bad ptr。
//原因参考http://bbs.csdn.net/topics/210005206
string *m_spDllName;
};
EXTERN_C DLLONE_API int g_iValue;//全局变量
EXTERN_C DLLONE_API int GetAbs(int iValue);//普通函数
DllOne.cpp
#include"DllOne.h"
#include<cmath>
#include<iostream>
DLLONE_API int g_iValue = 0;
DLLONE_API int GetAbs(int iValue)
{
return abs(iValue);
}
void CFirstDll::SetDllName(const string &sName)
{
*m_spDllName = sName;
}
void CFirstDll::PrintDllName()
{
cout << *m_spDllName << endl;
}
编译后就可以生成DllOne.dll和DllOne.lib。
DllOne.lib包含被DLL导出的函数和变量的符号名,而DllOne.dll包含实际的函数和数据。
在DllOne.dll的创建过程中,使用的是_declspec( dllexport )方式导出函数的,其实还有另一种导出函数的方式,那就是使用导出文件(.def)。
二、使用动态链接库
在使用DLL时有两种方式:隐式加载和显示加载。
隐式加载
1、新建一个名为DllTest的win32控制台工程。
2、将DllOne.lib和DllOne.h拷贝到DllTest的工程目录下。
3、将DllOne.lib添加到工程属性中,如下所示:
4、使用Dll中的函数和数据。
Test.cpp
#include"DllOne.h"
#include<iostream>
using namespace std;
void main()
{
g_iValue = -3;
int i = GetAbs(g_iValue);
cout << i << endl;
CFirstDll myDll;
myDll.SetDllName("implicit linking");
myDll.PrintDllName();
while(1);
}
5、将DllOne.dll添加到DllTest.exe所在的目录。
显示加载
1、新建一个名为DllTest的win32控制台工程。
2、使用LoadLibrary()加载Dll,如下所示:
Test.cpp
#include"windows.h"
#include<iostream>
using namespace std;
typedef int (*AbsFunc)(int iValue);//定义一个函数指针
void main()
{
HMODULE hDll = LoadLibrary(L"DllOne.dll");//加载dll库
if (hDll!=NULL)
{
//获取dll中GetAbs函数的地址
AbsFunc MyAbs = (AbsFunc)GetProcAddress(hDll, "GetAbs");
int i = MyAbs(-4);
cout << i << endl;
//动态加载时,不能通过如下方式使用全局变量和类
// g_iValue = 1;
// CFirstDll myDll;
// myDll.SetDllName("implicit linking");
// myDll.PrintDllName();
while(1);
FreeLibrary(hDll);
}
}
3、将DllOne.dll添加到DllTest.exe所在的目录。
在显示加载示例代码中只调用了dll中的GetAbs普通函数,这是因为在显示加载时是无法直接调用dll中的全局变量和类的,GetProcessAddress函数只能导出普通函数。所有如果想在显示加载时也使用dll的全局变量和类,则需要在dll源码中将全局变量和类封装进普通函数中。