C++编写DLL动态链接库的步骤与实现⽅法
本⽂实例讲述了C++编写DLL动态链接库的步骤与实现⽅法。分享给⼤家供⼤家参考,具体如下:
在写C++程序时,时常需要将⼀个class写成DLL,供客户端程序调⽤。这样的DLL可以导出整个class,也可以导出这个class的某个⽅法。
⼀、导出整个class
⽅法很简单,只需要在类的头⽂件中class和类名之间加上_declspec(dllexport),同时在另外⼀份提供给客户端调⽤程序使⽤的类的头⽂件中class和类名之间加上_declspec(dllimport)。为了能让客户端程序和DLL程序公⽤该类的⼀份头⽂件,通常在类的头⽂件中使⽤宏和预编译指令来处理。如下DLLTest.h:
#ifdef DLL_TEST_API
#else
#define DLL_TEST_API _declspec(dllimport)
#endif
Class DLL_TEST_API CDLLTest
{
Public:
CDLLTest();
~CDLLTest();
int Add(int a, int b);
};
DLLTest.cpp如下:
#define DLL_TEST_API  _declspec(dllexport)
#include "DLLTest.h"
这样,在DLL编译时DLL_TEST_API被定义为_declspec(dllexport),⽽且客户端程序编译时它被定义为
_declspec(dllimport)。
⼆、导出这个类的某个或者某⼏个⽅法
这时,需要将_declspec(dllexport)放到成员函数名前,如DLLTest.h:
#ifdef DLL_TEST_API
#else
#define DLL_TEST_API _declspec(dllimport)
#endif
Class CDLLTest
{
Public:
CDLLTest();
        ~CDLLTest();
int DLL_TEST_API Add(int a, int b);
};
但是,如果仅仅是这样的话,当客户端程序#include这个头⽂件后,定义DLLTest这个类的⼀个对象后(静态⽅式链接DLL),客户端程序⽆法链接通过,会提⽰构造函数和析构函数⽆法解析,此时,需要将构造函数和析构函数前也加上
DLL_TEST_API宏即可。
当然这⾥还有个问题就是类的函数在导出后,名字会发⽣变化,我们可以在函数名前再加上extern "C" ,如 extern "C"
DLL_TEST_API int Add(int a ,int b);但这只解决了C与C++调⽤时名字变更问题,可靠的⽅法还是增加⼀个模块定义⽂件def,在该⽂件中定义导出函数的名称,我们将在后⾯看到样例。
DLL编写完成后,就只剩下客户端程序如何去调⽤该DLL了,静态⽅式调⽤DLL和动态⽅式调⽤DLL。
⼀、静态⽅式调⽤DLL
这个⽅法就简单了,将DLLTest.h头⽂件和DLLTest.lib,DLLTest.dll⽂件拷贝到客户端程序的当前⽬录下,在客户端程序中#include<DLLTest.h>,然后通过#pragma comment(lib,"DLLTest.lib")的⽅式引⼊lib库,或者在客户端程序的⼯程属性⾥⾯增加对该lib⽂件的引⼊。
然后就可以在客户端程序中如同使⽤本地的⼀个class⼀样使⽤该DLL了,如:
dllTest.Add(1,2);
⼆、动态⽅式调⽤DLL
动态调⽤这个DLL,就需要对这个class进⾏修改了。
⾸先,在DLLTest.cpp⽂件中增加⼀个全局函数,该函数可以返回这个class的⼀个实例,这样,客户端程序调⽤这个全局函数后,得到该class的实例,就可以调⽤该class的实例⽅法了。
extern "C" _declspec(dllexport) CDLLTest* GetInstance()
{
return new CDLLTest;
}
注:extern "C" 只是解决了c与c++编译器之间的兼容问题,如果需要和其他编译器之间兼容,可靠的办法还是增加⼀个.def⽂件,⽂件内容如下:
LIBRARY "DLLTest"
EXPORTS
GetInstance = GetInstance
这样就指定了DLL的函数导出后的名称仍然不变。
这样,客户端程序就可以通过该函数来获取class的⼀个实例了。如下:
先需要定义⼀个函数指针类型:
typedef CDllTestBase* (*pfGetInst)();
//注:CDllTestBase类后⾯会介绍。
HMOUDLE hMod = LoadLibrary( _T("DLLTest.DLL") );
if(hMod)
{
pfGetInst pfGetInstance = (pfGetInst)GetProcAddress("GetInstance");
if( p )
{
//通过基类指针指向派⽣类对象
CDllTestBase * pInst = pfGetInstance ();
if( NULL != pInst )
{
pInst->Add( 1,2);
}
    if( NULL != pInst )
析构方法{
//释放对象
delete pInst;
}
}
}
当然,这⾥还是需要include这个DLL的头⽂件DLLTestBase.h,如果将之前所写的头⽂件DLLTest.h直接拷贝到客户端程序的当前⽬录下,并include进来的话,在编译连接时,是⽆法通过的,我们需要对这个头⽂件进⾏修改,⾸先增加⼀个.h ⽂件DLLTestBase.h,在这个⽂件中我们将需要在客户端程序中调⽤的函数都命名成纯虚函数,然后让CDLLTest类继承⾃CDLLTestBase类,DLLTestBase.h如下:
Class CDLLTestBase
{
Public:
Virtual ~CDLLTestBase(){};//虚析构函数,且为内联函数
Virtual int Add(int a, int b) = 0;
}
DLLTest.h修改后如下:
#include "DLLTestBase.h"
Class CDLLTest : public CDLLTestBase
{
Public:
CDLLTest();
int Add(int a, int b);
};
注:这⾥的DLLTestBase需要提供⼀个虚析构函数,这样在客户端程序中就可以通过基类指针来释放派⽣类对象了。
这样,只需要将DLLTestBase.h拷贝到客户端程序的当前⽬录下,然后在客户端程序中#include"DLLTestBase.h",就可以如上⾯介绍⼀样在客户端程序中调⽤DLL⾥⾯的⽅法了。
希望本⽂所述对⼤家VC++程序设计有所帮助。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。