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


    1.VS生成动态链接库:

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

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

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

    • VS项目属性常见问题

    2.显式加载动态链接库

    显示加载不需要修改项目的任何属性,只需要调用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失败!
    ";
    		return 0;
    	}
    	auto dllFunAdd = (FUN_ADD)GetProcAddress(hModule, "add");
    	auto dllFunSub = (FUN_ADD)GetProcAddress(hModule, "sub");
    	if (dllFunAdd == nullptr || dllFunSub == nullptr)
    	{
    		std::cout << "加载函数失败!
    ";
    		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选项

    3.隐式加载动态链接库

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

  • 相关阅读:
    JeeSite4.x 搭建并部署到服务器
    maven编译时出现There are test failures
    ecplise An incompatible version [1.2.14] of the APR based Apache Tomcat Native library is installed, while T
    maven "mvn不是内部或外部命令,也不是可运行的程序或批处理文件"
    rar自动压缩备份
    mysql 0x80004005 unable to connect to any of the specified mysql hosts
    mysql too many connections
    输出控制台信息到日志 并 通过cronolog对tomcat进行日志切分
    Node.js相关——package概念及NPM
    Node.js相关——CommonJS规范
  • 原文地址:https://www.cnblogs.com/mmmmmmmmm/p/14631336.html
Copyright © 2020-2023  润新知