本文介绍: 当前采用桌面框架tauri,现在需要调用读卡器硬件设备硬件厂商提供了32位的动态链接库,现在记录例子需要注意的点是使用libloading库和libc库,其他注意项:首先,对于只需要传值的字符串,很好解决,&str/ String可以简单地传递就能使用。对于需要提前分配char*/char[],简单办法就是使用固定长度数组作为参数获取返回值如果存的是字符串,使用strlen得到修改后的真正长度,然后构建vec然后通过vec构建String

前言

当前采用桌面端框架tauri,现在需要调用读卡器硬件设备硬件厂商提供了32位的动态链接库,现在记录例子,需要注意的点是使用libloading库和libc库,

[package]
name = "yyt-device-rust"
version = "0.0.1"
description = "yyt-device-rust"
authors = ["Alaia"]
license = ""
repository = ""
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[build-dependencies]
tauri-build = { version = "1.2", features = [] }

[dependencies]
tauri = { version = "1.2", features = [ "api-all"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
mac_address="*"
//重点依赖
libloading = "0.8"
encoding = "0.2.33"
libc = "0.2"


[features]
# this feature is used for production builds or when `devPath` points to the filesystem
# DO NOT REMOVE!!
custom-protocol = ["tauri/custom-protocol"]

#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use std::ffi::CString;
use libc::*;
use libloading::{Library, Symbol};
use encoding_rs::*;


type DcInit = extern "stdcall" fn(port: c_int, baud: c_int) -> *mut c_int;
type DcFindSpeed = extern "stdcall" fn(icdev: *mut c_int) -> *mut c_int;
type DcCardInfo = extern "stdcall" fn(
    icdev: *mut c_int,
    typeNum: c_int,
    text_len: &c_int,
    text: *mut c_char,
    photo_len: &c_int,
    photo: *mut c_char,
    fingerprint_len: &c_int, 
    fingerprint: *mut c_char,
    extra_len: &c_int,
    extra: *mut c_char,
) -> *mut c_int;
type DcParseTextInfo = extern "stdcall" fn(
    icdev: *mut c_int,
    typeNum: c_int,
    text_len: &c_int,
    text: *mut c_char,
    name: *mut c_char,
    sex: *mut c_char,
    nation: *mut c_char,
    birth_day: *mut c_char,
    address: *mut c_char,
    id_number: *mut c_char,
    department: *mut c_char,
    expire_start_day: *mut c_char,
    expire_end_day: *mut c_char,
    reserved: *mut c_char,
) -> *mut c_int;
type DcExit = extern "stdcall" fn(
    icdev: *mut c_int,
) -> *mut c_int;

type PrintInput = extern "stdcall" fn(
    InInfo: *mut c_char,
    OutInfo: *mut c_char,
) -> *mut c_void;

#[tauri::command]
fn get_mac_addr() -> Result<String, String> {
    let mac_result = mac_address::get_mac_address();
    if let Ok(Some(mac)) = mac_result {
        Ok(mac.to_string().into())
    } else {
        println!("Get Address Error");
        Err("Rust Get Address Error".into())
    }
}

#[tauri::command]
fn print_tickertape(input: String) -> Result<String, String> {
    let res: String = call_dynamic(input).unwrap();
    println!("Hello, world! {:?}", res);
    return Ok(res);
}

#[tauri::command]
fn read_id_card() -> Result<String, String> {
    let res: String = call_dynamic_card().unwrap();
    println!("Hello, world! {:?}", res);
    return Ok(res);
}

fn call_dynamic_card() -> Result<String, Box<dyn std::error::Error>> {
    unsafe {
        let lib: libloading::Library = libloading::Library::new("lib/dekabig/idCard/dcrf32.dll")?;
        let dc_init: libloading::Symbol<DcInit> = lib.get(b"dc_init")?;
        let dc_find_i_d_speed: libloading::Symbol<DcFindSpeed> = lib.get(b"dc_find_i_d_speed")?;
        let dc_sam_aread_card_info: libloading::Symbol<DcCardInfo> = lib.get(b"dc_SamAReadCardInfo")?;
        let dc_parse_text_info: libloading::Symbol<DcParseTextInfo> = lib.get(b"dc_ParseTextInfo")?;
        let dc_exit: libloading::Symbol<DcExit> = lib.get(b"dc_exit")?;
        let device_no: *mut c_int = dc_init(100, 115200);
        let dc_find_i_d_speed = dc_find_i_d_speed(device_no);
        println!("{:?}", device_no);
        println!("{:?}", dc_find_i_d_speed);
        let mut text_len = 256i32;
        let mut photo_len = 1024i32;
        let mut fingerprint_len = 1024i32;
        let mut extra_len = 70i32;
        let mut into_text = [0u8; 256];
        let mut into_photo = [0u8; 1024];
        let mut into_fingerprint = [0u8; 1024];
        let mut into_extra = [0u8; 70];
        let dc_sam_aread_card_info = dc_sam_aread_card_info(
            device_no,
            3,
            &text_len,
            into_text.as_mut_ptr() as *mut i8,
            &photo_len,
            into_photo.as_mut_ptr() as *mut i8,
            &fingerprint_len,
            into_fingerprint.as_mut_ptr() as *mut i8,
            &extra_len,
            into_extra.as_mut_ptr() as *mut i8,
        );
        println!("{:?}", dc_sam_aread_card_info);
        let mut name = [0u8; 64];
        let mut sex = [0u8; 8];
        let mut nation = [0u8; 12];
        let mut birth_day = [0u8; 36];
        let mut address = [0u8; 144];
        let mut id_number = [0u8; 76];
        let mut department = [0u8; 64];
        let mut expire_start_day = [0u8; 36];
        let mut expire_end_day = [0u8; 36];
        let mut reserved = [0u8; 76];
        let dc_parse_text_info = dc_parse_text_info(
            device_no,
            0,
            &text_len,
            into_text.as_mut_ptr() as *mut i8,
            name.as_mut_ptr() as *mut i8,
            sex.as_mut_ptr() as *mut i8,
            nation.as_mut_ptr() as *mut i8,
            birth_day.as_mut_ptr() as *mut i8,
            address.as_mut_ptr() as *mut i8,
            id_number.as_mut_ptr() as *mut i8,
            department.as_mut_ptr() as *mut i8,
            expire_start_day.as_mut_ptr() as *mut i8,
            expire_end_day.as_mut_ptr() as *mut i8,
            reserved.as_mut_ptr() as *mut i8,
        );
        let nameC = &name[0..strlen(name.as_ptr() as *const i8)];
        let (nameutf, _, _) = GBK.decode(nameC);
        println!("nameutf: {}", nameutf);
        let dc_exit = dc_exit(device_no);
        println!("dc_exit: {:?}", dc_exit);
        return Ok("123".into());
    }
}

fn call_dynamic(json: String) -> Result<String, Box<dyn std::error::Error>> {
    unsafe {
        let lib: libloading::Library = libloading::Library::new("lib/dekabig/tickertape/DC_Print.dll")?;
        let print_t: libloading::Symbol<PrintInput> = lib.get(b"Print_Input")?;
        let (json_out, _, _) = GBK.encode(&json);
        let cstring = CString::new(json_out).expect("cstring error");
        let mut output = [0u8; 1024];
        print_t(cstring.into_raw(), output.as_mut_ptr() as *mut i8,);
        let output_c: &[u8] = &output[0..strlen(output.as_ptr() as *const i8)];
        let (outputf, _, _)= GBK.decode(output_c);
        println!("nameutf: {}", outputf);
        return Ok(outputf.to_string());
    }
}

fn main() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![
            get_mac_addr,
            print_tickertape,
            read_id_card
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

其他注意项:首先,对于只需要传值的字符串,很好解决,&str/ String都可以简单地传递就能使用。

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

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

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

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

参考例子

//参考例子

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: %sn", 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"); // rust 字符串没有结尾的,
    };

    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
    };
}

原文地址:https://blog.csdn.net/weixin_42842069/article/details/134640962

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_15085.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注