• RS调用DLL 辉


    https://blog.csdn.net/bbdxf/article/details/87890141

    Rust调用DLL
    简单调用(动态)
    extern crate libloading;

    use std::env;
    use libloading::{Library, Symbol};

    type AddFunc = fn(isize, isize) -> isize;

    fn main() {
        let library_path = env::args().nth(1).expect("USAGE: loading <LIB>");
        println!("Loading add() from {}", library_path);

        let lib = Library::new(library_path).unwrap();

        unsafe {
            let func: Symbol<AddFunc> = lib.get(b"add").unwrap();

            let answer = func(1, 2);
            println!("1 + 2 = {}", answer);
        }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    高级Demo(动态)
    这个Demo解决了,c_char, c_char*, 数组,可变数组,String之间的类型转换,回调函数等。包含结构体的使用以及如何传递指针。


    extern crate libc;
    extern crate libloading;

    use libc::*;
    use libloading::{Library, Symbol};

    /*
    // test_c.dll 接口内容

    SDK_API void test_normal(int a, float b, const char* c){
        printf("a: %d, b: %.2f, c: %s\n", a, b, c);
    }

    SDK_API void test_p(int* a, float* b, char* c){
        printf("set *a=112233, *b=3.1415926, c='1234567890'\n");
        *a = 112233;
        *b = 3.1415926f;
        strcpy(c, "1234567890");
    }

    typedef struct _TEST_OBJ
    {
        int a;
        float* b;
        char c[256];
    }TEST_OBJ;

    SDK_API void test_t(TEST_OBJ* arg){
        arg->a = 222;
        arg->b = NULL;
        strcpy(arg->c, u8"hello, world! 你好!~");
    }
    typedef  int(*CB_FUN)(int a);

    SDK_API int test_cb(CB_FUN p){
        printf("cb: %X, call p(10)\n", p);
        int a = p(10);
        return a;
    }
    */

    type fn_test_normal = unsafe fn(c_int, c_float, &str);
    type fn_test_p = unsafe fn(&c_int, &c_float, *mut c_char);

    #[repr(C)]
    #[derive(Clone, Copy)]
    struct fn_struct_t {
        a: c_int,
        b: *mut c_float,
        c: [u8; 256],
    }

    type fn_test_t = unsafe fn(&mut fn_struct_t);

    type fn_test_cb = unsafe fn( fn(i32)->i32 ) -> i32;

    fn main() {
        let lib = Library::new("test_c.dll").unwrap();
        unsafe {
            let fun1: Symbol<fn_test_normal> = lib.get(b"test_normal").unwrap();
            fun1(1, 2.21, "Hello,world\0"); // rust 字符串没有结尾的\0,
        };

        println!();
        unsafe {
            let mut arg1 = 0i32;
            let mut arg2 = 0f32;
            let mut arg3 = [0u8; 256];  // 分配存储空间
            let fun2: Symbol<fn_test_p> = lib.get(b"test_p").unwrap();
            fun2(&arg1, &arg2, arg3.as_mut_ptr() as *mut i8); // set *a=112233, *b=3.1415926, c='1234567890'
            println!("{} {} {:?}", arg1, arg2, arg3[0]); // 112233 3.1415925 49
    //        let s = String::from_raw_parts(arg3.as_mut_ptr() as *mut u8, strlen(arg3.as_ptr()), arg3.len());
    //        println!("ret: {}", s); // ret: 1234567890, 有buf, 会导致下面的无输出,故使用3的方式构建字符串
            let sv = &arg3[0..strlen(arg3.as_ptr() as *const i8)]; // 通过strlen构造对应字符串的数组
            let s = String::from_utf8_unchecked(sv.to_vec()); // 字符串使用utf8编码的u8
            println!("ret: {}", s); // ret: 1234567890
        };

        println!();
        unsafe {
            let mut arg = fn_struct_t { a: 0, b: 0 as *mut f32, c: [0u8; 256] };
            let fun3: Symbol<fn_test_t> = lib.get(b"test_t").unwrap();
            fun3(&mut arg);
            println!("{} {:?} {:?}", arg.a, arg.b, arg.c[0]); // 222 0x0 104
            let sv = &arg.c[0..strlen(arg.c.as_ptr() as *const i8)]; // 通过strlen构造对应字符串的数组
            let s = String::from_utf8_unchecked(sv.to_vec()); // 字符串使用utf8编码的u8
            println!("ret: {}", s); // ret: hello, world! 你好!~
        };

        println!();
        unsafe {
            let arg = |arg:i32| {
                println!("arg cb called! arg is {}", arg); 
                arg*10+123
            };
            let fun4: Symbol<fn_test_cb> = lib.get(b"test_cb").unwrap();
            let r = fun4(arg);
            println!("ret: {}", r); // 223
        };
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    首先,对于只需要传值的字符串,很好解决,&str/ String都可以简单地传递就能使用。

    对于需要提前分配的char*/char[],简单办法就是使用固定长度数组作为参数。如果存的是字符串,使用strlen得到修改后的真正长度,然后构建vec,然后通过vec构建String。

    如果是函数返回值char*则,简单方法使用CStr加载;也可以类似参数那样,使用strlen探测长度,然后构建vec然后转到String。

    在libc中,c_char/c_int/c_float...都是i8/i32...的别名,所以,一般使用rust固有类型可能会更好理解。

    回调函数也可以作为普通的指针传递就OK了。

    静态链接Lib
    https://doc.rust-lang.org/nomicon/ffi.html

    块link上的属性extern提供了基本的构建块,用于指示rustc如何链接到本机库。今天有两种可接受的链接属性形式:

    #[link(name = "foo")]
    #[link(name = "foo", kind = "bar")]

    在这两种情况下,foo是我们要链接到的本机库的名称,在第二种情况下bar是编译器链接到的本机库的类型。目前有三种已知类型的本机库:

    动态 - #[link(name = "readline")]
    静态的 - #[link(name = "my_build_dependency", kind = "static")]
    构架 - #[link(name = "CoreFoundation", kind = "framework")] 请注意,框架仅适用于macOS目标。
    不同的kind值旨在区分本机库如何参与链接。从链接角度来看,Rust编译器会创建两种工件:partial(rlib / staticlib)和final(dylib / binary)。本机动态库和框架依赖关系传播到最终工件边界,而静态库依赖关系根本不传播,因为静态库直接集成到后续工件中。

    有关如何使用此模型的一些示例如下:

    本机构建依赖项。在编写一些Rust代码时,有时需要一些C / C ++粘合剂,但是以库格式分发C / C ++代码是一种负担。在这种情况下,代码将被存档libfoo.a,然后Rust crate将通过声明依赖#[link(name = "foo", kind = "static")]。
    无论包的输出风格如何,本机静态库都将包含在输出中,这意味着不需要分发本机静态库。
    正常的动态依赖。常见系统库(如readline)可在大量系统上使用,并且通常无法找到这些库的静态副本。当此依赖项包含在Rust crate中时,部分目标(如rlibs)将不会链接到库,但是当rlib包含在最终目标(如二进制文件)中时,将链接本机库。
    在macOS上,框架的行为与动态库的语义相同。

    extern crate libc;
    use libc::size_t;

    #[link(name = "snappy")]
    extern {
        fn snappy_max_compressed_length(source_length: size_t) -> size_t;
    }

    fn main() {
        let x = unsafe { snappy_max_compressed_length(100) };
        println!("max compressed length of a 100 byte buffer: {}", x);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    回调函数:

    // callback
    #[repr(C)]
    struct RustObject {
        a: i32,
        // Other members...
    }

    extern "C" fn callback(target: *mut RustObject, a: i32) {
        println!("I'm called from C with value {0}", a);
        unsafe {
            // Update the value in RustObject with the value received from the callback:
            (*target).a = a;
        }
    }

    #[link(name = "extlib")]
    extern {
       fn register_callback(target: *mut RustObject, cb: extern fn(*mut RustObject, i32)) -> i32;
       fn trigger_callback();
    }

    fn main() {
        // Create the object that will be referenced in the callback:
        let mut rust_object = Box::new(RustObject { a: 5 });
        unsafe {
            register_callback(&mut *rust_object, callback);
            trigger_callback();
        }
    }

    // c dll/lib
    typedef void (*rust_callback)(void*, int32_t);
    void* cb_target;
    rust_callback cb;

    int32_t register_callback(void* callback_target, rust_callback callback) {
        cb_target = callback_target;
        cb = callback;
        return 1;
    }

    void trigger_callback() {
      cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust.
    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    访问修改全局变量

    extern crate libc;

    use std::ffi::CString;
    use std::ptr;

    #[link(name = "readline")]
    extern {
        static mut rl_prompt: *const libc::c_char;
    }

    fn main() {
        let prompt = CString::new("[my-awesome-shell] $").unwrap();
        unsafe {
            rl_prompt = prompt.as_ptr();

            println!("{:?}", rl_prompt);

            rl_prompt = ptr::null();
        }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    一个Demo
    // libdemo1.dylib
    #include <stdio.h>

    #define EXPORT __attribute__((visibility("default")))

    #ifdef __cplusplus
    extern "C" {
    #endif

    EXPORT
    int test_normal(int a, float b, char *c) {
        printf("a: %d, b: %.2f c: %s\n", a, b, c);
        return 11;
    }

    #ifdef __cplusplus
    }
    #endif
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    rust调用:

    首先要export LIBRARY_PATH=/Users/{user}/cprj/demo1/cmake-build-release将lib库加入LIBRARY_PATH中,这样rust能找到lib文件。然后如下方式调用:

    extern crate libc;

    #[link(name = "demo1")]
    extern {
        fn test_normal(a: i32, b: f32, c: *const u8) -> i32;
    }

    fn main() {
        let x = unsafe { test_normal(100, 3.2, "213213\0".as_ptr()) };
        println!("test: {}", x);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    ————————————————
    版权声明:本文为CSDN博主「笨笨D幸福」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/bbdxf/article/details/87890141

  • 相关阅读:
    【Android】详解Android 网络操作
    【Android】详解Android Service
    【Android】Android的进程优先级
    【Windows】Dos中的日期的和时间
    【Android】详解Android Activity
    【Java】java数据库连接中C3P、DBCP、Druid连接池的使用
    【Windows】Windows中解析DOS的DIR命令使用
    【Android】解析Android的路径
    【Windows】Windows中解析DOS的for命令使用
    【Android】Android实现监听返回键,主键(HOME),菜单键
  • 原文地址:https://www.cnblogs.com/dhcn/p/16727825.html
Copyright © 2020-2023  润新知