Rust 调用包含回调函数的DLL

举报
福州司马懿 发表于 2025/03/24 09:48:52 2025/03/24
【摘要】 在 Rust 中调用 DLL(动态链接库)并通过回调函数持续接收数据是一种常见的与 C 语言库交互的方式。这通常需要使用 Rust 的 FFI(Foreign Function Interface)功能。以下是一个示例,演示如何在 Rust 中调用一个 C 语言的 DLL,并通过回调函数接收数据。 假设的 C 语言 DLL首先,假设我们有一个 C 语言编写的 DLL,其提供了一个函数来注册一...

在 Rust 中调用 DLL(动态链接库)并通过回调函数持续接收数据是一种常见的与 C 语言库交互的方式。这通常需要使用 Rust 的 FFI(Foreign Function Interface)功能。以下是一个示例,演示如何在 Rust 中调用一个 C 语言的 DLL,并通过回调函数接收数据。

假设的 C 语言 DLL

首先,假设我们有一个 C 语言编写的 DLL,其提供了一个函数来注册一个回调函数,并通过该回调函数发送数据。

C 语言头文件 example.h

#ifdef __cplusplus
extern "C" {
#endif

typedef void (*DataCallback)(int data);

void register_callback(DataCallback callback);
void start_data_stream();

#ifdef __cplusplus
}
#endif

C 语言实现 example.c

#include <stdio.h>
#include <windows.h>
#include "example.h"

static DataCallback g_callback = NULL;

void register_callback(DataCallback callback) {
    g_callback = callback;
}

void start_data_stream() {
    for (int i = 0; i < 10; ++i) {
        Sleep(1000); // Simulate some delay
        if (g_callback) {
            g_callback(i);
        }
    }
}

Rust 调用 DLL

在 Rust 中,我们需要定义一个回调函数,并使用 std::os::raw 模块中的类型来与 C 语言交互。

Rust 代码 main.rs

use std::os::raw::c_int;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;

// 定义回调函数类型,与 C 语言中的 typedef 对应
type DataCallback = extern "C" fn(data: c_int);

// 加载 DLL 并定义函数签名
#[link(name = "example")]
extern "C" {
    fn register_callback(callback: DataCallback);
    fn start_data_stream();
}

// 回调函数,接收数据
fn data_callback(data: c_int) {
    println!("Received data: {}", data);
}

fn main() {
    // 将回调函数传递给 DLL
    unsafe {
        register_callback(data_callback);
    }

    // 启动数据流
    thread::spawn(move || {
        unsafe {
            start_data_stream();
        }
    });

    // 主线程可以继续执行其他任务
    println!("Data stream started. Waiting for data...");

    // 防止主线程提前退出
    loop {
        thread::sleep(std::time::Duration::from_secs(1));
    }
}

解释

  1. 定义回调函数类型

    type DataCallback = extern "C" fn(data: c_int);
    

    这定义了一个与 C 语言兼容的回调函数类型。

  2. 加载 DLL 并定义函数签名

    #[link(name = "example")]
    extern "C" {
        fn register_callback(callback: DataCallback);
        fn start_data_stream();
    }
    

    使用 #[link(name = "example")] 属性加载 DLL,并定义 DLL 中函数的签名。

  3. 回调函数

    fn data_callback(data: c_int) {
        println!("Received data: {}", data);
    }
    

    定义一个简单的回调函数,打印接收到的数据。

  4. 注册回调并启动数据流

    unsafe {
        register_callback(data_callback);
    }
    
    thread::spawn(move || {
        unsafe {
            start_data_stream();
        }
    });
    

    使用 unsafe 块调用 C 函数,因为调用外部 C 函数是不安全的操作。启动一个线程来调用 start_data_stream,以便数据流可以在后台运行。

  5. 主线程保持活动

    loop {
        thread::sleep(std::time::Duration::from_secs(1));
    }
    

    使用一个无限循环来保持主线程的活动状态,防止程序提前退出。

注意事项

  • 编译 DLL:确保 C 语言代码已经编译为 DLL,并且 DLL 文件位于 Rust 项目的可执行文件路径中,或者在系统的 PATH 环境变量中。

  • 线程安全:确保回调函数是线程安全的,特别是在多线程环境下。

  • 错误处理:在生产环境中,应添加适当的错误处理和日志记录。

这样,你就可以在 Rust 中调用 DLL,并通过回调函数持续接收数据了!根据具体需求调整代码逻辑。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。