VS开发C++动态库及其调用程序

用VS建立一个解决方案,包括两个项目:动态库TestDll和应用程序TestExe。以下详细介绍TestDll动态库配置导出类和函数的方法,以及TestExe应用程序如何调用TestDll和配置项目依赖关系。

一、VS2019创建动态库项目并导出类和函数

1、创建动态库项目TestDll

创建TestDll动态库成功后,VS已经为库项目声明了一个预处理定义符:TESTDLL_EXPORTS(自动生成规则:项目名称大写+下划线+EXPORTS):

添加global.h头文件,利用预处理定义TESTDLL_EXPORTS增加类导出符和函数导出符,如下所示:

#pragma once
//导出类:如果有预定义,就是导出的,否则就是导入的宏
#ifdef TESTDLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API__declspec(dllimport)
#endif
 
//导出函数:如果有预定义,就是导出的,否则就是导入的宏
#ifdef TESTDLL_EXPORTS
#define DLL_API_C extern "C" __declspec(dllexport)
#else
#defineDLL_API_C extern "C" __declspec(dllimport)
#endif
 
//导出函数
DLL_API_C int calculate(int x, int y);

global.h文件,定义了DLL_API是导出类的声明符,DLL_API_C是导出函数的声明符,头文件最后还添加了一个caculate函数导出声明,caculate函数定义可在主函数的cpp文件中实现。

另外,TestDll项目添加了Shape父类,Circle和Square子类,这几个类的介绍可参见《C++虚函数多态和纯虚函数多态的经典用法》,这几个类以及整个解决方案可免费下载。TestDll项目组成如下所示:

2、导出Circle、Square类和calculate()函数

只有导出类和函数才能被其他程序调用。首先导出Circle类,修改Circle.h头文件

#pragma once
#include "global.h"
#include "Shape.h"
class DLL_API Circle:public Shape
{
public:
    Circle(){};
    Circle(std::string strName):Shape(strName) {};
    ~Circle(){};
    void init() override;
    void setRadius(int iRadius);
    virtual float getArea() override;
    virtual int getRadius() override;
private:
    int _iRadius;
};

由上可见,Circle类增加DLL_API即可导出;

同理,Square类增加DLL_API导出。

然后在动态库主函数cpp文件中增加calculate()函数的实现:

#include "pch.h"
#include "global.h"
DLL_API_C int calculate(int x, int y) {
   return x * y;
}
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
   switch (ul_reason_for_call)
   {
   case DLL_PROCESS_ATTACH:
   case DLL_THREAD_ATTACH:
   case DLL_THREAD_DETACH:
   case DLL_PROCESS_DETACH:
       break;
   }
   return TRUE;
}

由上可见,calculate()函数的实现也要由导出符DLL_API_C声明。

二、VS2019创建应用程序并调用动态库

1、创建TestExe应用程序

在解决方案中添加新控制台应用项目TestExe。解决方案中包含两个项目,一个是TestDll库项目,一个是TestExe应用程序项目,如下所示:

在TestExe.cpp应用程序文件中添加如下代码,包含Circle.h和Square.h头文件(global.h包含于两个类头文件,因此也包含了calculate()导出函数的声明),即可调用TestDll库的导出类Circle、Square和导出函数calculate():

#include <iostream>
#include "Circle.h"
#include "Square.h"
int main()
{
   std::cout << "Call the dll function caculate. " << std::endl;
   int iZ =caculate(2, 10);
   std::cout << "caculate iZ:" << iZ << std::endl;
   std::cout << "Please input a number :1 or 2. 1 means a circleshape,2 means a square shape. " << std::endl;
   intiShapeType = 0;//1或者2分别代表圆和正方形
   std::cin >>iShapeType;
   Shape* pShape= nullptr;
   if(iShapeType == 1)
       pShape = new Circle("Circle");
   else if (iShapeType == 2)
       pShape = new Square("Square");
   else {
       std::cout << "Input error.";
       return 0;
   }
   pShape->init();
   float fArea =pShape->getArea();
   std::cout <<pShape->getName() << " Area:" << fArea << std::endl;
   int iPosX,iPosY;
   pShape->getPos(iPosX, iPosY);
   std::cout <<pShape->getName() << " CenterPosX:" << iPosX << " CenterPosY:" << iPosY << std::endl;
   intiSideLen = pShape->getSideLength();
   std::cout <<pShape->getName() << " SideLength:" << iSideLen << std::endl;
   int iRadius= pShape->getRadius();
   std::cout <<pShape->getName() << " Radius:" << iRadius << std::endl;
}

此时还需要配置TestExe,包含TestDll的所需头文件,以及显式配置TestDll库的导入。

2、配置TestExe调用TestDll库

(1)配置包含TestDll库的头文件路径

C/C++——>常规——>附加包含目录,填写相对路径:..\TestDll

(2)链接库设置,配置链接TestDll

TestDll库项目编译后生成TestDll.lib和TestDll.dll两个文件,采用 TestExe应用程序显式链接lib的配置方式,首先链接器——>常规——>附加库目录:配置TestDll的lib库编译生成路径。

其次添加TestExe应用程序的lib依赖,链接器——>输入——>附加依赖项:添加TestDll.lib。

至此TestExe应用程序项目配置调用动态库完毕,可以编译运行了(由于两个项目在一个解决方案中,TestDll生成的dll文件与TestExe的exe文件在同一个目录下,exe可直接运行)。另外,可设置TestExe项目依赖于TestDll项目(TestExe项目右键——>生成依赖项——>项目依赖项),每次TestExe重编译时,如果TestDll已经改动,会先编译TestDll后编译TestExe。

CSDN免费下载: C++动态库创建和应用程序调用动态库的源码

猜你喜欢

转载自blog.csdn.net/weixin_43369786/article/details/129218052