windows下创建并使用动态链接库(.dll)

定义:

动态链接库(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源码中将全局变量和类封装进普通函数中。




©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页