C++编写DLL动态链接库的步骤与实现方法
原文:http://www.jb51.net/article/90111.htm
本文实例讲述了C++编写DLL动态链接库的步骤与实现方法。分享给大家供大家参考,具体如下:
在写C++程序时,时常需要将一个class写成DLL,供客户端程序调用。这样的DLL可以导出整个class,也可以导出这个class的某个方法。
一、导出整个class
方法很简单,只需要在类的头文件中class和类名之间加上_declspec(dllexport),同时在另外一份提供给客户端调用程序使用的类的头文件中class和类名之间加上_declspec(dllimport)。为了能让客户端程序和DLL程序公用该类的一份头文件,通常在类的头文件中使用宏和预编译指令来处理。如下DLLTest.h:
|
1
2
3
4
5
6
7
8
9
10
11
|
#ifdef DLL_TEST_API#else#define DLL_TEST_API _declspec(dllimport)#endifClass DLL_TEST_API CDLLTest{ Public: CDLLTest(); ~CDLLTest(); int Add(int a, int b);}; |
DLLTest.cpp如下:
|
1
2
|
#define DLL_TEST_API _declspec(dllexport)#include "DLLTest.h" |
这样,在DLL编译时DLL_TEST_API被定义为_declspec(dllexport),而且客户端程序编译时它被定义为_declspec(dllimport)。
二、导出这个类的某个或者某几个方法
这时,需要将_declspec(dllexport)放到成员函数名前,如DLLTest.h:
|
1
2
3
4
5
6
7
8
9
10
11
|
#ifdef DLL_TEST_API#else#define DLL_TEST_API _declspec(dllimport)#endifClass 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了,如:
|
1
2
|
CDLLTest dllTest;dllTest.Add(1,2); |
二、动态方式调用DLL
动态调用这个DLL,就需要对这个class进行修改了。
首先,在DLLTest.cpp文件中增加一个全局函数,该函数可以返回这个class的一个实例,这样,客户端程序调用这个全局函数后,得到该class的实例,就可以调用该class的实例方法了。
|
1
2
3
4
|
extern "C" _declspec(dllexport) CDLLTest* GetInstance(){ return new CDLLTest;} |
注:extern "C" 只是解决了c与c++编译器之间的兼容问题,如果需要和其他编译器之间兼容,可靠的办法还是增加一个.def文件,文件内容如下:
|
1
2
3
|
LIBRARY "DLLTest"EXPORTSGetInstance = GetInstance |
这样就指定了DLL的函数导出后的名称仍然不变。
这样,客户端程序就可以通过该函数来获取class的一个实例了。如下:
先需要定义一个函数指针类型:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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如下:
|
1
2
3
4
5
6
|
Class CDLLTestBase{ Public: Virtual ~CDLLTestBase(){};//虚析构函数,且为内联函数 Virtual int Add(int a, int b) = 0;} |
DLLTest.h修改后如下:
|
1
2
3
4
5
6
7
8
|
#include "DLLTestBase.h"Class CDLLTest : public CDLLTestBase{ Public: CDLLTest(); ~CDLLTest(); int Add(int a, int b);}; |
注:这里的DLLTestBase需要提供一个虚析构函数,这样在客户端程序中就可以通过基类指针来释放派生类对象了。
这样,只需要将DLLTestBase.h拷贝到客户端程序的当前目录下,然后在客户端程序中#include"DLLTestBase.h",就可以如上面介绍一样在客户端程序中调用DLL里面的方法了。
希望本文所述对大家VC++程序设计有所帮助。
C++编写DLL动态链接库的步骤与实现方法的更多相关文章
- Delphi 编写DLL动态链接库文件的知识和样例(有详细步骤,很清楚)
一.DLL动态链接库文件的知识简介: Windows的发展要求允许同时运行的几个程序共享一组函数的单一拷贝.动态链接库就是在这种情况下出现的.动态链接库不用重复编译或链接,一旦装入内存,Dlls函数可 ...
- Delphi 编写DLL动态链接库文件的知识
一.DLL动态链接库文件的知识简介: Windows的发展要求允许同时运行的几个程序共享一组函数的单一拷贝.动态链接库就是在这种情况下出现的.动态链接库不用重复编译或链接,一旦装入内存,Dlls函数可 ...
- 怎样用VB编写.DLL动态链接库文件
VB一般可以生成两种特殊的DLL,一个是ActiveX DLL和ActiveX Control(*.ocx).这两种DLL都是VB支持的标准类型,在VB自身的例子中有,你可以参考.更详细的介绍可以参考 ...
- 详解VB.net编写DLL(动态链接库、应用程序扩展)文件
首先,我们启动VS(Visual-Studio简称),我使用的是VS2008版本. 新建一个项目-选择内裤(额...不好意思)→类库 ,名称就默认吧. 编写类库没有窗体设计,因此我们不能使用工具箱中的 ...
- Qt Creator编译运行成功,但是显示系统找不到指定的文件(比如urlmon.dll动态链接库)
问题: 以前自己写的一个QT界面程序,在win 7 的32位系统上运行没有出现任何问题,但是重装系统之后,同样的程序放到win10 的64位系统下运行会出现警告:onecoreuap\inetcore ...
- BCB如何编写,调用动态链接库DLL
一 编写动态链接库DLL DLL简称动态链接库,是Windows中程序的重要组成部分.想象一下,一个程序需要多人共同完成开发,怎么个共同法?这时我们就要考虑把程序分为好几个模块,团队每一个成员开发一个 ...
- 在 C# 中加载自己编写的动态链接库
一.发生的背景 在开发新项目中使用了新的语言开发 C# 和新的技术方案 WEB Service,但是在新项目中,一些旧的模块需要继续使用,一般是采用 C 或 C++ 或 Delphi 编写的,如 ...
- lib静态链接库,dll动态链接库,h文件
最近在弄摄像头,发现我在调用摄像头自带的函数的时候,库没连接上,于是经过高人指点,学习了一下lib静态链接库,dll动态链接库来补充一下自己的基础知识. 一.首先我们来介绍一下lib静态链接库. li ...
- DLL动态链接库导出函数方法 -- 动态导出(.def文件导出)
简介 动态链接库最大的优势在于可以提供给其他应用程序共享的资源,最小化应用程序代码的复杂度,其中一个十分重要的功能就是dll可以导出封装函数的功能.导出函数有两种主要方式,分别是静态导入和动态导入,本 ...
随机推荐
- redis介绍(4)实战场景
redis我主要在两方面说明: 集群下的session的管理 Tomcat 与 DB之间缓存
- Nginx 配置多站点vhost
假设你想在Linux Nginx中用不同的域名访问不同的目录,这时就要配置多个vhost,具体配置如下,假设网站根目录设定在/var/www/ 1.在/var/www/下新建两个目录 /var/www ...
- 回归JavaScript基础(三)
主题:JavaScript基本概念. 任何语言的核心必然会描述这门语言最基本的工作原理.这部分内容对我们来说,读起来很乏味,甚至会产生困意,但这部分内容却是重要的!我有幸拜读<JavaScrip ...
- Tomcat性能监控之Probe
目前采用java进行开发的系统居多,这些系统运行在java容器中,通过对容器的监控可以了解到java进程的运行状况,分析java程序问题.目前市面上流行的中间件有很多(Tomcat.jetty.jbo ...
- Vue2学习笔记:数据交互vue-resource
基本语法 必须引入一个库:vue-resource github地址 // 基于全局Vue对象使用http Vue.http.get('/someUrl', [options]).then(succe ...
- ASP.Net WebAPI的返回值
Asp.Net WebAPI服务函数的返回值主要可以分为void.普通对象.HttpResponseMessag.IHttpActionResult e四种,本文这里简单的介绍一下它们的区别. 一.返 ...
- python_循环(迭代)
#for 和 while #for用来迭代处理,什么叫迭代?你就当没看到这个词,for是把一堆玩意做一个一个加工用的,比如吃一袋花生,得一个一个剥吧,就是这意思 a = 'abcde' #每个字母当做 ...
- UIWindow的windowLevel详解
UIWindow的windowLevel详解
- 固定UIScrollView滑动的方向
固定UIScrollView滑动的方向 一般而言,我们通过这两个参数CGRectMake以及contentSize就可以自动的让UIScrollView只往一个方向滚动.但我遇到过非常奇葩的情况,那就 ...
- 多线程应用-函数方式(thread)
多线程只能使用一颗CPU,无法发挥多核心的优势.计算密集型用python的多线程效果不明显的,I/O密集型才能看出效果,可以发挥多核优势. GIL是全局资源锁,所以,如果没有涉及到资源的调用,是不会体 ...