• 【dll】windows下使用vs编译动态链接库dll与使用


    一、需求

     编译出可供其他平台使用的基于c语言的函数库dll。

    二、前言

     网上很多相关操作,但部分说明不详细或是没有配套的示意图导致操作遇到困难,且使用vs时会由于需要进行各种配置导致编译生成失败,因此才准备将每一步操作都记录下来,确保按照操作步骤能够顺利生成dll库。分为两部分,第一部分是工程创建,经过各种工程类型选择的测试,使用如下方法可减少更多的配置操作。第二部分是c代码编写,涉及到MicrosoftVC的一些关键字与声明的操作。

    三、代码工程与项目操作

    默认已安装且可正常使用visual stdio开发项目。

    3.1新建项目

    左上角标签卡,“文件”->“新建”->“项目”,如下图:

    3.2使用向导新建

    经试验多个项目类,其他类需要创建后进行配置,使用向导新建项目后可直接编译生成dll库。因此选择“Visual C++”->“Windows桌面”->"Windows桌面向导“,命名工程后确认生成,如下图:

     3.3选择应用程序类型

    应用程序类型默认为”.exe“,此时需进入下拉选框选择”动态链接库(dll)“。然后勾选”空项目“确保新生成的工程中代码干净。如下图: 

    3.4创建完成

    此时工程相关操作已完成。

    3.5平台切换

    默认为x86平台,需切换到x64平台,否则生成的dll会造成不兼容导致无法准确读取的情况,配置如图:

    四、c代码操作

    文件创建与基本声明部分省略,源码会放到文章末尾的附录处。

    4.1声明修饰

    如需使用dll,在函数的外部声明处需使用”__declspec(dllexport)“和”__declspec(dllimport)“关键词进行修饰。

    • __declspec(dllexport):用于通过编译产生dll进行数据导出的函数
    • __declspec(dllimport):用于通过调用dll进行获取导入数据的函数

    上述修饰一般在函数类型声明前,如下:

     4.2编译

    编译成功后会在子目录下产生对应工程名称的dll文件,如下:

    五、验证使用

    验证需使用另外一个全新的项目,例如自带”hello world!“的 控制台应用。

    5.1头文件声明

    必备声明如下:

    #include//必备

     5.2读取dll文件

    使用LoadLibrary函数读取,用HINSTANCE类型变量接收。

    1. HINSTANCE hDll = LoadLibrary(_T("dll1.dll"));
    2. if (hDll == NULL) {
    3. printf("lib not exist.");
    4. return 1;
    5. }

     5.3定义函数类型

    已知dll函数的声明类型与参数类型。

    1. using functionPtrCreate = t_obj*(*)();
    2. using functionPtrSetID = void(*)(t_obj*,long);
    3. using functionPtrGetID = long(*)(t_obj*);

    5.4GetProcAddress加载函数

    1. functionPtrCreate objCreate = (functionPtrCreate)GetProcAddress(hDll, "objCreate");
    2. functionPtrSetID objSetID = (functionPtrSetID)GetProcAddress(hDll, "objSetID");
    3. functionPtrGetID objGetID = (functionPtrGetID)GetProcAddress(hDll, "objGetID");

    5.5使用加载的函数输出结果

    输入:

    objSetID(temp, 10086);

     输出:

    std::cout << objGetID(temp);

    结果: 

    附录 源码

    1、dll_config_global.h

    1. #ifndef _DLL_CONFIG_GLOBAL_H_
    2. #define _DLL_CONFIG_GLOBAL_H_
    3. /*逻辑分支,判断环境*/
    4. #if defined(_MSC_VER) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
    5. # define DLL_CONFIG_DECL_EXPORT __declspec(dllexport)//用于dll数据导出
    6. # define DLL_CONFIG_DECL_IMPORT __declspec(dllimport)//用于导入dll数据
    7. #else
    8. # define DLL_CONFIG_DECL_EXPORT __attribute__((visibility("default")))//失效
    9. # define DLL_CONFIG_DECL_IMPORT __attribute__((visibility("default")))//失效
    10. #endif
    11. #endif // _DLL_CONFIG_GLOBAL_H_

     2、dll_demo.h

    1. #ifndef _DLL_DEMO_H_
    2. #define _DLL_DEMO_H_
    3. /*dll编译需要使用的全局配置文件*/
    4. #include "dll_config_global.h"
    5. /*c库*/
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. /*结构体类声明*/
    13. typedef struct _obj {
    14. bool En;//使能
    15. long ID;//id
    16. const char * name;//一般名称
    17. void * data;//数据包
    18. } t_obj;//基本对象
    19. /*函数外部声明*/
    20. #ifdef _cplusplus
    21. extern "C" {
    22. #endif // _cplusplus{}
    23. DLL_CONFIG_DECL_EXPORT t_obj* objCreate();
    24. DLL_CONFIG_DECL_EXPORT void objEnable(t_obj*obj);
    25. DLL_CONFIG_DECL_EXPORT void objDisable(t_obj*obj);
    26. DLL_CONFIG_DECL_EXPORT bool objGetEn(t_obj*obj);
    27. DLL_CONFIG_DECL_EXPORT void objClearID(t_obj*obj);
    28. DLL_CONFIG_DECL_EXPORT void objSetID(t_obj*obj, long val);
    29. DLL_CONFIG_DECL_EXPORT long objGetID(t_obj*obj);
    30. DLL_CONFIG_DECL_EXPORT void objClearName(t_obj*obj);
    31. DLL_CONFIG_DECL_EXPORT void objSetName(t_obj*obj, char*val);
    32. DLL_CONFIG_DECL_EXPORT const char* objGetName(t_obj*obj);
    33. DLL_CONFIG_DECL_EXPORT void objClearData(t_obj*obj);
    34. DLL_CONFIG_DECL_EXPORT void objSetData(t_obj*obj, void*p, long length);
    35. DLL_CONFIG_DECL_EXPORT void* objGetData(t_obj*obj);
    36. #ifdef _cplusplus
    37. #endif // _cplusplus{}
    38. #endif // _DLL_DEMO_H_

    3、dll_demo.c

    1. #include"dll_demo.h"
    2. //----节0
    3. /*创建基本对象*/
    4. DLL_CONFIG_DECL_EXPORT t_obj* objCreate() {
    5. return (t_obj*)malloc(sizeof(t_obj));
    6. }
    7. //----节1
    8. /*使能对象*/
    9. DLL_CONFIG_DECL_EXPORT void objEnable(t_obj*obj)
    10. {
    11. obj->En = true;
    12. }
    13. /*失能对象*/
    14. DLL_CONFIG_DECL_EXPORT void objDisable(t_obj*obj)
    15. {
    16. obj->En = false;
    17. }
    18. /*获取对象状态*/
    19. DLL_CONFIG_DECL_EXPORT bool objGetEn(t_obj*obj)
    20. {
    21. return obj->En;
    22. }
    23. //----节2
    24. /*清空id*/
    25. DLL_CONFIG_DECL_EXPORT void objClearID(t_obj*obj)
    26. {
    27. obj->ID = 0x00;
    28. }
    29. /*设置id*/
    30. DLL_CONFIG_DECL_EXPORT void objSetID(t_obj*obj,long val)
    31. {
    32. obj->ID = val;
    33. }
    34. /*获取对象id*/
    35. DLL_CONFIG_DECL_EXPORT long objGetID(t_obj*obj)
    36. {
    37. return obj->ID;
    38. }
    39. //----节3
    40. /*清空名称*/
    41. DLL_CONFIG_DECL_EXPORT void objClearName(t_obj*obj)
    42. {
    43. obj->name = NULL;
    44. }
    45. /*设置名称*/
    46. DLL_CONFIG_DECL_EXPORT void objSetName(t_obj*obj,char*val)
    47. {
    48. obj->name = val;
    49. }
    50. /*获取对象名称*/
    51. DLL_CONFIG_DECL_EXPORT const char* objGetName(t_obj*obj)
    52. {
    53. return obj->name;
    54. }
    55. //----节4
    56. /*清空数据包*/
    57. DLL_CONFIG_DECL_EXPORT void objClearData(t_obj*obj)
    58. {
    59. free(obj->data);
    60. obj->data = NULL;
    61. }
    62. /*设置数据包*/
    63. DLL_CONFIG_DECL_EXPORT void objSetData(t_obj*obj,void*p,long length)
    64. {
    65. obj->data = malloc(length);
    66. memcpy(obj->data, p, length);
    67. }
    68. /*获取对象数据包*/
    69. DLL_CONFIG_DECL_EXPORT void* objGetData(t_obj*obj)
    70. {
    71. return obj->data;
    72. }

    4、dllUse.cpp

    1. #include
    2. #include//必备
    3. #include
    4. //#pragma comment(lib,"dll1.lib")
    5. typedef struct _obj {
    6. bool En;//使能
    7. long ID;//id
    8. const char * name;//一般名称
    9. void * data;//数据包
    10. } t_obj;//基本对象
    11. int main()
    12. {
    13. HINSTANCE hDll = LoadLibrary(_T("dll1.dll"));
    14. if (hDll == NULL) {
    15. printf("lib not exist.");
    16. return 1;
    17. }
    18. using functionPtrCreate = t_obj*(*)();
    19. using functionPtrSetID = void(*)(t_obj*,long);
    20. using functionPtrGetID = long(*)(t_obj*);
    21. //找到所需要的函数
    22. functionPtrCreate objCreate = (functionPtrCreate)GetProcAddress(hDll, "objCreate");
    23. functionPtrSetID objSetID = (functionPtrSetID)GetProcAddress(hDll, "objSetID");
    24. functionPtrGetID objGetID = (functionPtrGetID)GetProcAddress(hDll, "objGetID");
    25. t_obj* temp = objCreate();
    26. objSetID(temp, 10086);
    27. std::cout << objGetID(temp);
    28. }

  • 相关阅读:
    基于微信健身房私教预约小程序系统设计与实现 开题报告
    HDFS(Hadoop分布式文件系统)具有高吞吐量特点的原因
    vue 环境变量那些事
    python+pytest接口自动化-接口测试基础,http协议基础(一)
    一文搞懂堆外内存(模拟内存泄漏)
    天才程序员周弈帆 | Stable Diffusion 解读(三):原版实现源码解读(篇幅略长,建议收藏!)
    博途PLC S7-1200/1500 ModbusTcp通信SCL代码篇(轮询)
    HYSES data北美多源水文气象数据
    【数据结构初阶】链式二叉树接口实现+痛苦的OJ题
    为什么会出现图里面的状况啊,可以生成可执行文件,但一直说使用未清楚定义的东西,如图上出现红叉的地方
  • 原文地址:https://blog.csdn.net/qq_34217861/article/details/126537073