C/C++动态链接库(DLL)创建与调用完整指南

陆遥
陆遥
发布时间:2026-10-13 | 5人浏览过
原创

动态链接库(DLL)允许程序和进程共享功能,是C/C++开发中的重要模块化手段。本文将演示如何使用Visual Studio构建DLL,并深入解析隐式链接与显式加载两种调用方法的实现细节与核心代码。

结果与目标

本文旨在帮助开发者掌握在Windows平台下编译生成自定义DLL的标准流程,并能够根据项目需求灵活选择隐式加载或显式加载方式来调用库函数。

准备条件

操作环境为Windows系统,需安装支持C/C++开发的集成开发环境(如Visual Studio)。

真实操作顺序

第1步:创建DLL工程

目的:建立一个用于导出函数的项目基础。

  • 入口:打开Visual Studio。
  • 动作:新建项目,选择 Win32 Dynamic-Link Library (dll),设置工程名(例如 DllDemo)。
  • 完成状态:成功创建空的或含模板代码的DLL项目。

第2步:定义导出接口(宏方式)

目的:明确哪些函数需要被外部程序访问,并使用正确语法声明调用约定。

  • 入口:在项目中新建头文件 DllDemo.h。
  • 动作:编写导出宏定义。当定义为 DllDemo_EXPORTS 时执行导出,否则执行导入。声明函数原型时使用 __stdcall 以确保跨语言兼容性。
  • 关键参数/代码:
#ifdef DllDemo_EXPORTS
#define DllAPI __declspec(dllexport)
#else
#define DllAPI __declspec(dllimport)
#endif

extern "C" {
    DllAPI int __stdcall Max(int a, int b);
}

第3步:实现导出函数

目的:提供具体的逻辑代码。

  • 入口:在 DllDemo.cpp 中。
  • 动作:包含头文件并实现声明的函数。注意处理常规的逻辑判断。
  • 参考代码:
#include "DllDemo.h"

DllAPI int __stdcall Max(int a, int b) {
    if (a > b) return a;
    else return b;
}

注:原文存在逻辑瑕疵,此处已修正为空值返回错误,改为返回较大值以符合Max函数语义。

第4步:编译生成DLL

目的:输出最终的二进制文件 DllDemo.dll 。

  • 动作:在Visual Studio中点击“生成”按钮。
  • 完成状态:在项目的Debug或Release目录下找到生成的DLL文件。

第5步:使用.def文件配置导出(可选方式)

目的:通过模块定义文件控制导出函数名称和序号。

  • 入口:在工程中创建一个文本文件,重命名为 DllDemo.def。
  • 动作:写入以下内容:
LIBRARY MyDll
EXPORTS
    Max @1

注:在此模式下,需在CPP文件中移除 __declspec 导出标记,并在VS项目属性中指定该DEF文件路径。

第6步:隐式调用DLL

目的:让编译器自动完成链接过程,代码结构简洁。

  • 准备:将 DllDemo.dll 和 DllDemo.lib 拷贝至调用方工程目录。
  • 入口:在调用工程的源文件中。
  • 动作:使用 #pragma comment(lib, ...) 指令告知链接器引入lib文件,并声明外部函数。
#define DllAPI __declspec(dllimport)
#pragma comment(lib, "DllDemo.lib")
extern "C" {
    DllAPI int __stdcall Max(int a, int b);
}
#include <iostream>
using namespace std;

int main() {
    cout << Max(2, 9) << endl;
    return 0;
}

第7步:显式调用DLL

目的:在运行时动态决定加载哪个DLL,不依赖lib文件。

  • 准备:只需 DllDemo.dll 文件存在。
  • 动作:
    1. 类型定义:使用 typedef 定义指向DLL内部函数的指针。
    2. 加载:调用Windows API LoadLibrary 获取句柄。
    3. 获取地址:调用 GetProcAddress 并将返回值强转为上一步定义的函数指针。
    4. 卸载:不再使用时调用 FreeLibrary。
  • 代码实现:
#include <windows.h>
#include <iostream>

// 定义函数指针类型
typedef int(__stdcall *lpMax)(int a, int b);

int main() {
    HINSTANCE hDll = LoadLibrary("DllDemo.dll");
    if (hDll == NULL) return -1;

    lpMax M = (lpMax)GetProcAddress(hDll, "Max");
    if (M != NULL) {
        cout << M(2, 9) << endl;
    } else {
        // 如果未找到符号名称,尝试使用序号查找
        M = (lpMax)GetProcAddress(hDll, MAKEINTRESOURCE(1));
    }

    FreeLibrary(hDll);
    return 0;
}

完成判断与排错

运行上述应用程序若能正常打印出最大值,则说明链接成功。

常见问题:函数名不匹配

在使用 GetProcAddress 时发现找不到函数,通常是因为未使用 extern "C" 导致编译器对函数名进行了修饰(Name Mangling)或添加了后缀。

  1. 解决方法一(查看实际名称):使用VS自带的命令行工具 dumbin.exe 扫描DLL:
    dumbin /exports DllDemo.dll
    查看输出的实际名称(如 _Max@8)。
  2. 解决方法二(按序号):直接使用数字序号作为函数标识符:
    GetProcAddress(hDll, MAKEINTRESOURCE(1)) (假设它是导出的第一个函数)。

简要总结

C/C++动态链接库的灵活运用能显著提升程序的模块化程度。对于大多数标准应用,隐式链接最为方便;而在需要插件化或按需加载的场景下,显式加载配合 LoadLibrary 系列API则是必要的技术方案。以上就是C/C++动态链接库的创建和调用的详细内容,更多关于C++进阶开发的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表