文章目录
DLL编写
新建一个C/ C++ library工程
注意type选shared是动态库,选static是静态库,这里选shared
添加导出函数
library.h
#ifndef DLL_GENERATE_LIBRARY_H
#define DLL_GENERATE_LIBRARY_H
// extern "C":以C方式导出
// __declspec(dllexport) 声明一个导出函数
extern "C" __declspec(dllexport) void MyAdd(int a, int b);
#endif //DLL_GENERATE_LIBRARY_H
library.cpp
#include "library.h"
#include <iostream>
// 实现
void MyAdd(int a, int b) {
std::cout << a + b << std::endl;
}
编译
编译后生成在CMakeFiles文件夹下生成dll文件
静态调用和动态调用简介
static
:通过链接器将DLL的导出函数写入exe中
dynamic
:不是在链接时完成的,而是在运行时完成的,不会在exe中写入DLL的函数
区别
:静态调用时,如果装载器找不到DLL,程序会直接报错退出;动态调用时如果找不到DLL,程序的其他部分可以正常执行
动态调用函数
LoadLibrary
GetProcAddress
比较
-
静态调用在编译时就将dll的导出函数写入exe,所以其在编译时需指定dll文件的位置
而动态调用是exe执行时进行Load,因此load传参时,应以exe所在目录作为当前工作目录,传入dll文件的相对路径,注意不同OS下文件路径的写法。
-
静态调用时,函数的声明方式是使用extern声明一个外部函数,提示编译器到别的文件中寻找此函数的实现。
extern详解而动态调用是通过typedef定义函数指针,指向一个与导出函数同返回值同参数的函数,然后在dll中获得导出函数的地址,强转为此种指针,就可以通过此指针变量进行函数调用了。
函数指针及其定义和用法
静态调用DLL
新建一个C++ Executable工程
目录、配置项、环境变量
新建目录lib,把上个工程生成的dll拷贝进去
CMakeLists修改
cmake_minimum_required(VERSION 3.13)
project(dll_use)
set(CMAKE_CXX_STANDARD 14)
# 指定lib目录为当前目录下的lib文件夹
link_directories(lib)
add_executable(dll_use main.cpp)
target_link_libraries(dll_use libdll_generate.dll)
环境变量的值:lib目录的绝对路径
编码
main.cpp
#include <iostream>
// 声明一个使用C命名约定的外部函数(DLL中)
extern "C"{
void MyAdd(int a, int b);
}
int main() {
MyAdd(1, 2);
return 0;
}
编译运行
动态调用DLL
目录结构
注意是以exe所在目录为当前目录,写dll的相对路径
代码
#include <iostream>
#include <windows.h>
// 定义一种名为lpMyAdd的函数指针,此函数以两个int为参数,返回值为void
typedef void (*lpMyAdd)(int, int);
int main() {
// DLL句柄
HINSTANCE hModule;
// 函数指针
lpMyAdd MyAdd;
// 加载DLL
hModule = LoadLibrary("..\\lib\\libdll_generate.dll");
if (hModule != NULL) {
// 传入DLL句柄,获得MyAdd函数的地址,然后强转为lpMyAdd类型
MyAdd = (lpMyAdd) GetProcAddress(hModule, "MyAdd");
if (MyAdd != NULL) {
MyAdd(1, 2);
}
else {
std::cout << "cannot find func" << std::endl;
}
// 释放
FreeLibrary(hModule);
}
else {
std::cout << "cannot load dll" <<std::endl;
}
return 0;
}