前言
DLL,即动态链接库,是一种在Windows操作系统中广泛使用的文件类型。在大型项目开发中,通过将编写的功能封装成DLL,可以方便地将这些模块集成到一个程序中,提高团队开发效率。最近一段时间工作上用到dll的生成与调用,在此做一个小结。
一、dll的生成
1.1 dll工程创建
步骤1:创建dll工程,选择动态链接库(DLL)

步骤2:配置项目,添加工程名和保存路径

步骤3:预处理器设置,右击工程属性、在配置属性的C/C++下的预处理器下添加FOUR_OPERATIONS_DLL。

步骤4:创建头文件和源文件,头文件用于放入声明,源文件用于放入代码实现。


1.2 dll代码创建
步骤5:头文件代码,放入封装的类和函数的声明。
#pragma once
#include <iostream>
#ifdef FOUR_OPERATIONS_DLL
#define FOUR_OPERATIONS_API __declspec(dllexport)
#else
#define FOUR_OPERATIONS_API __declspec(dllimport)
#endif
class FOUR_OPERATIONS_API CFourOperations
{
public:
void SetNum1(int iNum1);
void SetNum2(int iNum2);
int GetNum1();
int GetNum2();
int Addition();
int Subtraction();
int Multiplication();
int Division();
private:
int m_iNum1;
int m_iNum2;
};
extern"C"
{
FOUR_OPERATIONS_API int Square(int iNum);
// 导出函数,返回类的实例的指针
FOUR_OPERATIONS_API CFourOperations* CreateClassInstance();
// 导出函数,释放类的实例指针
FOUR_OPERATIONS_API void DeleteClassInstance(CFourOperations* instance);
}
步骤7:源文件代码,放入封装的类和函数的实现。
#include "pch.h"
#include "FourOperationsDll.h"
void CFourOperations::SetNum1(int iNum1)
{
m_iNum1 = iNum1;
}
void CFourOperations::SetNum2(int iNum2)
{
m_iNum2 = iNum2;
}
int CFourOperations::GetNum1()
{
return m_iNum1;
}
int CFourOperations::GetNum2()
{
return m_iNum2;
}
int CFourOperations::Addition()
{
return m_iNum1 + m_iNum2;
}
int CFourOperations::Subtraction()
{
return m_iNum1 - m_iNum2;
}
int CFourOperations::Multiplication()
{
return m_iNum1 * m_iNum2;
}
int CFourOperations::Division()
{
if (0 == m_iNum2)
{
return 0;
}
else
{
return m_iNum1 / m_iNum2;
}
}
extern"C"
{
FOUR_OPERATIONS_API int Square(int iNum)
{
return iNum * iNum;
}
// 导出函数,返回类的实例的指针
FOUR_OPERATIONS_API CFourOperations* CreateClassInstance()
{
return new CFourOperations();
}
// 导出函数,释放类的实例指针
FOUR_OPERATIONS_API void DeleteClassInstance(CFourOperations* instance)
{
delete instance;
}
}
步骤6:在项目处右击选择重新生成,生成dll文件。

步骤7:由文件夹下找到生成的dll文件。

二、dll的调用
接下来我们尝试调用上一章所创建的dll。
2.1 环境配置
步骤1:首先,创建一个新的工程。

步骤2:在工程文件夹下,分别创建dll和include文件夹,放入我们上一章所生成的dll文件和头文件。

步骤3:创建一个demo源文件。

步骤4:添加头文件和lib

#include "..\include\FourOperationsDll.h"
#pragma comment(lib, "../FourOperationsDll/FourOperationsDll.lib")
步骤5:配置dll文件路径,右击项目属性,在配置属性下选择调试,单击环境后取消从父级或项目默认设置继承,在环境对话框下配置dll文件路径path=%path%;…/FourOperationsDll。

2.2 隐式调用
隐式调用是指编译器在编译时会自动处理DLL的加载和卸载。这种方式下,需要将DLL对应的.LIB文件(包含函数入口位置信息)加入到应用程序的工程中。当程序运行时,操作系统会根据.LIB文件中的信息加载相应的DLL文件到内存中。这种方法比较简单,适合常规需求,但可能会导致DLL被多次加载到内存中。
// 隐示调用在配置好环境后可以直接创建类
CFourOperations* p = new CFourOperations();
int iNum1 = 10;
int iNum2 = 6;
// 调用dll的类成员函数
p->SetNum1(iNum1);
p->SetNum2(iNum2);
std::cout << "iNum1 = " << p->GetNum1() << std::endl;
std::cout << "iNum2 = " << p->GetNum2() << std::endl;
std::cout << "iNum1 + iNum2 = " << p->Addition() << std::endl;
std::cout << "iNum1 - iNum2 = " << p->Subtraction() << std::endl;
std::cout << "iNum1 * iNum2 = " << p->Multiplication() << std::endl;
std::cout << "iNum1 / iNum2 = " << p->Division() << std::endl;
// 调用dll的函数
std::cout << "iNum1^2 = " << Square(iNum1) << std::endl;
// 释放对象
delete p;
p = NULL;
2.3 显示调用
显示调用是指程序在运行时手动加载和卸载DLL。这种方式不需要.LIB文件,而是通过特定的API函数(如LoadLibrary和FreeLibrary)来控制DLL的加载和卸载。显示调用允许程序在需要时才加载DLL,不需要时可以卸载,从而节省资源。缺
// 显示调用需要手动调用dll
HMODULE hDll = LoadLibrary(L"FourOperationsDll.dll");
if (hDll == NULL)
{
std::cerr << "Failed to load FourOperationsDll.dll" << std::endl;
return;
}
// 创建函数指针
typedef CFourOperations* (*CreateClassInstanceFunc)();
typedef void (*DeleteClassInstanceFunc)(CFourOperations*);
typedef int(*SquareFunc)(int);
// 获取函数地址
CreateClassInstanceFunc createClassInstance = (CreateClassInstanceFunc)GetProcAddress(hDll, "CreateClassInstance");
if (NULL == createClassInstance)
{
std::cerr << "Failed to get CreateClassInstance function" << std::endl;
FreeLibrary(hDll);
return;
}
DeleteClassInstanceFunc deleteClassInstance = (DeleteClassInstanceFunc)GetProcAddress(hDll, "DeleteClassInstance");
if (NULL == deleteClassInstance)
{
std::cerr << "Failed to get DeleteClassInstance function" << std::endl;
FreeLibrary(hDll);
return;
}
SquareFunc square = (SquareFunc)GetProcAddress(hDll, "Square");
if (NULL == square)
{
std::cerr << "Failed to get Square function" << std::endl;
FreeLibrary(hDll);
return;
}
// 创建对象
CFourOperations* p = createClassInstance();
int iNum1 = 11;
int iNum2 = 5;
// 调用dll的类成员函数
p->SetNum1(iNum1);
p->SetNum2(iNum2);
std::cout << "iNum1 = " << p->GetNum1() << std::endl;
std::cout << "iNum2 = " << p->GetNum2() << std::endl;
std::cout << "iNum1 + iNum2 = " << p->Addition() << std::endl;
std::cout << "iNum1 - iNum2 = " << p->Subtraction() << std::endl;
std::cout << "iNum1 * iNum2 = " << p->Multiplication() << std::endl;
std::cout << "iNum1 / iNum2 = " << p->Division() << std::endl;
// 调用dll的函数
std::cout << "iNum1^2 = " << square(iNum1) << std::endl;
// 释放对象
deleteClassInstance(p);
// 释放dll
FreeLibrary(hDll);
总结
以上就是今天要讲的内容,本文仅仅简单介绍了dll的创建和调用等基本操作。新人能力有限,如有不足之处欢迎大佬指点纠正。
本文详细介绍了如何在Windows平台上创建和调用DLL(动态链接库),包括工程创建、代码实现、头文件配置、环境设置以及隐式调用和显示调用的区别。
6597

被折叠的 条评论
为什么被折叠?



