C++ 动态库DLL的使用方法

一、VS生成动态链接库:

  • 使用VS直接新建DLL项目会生成一些多余的文件,所以建议新建空项目,写完代码后,在项目属性页->配置属性->常规->配置类型->改为:动态库DLL,最后生成即可

  • 生成DLL项目和调用DLL项目配置属性要一致(同样是x64或者x86,隐式调用时必须同为release或debug)

  • 导出DLL可以使用__declspec(dllexport)(声明一个导出函数,意味着这个函数要从本DLL导出),也可以使用def文件(如果DLL全是C++类的话,无法使用def文件导出指定函数)

  • VS项目属性常见问题

二、显式加载动态链接库

显示加载不需要修改项目的任何属性,只需要调用LoadLibrary()GetProcAddress()函数即可

具体步骤:加载dll -> 获取函数地址 -> 使用 -> 卸载

生成DLL文件代码:

//.h文件
#pragma once
#ifdef __cplusplus
extern "C"
{
__declspec(dllexport) int add(int a, int b);

__declspec(dllexport) int sub(int a, int b);
}
#endif // __cplusplus

//.cpp文件
#include "MyDLL.h"

int add(int a, int b)
{
	return a + b;
}

int sub(int a, int b)
{
	return a - b;
}

加载DLL文件代码

#include <iostream>
#include <Windows.h>

//声明函数指针,指向找到的函数地址,后面通过函数指针调用DLL中定义的函数
typedef int(*FUN_ADD)(int, int);
typedef int(*FUN_SUB)(int, int);

int main()
{
	HMODULE hModule = LoadLibrary(L"./DLL/bin/13GenerateDLL");
	if (hModule == nullptr)
	{
		std::cout << "加载DLL失败!\n";
		return 0;
	}
	auto dllFunAdd = (FUN_ADD)GetProcAddress(hModule, "add");
	auto dllFunSub = (FUN_ADD)GetProcAddress(hModule, "sub");
	if (dllFunAdd == nullptr || dllFunSub == nullptr)
	{
		std::cout << "加载函数失败!\n";
		return 0;
	}

	std::cout << "3 add 2 :" << dllFunAdd(3, 2) << std::endl;
	std::cout << "4 sub 2 :" << dllFunSub(4, 2) << std::endl;
        
        FreeLibrary(hModule);

	system("pause");
	return 0;
}

说明:

  • 使用显示调用方法(LoadLibrary()),需要以C的方式(extern "C")导出DLL,因为C++有类和重载的缘故,导出的函数名会加上一些符号,将函数原名直接传入GetProcAddress()返回为0,

  • 如果要使用C++方式导出,可以使用depend查看函数符号名,将符号传入GetProcAddress()即可。例如:auto fun = (FUN_ADD)GetProcAddress(hModule, "?add@@YAHHH@Z");

  • 要在导出函数的函数声明之前加上__declspec(dllexport),不然GetProcAddress()找不到函数

  • 对于函数GetPrcoAddress()无论项目属性是宽字符还是窄字符,第二个参数都是ANSI

  • 显式调用必须声明一个函数指针,指向找到的函数地址,通过函数指针调用DLL中定义的函数

  • 函数LoadLibrary()需要包含头文件Windows.h,参数为DLL文件路径名,根据自己需要设置。

  • 使用完DLL记得卸载FreeLibrary();

  • 可以使用DUMPBIN(VS安装目录下有这个程序)查看.obj文件、.lib库、.dll库、.exe执行文件,包含了哪些函数以及相关的信息(符号清单)DUMPBIN选项

三、隐式加载动态链接库

隐式加载需要在项目属性中设置包含目录以及附加项,可以在程序中直接用函数原名调用DLL中的函数

具体步骤:包含头文件 -> 包含lib文件 -> dll添加正确 -> 调用函数原名

生成DLL文件代码:

//.h文件
#pragma once

__declspec(dllexport) int add(int a, int b);

__declspec(dllexport) int sub(int a, int b);

//.cpp文件
#include "MyDLL.h"

int add(int a, int b)
{
	return a + b;
}

int sub(int a, int b)
{
	return a - b;
}

加载DLL文件代码:

#include <iostream>

#include <MyDLL.h>
#pragma comment(lib,"13GenerateDLL.lib")

int main()
{
	std::cout << "3 add 2 :" << add(3, 2) << std::endl;
	std::cout << "4 sub 2 :" << sub(4, 2) << std::endl;

	system("pause");
	return 0;
}

说明:

  • 隐式加载DLL,首先需要将生成DLL的头文件包含到调用DLL的程序中(此处的头文件没有__declspec(dllexport),即只有函数声明),其次再将lib文件包含进去(lib文件会在生成DLL文件时自动生成)

  • 包含lib有两种方式(以下路径中*为本人项目路径,根据自己实际情况填写):

    1. 直接在项目属性中的 链接器->输入->附加依赖项 填入lib的路径,此处需要包含lib文件名,例如:***\12LoadDLL\DLL\lib\13GenerateDLL.lib
    2. 在项目属性中的 链接器->常规->附加库目录 填入lib的路径,此处不需要包含lib文件名,例如:***\12LoadDLL\DLL\lib,然后在调用DLL程序的开头处添加#pragma comment(lib,"13GenerateDLL.lib")
  • 生成的DLL文件必须放到调用DLL程序的exe文件目录下(如果没有正确放置DLL文件,VS2019会报错:无法定位程序输入点...直接双击exe文件(不在vs下调试)会报错:由于找不到*.dll,无法继续执行代码...)

四、VS release断点调试

设置以下选项即可


posted @ 2021-04-08 11:16  滴哒哒哒  阅读(443)  评论(0编辑  收藏  举报