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

封装库学习心得

以前用别人的框架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来调用静态库中的类成员函数了。

 

              文档制作人:张靖
              2010年12月28日星期二
              边锋用户中心

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值