您的位置:首页 > 其它

动态链接库和静态链接库的创建及应用实例

2014-05-06 23:21 429 查看
封装库学习心得

以前用别人的框架API函数,只能看到一个接口类,这个接口类里面全是纯虚的方法,但不明白是如何实现这些功能的,现在狠下心将其研究清楚。

封装库按照大类可以分为两种,即动态链接库和静态库

而动态链接库又分为两种加载的方式,动态加载和静态加载。

下面我就讲讲这这些库的具体创建和具体应用。

一,动态库的创建

我用的vs2003编译工具,我以游戏大厅房间桌子的一些接口为例,具体创建一个动态库的步骤如下

1,新建项目,选择win32项目(不是win32控制台程序),然后在设置里面选择DLL,完成。

新建一个头文件,这个头文件名字叫IRoomTable.h,在头文件里面写一个纯虚类,如下

class IRoomTable

{

public:

virtual ~IRoomTable(){};

virtual int GetRoomID()=0;

virtual unsigned long getGameID()=0; // 游戏id

virtual const char* getGameName()=0; // 游戏名字

virtual unsigned long getRoomID()=0; // 游戏房间id

virtual const char* getRoomName()=0; // 游戏房间名字

virtual unsigned short getTableID()=0; // 桌子ID,从1开始

virtual const char* getTableName()=0;// 桌子名字

};

2,新建一个头文件,文件名叫RoomTable.h,这个头文件里面写一个类RoomTable,继承于IRoomTable,具体实现如下

#pragma once

#include "IRoomTable.h"

class RoomTable :

public IRoomTable

{

public:

RoomTable(void);

virtual ~RoomTable(void);

int GetRoomID();

virtual unsigned long getGameID(); // 游戏id

virtual const char* getGameName(); // 游戏名字

virtual unsigned long getRoomID(); // 游戏房间id

virtual const char* getRoomName(); // 游戏房间名字

virtual unsigned short getTableID(); // 桌子ID,从1开始

virtual const char* getTableName(); // 桌子名字

private:

char *m_gamename;

char *m_roomname;

char *m_tablename;

};

3,再新建一个RoomTable.cpp文件,这个文件里是RoomTable类的实现,代码如下

#include "StdAfx.h"

#include "./roomtable.h"

RoomTable::RoomTable(void)

{

m_gamename = new char[20];

m_roomname = new char[20];

m_tablename = new char[20];

}

RoomTable::~RoomTable(void)

{

delete m_gamename;

delete m_roomname;

delete m_tablename;

}

int RoomTable::GetRoomID()

{

return 13141;

}

unsigned long RoomTable::getGameID()

{

return 13141;

}

const char* RoomTable::getGameName()

{

strcpy(m_gamename,"BaiShanMJ");

return m_gamename;

}

unsigned long RoomTable::getRoomID()

{

return 13141;

}

const char* RoomTable::getRoomName()

{

m_roomname = new char[20];

strcpy(m_roomname,"BaiShanMJ");

return m_roomname;

}

unsigned short RoomTable::getTableID()

{

return 13141;

}

const char* RoomTable::getTableName()

{

m_tablename = new char[20];

strcpy(m_tablename,"BaiShanMJ");

return m_tablename;

}

4,到现在为止,我们已经实现了RoomTable这个类,现在,我们要做的就是对外开放一个创建这个类对象的接口,也就是要将我们实现的类导出去。具体做法如下

(1)新建一个头文件IExport.h,在这个头文件里实现如下

#ifndef IROOMTABLE_IROOMTABLE

#define IROOMTABLE_IROOMTABLE

class IRoomTable;

extern "C" __declspec( dllexport ) IRoomTable* CreateRoomTable();

extern "C" __declspec( dllexport ) void RealseRoomTable(IRoomTable* roomtable);

#endif

注意,这里的CreateRoomTable没有带任何参数,那是因为我们这个类的构造函数是无参构造函数,如果是有参数的构造函数,那么就要加入相对应的参数。

(2)在工程的DllMain的主文件里加入两个导出接口的实现,当然,可以在任何一个cpp中来实现这个,我们只不过选的是DllMain文件里。

#include "stdafx.h"

#include "IExport.h"

#include "RoomTable.h"

BOOL APIENTRY DllMain( HANDLE hModule,

DWORD ul_reason_for_call,

LPVOID lpReserved

)

{

return TRUE;

}

extern "C" __declspec( dllexport ) IRoomTable* CreateRoomTable()

{

return new RoomTable();

}

extern "C" __declspec( dllexport ) void RealseRoomTable(IRoomTable* logicengine)

{

if ( logicengine )

{

delete logicengine;

}

}

好了,到目前为止,我们的动态库就完成了,包括里面类的实现,包括类的导出,都可以实现了。这时编译,就可以在Debug下面看到一个以dll结尾的动态库,要设置动态库的生成名称,可以在项目的设置属性里面修改。

二,动态库的加载及应用

动态加载

首先应该将动态库放到新建的工程的工作目录下,一般是Debug目录

1,动态加载

这里是函数指针类型,通过CreateLogicEngine这种类型就可以来创建一个函数指针。

typedef IRoomTable* (*CreateLogicEngine)();

HINSTANCE m_hinstace;

获取加载的动态库的实例句柄

m_hinstace = LoadLibrary("RoomTableDll.dll");

if (!m_hinstace)

{

return false;

}

通过函数指针定义一个函数

CreateLogicEngine _CreateLogicEngine;

在动态库中寻找CreateRoomTable这个函数,并将其地址返回给_CreateLogicEngine,当然,别忘了强制类型装换。

_CreateLogicEngine = (CreateLogicEngine)GetProcAddress(m_hinstace, "CreateRoomTable");

用_CreateLogicEngine来创建对象,这样就可以用m_le来调用动态库里面的函数了。

IRoomTable *m_le = _CreateLogicEngine();

2,静态加载

(1)如果要静态加载,那么要将和动态库一起生成的一个lib文件也放到工作目录下(注意,这个lib里面只不过是包含了动态库里面的函数的映射,通过这个函数映射可以找到动态库里面的具体实现,这个lib和我们创建一个静态库项目所生成的静态库是不一样的,后面会讲到)

(2)第二步是将静态库加载到程序工程中来,可以在附加依赖项中来加,也可以用

#pragma comment(lib, "RoomTableDll.lib")来加。

(3)将#include "IRoomTable.h"虚接口文件

和#include "IExport.h"导出文件加入到工程中

并在应用的地方包含这两个头文件。

这些工作都做好以后,就可以这样在创建动态库中类的对象。

IRoomTable *m_le = CreateRoomTable();

这里再也不用用函数指针来加载,而是直接用动态库中的导出接口函数CreateRoomTable

3,应用

所谓应用就是直接用m_le指针对象来直接调用动态库类中的接口。实例如下

int gameID = m_le->getGameID();

cout<<"gameID:"<<gameID<<endl;

cout<<"RoomID:"<<m_le->GetRoomID()<<endl;

cout<<"TableID:"<<m_le->getTableID()<<endl;

const char *gamename = m_le->getGameName();

cout<<"gamename:"<<gamename<<endl;

cout<<"roomname:"<<m_le->getRoomName()<<endl;

cout<<"tablename:"<<m_le->getTableName()<<endl;

cout<<m_le->getRoomName()<<endl;

三,静态库创建

说道静态库,那么就比较简单,其实现和调用和动态库基本上差不多

1, 创建一个win32项目(不是win32控制台程序),然后在设置里面选择静态库lib

2, 接下来和动态库的创建基本上一样,只是不用创建导出文件IExport.h了,也不用在IExport.h对接口函数进行实现了,但是要在虚接口文件IRoomTable.h的文件中添加创建对象的接口

IRoomTable* Createtable();

void ReleaseTable(IRoomTable* table);

并随便在一个cpp中对其进行实现,譬如就在RoomTable.cpp中对其进行实现

IRoomTable* Createtable()

{

return new RoomTable();

}

void ReleaseTable(IRoomTable* table)

{

if (table)

{

delete table;

}

}

这样,一个静态库就创建好了

四,静态库的加载及应用

(1) 首先,要将编译生成的静态库lib文件放到工作目录下面,然后在附加依赖项中添加这个lib文件或者用#pragma comment(lib, "*.lib")来加载

(2) 第二步是将动态库中的虚接口文件IRoomTable.h包含到工程中来,然后直接就用虚接口中的Createtable方法来创建对象,并返回给基类指针。

IRoomTable *m_le= Createtable();

这样就可以直接用m_le来调用静态库中的类成员函数了。

注:动态库的加载好像还是有点问题,后续再完善用例。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: