VC++动态链接库编程之非MFC DLL

本文介绍VC++环境下非MFCDLL的开发,涵盖DLL导出变量、全局变量访问、类的导出与导入等内容,展示了如何在DLL与应用程序间共享数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

VC++动态链接库编程之非MFC DLL

  4.6 DLL导出变量

  DLL定义的全局变量可以被调用进程访问;DLL也可以访问调用进程的全局数据,我们来看看在应用工程中引用DLL中变量的例子( 单击此处下载本工程)。

/* 文件名:lib.h */

#ifndef LIB_H
#define LIB_H
extern int dllGlobalVar;
#endif

/* 文件名:lib.cpp */

#include "lib.h"
#include <windows.h>

int dllGlobalVar;

BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
 switch (ul_reason_for_call)
 {
  case DLL_PROCESS_ATTACH:
   dllGlobalVar = 100; //在dll被加载时,赋全局变量为100
   break;
  case DLL_THREAD_ATTACH:
  case DLL_THREAD_DETACH:
  case DLL_PROCESS_DETACH:
   break;
 }
 return TRUE;
}

  ;文件名:lib.def

  ;在DLL中导出变量

LIBRARY "dllTest"

EXPORTS

dllGlobalVar CONSTANT

;或dllGlobalVar DATA

GetGlobalVar

  从lib.h和lib.cpp中可以看出,全局变量在DLL中的定义和使用方法与一般的程序设计是一样的。若要导出某全局变量,我们需要在.def文件的EXPORTS后添加:

  变量名 CONSTANT   //过时的方法

  或

  变量名 DATA     //VC++提示的新方法

  在主函数中引用DLL中定义的全局变量:

#include <stdio.h>
#pragma comment(lib,"dllTest.lib")

extern int dllGlobalVar;

int main(int argc, char *argv[])
{
 printf("%d ", *(int*)dllGlobalVar);
 *(int*)dllGlobalVar = 1;
 printf("%d ", *(int*)dllGlobalVar);
 return 0;
}

  特别要注意的是用extern int dllGlobalVar声明所导入的并不是DLL中全局变量本身,而是其地址,应用程序必须通过强制指针转换来使用DLL中的全局变量。这一点,从*(int*)dllGlobalVar可以看出。因此在采用这种方式引用DLL全局变量时,千万不要进行这样的赋值操作:

dllGlobalVar = 1;

  其结果是dllGlobalVar指针的内容发生变化,程序中以后再也引用不到DLL中的全局变量了。

  在应用工程中引用DLL中全局变量的一个更好方法是:

#include <stdio.h>
#pragma comment(lib,"dllTest.lib")

extern int _declspec(dllimport) dllGlobalVar; //用_declspec(dllimport)导入
int main(int argc, char *argv[])
{
 printf("%d ", dllGlobalVar);
 dllGlobalVar = 1; //这里就可以直接使用, 无须进行强制指针转换
 printf("%d ", dllGlobalVar);
 return 0;
}

  通过_declspec(dllimport)方式导入的就是DLL中全局变量本身而不再是其地址了,笔者建议在一切可能的情况下都使用这种方式。

  4.7 DLL导出类

  DLL中定义的类可以在应用工程中使用。

  下面的例子里,我们在DLL中定义了point和circle两个类,并在应用工程中引用了它们( 单击此处下载本工程)。

//文件名:point.h,point类的声明

#ifndef POINT_H
#define POINT_H
#ifdef DLL_FILE
 class _declspec(dllexport) point //导出类point
#else
 class _declspec(dllimport) point //导入类point
#endif
{
 public:
  float y;
  float x;
  point();
  point(float x_coordinate, float y_coordinate);
};

#endif

//文件名:point.cpp,point类的实现

#ifndef DLL_FILE
 #define DLL_FILE
#endif

#include "point.h"

//类point的缺省构造函数

point::point()
{
 x = 0.0;
 y = 0.0;
}

//类point的构造函数

point::point(float x_coordinate, float y_coordinate)
{
 x = x_coordinate;
 y = y_coordinate;
}

//文件名:circle.h,circle类的声明

#ifndef CIRCLE_H
#define CIRCLE_H
#include "point.h"
#ifdef DLL_FILE
class _declspec(dllexport)circle //导出类circle
#else
class _declspec(dllimport)circle //导入类circle
#endif
{
 public:
  void SetCentre(const point &centrePoint);
  void SetRadius(float r);
  float GetGirth();
  float GetArea();
  circle();
 private:
  float radius;
  point centre;
};

#endif

//文件名:circle.cpp,circle类的实现

#ifndef DLL_FILE
#define DLL_FILE
#endif
#include "circle.h"
#define PI 3.1415926

//circle类的构造函数

circle::circle()
{
 centre = point(0, 0);
 radius = 0;
}

//得到圆的面积

float circle::GetArea()
{
 return PI *radius * radius;
}

//得到圆的周长

float circle::GetGirth()
{
 return 2 *PI * radius;
}

//设置圆心坐标

void circle::SetCentre(const point &centrePoint)
{
 centre = centrePoint;
}

//设置圆的半径

void circle::SetRadius(float r)
{
 radius = r;
}

  类的引用:

#include "../circle.h"  //包含类声明头文件

#pragma comment(lib,"dllTest.lib");

int main(int argc, char *argv[])
{
 circle c;
 point p(2.0, 2.0);
 c.SetCentre(p);
 c.SetRadius(1.0);
 printf("area:%f girth:%f", c.GetArea(), c.GetGirth());
 return 0;
}

  从上述源代码可以看出,由于在DLL的类实现代码中定义了宏DLL_FILE,故在DLL的实现中所包含的类声明实际上为:

class _declspec(dllexport) point //导出类point
{
 …
}

  和

class _declspec(dllexport) circle //导出类circle
{
 …
}

  而在应用工程中没有定义DLL_FILE,故其包含point.h和circle.h后引入的类声明为:

class _declspec(dllimport) point //导入类point
{
 …
}

  和

class _declspec(dllimport) circle //导入类circle
{
 …
}

  不错,正是通过DLL中的

class _declspec(dllexport) class_name //导出类circle 
{
 …
}

  与应用程序中的

class _declspec(dllimport) class_name //导入类
{
 …
}

  匹对来完成类的导出和导入的!

  我们往往通过在类的声明头文件中用一个宏来决定使其编译为class _declspec(dllexport) class_name还是class _declspec(dllimport) class_name版本,这样就不再需要两个头文件。本程序中使用的是:

#ifdef DLL_FILE
 class _declspec(dllexport) class_name //导出类
#else
 class _declspec(dllimport) class_name //导入类
#endif

  实际上,在MFC DLL的讲解中,您将看到比这更简便的方法,而此处仅仅是为了说明_declspec(dllexport)与_declspec(dllimport)匹对的问题。

  由此可见,应用工程中几乎可以看到DLL中的一切,包括函数、变量以及类,这就是DLL所要提供的强大能力。只要DLL释放这些接口,应用程序使用它就将如同使用本工程中的程序一样!

  本章虽以VC++为平台讲解非MFC DLL,但是这些普遍的概念在其它语言及开发环境中也是相同的,其思维方式可以直接过渡。 接下来,我们将要研究MFC规则DLL。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值