c语言dll c 调用

99ANYc3cd6
预计阅读时长 18 分钟
位置: 首页 C语言 正文
  1. 创建 DLL (动态链接库):编写代码并编译成 .dll 文件。
  2. 创建导入库 (.lib):为了让调用方能顺利链接,我们需要一个 .lib 文件。
  3. 调用 DLL (可执行程序):编写代码,加载 DLL 并调用其中的函数。

环境准备

我们将使用 Visual Studio 和它的 MSVC (Microsoft Visual C++) 编译器,因为它对 Windows 平台的 DLL 支持最简单、最标准,如果你使用 MinGW (GCC),语法略有不同,但核心概念一致。

c语言dll c 调用
(图片来源网络,侵删)
  1. 安装 Visual Studio (Community 版本是免费的)。
  2. 在安装时,确保勾选了 “使用 C++ 的桌面开发” 工作负载。

第一部分:创建 DLL 项目

我们将创建一个名为 MyMathLib 的数学库,它包含两个函数:AddMultiply

创建项目

  1. 打开 Visual Studio。
  2. 选择 “创建新项目”。
  3. 搜索并选择 “动态链接库 (DLL)” 模板,然后点击 “下一步”。
  4. 项目命名为 MyMathLib,选择一个位置,然后点击 “创建”。

编写 DLL 代码

Visual Studio 会为你生成一个 dllmain.c 文件,我们可以直接修改它,或者创建一个新的 .c 文件,为了清晰,我们创建一个 math.c 文件。

math.c

#include <windows.h> // 包含 Windows API 头文件,用于导出函数
// 定义导出宏,这是告诉编译器哪些函数需要被导出到 DLL 中的关键。
// 当 DLL 编译时,__declspec(dllexport) 会使函数可见。
// 当调用方编译时,这个宏应该是空的,所以我们通常使用条件编译。
#ifdef MYMATHLIB_EXPORTS // 在项目设置中定义这个宏
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif
// 导出的加法函数
API int Add(int a, int b) {
    return a + b;
}
// 导出的乘法函数
API int Multiply(int a, int b) {
    return a * b;
}

math.h (头文件)

c语言dll c 调用
(图片来源网络,侵删)
#ifndef MATH_H
#define MATH_H
// 同样,在头文件中也使用这个宏来确保正确的导入/导出声明
#ifdef MYMATHLIB_EXPORTS
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif
// 声明导出的函数,这样调用方可以知道这些函数的存在
API int Add(int a, int b);
API int Multiply(int a, int b);
#endif // MATH_H

设置项目属性以导出函数

为了让 MYMATHLIB_EXPORTS 宏在编译 DLL 时被定义,我们需要在项目属性中进行设置:

  1. 在 “解决方案资源管理器” 中右键点击 MyMathLib 项目。
  2. 选择 “属性”。
  3. 在 “C/C++” -> “预处理器” -> “预处理器定义” 中,添加 MYMATHLIB_EXPORTS; (注意分号)。
  4. 点击 “应用” 和 “确定”。

编译 DLL

按下 Ctrl + B (生成解决方案) 或点击菜单栏的 “生成” -> “生成解决方案”。

编译成功后,你会在项目的 x64/Debug (或 x64/Release) 目录下找到两个关键文件:

  • MyMathLib.dll:动态链接库文件,这是运行时需要的。
  • MyMathLib.lib:导入库文件,这是链接时需要的。

第二部分:调用 DLL 项目

现在我们创建一个新的控制台应用程序来使用刚刚创建的 MyMathLib.dll

c语言dll c 调用
(图片来源网络,侵删)

创建项目

  1. 在 Visual Studio 中,“创建新项目”。
  2. 选择 “控制台应用” 模板,语言选择 C++。
  3. 项目命名为 MyMathApp,然后点击 “创建”。

准备工作

  1. 复制文件:将 MyMathLib.dllMyMathLib.libMyMathLib 的输出目录复制到 MyMathApp 的输出目录 (x64/Debugx64/Release)。
    • 为什么? MyMathApp.exe 运行时需要 MyMathLib.dll,链接器需要 MyMathLib.lib 来找到函数的地址。
  2. 包含头文件:将 MyMathLib 项目中的 math.h 复制到 MyMathApp 项目文件夹下,并在你的源文件中包含它。

编写调用代码

有两种主要的方式来调用 DLL 中的函数:

  • 隐式链接 (Implicit Linking / 静态加载)

    • 这是最简单、最常用的方式,它通过链接器在程序启动时自动加载 DLL。
    • 你需要 .lib 文件和 .h 文件。
  • 显式链接 (Explicit Linking / 动态加载)

    • 更灵活,也更复杂,你在程序运行时手动加载和卸载 DLL。
    • 你只需要 .dll 文件,不需要 .lib 文件。

隐式链接 (推荐用于开发)

这是最标准、最简单的方法,链接器会帮你处理大部分事情。

main.c

#include <stdio.h>
#include <windows.h> // 包含 Windows API
// 包含我们自己的头文件
// 注意:这里不需要定义 MYMATHLIB_EXPORTS,因为我们是在“导入”函数
#include "math.h"
int main() {
    int result1 = Add(10, 20);
    printf("隐式链接: 10 + 20 = %d\n", result1);
    int result2 = Multiply(10, 20);
    printf("隐式链接: 10 * 20 = %d\n", result2);
    // 程序结束时,Windows 会自动卸载 DLL
    printf("程序执行完毕,\n");
    return 0;
}

配置链接器:

为了让链接器知道去哪里找 MyMathLib.lib,你需要设置它的附加依赖项。

  1. 右键点击 MyMathApp 项目 -> “属性”。
  2. 转到 “链接器” -> “输入” -> “附加依赖项”。
  3. 在输入框中,添加 MyMathLib.lib
  4. 确保 “链接器” -> “常规” -> “附加库目录” 指向了 MyMathLib.lib 所在的目录(通常是 MyMathApp 的输出目录)。
  5. 点击 “应用” 和 “确定”。

显式链接 (更灵活)

这种方法在运行时通过 API 加载 DLL,适合插件系统或可选功能。

main.c

#include <stdio.h>
#include <windows.h>
// 为了使用显式链接,我们不能直接使用 API 宏,需要自己处理函数指针
// 我们可以直接声明函数原型,但用 typedef 来定义函数指针类型,这样更安全
typedef int (*AddFunc)(int, int);
typedef int (*MultiplyFunc)(int, int);
int main() {
    // 1. 加载 DLL
    HMODULE hDll = LoadLibrary(L"MyMathLib.dll"); // 注意:使用宽字符 L"..."
    if (hDll == NULL) {
        printf("错误: 无法加载 MyMathLib.dll,请确保 DLL 文件在正确的路径下,\n");
        return 1;
    }
    // 2. 从 DLL 中获取函数地址
    AddFunc pAdd = (AddFunc)GetProcAddress(hDll, "Add");
    MultiplyFunc pMultiply = (MultiplyFunc)GetProcAddress(hDll, "Multiply");
    if (pAdd == NULL || pMultiply == NULL) {
        printf("错误: 无法从 DLL 中获取函数地址,\n");
        FreeLibrary(hDll); // 加载失败,记得释放
        return 1;
    }
    // 3. 调用函数
    int result1 = pAdd(10, 20);
    printf("显式链接: 10 + 20 = %d\n", result1);
    int result2 = pMultiply(10, 20);
    printf("显式链接: 10 * 20 = %d\n", result2);
    // 4. 卸载 DLL
    FreeLibrary(hDll);
    printf("程序执行完毕,\n");
    return 0;
}

注意:使用显式链接时,你不需要在项目属性中设置 .lib 文件,也不需要包含那个特殊的 math.h,你只需要标准的 windows.h


总结与对比

特性 隐式链接 显式链接
所需文件 .dll, .lib, .h 仅需 .dll
加载时机 程序启动时,由操作系统加载 运行时,由 LoadLibrary 手动加载
链接方式 编译时链接器处理 运行时 GetProcAddress 获取函数地址
优点 简单,代码清晰,编译器检查类型 灵活,可以按需加载/卸载,适合插件
缺点 程序启动时必须能找到 DLL 代码复杂,需要手动处理函数指针和错误
适用场景 标准库开发,依赖关系明确的程序 插件系统,可选功能,版本管理

对于初学者和大多数应用场景,隐式链接是首选,只有当你需要高度的灵活性时,才考虑使用显式链接

编译并运行 MyMathApp 项目,你应该能看到成功调用 DLL 函数的输出。

-- 展开阅读全文 --
头像
哪种C语言编程软件最适合初学者?
« 上一篇 今天
dedecms如何搭建高效电商站点?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]