在写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)
#endifClass 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)
#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了,如:

CDLLTest dllTest;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”EXPORTSGetInstance = 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();~CDLLTest();int  Add(int a, int b);
};

注:这里的DLLTestBase需要提供一个虚析构函数,这样在客户端程序中就可以通过基类指针来释放派生类对象了。

这样,只需要将DLLTestBase.h拷贝到客户端程序的当前目录下,然后在客户端程序中#include”DLLTestBase.h”,就可以如上面介绍一样在客户端程序中调用DLL里面的方法了。

C++编写DLL的方法相关推荐

  1. windows下如何使用QT编写dll程序 .

    Windows 下如何使用 QT 编写 dll 程序 因为 QT 必须有调用 QApplication 的 exec 方法,这样才能产生消息循环, QT 的程序才可以运行.所以说如果我们使用了 QT ...

  2. Delphi环境中编写调用DLL的方法和技巧

    Delphi环境中编写调用DLL的方法和技巧 第一章 为什么要使用动态链接库(DLL) top 提起DLL您一定不会陌生,在Windows中有着大量的以DLL为后缀的文件,它们是保证Windows正常 ...

  3. 使用vs2019编写dll

    本文通过一个demo演示dll的编写和调用. 一.编写dll 首先编写一个dll,它提供一个加法函数. 使用visual studio新建项目,我把项目命名为AddDll,选择模板windows桌面向 ...

  4. 怎样用VB编写.DLL动态链接库文件 1

    怎样用VB编写.DLL动态链接库文件 编号: QA000507     建立日期: 1999年2月10日 最后修改日期: 2006年8月13日 所属类别: Visual Basic - 其他方面   ...

  5. .net core 调用c dll_Qt编写DLL给外部程序调用,提供VC/C#/C调用示例(含事件)

    一.前言 最近这阵子,接了个私活,封装一个开发包俗称的SDK给客户调用,查阅了很多人家的SDK,绝大部分用VC编写,而且VC6.0居多,估计也是为了兼容大量的XP用户及IE浏览器,XP自带了VC6.0 ...

  6. c 的dll php调用方法,PHP调用C#开发的dll类库方法,_PHP教程

    PHP调用C#开发的dll类库方法, 有的时候,我们需要在php中利用到其他语言编写的dll类库,如C#编写的dll,方法就是利用PHP new COM方法来调用,在调用之前先要把dll库注册并把程序 ...

  7. windows下编写dll

    dll的优点 简单的说,dll有以下几个优点: 1) 节省内存.同一个软件模块,若是以源代码的形式重用,则会被编译到不同的可执行程序中,同时运行这些exe时这些模块的二进制码会被重复加载到内存中.如果 ...

  8. qt编译c语言dll,QT编写DLL给外部程序调用,提供VC/C#/C调用示例(含事件)

    最近这阵子,接了个私活,封装一个开发包俗称的SDK给客户调用,查阅了不少人家的SDK,绝大部分用VC编写,并且VC6.0居多,估计也是为了兼容大量的XP用户及IE浏览器,XP自带了VC6.0运行库,因 ...

  9. C#直接使用DllImport外部Dll的方法

    C#.Net调用基本格式: [DLLImport("DLL文件路径")] 修饰符 extern 返回值类型 方法名称(参数列表) 如: [csharp] view plain co ...

最新文章

  1. linux下java进程占用高问题分析过程
  2. 少儿编程python教材_少儿编程|Python环境安装
  3. 授以渔 - Autodesk Forge 学习简谈 - 引言
  4. AI理论知识整理(2)-对称矩阵-特征值与特征向量
  5. 指针数组的初始化和遍历,并且通过for循环方式、函数传参方式进行指针数组的遍历...
  6. Leetcode 08. 字符串转换整数 (atoi)
  7. android filehelper,为AndroidStudio开发mvp插件(MvpHelper)
  8. RenderMan:渲染技术
  9. sublime 插件(持续更新)
  10. html添加空隙,html空隙
  11. 公共教室计算机安全调查报告论文,计算机实习调查报告.docx
  12. JS实现抽奖活动程序
  13. 收藏夹吃灰系列(四):谁说Spring提供的@Scheduled定时不好用?师妹看了直呼叫好!
  14. codeblock找不到pthread
  15. 图像的灰度化灰度值的读取Matlab
  16. 【web】【django】datatable的button扩展实现纯前端下载和copy指定列内容,以及django的HTTPResponse实现下载功能
  17. 超详细的ROC曲线绘制教程
  18. web软件上线测试,百度“软件搜索”今日上线测试
  19. 音频可视化(一):音频基础知识
  20. 两台电脑上zotero+坚果云同步文件夹混乱的问题

热门文章

  1. VMware 创建开启虚拟机时候报错的解决方式
  2. Notepad++远程连接Linux系统
  3. 2018中国计算机图形学大会,第十二届中国计算机图形学大会 (Chinagraph2018)
  4. 量子纠缠在量子计算机中的作用,量子纠缠
  5. redis value多大会影响性能_选择合适Redis数据结构,减少80%的内存占用
  6. unsigned short占几个字节_ARM中,字、半字、字节分别是多少位?
  7. rs232转usb驱动for server 2008_电子史 · 什么插头是需要转一圈才能插进去的?
  8. 自制一个害羞的口罩,见人就闭嘴,戴着可以喝奶茶
  9. VHDL-std_logic_vector转换为integer注意
  10. android 电池栏的高度,Android如何取得状态栏、任务栏高度