经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
关于使用rust调用c++静态库并编译nodejs包的问题
来源:jb51  时间:2022/8/2 16:46:08  对本文有异议

在项目上经常要用到身份证阅读器、护照阅读仪、指纹仪等各种品牌硬件,假如每套系统的都做集成开发那代码的维护成本将变得很高,为此采用rust来调用厂家提供的sdk c++开发包并封装成nodejs包,用fastify来开发成web api独立的服务形式。这样我们开发系统时只需调用web接口即可,跨平台又可共用,方便快捷,话不多说来看代码如何实现。

一、创建项目

安装rust后,打开vs新建一个工程目录,我们通过cargo new创建的一个package项目,加上--lib参数后创建的项目就是库项目(library package)。
cargo new --lib reader
package 就是一个项目,因此它包含有独立的 Cargo.toml 文件,用于项目配置。库项目只能作为三方库被其它项目引用,而不能独立运行,即src/lib.rs。
典型的package
如果一个 package 同时拥有 src/main.rs 和 src/lib.rs,那就意味着它包含两个包:库包和二进制包,这两个包名也都是 test_math —— 都与 package 同名。
一个真实项目中典型的 package,会包含多个二进制包,这些包文件被放在 src/bin 目录下,每一个文件都是独立的二进制包,同时也会包含一个库包,该包只能存在一个 src/lib.rs:
.
├── Cargo.toml
├── Cargo.lock
├── src
│ ├── main.rs
│ ├── lib.rs
│ └── bin
│ └── main1.rs
│ └── main2.rs
├── tests
│ └── some_integration_tests.rs
├── benches
│ └── simple_bench.rs
└── examples
└── simple_example.rs

唯一库包:src/lib.rs
默认二进制包:src/main.rs,编译后生成的可执行文件与package同名
其余二进制包:src/bin/main1.rs 和 src/bin/main2.rs,它们会分别生成一个文件同名的二进制可执行文件
集成测试文件:tests 目录下
性能测试benchmark文件:benches 目录下
项目示例:examples 目录下
这种目录结构基本上是 Rust 的标准目录结构,在 github 的大多数项目上,你都将看到它的身影。
运行Cargo build命令,我们在target\debug目录下可以看到编译后的结果。

二、Cargo.toml

  1. [package]
  2. name = "reader"
  3. version = "0.1.0"
  4. edition = "2018"
  5. exclude = ["reader.node"]
  6. # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
  7.  
  8. [dependencies]
  9. libc = "0.2.9"
  10. libloading = "0.7"
  11. once_cell = "1.8"
  12. serde = { version = "1.0", features = ["derive"] }
  13. widestring = "0.5.1"
  14. serde_json = "1.0"
  15. base64 = "0.13"
  16. hex="0.4.2"
  17. encoding = "0.2"
  18. tokio={version="1.18.0",features = ["full"]}
  19.  
  20. [dependencies.neon]
  21. version = "0.9"
  22. default-features = false
  23. features = ["napi-5", "channel-api"]
  24.  
  25. [lib]
  26. crate-type = ["cdylib"]

三、package.json

  1. {
  2. "name": "reader",
  3. "version": "0.1.0",
  4. "description": "",
  5. "main": "index.node",
  6. "scripts": {
  7. "build": "cargo-cp-artifact -nc index.node -- cargo build --message-format=json-render-diagnostics",
  8. "build-debug": "npm run build --",
  9. "build-release": "npm run build -- --release",
  10. "build_win32": "npm run build -- --release --target=i686-pc-windows-msvc",
  11. "test": "cargo test",
  12. "run": "cargo run"
  13. },
  14. "author": "",
  15. "license": "ISC",
  16. "devDependencies": {
  17. "cargo-cp-artifact": "^0.1"
  18. },
  19. "dependencies": {
  20. "express": "^4.17.3"
  21. }
  22. }

我们可以打印rust看看编译输出支持哪些架构
rustc --print target-list
//添加 x86编译链接器
rustup target add i686-pc-windows-msvc

四、代码分析

  1. use std::collections::HashMap;
  2. use std::str;
  3. use std::fmt::Write;
  4. use std::io::{Error};
  5.  
  6. extern crate encoding;
  7. use encoding::all::GB18030;
  8. use encoding::{DecoderTrap,EncoderTrap,Encoding};
  9.  
  10. use tokio::time::{sleep, Duration,Instant};
  11. use libc::{c_int, c_void};
  12. use libloading::{Library, Symbol};
  13. use neon::prelude::*;
  14. use once_cell::sync::OnceCell;
  15. use serde::{Deserialize, Serialize};
  16.  
  17. use widestring::{WideCStr, WideCString, WideChar};
  18. // 编码转换 utf8 -> utf16le
  19. fn encode(source: &str) -> WideCString {
  20. let string_source = source.to_string() + "\0";
  21. WideCString::from_str(&string_source).unwrap()
  22. }
  23. // 解码转换 utf16le -> utf8
  24. fn decode(source: &[WideChar]) -> String {
  25. WideCStr::from_slice_truncate(source)
  26. .unwrap()
  27. .to_string()
  28. .unwrap()
  29. }
  30. // 加载 dll
  31. static LIBRARY: OnceCell<Library> = OnceCell::new();
  32.  
  33. //指定编译架构
  34. static MACHINE_KIND: &str = if cfg!(target_os = "windows") {
  35. if cfg!(target_arch = "x86") {
  36. "win32"
  37. } else if cfg!(target_arch = "x86_x64") {
  38. "win64"
  39. } else {
  40. "other"
  41. }
  42. } else if cfg!(target_os = "linux") {
  43. if cfg!(target_arch = "x86") {
  44. "linux32"
  45. } else if cfg!(target_arch = "x86_64") {
  46. "linux64"
  47. } else if cfg!(target_arch = "aarch64") {
  48. "aarch64"
  49. } else if cfg!(target_arch = "arm") {
  50. "arm"
  51. } else {
  52. "other"
  53. }
  54. } else {
  55. "other"
  56. };
  1. //定义函数方法名,这里要根据c++库的函数名和参数来定义,函数名和参数类型务必要一致。
  2. type LPCTSTR = *const WideChar;
  3. type BOOL = c_int;
  4. type INITPTR = *const i8;
  5. type CANRST = *mut WideChar;
  6. // 打开设备
  7. type S2V7_open = unsafe extern "system" fn() -> c_int;
  8. // 关闭设备
  9. type S2V7_close = unsafe extern "system" fn() -> c_int;
  10. //【set mode 设置读证功能】
  11. type S2V7_set_mode =
  12. unsafe extern "system" fn(flg_takeColor: c_int, flg_takeUV: c_int, flg_readChipInfo: c_int, flg_readChipFace: c_int) -> c_int; // Type = 0 即可
  13. //【wait Doc. in 等待放卡】
  14. type S2V7_wait_DocIn =
  15. unsafe extern "system" fn(timeout: f64, flg_in: INITPTR) -> c_int; // Type = 0 即可
  16. //【wait Doc. out 等待拿卡】
  17. type S2V7_wait_DocOut =
  18. unsafe extern "system" fn(timeout: f64, flg_out: INITPTR) -> c_int; // Type = 0 即可
  19. //【process 执行读卡过程】
  20. type S2V7_process = unsafe extern "system" fn() -> c_int;
  21. //读取卡类型
  22. type S2V7_get_cardType = unsafe extern "system" fn() -> c_int;
  23. //保存彩照
  24. type S2V7_VIS_saveColor = unsafe extern "system" fn(imgPath: LPCTSTR) -> c_int;
  25. //保存红外照
  26. type S2V7_VIS_saveIR = unsafe extern "system" fn(imgPath: LPCTSTR) -> c_int;
  27. //【get MRZ text 获取OCR文字信息】
  28. type S2V7_VIS_getMRZtext = unsafe extern "system" fn(text: LPCTSTR) -> c_int;
  29. //show text information 文字信息
  30. type S2V7_RDO_getBytesByIndex = unsafe extern "system" fn(index: c_int,data: LPCTSTR) -> c_int;
  31. type S2V7_VIS_getBytesByIndex = unsafe extern "system" fn(index: c_int,data: LPCTSTR) -> c_int;
  32. type S2V7_RF_active = unsafe extern "system" fn(antenna: c_int,atr: LPCTSTR, atr_len: c_int) -> c_int;
  33. //构建函数实例
  34. static V7_OPEN: OnceCell<Symbol<S2V7_open>> = OnceCell::new();
  35. static V7_CLOSE: OnceCell<Symbol<S2V7_close>> = OnceCell::new();
  36. static V7_SET_MODE: OnceCell<Symbol<S2V7_set_mode>> = OnceCell::new();
  37. static V7_WAIT_DOCINT: OnceCell<Symbol<S2V7_wait_DocIn>> = OnceCell::new();
  38. static V7_WAIT_DOCOUT: OnceCell<Symbol<S2V7_wait_DocOut>> = OnceCell::new();
  39. static V7_PROCESS: OnceCell<Symbol<S2V7_process>> = OnceCell::new();
  40. static V7_GET_CARDTYPE: OnceCell<Symbol<S2V7_get_cardType>> = OnceCell::new();
  41. static V7_VIS_SAVECOLOR: OnceCell<Symbol<S2V7_VIS_saveColor>> = OnceCell::new();
  42. static V7_VIS_SAVEIR: OnceCell<Symbol<S2V7_VIS_saveIR>> = OnceCell::new();
  43. static V7_VIS_GETMRZTEXT: OnceCell<Symbol<S2V7_VIS_getMRZtext>> = OnceCell::new();
  44. static V7_RDO_getBytesByIndex: OnceCell<Symbol<S2V7_RDO_getBytesByIndex>> = OnceCell::new();
  45. static V7_VIS_getBytesByIndex: OnceCell<Symbol<S2V7_VIS_getBytesByIndex>> = OnceCell::new();
  46. static V7_RF_active: OnceCell<Symbol<S2V7_RF_active>> = OnceCell::new();
  1. // 对外导出函数方法
  2. #[neon::main]
  3. fn main(mut cx: ModuleContext) -> NeonResult<()> {
  4. cx.export_function("init", init_by_node)?;
  5. cx.export_function("start", start)?;
  6. }
  7. //加载dll并对函数进行初始化操作
  8. pub fn init_by_node(mut cx: FunctionContext) -> JsResult<JsNumber> {
  9. //外部传进来的参数(根据自己的需要来定义)
  10. let directory = cx.argument::<JsString>(0)?.value(&mut cx);
  11. let userid = cx.argument::<JsString>(1)?.value(&mut cx);
  12. unsafe {
  13. DIRECTORY_PATH.take();
  14. DIRECTORY_PATH.set(directory).unwrap();
  15. USER_ID.take();
  16. USER_ID.set(userid).unwrap();
  17. };
  18. let result = init() as f64;
  19. Ok(cx.number(result))
  20. }
  21. //核心代码,加载dll函数并映射
  22. fn init() -> c_int {
  23. let directory = unsafe { DIRECTORY_PATH.get().unwrap() };
  24. let userid = unsafe { USER_ID.get().unwrap() };
  25. let directory_path = std::path::Path::new(directory).join(MACHINE_KIND);
  26. if directory_path.exists() {
  27. let dll_path = directory_path.join(libloading::library_filename("STAR200_V7_DRV"));
  28. println!("dll_path: {:?}", dll_path);
  29. if dll_path.exists() {
  30. match init_dll(dll_path.to_str().unwrap()).is_ok() {
  31. true => {
  32. // 打开设备
  33. let init_result = unsafe {V7_OPEN.get_unchecked()()};
  34. if init_result == 0 {
  35. println!("设备打开成功");
  36. return ResultType::Success as c_int;
  37. } else {
  38. println!("设备打开失败,代码:{:?}",init_result);
  39. return ResultType::DeviceNotFound as c_int;
  40. }
  41. }
  42. false => {
  43. return ResultType::INITDLLFail as c_int;
  44. }
  45. }
  46. } else {
  47. return ResultType::DllPathNotExist as c_int;
  48. }
  49. } else {
  50. println!("{:?}", directory_path);
  51. return ResultType::DirectoryPathNotExist as c_int;
  52. }
  53. }
  54. // 加载dll
  55. fn init_dll(dll_path: &str) -> Result<bool, Box<dyn std::error::Error>> {
  56. unsafe {
  57. if INITDLL {
  58. return Ok(true);
  59. }
  60. }
  61. println!("加载dll");
  62. println!("dll_path");
  63. let library = LIBRARY.get_or_init(|| unsafe { Library::new(dll_path).unwrap() });
  64. println!("S2V7_open");
  65. V7_OPEN.get_or_init(|| unsafe { library.get::<S2V7_open>(b"S2V7_open").unwrap() });
  66. println!("S2V7_close");
  67. V7_CLOSE.get_or_init(|| unsafe { library.get::<S2V7_close>(b"S2V7_close").unwrap() });
  68. println!("S2V7_set_mode");
  69. V7_SET_MODE.get_or_init(|| unsafe {library.get::<S2V7_set_mode>(b"S2V7_set_mode").unwrap()});
  70. println!("S2V7_wait_DocIn");
  71. V7_WAIT_DOCINT.get_or_init(|| unsafe { library.get::<S2V7_wait_DocIn>(b"S2V7_wait_DocIn").unwrap() });
  72. println!("S2V7_wait_DocOut");
  73. V7_WAIT_DOCOUT.get_or_init(|| unsafe { library.get::<S2V7_wait_DocOut>(b"S2V7_wait_DocOut").unwrap() });
  74. V7_PROCESS.get_or_init(|| unsafe { library.get::<S2V7_process>(b"S2V7_process").unwrap() });
  75. V7_GET_CARDTYPE.get_or_init(|| unsafe { library.get::<S2V7_get_cardType>(b"S2V7_get_cardType").unwrap() });
  76. V7_VIS_SAVECOLOR.get_or_init(|| unsafe { library.get::<S2V7_VIS_saveColor>(b"S2V7_VIS_saveColor").unwrap() });
  77. V7_VIS_SAVEIR.get_or_init(|| unsafe { library.get::<S2V7_VIS_saveIR>(b"S2V7_VIS_saveIR").unwrap() });
  78. V7_VIS_GETMRZTEXT.get_or_init(|| unsafe { library.get::<S2V7_VIS_getMRZtext>(b"S2V7_VIS_getMRZtext").unwrap() });
  79. V7_RDO_getBytesByIndex.get_or_init(|| unsafe { library.get::<S2V7_RDO_getBytesByIndex>(b"S2V7_RDO_getBytesByIndex").unwrap() });
  80. V7_VIS_getBytesByIndex.get_or_init(|| unsafe { library.get::<S2V7_VIS_getBytesByIndex>(b"S2V7_VIS_getBytesByIndex").unwrap() });
  81. V7_RF_active.get_or_init(|| unsafe { library.get::<S2V7_RF_active>(b"S2V7_RF_active").unwrap() });
  82. unsafe {
  83. INITDLL = true;
  84. }
  85. Ok(true)
  86. }
  1. //创建新线程来监测设备读证操作
  2. fn start(mut cx: FunctionContext) -> JsResult<JsUndefined> {
  3. let callback = cx.argument::<JsFunction>(0)?.root(&mut cx);
  4. let mut channel = cx.channel();
  5. channel.reference(&mut cx);
  6. println!("start {}", channel.has_ref());
  7. let index = unsafe {
  8. DEVICE_START_INDEX += 1;
  9. DEVICE_START_INDEX
  10. };
  11. std::thread::spawn(move || {
  12. // Do the heavy lifting inside the background thread.
  13. device_start(callback, channel, index);
  14. });
  15. Ok(cx.undefined())
  16. }
  17. use std::sync::{Arc, Mutex};
  18. fn device_start(callback: Root<JsFunction>, channel: Channel, index: u64) {
  19. let index = index;
  20. let callback = Arc::new(Mutex::new(callback));
  21. //设置读证功能
  22. unsafe { V7_SET_MODE.get_unchecked()(1,1,1,1) };
  23. loop {
  24. if index != unsafe { DEVICE_START_INDEX } {
  25. break;
  26. };
  27. let callback_clone = Arc::clone(&callback);
  28. let mut result = RecogIDCardEXResult::default();
  29. let mut flg_in:i8=0;
  30. match unsafe { V7_WAIT_DOCINT.get_unchecked()(5.0,&mut flg_in) } {
  31. // 设备正常 检测是否有放入证件
  32. 0 => {
  33. if flg_in==0{
  34. //检查是否放入超时
  35. result.record_type = ResultType::CheckCardNotInOrOut as i32;
  36. break;
  37. }
  38. result.device_online = true;
  39. result.device_name =unsafe { DEVCIE_NAME.get_or_init(|| "".to_string()).to_string() };
  40. match unsafe { V7_PROCESS.get_unchecked()() } {
  41. // 证件有放入
  42. 0 => {
  43. result.record_type = ResultType::CheckCardInput as i32;
  44. }
  45. // 未检测到OCR区域
  46. -1 => {
  47. result.record_type = ResultType::OCRFail as i32;
  48. }
  49. // 设备离线
  50. -3 => {
  51. result.device_online = false;
  52. result.record_type = init();
  53. }
  54. _ => {
  55. result.record_type = ResultType::Unknown as i32;
  56. }
  57. }
  58. }
  59. -3 => {
  60. //设备离线
  61. let init = init();
  62. result.device_online = false;
  63. result.record_type = init;
  64. }
  65. _ => {
  66. //未知错误
  67. result.record_type = ResultType::Unknown as i32;
  68. }
  69. };
  70. if unsafe { *NEED_RECORD.get_or_init(|| false) } {
  71. println!("手工点击识别+1");
  72. result.record_type = ResultType::CheckCardInput as i32;
  73. }
  74. // let time_now = std::time::Instant::now();
  75. if result.record_type == ResultType::CheckCardInput as i32 {
  76. let _result = recog_card();
  77. result.success = _result.success;
  78. result.img_base64 = _result.img_base64;
  79. result.reg_info = _result.reg_info;
  80. result.card_type = _result.card_type;
  81. result.card_name = _result.card_name;
  82. }
  83. let neet_sendinfo = if Some(true) == unsafe { NEED_RECORD.take() } {
  84. true
  85. } else {
  86. false
  87. };
  88. // let elapsed = time_now.elapsed();
  89. // println!("识别时间结束时间 {:.6?}", elapsed);
  90. if result.record_type != ResultType::CheckCardNotInOrOut as i32
  91. && (*unsafe { RESULT_TYPE.get_or_init(|| -10000) } != result.record_type
  92. || result.record_type == ResultType::CheckCardInput as i32
  93. || neet_sendinfo)
  94. {
  95. unsafe {
  96. RESULT_TYPE.take();
  97. RESULT_TYPE.set(result.record_type).unwrap();
  98. }
  99. channel.send(move |mut cx| {
  100. let result_json = serde_json::to_string(&result).unwrap();
  101. let callback = callback_clone.lock().unwrap().to_inner(&mut cx);
  102. let this = cx.undefined();
  103. let args = vec![cx.string(&result_json)];
  104. callback.call(&mut cx, this, args)?;
  105. Ok(())
  106. });
  107. }
  108. std::thread::sleep(std::time::Duration::from_millis(20));
  109. }
  110. }

完整源码

  1. use std::collections::HashMap;
  2. use libc::{c_int, c_void};
  3. use libloading::{Library, Symbol};
  4. use neon::prelude::*;
  5. use once_cell::sync::OnceCell;
  6. use serde::Serialize;
  7. extern crate encoding;
  8. use encoding::all::GB18030;
  9. use encoding::{DecoderTrap,EncoderTrap,Encoding};
  10. use widestring::{WideCStr, WideCString, WideChar};
  11. // 编码转换 utf8 -> utf16le
  12. fn encode(source: &str) -> WideCString {
  13. let string_source = source.to_string() + "\0";
  14. WideCString::from_str(&string_source).unwrap()
  15. }
  16. // 解码转换 utf16le -> utf8
  17. fn decode(source: &[WideChar]) -> String {
  18. WideCStr::from_slice_truncate(source)
  19. .unwrap()
  20. .to_string()
  21. .unwrap()
  22. }
  23. // 加载 dll
  24. static LIBRARY: OnceCell<Library> = OnceCell::new();
  25. static MACHINE_KIND: &str = if cfg!(target_os = "windows") {
  26. if cfg!(target_arch = "x86") {
  27. "win32"
  28. } else if cfg!(target_arch = "x86_x64") {
  29. "win64"
  30. } else {
  31. "other"
  32. }
  33. } else if cfg!(target_os = "linux") {
  34. if cfg!(target_arch = "x86") {
  35. "linux32"
  36. } else if cfg!(target_arch = "x86_64") {
  37. "linux64"
  38. } else if cfg!(target_arch = "aarch64") {
  39. "aarch64"
  40. } else if cfg!(target_arch = "arm") {
  41. "arm"
  42. } else {
  43. "other"
  44. }
  45. } else {
  46. "other"
  47. };
  48. //设置识别的证件 ID
  49. // 设置当前要识别的证件类型,并将
  50. // 之前已经设置的证件类型清除。
  51. // nMainID 主要识别类型,nSubID 子类型
  52. // nSubID 头指针,默认将数组
  53. // nSubID 第 一 个 元 素 赋 值 为 0 即
  54. // nSubID[0]=0
  55. // type S = c_int[];
  56. type LPCTSTR = *const WideChar;
  57. type BOOL = c_int;
  58. type INITPTR = *const i8;
  59. type CANRST = *mut WideChar;
  60. // 打开设备
  61. type S2V7_open = unsafe extern "system" fn() -> c_int;
  62. // 关闭设备
  63. type S2V7_close = unsafe extern "system" fn() -> c_int;
  64. //【set mode 设置读证功能】
  65. type S2V7_set_mode =
  66. unsafe extern "system" fn(flg_takeColor: c_int, flg_takeUV: c_int, flg_readChipInfo: c_int, flg_readChipFace: c_int) -> c_int; // Type = 0 即可
  67. //【wait Doc. in 等待放卡】
  68. type S2V7_wait_DocIn =
  69. unsafe extern "system" fn(timeout: f64, flg_in: INITPTR) -> c_int; // Type = 0 即可
  70. //【wait Doc. out 等待拿卡】
  71. type S2V7_wait_DocOut =
  72. unsafe extern "system" fn(timeout: f64, flg_out: INITPTR) -> c_int; // Type = 0 即可
  73. //【process 执行读卡过程】
  74. type S2V7_process = unsafe extern "system" fn() -> c_int;
  75. //读取卡类型
  76. type S2V7_get_cardType = unsafe extern "system" fn() -> c_int;
  77. //保存彩照
  78. type S2V7_VIS_saveColor = unsafe extern "system" fn(imgPath: LPCTSTR) -> c_int;
  79. //保存红外照
  80. type S2V7_VIS_saveIR = unsafe extern "system" fn(imgPath: LPCTSTR) -> c_int;
  81. //【get MRZ text 获取OCR文字信息】
  82. type S2V7_VIS_getMRZtext = unsafe extern "system" fn(text: LPCTSTR) -> c_int;
  83. //show text information 文字信息
  84. type S2V7_RDO_getBytesByIndex = unsafe extern "system" fn(index: c_int,data: LPCTSTR) -> c_int;
  85. type S2V7_VIS_getBytesByIndex = unsafe extern "system" fn(index: c_int,data: LPCTSTR) -> c_int;
  86. type S2V7_RF_active = unsafe extern "system" fn(antenna: c_int,atr: LPCTSTR, atr_len: c_int) -> c_int;
  87. static V7_OPEN: OnceCell<Symbol<S2V7_open>> = OnceCell::new();
  88. static V7_CLOSE: OnceCell<Symbol<S2V7_close>> = OnceCell::new();
  89. static V7_SET_MODE: OnceCell<Symbol<S2V7_set_mode>> = OnceCell::new();
  90. static V7_WAIT_DOCINT: OnceCell<Symbol<S2V7_wait_DocIn>> = OnceCell::new();
  91. static V7_WAIT_DOCOUT: OnceCell<Symbol<S2V7_wait_DocOut>> = OnceCell::new();
  92. static V7_PROCESS: OnceCell<Symbol<S2V7_process>> = OnceCell::new();
  93. static V7_GET_CARDTYPE: OnceCell<Symbol<S2V7_get_cardType>> = OnceCell::new();
  94. static V7_VIS_SAVECOLOR: OnceCell<Symbol<S2V7_VIS_saveColor>> = OnceCell::new();
  95. static V7_VIS_SAVEIR: OnceCell<Symbol<S2V7_VIS_saveIR>> = OnceCell::new();
  96. static V7_VIS_GETMRZTEXT: OnceCell<Symbol<S2V7_VIS_getMRZtext>> = OnceCell::new();
  97. static V7_RDO_getBytesByIndex: OnceCell<Symbol<S2V7_RDO_getBytesByIndex>> = OnceCell::new();
  98. static V7_VIS_getBytesByIndex: OnceCell<Symbol<S2V7_VIS_getBytesByIndex>> = OnceCell::new();
  99. static V7_RF_active: OnceCell<Symbol<S2V7_RF_active>> = OnceCell::new();
  100. // static
  101. static mut INITDLL: bool = false;
  102. static mut DEVICE_START_INDEX: u64 = 0;
  103. static mut DIRECTORY_PATH: OnceCell<String> = OnceCell::new();
  104. static mut USER_ID: OnceCell<String> = OnceCell::new();
  105. static mut DEVCIE_NAME: OnceCell<String> = OnceCell::new();
  106. static mut RESULT_TYPE: OnceCell<i32> = OnceCell::new();
  107. static mut NEED_RECORD: OnceCell<bool> = OnceCell::new();
  108. // 初始化dll
  109. fn init_dll(dll_path: &str) -> Result<bool, Box<dyn std::error::Error>> {
  110. unsafe {
  111. if INITDLL {
  112. return Ok(true);
  113. }
  114. }
  115. println!("加载dll");
  116. println!("dll_path");
  117. let library = LIBRARY.get_or_init(|| unsafe { Library::new(dll_path).unwrap() });
  118. println!("S2V7_open");
  119. V7_OPEN.get_or_init(|| unsafe { library.get::<S2V7_open>(b"S2V7_open").unwrap() });
  120. println!("S2V7_close");
  121. V7_CLOSE.get_or_init(|| unsafe { library.get::<S2V7_close>(b"S2V7_close").unwrap() });
  122. println!("S2V7_set_mode");
  123. V7_SET_MODE.get_or_init(|| unsafe {library.get::<S2V7_set_mode>(b"S2V7_set_mode").unwrap()});
  124. println!("S2V7_wait_DocIn");
  125. V7_WAIT_DOCINT.get_or_init(|| unsafe { library.get::<S2V7_wait_DocIn>(b"S2V7_wait_DocIn").unwrap() });
  126. println!("S2V7_wait_DocOut");
  127. V7_WAIT_DOCOUT.get_or_init(|| unsafe { library.get::<S2V7_wait_DocOut>(b"S2V7_wait_DocOut").unwrap() });
  128. V7_PROCESS.get_or_init(|| unsafe { library.get::<S2V7_process>(b"S2V7_process").unwrap() });
  129. V7_GET_CARDTYPE.get_or_init(|| unsafe { library.get::<S2V7_get_cardType>(b"S2V7_get_cardType").unwrap() });
  130. V7_VIS_SAVECOLOR.get_or_init(|| unsafe { library.get::<S2V7_VIS_saveColor>(b"S2V7_VIS_saveColor").unwrap() });
  131. V7_VIS_SAVEIR.get_or_init(|| unsafe { library.get::<S2V7_VIS_saveIR>(b"S2V7_VIS_saveIR").unwrap() });
  132. V7_VIS_GETMRZTEXT.get_or_init(|| unsafe { library.get::<S2V7_VIS_getMRZtext>(b"S2V7_VIS_getMRZtext").unwrap() });
  133. V7_RDO_getBytesByIndex.get_or_init(|| unsafe { library.get::<S2V7_RDO_getBytesByIndex>(b"S2V7_RDO_getBytesByIndex").unwrap() });
  134. V7_VIS_getBytesByIndex.get_or_init(|| unsafe { library.get::<S2V7_VIS_getBytesByIndex>(b"S2V7_VIS_getBytesByIndex").unwrap() });
  135. V7_RF_active.get_or_init(|| unsafe { library.get::<S2V7_RF_active>(b"S2V7_RF_active").unwrap() });
  136. unsafe {
  137. INITDLL = true;
  138. }
  139. Ok(true)
  140. }
  141. fn init() -> c_int {
  142. let directory = unsafe { DIRECTORY_PATH.get().unwrap() };
  143. let userid = unsafe { USER_ID.get().unwrap() };
  144. let directory_path = std::path::Path::new(directory).join(MACHINE_KIND);
  145. if directory_path.exists() {
  146. let dll_path = directory_path.join(libloading::library_filename("STAR200_V7_DRV"));
  147. println!("dll_path: {:?}", dll_path);
  148. if dll_path.exists() {
  149. match init_dll(dll_path.to_str().unwrap()).is_ok() {
  150. true => {
  151. // 打开设备
  152. let init_result = unsafe {V7_OPEN.get_unchecked()()};
  153. if init_result == 0 {
  154. println!("设备打开成功");
  155. return ResultType::Success as c_int;
  156. } else {
  157. println!("设备打开失败,代码:{:?}",init_result);
  158. return ResultType::DeviceNotFound as c_int;
  159. }
  160. }
  161. false => {
  162. return ResultType::INITDLLFail as c_int;
  163. }
  164. }
  165. } else {
  166. return ResultType::DllPathNotExist as c_int;
  167. }
  168. } else {
  169. println!("{:?}", directory_path);
  170. return ResultType::DirectoryPathNotExist as c_int;
  171. }
  172. }
  173. pub fn init_by_node(mut cx: FunctionContext) -> JsResult<JsNumber> {
  174. let directory = cx.argument::<JsString>(0)?.value(&mut cx);
  175. let userid = cx.argument::<JsString>(1)?.value(&mut cx);
  176. unsafe {
  177. DIRECTORY_PATH.take();
  178. DIRECTORY_PATH.set(directory).unwrap();
  179. USER_ID.take();
  180. USER_ID.set(userid).unwrap();
  181. };
  182. let result = init() as f64;
  183. Ok(cx.number(result))
  184. }
  185. #[allow(dead_code)] // 允许dead_code
  186. enum ResultType {
  187. DirectoryPathNotExist = -2003, // 找不到运行目录
  188. DllPathNotExist = -2001, // 找不到dll文件
  189. INITDLLFail = -2000, // 初始化dll
  190. Success = 0, // 成功
  191. UserIdFail = 2001, //用户 ID 错误
  192. DeviceInitFail = 2002, // 设备初始化失败
  193. DeviceKernelInitFail = 2003, // 初始化核心失败
  194. DeviceDatInitFail = 2004, //未找到授权文件
  195. DeviceNotInit = 2101, // 设备未初始化
  196. DeviceNotFound = 2102, // 没有找到设备
  197. DeviceReConnect = 2103, // 重新连接设备
  198. Unknown = -100, // 未知错误
  199. CheckCardInput = 3001, // 证件放入设备
  200. CheckCardOut = 3002, // 证件移出设备
  201. CheckCardNotInOrOut = 3000, // 证件无放入或拿出
  202. CheckCardBarCode = 3003, // 检测到手机条码
  203. OCRFail=-1, // 未检测到OCR区域
  204. }
  205. type RecogIDCardEXResultItem = HashMap<i32, [String; 2]>;
  206. #[derive(Default, Serialize)]
  207. pub struct RecogIDCardEXResultObject {
  208. pub viz_result: RecogIDCardEXResultItem,
  209. pub viz_orc_result: RecogIDCardEXResultItem,
  210. pub mrz_result: RecogIDCardEXResultItem,
  211. pub mrz_ocr_result: RecogIDCardEXResultItem,
  212. pub chip_result: RecogIDCardEXResultItem,
  213. }
  214. #[derive(Default, Serialize)]
  215. pub struct RecogIDCardEXResult {
  216. pub device_name: String,
  217. pub device_online: bool,
  218. pub reg_info: RecogIDCardEXResultObject,
  219. pub img_base64: HashMap<String, String>,
  220. pub card_type: i32,
  221. pub record_type: i32,
  222. pub card_name: String,
  223. pub success: bool, // 识别是否成功
  224. }
  225. static SAVE_IMAGE_REUSLT_NAME: [&str; 5] = [
  226. "tempHeadEC.jpg",
  227. "tempHead.jpg",
  228. "tempUV.jpg",
  229. "tempIR.jpg",
  230. "temp.jpg",
  231. ];
  232. fn start(mut cx: FunctionContext) -> JsResult<JsUndefined> {
  233. let callback = cx.argument::<JsFunction>(0)?.root(&mut cx);
  234. let mut channel = cx.channel();
  235. channel.reference(&mut cx);
  236. println!("start {}", channel.has_ref());
  237. let index = unsafe {
  238. DEVICE_START_INDEX += 1;
  239. DEVICE_START_INDEX
  240. };
  241. std::thread::spawn(move || {
  242. // Do the heavy lifting inside the background thread.
  243. device_start(callback, channel, index);
  244. });
  245. Ok(cx.undefined())
  246. }
  247. use std::sync::{Arc, Mutex};
  248. fn device_start(callback: Root<JsFunction>, channel: Channel, index: u64) {
  249. let index = index;
  250. let callback = Arc::new(Mutex::new(callback));
  251. //设置读证功能
  252. unsafe { V7_SET_MODE.get_unchecked()(1,1,1,1) };
  253. loop {
  254. if index != unsafe { DEVICE_START_INDEX } {
  255. break;
  256. };
  257. let callback_clone = Arc::clone(&callback);
  258. let mut result = RecogIDCardEXResult::default();
  259. let mut flg_in:i8=0;
  260. match unsafe { V7_WAIT_DOCINT.get_unchecked()(5.0,&mut flg_in) } {
  261. // 设备正常 检测是否有放入证件
  262. 0 => {
  263. if flg_in==0{
  264. //检查是否放入超时
  265. result.record_type = ResultType::CheckCardNotInOrOut as i32;
  266. break;
  267. }
  268. result.device_online = true;
  269. result.device_name =unsafe { DEVCIE_NAME.get_or_init(|| "".to_string()).to_string() };
  270. match unsafe { V7_PROCESS.get_unchecked()() } {
  271. // 证件有放入
  272. 0 => {
  273. result.record_type = ResultType::CheckCardInput as i32;
  274. }
  275. // 未检测到OCR区域
  276. -1 => {
  277. result.record_type = ResultType::OCRFail as i32;
  278. }
  279. // 未找到非接卡
  280. // v if v/10 == -21 => {
  281. // result.record_type = ResultType::OCRFail as i32;
  282. // }
  283. // 设备离线
  284. -3 => {
  285. result.device_online = false;
  286. result.record_type = init();
  287. }
  288. _ => {
  289. result.record_type = ResultType::Unknown as i32;
  290. }
  291. }
  292. }
  293. -3 => {
  294. //设备离线
  295. let init = init();
  296. result.device_online = false;
  297. result.record_type = init;
  298. }
  299. _ => {
  300. //未知错误
  301. result.record_type = ResultType::Unknown as i32;
  302. }
  303. };
  304. if unsafe { *NEED_RECORD.get_or_init(|| false) } {
  305. println!("手工点击识别+1");
  306. result.record_type = ResultType::CheckCardInput as i32;
  307. }
  308. // let time_now = std::time::Instant::now();
  309. if result.record_type == ResultType::CheckCardInput as i32 {
  310. let _result = recog_card();
  311. result.success = _result.success;
  312. result.img_base64 = _result.img_base64;
  313. result.reg_info = _result.reg_info;
  314. result.card_type = _result.card_type;
  315. result.card_name = _result.card_name;
  316. }
  317. let neet_sendinfo = if Some(true) == unsafe { NEED_RECORD.take() } {
  318. true
  319. } else {
  320. false
  321. };
  322. // let elapsed = time_now.elapsed();
  323. // println!("识别时间结束时间 {:.6?}", elapsed);
  324. if result.record_type != ResultType::CheckCardNotInOrOut as i32
  325. && (*unsafe { RESULT_TYPE.get_or_init(|| -10000) } != result.record_type
  326. || result.record_type == ResultType::CheckCardInput as i32
  327. || neet_sendinfo)
  328. {
  329. unsafe {
  330. RESULT_TYPE.take();
  331. RESULT_TYPE.set(result.record_type).unwrap();
  332. }
  333. channel.send(move |mut cx| {
  334. let result_json = serde_json::to_string(&result).unwrap();
  335. let callback = callback_clone.lock().unwrap().to_inner(&mut cx);
  336. let this = cx.undefined();
  337. let args = vec![cx.string(&result_json)];
  338. callback.call(&mut cx, this, args)?;
  339. Ok(())
  340. });
  341. }
  342. std::thread::sleep(std::time::Duration::from_millis(20));
  343. }
  344. }
  345. // 白光图、红外
  346. // 图、紫外图、版面头像和芯片头像
  347. pub fn recog_card() -> RecogIDCardEXResult {
  348. let time_now = std::time::Instant::now();
  349. let mut result = RecogIDCardEXResult::default();
  350. result.device_online = true;
  351. let img_path_directory = std::path::Path::new(unsafe { DIRECTORY_PATH.get().unwrap() });
  352. let ir_img_path = img_path_directory.join("ir.jpg");
  353. let color_img_path = img_path_directory.join("color.jpg");
  354. //显示红外照
  355. let irResult = unsafe {V7_VIS_SAVEIR.get_unchecked()(encode(ir_img_path.to_str().unwrap()).as_ptr() as LPCTSTR)};
  356. //显示彩照
  357. let colorResult = unsafe {V7_VIS_SAVECOLOR.get_unchecked()(encode(color_img_path.to_str().unwrap()).as_ptr() as LPCTSTR)};
  358. if irResult==0{
  359. if ir_img_path.exists() {
  360. match std::fs::read(&ir_img_path) {
  361. Ok(image_data) => {
  362. println!("读取照片成功");
  363. let image_data = base64::encode(&image_data);
  364. let base64_string = String::from("data:image/jpg;base64,");
  365. std::fs::remove_file(ir_img_path).unwrap();
  366. result.img_base64.insert("0".to_string(), base64_string + &image_data);
  367. }
  368. Err(e) => {
  369. println!("读取照片抛异常");
  370. println!(
  371. "{:?} {:?}",
  372. e,
  373. "ir.jpg",
  374. );
  375. }
  376. };
  377. }
  378. }
  379. if colorResult==0{
  380. if color_img_path.exists() {
  381. match std::fs::read(&color_img_path) {
  382. Ok(image_data) => {
  383. println!("读取照片成功");
  384. let image_data = base64::encode(&image_data);
  385. let base64_string = String::from("data:image/jpg;base64,");
  386. std::fs::remove_file(color_img_path).unwrap();
  387. result.img_base64.insert("1".to_string(), base64_string + &image_data);
  388. }
  389. Err(e) => {
  390. println!("读取照片抛异常");
  391. println!(
  392. "{:?} {:?}",
  393. e,
  394. "color.jpg",
  395. );
  396. }
  397. };
  398. }
  399. }
  400. let mut ocritem = RecogIDCardEXResultObject::default();
  401. let mut index: c_int = 0;
  402. //orc识别文字
  403. let mut mrztext = [0; 1024];
  404. let x = unsafe {V7_VIS_GETMRZTEXT.get_unchecked()(mrztext.as_mut_ptr())};
  405. if x==0{
  406. let result_item = ["MRZ".to_string(), decode(&mrztext)];
  407. ocritem.mrz_result.insert(index, result_item);
  408. index+=1;
  409. }
  410. let mut data:[u16; 256] = [0; 256];
  411. let mut len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(0,data.as_mut_ptr())};
  412. if len>0{
  413. ocritem.mrz_result.insert(index, ["编号".to_string(), decode(&data)]);
  414. index+=1;
  415. len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(1,data.as_mut_ptr())};
  416. ocritem.mrz_result.insert(index, ["国籍".to_string(), decode(&data)]);
  417. index+=1;
  418. len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(2,data.as_mut_ptr())};
  419. ocritem.mrz_result.insert(index, ["民族".to_string(), decode(&data)]);
  420. index+=1;
  421. len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(3,data.as_mut_ptr())};
  422. ocritem.mrz_result.insert(index, ["姓名".to_string(), decode(&data)]);
  423. index+=1;
  424. len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(4,data.as_mut_ptr())};
  425. let cardType= unsafe {V7_GET_CARDTYPE.get_unchecked()()};
  426. if cardType==101{
  427. //身份证是UTF8格式
  428. ocritem.mrz_result.insert(index, ["中文名".to_string(), decode(&data)]);
  429. }else{
  430. ocritem.mrz_result.insert(index, ["中文名".to_string(), decode(&data)]);
  431. // //中国护照的中文姓名 是GBK编码的
  432. // let name=GB18030.decode(&data, DecoderTrap::Strict).unwrap();
  433. // ocritem.mrz_result.insert(index, ["中文名".to_string(), name.replace("\u{0}","")]);
  434. }
  435. index+=1;
  436. len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(5,data.as_mut_ptr())};
  437. ocritem.mrz_result.insert(index, ["性别".to_string(), decode(&data)]);
  438. index+=1;
  439. len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(6,data.as_mut_ptr())};
  440. ocritem.mrz_result.insert(index, ["出生日期".to_string(), decode(&data)]);
  441. index+=1;
  442. len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(7,data.as_mut_ptr())};
  443. ocritem.mrz_result.insert(index, ["地址".to_string(), decode(&data)]);
  444. index+=1;
  445. len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(8,data.as_mut_ptr())};
  446. ocritem.mrz_result.insert(index, ["签发机关".to_string(), decode(&data)]);
  447. index+=1;
  448. len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(9,data.as_mut_ptr())};
  449. ocritem.mrz_result.insert(index, ["有效期始".to_string(), decode(&data)]);
  450. index+=1;
  451. len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(10,data.as_mut_ptr())};
  452. ocritem.mrz_result.insert(index, ["有效期止".to_string(), decode(&data)]);
  453. index+=1;
  454. len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(20,data.as_mut_ptr())};
  455. ocritem.mrz_result.insert(index, ["港澳台ID".to_string(), decode(&data)]);
  456. index+=1;
  457. }
  458. else{
  459. len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(0,data.as_mut_ptr())};
  460. ocritem.mrz_result.insert(index, ["编号".to_string(), decode(&data)]);
  461. index+=1;
  462. len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(1,data.as_mut_ptr())};
  463. ocritem.mrz_result.insert(index, ["国籍".to_string(), decode(&data)]);
  464. index+=1;
  465. len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(2,data.as_mut_ptr())};
  466. ocritem.mrz_result.insert(index, ["民族".to_string(), decode(&data)]);
  467. index+=1;
  468. len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(3,data.as_mut_ptr())};
  469. ocritem.mrz_result.insert(index, ["姓名".to_string(), decode(&data)]);
  470. index+=1;
  471. //中国护照的中文姓名 是GBK编码的, 身份证不会执行到这里
  472. len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(4,data.as_mut_ptr())};
  473. ocritem.mrz_result.insert(index, ["中文名".to_string(), decode(&data)]);
  474. // let name=GB18030.decode(&data, DecoderTrap::Strict).unwrap();
  475. // ocritem.mrz_result.insert(index, ["中文名".to_string(), name.replace("\u{0}","")]);
  476. index+=1;
  477. len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(5,data.as_mut_ptr())};
  478. ocritem.mrz_result.insert(index, ["性别".to_string(), decode(&data)]);
  479. index+=1;
  480. len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(6,data.as_mut_ptr())};
  481. ocritem.mrz_result.insert(index, ["出生日期".to_string(), decode(&data)]);
  482. index+=1;
  483. len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(7,data.as_mut_ptr())};
  484. ocritem.mrz_result.insert(index, ["地址".to_string(), decode(&data)]);
  485. index+=1;
  486. len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(8,data.as_mut_ptr())};
  487. ocritem.mrz_result.insert(index, ["签发机关".to_string(), decode(&data)]);
  488. index+=1;
  489. len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(9,data.as_mut_ptr())};
  490. ocritem.mrz_result.insert(index, ["有效期始".to_string(), decode(&data)]);
  491. index+=1;
  492. len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(10,data.as_mut_ptr())};
  493. ocritem.mrz_result.insert(index, ["有效期止".to_string(), decode(&data)]);
  494. index+=1;
  495. len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(20,data.as_mut_ptr())};
  496. ocritem.mrz_result.insert(index, ["港澳台ID".to_string(), decode(&data)]);
  497. index+=1;
  498. }
  499. result.reg_info=ocritem;
  500. result.success = true;
  501. result.card_type = unsafe {V7_GET_CARDTYPE.get_unchecked()()};
  502. let elapsed = time_now.elapsed();
  503. println!("{:.6?}", elapsed);
  504. return result;
  505. }
  506. pub fn regcord_by_node(mut cx: FunctionContext) -> JsResult<JsNull> {
  507. println!("regcord_by_node");
  508. unsafe {
  509. NEED_RECORD.take();
  510. NEED_RECORD.set(true).unwrap();
  511. };
  512. Ok(cx.null())
  513. }
  514. #[neon::main]
  515. fn main(mut cx: ModuleContext) -> NeonResult<()> {
  516. cx.export_function("init", init_by_node)?;
  517. cx.export_function("start", start)?;
  518. cx.export_function("regcord_by_node", regcord_by_node)?;
  519. Ok(())
  520. }

到此这篇关于使用rust调用c++静态库并编译nodejs包的文章就介绍到这了,更多相关rust调用c++静态库内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号