易语言如何调用C语言DLL文件?

99ANYc3cd6
预计阅读时长 22 分钟
位置: 首页 C语言 正文

核心原理:为什么能调用?

易语言之所以能调用 C 的 DLL,是因为它们都遵循 Windows API 调用约定,本质上是操作系统提供的标准机制。

易语言 调用c 的dll文件
(图片来源网络,侵删)
  1. 编译为机器码:无论是用 C 语言(如 Visual C++)还是易语言编写的程序,最终都会被编译成 Windows 操作系统能够理解的机器码(.exe.dll)。
  2. 函数入口点:DLL 文件内部包含一个个的函数,这些函数在编译时会被赋予一个标准的“入口点”或“导出名”(Export Name),当外部程序(如易语言程序)想要调用这个函数时,操作系统会根据这个导出名找到函数在内存中的地址,然后跳转到该地址执行代码。
  3. 参数传递:调用函数时,参数的传递方式(通过堆栈还是寄存器)和清理方式由调用约定决定,C 语言默认使用 __cdecl,而 Windows API 使用 __stdcall,易语言在调用 DLL 时,默认使用 __stdcall,这与 Windows API 完全兼容,所以可以无缝调用。

DLL 就像一个“工具箱”,易语言是“使用者”,C 语言是“制造者”,只要工具箱里的工具(函数)有明确的规格(参数和返回值类型),使用者就能正确地使用它们。


准备工作:编写 C 语言 DLL

我们将使用 Visual Studio 2025/2025 来创建一个简单的 DLL。

创建 DLL 项目

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

编写 C 代码

打开 MyCLib.hMyCLib.cpp 文件,编写如下代码:

MyCLib.h (头文件)

易语言 调用c 的dll文件
(图片来源网络,侵删)
// 为了防止头文件被重复包含
#pragma once
// 使用 extern "C" 来告诉 C++ 编译器,使用 C 语言的命名规则来导出函数
// 这样可以避免 C++ 的名称修饰(Name Mangling),让易语言能找到正确的函数名
#ifdef __cplusplus
extern "C" {
#endif
// 导出函数声明
// __declspec(dllexport) 表示这个函数要从 DLL 中导出出来
// __stdcall 是标准的调用约定,与易语言兼容
__declspec(dllexport) int __stdcall Add(int a, int b);
__declspec(dllexport) const char* __stdcall GetHelloMessage();
__declspec(dllexport) void __stdcall PrintArray(int* arr, int size);
#ifdef __cplusplus
}
#endif

MyCLib.cpp (源文件)

#include "MyCLib.h"
#include <stdio.h> // 用于 printf
// 函数定义
int __stdcall Add(int a, int b) {
    return a + b;
}
const char* __stdcall GetHelloMessage() {
    // 注意:在 DLL 中返回静态字符串或堆上分配的内存是安全的
    // 不要返回局部变量的地址,因为函数结束后局部变量会被销毁
    return "Hello from C DLL!";
}
void __stdcall PrintArray(int* arr, int size) {
    printf("C DLL received an array: [");
    for (int i = 0; i < size; i++) {
        printf("%d", arr[i]);
        if (i < size - 1) {
            printf(", ");
        }
    }
    printf("]\n");
}

编译 DLL

  • 在 Visual Studio 中,选择 生成 -> 生成解决方案 (或按 F7)。
  • 编译成功后,你可以在项目的 x64\Debug (或 x64\Release) 文件夹下找到生成的 DLL 文件:MyCLib.dll
  • 重要:你还需要将 MyCLib.h 头文件复制出来,虽然易语言不直接用它,但它能帮你清晰地知道 DLL 里有哪些函数、参数和返回值类型。

在易语言中调用 DLL

我们打开易语言,来调用刚刚生成的 MyCLib.dll

新建易语言程序

  • 打开易语言,创建一个“Windows 窗口程序”。
  • 在窗口上放置几个控件:
    • 一个“编辑框”,变量名为 编辑框_数值110
    • 另一个“编辑框”,变量名为 编辑框_数值220
    • 一个“按钮”,标题为“调用 Add 函数”,变量名为 按钮_调用加法
    • 一个“标签”,变量名为 标签_结果,用于显示加法结果。
    • 一个“按钮”,标题为“调用 GetHelloMessage”,变量名为 按钮_调用字符串
    • 一个“标签”,变量名为 标签_消息,用于显示字符串。
    • 一个“按钮”,标题为“调用 PrintArray”,变量名为 按钮_调用数组
    • 一个“标签”,变量名为 标签_数组信息,用于显示调用结果。

声明外部 DLL 函数

这是最关键的一步,在易语言代码窗口的“程序集”下,点击“外部DLL命令”,然后点击“新建”。

使用“查看DLL命令”工具(推荐)

易语言 调用c 的dll文件
(图片来源网络,侵删)
  1. 点击工具栏上的“查看DLL命令”按钮。

  2. 在弹出的窗口中,点击“选择DLL”,找到你刚才生成的 MyCLib.dll 文件。

  3. DLL 文件加载后,它会自动扫描并列出所有导出的函数。

  4. 选中 Add 函数,点击“添加”。

  5. 在右侧的“定义”窗口中,你需要设置参数和返回值的类型:

    • 返回值类型:选择“整数”。
    • 参数1:名称可以填 a,类型选择“整数”。
    • 参数2:名称可以填 b,类型选择“整数”。
  6. 点击“确定”,易语言会自动生成代码。

  7. 用同样的方法添加 GetHelloMessagePrintArray 函数。

    • GetHelloMessage:
      • 返回值类型:文本
      • 无参数
    • PrintArray:
      • 返回值类型:无返回值
      • 参数1:名称 arr,类型选择整数型,并勾选“指针”或“地址”。
      • 参数2:名称 size,类型选择“整数”。

手动编写声明代码

如果你没有“查看DLL命令”工具,或者想手动控制,可以直接在代码编辑器中输入:

.版本 2
.程序集 窗口程序集_启动窗口
.子程序 __启动窗口_创建完毕, , 公开
.局部变量 a, 整数)
.局部变量 b, 整数)
.局部变量 p, 整数型) ' 用于接收数组指针
.(真)
    ' --- 声明外部 DLL 函数 ---
    .子程序 Add, 整数, 公开, "MyCLib.dll"
    .参数 a, 整数
    .参数 b, 整数
    .子程序 GetHelloMessage, 文本, 公开, "MyCLib.dll"
    ' 无参数
    .子程序 PrintArray, , 公开, "MyCLib.dll"
    .参数 arr, 整数型, , 指针 ' 声明为指针类型
    .参数 size, 整数
.如果结束

注意.版本 2 是必须的,它让易语言支持更现代的语法,特别是“指针”类型的参数。

编写按钮事件代码

为按钮编写点击事件。

“调用 Add 函数”按钮的代码:

.版本 2
.程序集 窗口程序集_启动窗口
.子程序 _按钮_调用加法_被单击
.局部变量 结果, 整数)
' 从编辑框获取数值
结果 = 编辑框_数值1.取文本到数值 (真)
.(结果 = 0, 真)
    信息框 (“数值1输入无效!”, 0, , )
    返回 ()
.否则
    .局部变量 a, 整数)
    a = 结果
.如果结束
结果 = 编辑框_数值2.取文本到数值 (真)
.(结果 = 0, 真)
    信息框 (“数值2输入无效!”, 0, , )
    返回 ()
.否则
    .局部变量 b, 整数)
    b = 结果
.如果结束
' 调用 C DLL 中的 Add 函数
结果 = Add (a, b)
' 显示结果
标签_结果.内容 = “计算结果: ” = 到文本 (结果)

“调用 GetHelloMessage”按钮的代码:

.版本 2
.程序集 窗口程序集_启动窗口
.子程序 _按钮_调用字符串_被单击
.局部变量 消息, 文本)
' 调用 C DLL 中的 GetHelloMessage 函数
消息 = GetHelloMessage ()
' 显示消息
标签_消息.内容 = 消息

“调用 PrintArray”按钮的代码:

.版本 2
.程序集 窗口程序集_启动窗口
.子程序 _按钮_调用数组_被单击
.局部变量 数组数据, 整数, , "0,1,2,3,4")
.局部变量 数组大小, 整数)
.局部变量 p, 整数型) ' 指针变量
' 准备数据
数组大小 = 取数组成员数 (数组数据)
' 关键步骤:获取数组的内存地址(指针)
p = 取数据地址 (数组数据)
' 调用 C DLL 中的 PrintArray 函数,并传递指针和大小
PrintArray (p, 数组大小)
' 告诉用户调用成功
标签_数组信息.内容 = “已成功向 C DLL 发送数组,请查看易语言控制台输出。”
' 在易语言控制台打印信息,方便调试
输出调试文本 (“易语言:已调用 PrintArray 函数”)

运行和测试

  • F5 运行易语言程序。
  • 点击“调用 Add 函数”按钮,标签_结果 应该会显示 30
  • 点击“调用 GetHelloMessage”按钮,标签_消息 应该会显示 Hello from C DLL!
  • 点击“调用 PrintArray”按钮,标签_数组信息 会出现提示。请回到 Visual Studio 窗口,你会看到调试控制台(Output 窗口)打印出了:
    C DLL received an array: [0, 1, 2, 3, 4]

    这证明了 C 函数成功接收并处理了从易语言传递过来的数组数据。


常见问题与解决方法

  1. “无法找到入口点”或“找不到指定的模块”

    • 原因:最常见的原因是函数名或调用约定不匹配。
      • 函数名:确保 C 函数声明使用了 extern "C",并且易语言声明的函数名与 DLL 中的导出名完全一致(区分大小写),你可以使用 Dependency Walker (depends.exe) 或 Process Monitor (ProcMon) 等工具来查看 DLL 中实际导出的函数名。
      • 调用约定:C 函数必须是 __stdcall,与易语言默认的调用约定一致,C 函数是 __cdecl,易语言调用时可能会出错。
    • 解决:检查函数名拼写、大小写,以及 C 函数的 __declspec__stdcall 声明。
  2. “内存访问违规”或“程序崩溃”

    • 原因:通常是由于参数传递错误导致的。
      • 类型不匹配:易语言传递的参数类型(如“整数”是 4 字节)与 C 函数期望的类型(如 long 可能是 8 字节)不一致。
      • 指针错误:对于指针或数组参数,易语言必须使用“取数据地址”来获取内存地址,并正确声明为“指针”类型,传递错误的地址或无效的指针会导致程序崩溃。
      • 字符串处理:C 函数返回的字符串最好是静态分配的(如 char* s = "hello";),如果是在函数内部动态分配的内存(malloc),易语言使用完后需要想办法释放,否则会造成内存泄漏,对于 DLL 返回的字符串,易语言通常只能读取,不能修改。
    • 解决:仔细核对每个参数在 C 和易语言中的类型定义,对于指针,确保传递的是有效的地址。
  3. DLL 文件找不到

    • 原因:易语言程序运行时找不到 MyCLib.dll 文件。
    • 解决:将 MyCLib.dll 文件复制到以下任一位置:
      • 易语言程序所在的同一目录下(最常用)。
      • C:\Windows\System32 目录下(不推荐,可能导致系统混乱)。
      • 在 Visual Studio 中设置 DLL 的输出目录,使其与易语言的 exe 文件放在一起。

调用 C DLL 的核心流程可以总结为:

  1. C 端
    • 使用 __declspec(dllexport)__stdcall 关键字导出函数。
    • 使用 extern "C" 避免名称修饰。
  2. 易语言端
    • 使用“外部DLL命令”或手动代码,声明与 C 函数参数和返回值类型对应的易语言子程序。
    • 对于指针/数组参数,使用“取数据地址”并声明为“指针”类型。
    • 调用声明的子程序,并传递正确的参数。

遵循以上步骤和原则,你就可以成功地在易语言中调用绝大多数用 C 语言编写的 DLL 文件了。

-- 展开阅读全文 --
头像
dede推荐与未推荐有何区别?
« 上一篇 今天
爱织梦idedecms是什么?
下一篇 » 今天

相关文章

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

目录[+]