以下示例均在VS2022环境下完成。
一、创建动态链接库(C++)
1.新建动态链接库项目模版:
2.新建项目MyC++_Dll后,默认目录结构如下:
3.添加并新建头文件MyC++_Dll.h和源码文件MyC++_Dll.cpp(用于声明和定义函数接口):
4.MyC++_Dll.h示例如下:
#pragma once#ifdef _EXPORTING#define _DLL_API _declspec(dllexport)#else#define _DLL_API _declspec(dllimport)#endif#ifdef __cplusplusclass Dll_Class{public:Dll_Class();~Dll_Class();virtual int Addition(int a, int b);};extern "C"{_DLL_API Dll_Class *CreateObject();_DLL_API void ReleaseObject(Dll_Class *pObject);_DLL_API int Multiplication_TypeC(int a, int b);_DLL_API int Addition_TypeC(int a, int b);}#endif
注意:
_EXPORTING 是笔者自定义宏,用于区分当前是导出dll还是调用dll,要实现导出函数,还需要在实现Dll函数功能的项目属性里,添加预处理定义(记得结尾加分号),如下图:
_declspec(dllexport) 是VC的关键字,表示导出函数到dll;
_declspec(dllimport) 是VC的关键字,表示从dll调用函数;
_DLL_API 是笔者自定义宏,用于给需要导入导出的函数接口简化代码、快速替换_declspec(dllimport)和_declspec(dllexport)关键字;
如果_EXPORTING被定义,采用导出模式,否则为调用模式;
__cplusplus 宏表示采用的是C++的编译环境,通过#ifdef __cplusplus可判断当前是否为C++的编译环境;
extern "C" {} 表示代码块内的函数采用C语言方式编译.
5.MyC++_Dll.cpp示例如下(具体功能实现):
#include "pch.h"#include "MyC++_Dll.h"Dll_Class::Dll_Class() {}Dll_Class::~Dll_Class() {}int Dll_Class::Addition(int a, int b) {return a + b;}Dll_Class* CreateObject() {Dll_Class* pClass = new Dll_Class();return pClass;}void ReleaseObject(Dll_Class* pObject) {if (pObject) {delete pObject;pObject = NULL;}}int Multiplication_TypeC(int a, int b) {return a * b;}int Addition_TypeC(int a, int b) {return a + b;}
6.编译代码生成lib和dll等文件,如下图:
二、创建动态链接库(C)
1.新建空项目MyC_Dll:
2.添加并新建头文件MyC_Dll.h和源码文件MyC_Dll.cpp(用于声明和定义函数接口):
3.MyC_Dll.h示例如下:
#ifndef _MYC_DLL_HEADER_FILE#define _MYC_DLL_HEADER_FILE#ifdef _EXPORTING#define _DLL_API __declspec(dllexport)#else#define _DLL_API __declspec(dllimport)#endif#ifdef __cplusplusextern "C"{_DLL_API int Addition_TypeC(int a, int b);_DLL_API int Multiplication_TypeC(int a, int b);}#endif#endif
注意:
_EXPORTING 是笔者自定义宏,用于区分当前是导出dll还是调用dll,要实现导出函数,还需要在实现Dll函数功能的项目属性里,添加预处理定义(记得结尾加分号),如下图:
_declspec(dllexport) 是VC的关键字,表示导出函数到dll;
_declspec(dllimport) 是VC的关键字,表示从dll调用函数;
_DLL_API 是笔者自定义宏,用于给需要导入导出的函数接口简化代码、快速替换_declspec(dllimport)和_declspec(dllexport)关键字;
如果_EXPORTING被定义,采用导出模式,否则为调用模式;
__cplusplus 宏表示采用的是C++的编译环境,通过#ifdef __cplusplus可判断当前是否为C++的编译环境;
extern "C" {} 表示代码块内的函数采用C语言方式编译.
4.MyC_Dll.cpp示例如下(具体功能实现):
#include "MyC_Dll.h"int Addition_TypeC(int a, int b) {return a + b;}int Multiplication_TypeC(int a, int b) {return a * b;}
5.要在项目属性里修改配置类型为动态库(.dll)才能生成dll,如下图:
6.编译代码生成lib和dll等文件,如下图:
三、隐式调用Dll
1.创建空项目Call_dll:
2.添加并新建源码文件Call_Dll.cpp:
3.Call_Dll.cpp示例如下(具体调用函数接口实现):
//定义是否用C语言编译//#define USING_C#ifdef USING_C#include <stdio.h>#include "../MyC_Dll/MyC_Dll.h"#pragma comment(lib, "../Debug/MyC_Dll.lib")#else#include <iostream>using namespace std;#include "../MyC++_Dll/MyC++_Dll.h"#pragma comment(lib, "../Debug/MyC++_Dll.lib")#endifint main(){#ifdef USING_Cint a = 8, b = 6;printf("Addition_TypeC result = %d\n", Addition_TypeC(a, b));printf("Multiplication_TypeC result = %d\n", Multiplication_TypeC(a, b));#elseint a = 8, b = 6;Dll_Class* pMyDll_Object = CreateObject();cout << "My_Dll_Class.Addition result = " << pMyDll_Object->Addition(a, b) << endl;cout << "Addition_TypeC result = " << Addition_TypeC(a, b) << endl;cout << "Multiplication_TypeC result = " << Multiplication_TypeC(a, b) << endl;ReleaseObject(pMyDll_Object);#endifreturn 0;}
注意:
(1)#pragma comment(lib, Lib文件)和 #include "dll头文件"要确保真实存在的路径.
(2)笔者这里用#ifdef USING_C来选择用C语言还是C++风格(二者主要区别在于用C还是C++编程语句,以及调用Dll的数据结构类型,是否是C++独有的)调用.
4.Dll文件复制到Call_Dll项目生成的目标路径,如下图:
注意:隐式调用,要求dll文件与exe文件在同一目录或者dll文件注册在操作系统的全局运行环境.
5.编译代码生成exe文件,运行结果如下图:
C++:
C:
四、显式调用Dll
1.创建空项目Call_dll:
2.添加并新建源码文件Call_Dll.cpp:
3.Call_Dll.cpp示例如下(具体调用函数接口实现):
//定义是否用C语言编译//#define USING_C#ifdef USING_C#include <stdio.h>#else#include <iostream>using namespace std;#endif#include <Windows.h>int main(){HINSTANCE hdll;#ifdef USING_Ctypedef int (*_Fun_Addition_TypeC)(int, int);typedef int (*_Fun_Multiplication_TypeC)(int, int);hdll = LoadLibrary(L"MyC_Dll.dll");if (hdll == NULL) {printf("Error: Load dll fail.\n");return -1;}_Fun_Addition_TypeC Addition_TypeC;_Fun_Multiplication_TypeC Multiplication_TypeC;Addition_TypeC = (_Fun_Addition_TypeC)GetProcAddress(hdll, "Addition_TypeC");Multiplication_TypeC = (_Fun_Multiplication_TypeC)GetProcAddress(hdll, "Multiplication_TypeC");if (Addition_TypeC == NULL || Multiplication_TypeC == NULL) {printf("Error: Call functions fail.\n");return -2;}int a = 8, b = 6;printf("Addition_TypeC result = %d\n", Addition_TypeC(a, b));printf("Multiplication_TypeC result = %d\n", Multiplication_TypeC(a, b));#elseclass _Dll_Class{public://_Dll_Class();//~_Dll_Class();virtual int Addition(int a, int b)=0;};typedef _Dll_Class* (*_Fun_CreateObject)();typedef void (*_Fun_ReleaseObject)(_Dll_Class*);typedef int (*_Fun_Multiplication_TypeC)(int, int);typedef int (*_Fun_Addition_TypeC)(int, int);hdll = LoadLibrary(L"MyC++_Dll.dll");if (hdll == NULL) {printf("Error: Load dll fail.\n");return -1;}_Fun_CreateObject CreateObject = (_Fun_CreateObject)GetProcAddress(hdll, "CreateObject");_Fun_ReleaseObject ReleaseObject = (_Fun_ReleaseObject)GetProcAddress(hdll, "ReleaseObject");_Fun_Addition_TypeC Addition_TypeC = (_Fun_Addition_TypeC)GetProcAddress(hdll, "Addition_TypeC");_Fun_Multiplication_TypeC Multiplication_TypeC = (_Fun_Multiplication_TypeC)GetProcAddress(hdll, "Multiplication_TypeC");if (CreateObject == NULL || ReleaseObject ==NULL || Addition_TypeC == NULL || Multiplication_TypeC == NULL) {printf("Error: Call functions fail.\n");return -2;}int a = 8, b = 6;_Dll_Class* pMyDll_Object = CreateObject();cout << "My_Dll_Class.Addition result = " << pMyDll_Object->Addition(a, b) << endl;cout << "Addition_TypeC result = " << Addition_TypeC(a, b) << endl;cout << "Multiplication_TypeC result = " << Multiplication_TypeC(a, b) << endl;ReleaseObject(pMyDll_Object);#endifif (hdll == NULL) {FreeLibrary(hdll);hdll = NULL;}return 0;}
注意:
(1)LoadLibrary(dll文件路径)要确保真实存在的路径.
(2)笔者这里用#ifdef USING_C来选择用C语言还是C++风格(二者主要区别在于用C还是C++编程语句,以及调用Dll的数据结构类型,是否是C++独有的)调用.
4.Dll文件复制到LoadLibrary(dll文件路径)指定的路径,如下图:
注意:显式调用,要求dll文件路径与LoadLibrary(dll文件路径)相同,当前示例与exe文件同目录。
5.编译代码生成exe文件,运行结果如下图:
C++:
C: