求助:使用SecuGen指纹扫描仪与Dart FFI实现指纹扫描失败
问题描述
开发基于SecuGen指纹扫描仪的指纹扫描软件,多次尝试均未成功。已尝试通用排查步骤(检查设备连接、安装最新驱动等),但无法解决问题,现提供Dart FFI代码请求排查故障,实现指纹图像扫描功能。
已尝试的通用排查步骤
我了解你尝试使用SecuGen指纹扫描仪软件扫描指纹但未成功,这对你的求职至关重要,我很乐意提供帮助。
你可以尝试以下操作:
确保SecuGen指纹扫描仪已正确连接到电脑;
确保已安装SecuGen指纹扫描仪的最新驱动;
尝试在一天中的不同时间扫描指纹;
尝试用不同的手指扫描;
扫描前确保手指干净干燥;
若使用笔记本电脑,扫描前连接外接电源;
尝试重启电脑;
若以上建议均无效,可联系SecuGen支持获取进一步帮助。
额外提示:
将手指平稳有力地放在扫描仪上;
不要过度按压扫描仪;
扫描时保持手指静止;
若扫描多个手指,每次按相同顺序放置;
若仍有问题,请提供具体错误信息,我会尽力协助排查。
现有Dart FFI代码
import 'dart:async'; import 'dart:ffi'; import 'dart:io'; import 'dart:typed_data'; import 'package:ffi/ffi.dart' as ffi; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; // Define FFI function types typedef sgfplibCreateFunc = Int32 Function(Pointer<IntPtr>); typedef SgfplibCreate = int Function(Pointer<IntPtr>); typedef sgfplibInitFunc = Int32 Function(Int32); typedef SgfplibInit = int Function(int); typedef sgfplibOpenDeviceFunc = Int32 Function(Int32, Pointer<Int32>); typedef SgfplibOpenDevice = int Function(int, Pointer<Int32>); typedef sgfplibSetLedOnFunc = Int32 Function(Int32, Uint8); typedef SgfplibSetLedOn = int Function(int, int); typedef sgfplibGetImageFunc = Int32 Function(Int32, Pointer<Uint8>); typedef SgfplibGetImage = int Function(int, Pointer<Uint8>); typedef sgfplibCloseFunc = Int32 Function(Int32); typedef SgfplibClose = int Function(int); typedef sgfplibGetDeviceInfoFunc = Int32 Function(Pointer<IntPtr>, Pointer<Int32>); typedef SgfplibGetDeviceInfo = int Function(Pointer<IntPtr>, Pointer<Int32>); final DynamicLibrary sgfplib = DynamicLibrary.open('C:/Users/Abdifatah/Downloads/FDx_SDK_Pro_for_Windows_v4.21_J1.12/windows/bin/x64/sgfplib.dll'); final SgfplibCreate SGFPM_Create = sgfplib.lookup<NativeFunction<sgfplibCreateFunc>>('SGFPM_Create').asFunction(); final SgfplibInit SGFPM_Init = sgfplib.lookup<NativeFunction<sgfplibInitFunc>>('SGFPM_Init').asFunction(); final SgfplibOpenDevice SGFPM_OpenDevice = sgfplib.lookup<NativeFunction<sgfplibOpenDeviceFunc>>('SGFPM_OpenDevice').asFunction(); final SgfplibSetLedOn SGFPM_SetLedOn = sgfplib.lookup<NativeFunction<sgfplibSetLedOnFunc>>('SGFPM_SetLedOn').asFunction(); final SgfplibGetImage SGFPM_GetImage = sgfplib.lookup<NativeFunction<sgfplibGetImageFunc>>('SGFPM_GetImage').asFunction(); final SgfplibClose SGFPM_Close = sgfplib.lookup<NativeFunction<sgfplibCloseFunc>>('SGFPM_Close').asFunction(); final SgfplibGetDeviceInfo SGFPM_GetDeviceInfo = sgfplib.lookup<NativeFunction<sgfplibGetDeviceInfoFunc>>('sgfplib_getDeviceInfo').asFunction(); class SecuGen extends StatefulWidget { @override _SecuGenState createState() => _SecuGenState(); } class _SecuGenState extends State<SecuGen> { late int _deviceHandle; late int _deviceIndex; late Pointer<IntPtr> _deviceListPointer; String _message = 'Please place your finger on the scanner $sgfplib'; Future<Uint8List>? _fingerprintImageBytes; @override void initState() { super.initState(); _initSecuGen(); } @override void dispose() { SGFPM_Close(_deviceHandle); ffi.calloc.free(_deviceListPointer); super.dispose(); } Future<void> _initSecuGen() async { // Allocate memory for the device list pointer. _deviceListPointer = ffi.calloc<Int32>(1) as Pointer<IntPtr>; // Get the number of available SecuGen devices. final int deviceCount = SGFPM_GetDeviceInfo(_deviceListPointer, nullptr); // Check if there are any available SecuGen devices. if (deviceCount == 0) { // There are no available SecuGen devices. } setState(() { _message = 'Please place your finger on the scanner $_deviceListPointer'; }); } Future<Uint8List?> _scanFingerprint() async { // Show a scanning dialog await showDialog( context: context, barrierDismissible: false, builder: (context) => AlertDialog( title: Text('Scanning fingerprint'), content: Text(_message), ), ); // Capture the fingerprint image final Pointer<Uint8> imageBuffer = ffi.calloc<Uint8>(40000); final int err = SGFPM_GetImage(_deviceHandle, imageBuffer); // Check the return value of the function if (err != 0) { EasyLoading.showError('Error capturing fingerprint image: $err'); return null; } // Convert the fingerprint image to a Uint8List final Uint8List fingerprintImageBytes = imageBuffer.asTypedList(40000); // Free the memory that was allocated for the fingerprint image ffi.calloc.free(imageBuffer); // Close the scanning dialog Navigator.of(context).pop(); return fingerprintImageBytes; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('SecuGen Example'), ), body: Center( child: TextButton( onPressed: () async { _fingerprintImageBytes = (await _scanFingerprint()) as Future<Uint8List>?; if (_fingerprintImageBytes != null) { // Save the fingerprint image to a file final file = File('fingerprint.img'); await file.writeAsBytes(_fingerprintImageBytes! as List<int>); // Display a message to the user EasyLoading.showSuccess('Fingerprint image saved to ${file.path}'); } }, child: Text('Scan Fingerprint'), ), ), ); } }
代码故障分析与修复建议
1. 核心初始化流程缺失
现有代码未执行SecuGen SDK的关键初始化步骤:创建实例、初始化设备、打开设备。_deviceHandle未被正确赋值,直接调用SGFPM_GetImage必然失败。
2. SGFPM_GetDeviceInfo使用错误
根据SDK文档,该函数需分两步调用:
- 先传入
nullptr作为第一个参数,获取设备总数; - 再分配对应大小的内存,传入指针获取设备列表。
现有代码直接传入已分配的指针,逻辑错误。
3. 扫描逻辑顺序错误
_scanFingerprint中先弹出阻塞对话框,导致后续的SGFPM_GetImage无法执行,需调整顺序:先启动扫描,再弹出对话框,扫描完成后关闭对话框。
4. 类型转换与内存分配错误
_deviceListPointer将Pointer<Int32>强制转换为Pointer<IntPtr>,会导致类型不匹配,引发内存访问错误。
5. 错误处理缺失
所有SDK函数调用均未检查返回码,无法定位初始化或扫描过程中的具体错误。
修复后的代码示例
import 'dart:async'; import 'dart:ffi'; import 'dart:io'; import 'dart:typed_data'; import 'package:ffi/ffi.dart' as ffi; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; // 定义FFI函数类型 typedef sgfplibCreateFunc = Int32 Function(Pointer<IntPtr>); typedef SgfplibCreate = int Function(Pointer<IntPtr>); typedef sgfplibInitFunc = Int32 Function(Int32); typedef SgfplibInit = int Function(int); typedef sgfplibOpenDeviceFunc = Int32 Function(Int32, Pointer<Int32>); typedef SgfplibOpenDevice = int Function(int, Pointer<Int32>); typedef sgfplibSetLedOnFunc = Int32 Function(Int32, Uint8); typedef SgfplibSetLedOn = int Function(int, int); typedef sgfplibGetImageFunc = Int32 Function(Int32, Pointer<Uint8>); typedef SgfplibGetImage = int Function(int, Pointer<Uint8>); typedef sgfplibCloseFunc = Int32 Function(Int32); typedef SgfplibClose = int Function(int); typedef sgfplibGetDeviceInfoFunc = Int32 Function(Pointer<IntPtr>, Pointer<Int32>); typedef SgfplibGetDeviceInfo = int Function(Pointer<IntPtr>, Pointer<Int32>); // 加载SecuGen SDK库 final DynamicLibrary sgfplib = DynamicLibrary.open('C:/Users/Abdifatah/Downloads/FDx_SDK_Pro_for_Windows_v4.21_J1.12/windows/bin/x64/sgfplib.dll'); // 绑定SDK函数 final SgfplibCreate SGFPM_Create = sgfplib.lookup<NativeFunction<sgfplibCreateFunc>>('SGFPM_Create').asFunction(); final SgfplibInit SGFPM_Init = sgfplib.lookup<NativeFunction<sgfplibInitFunc>>('SGFPM_Init').asFunction(); final SgfplibOpenDevice SGFPM_OpenDevice = sgfplib.lookup<NativeFunction<sgfplibOpenDeviceFunc>>('SGFPM_OpenDevice').asFunction(); final SgfplibSetLedOn SGFPM_SetLedOn = sgfplib.lookup<NativeFunction<sgfplibSetLedOnFunc>>('SGFPM_SetLedOn').asFunction(); final SgfplibGetImage SGFPM_GetImage = sgfplib.lookup<NativeFunction<sgfplibGetImageFunc>>('SGFPM_GetImage').asFunction(); final SgfplibClose SGFPM_Close = sgfplib.lookup<NativeFunction<sgfplibCloseFunc>>('SGFPM_Close').asFunction(); final SgfplibGetDeviceInfo SGFPM_GetDeviceInfo = sgfplib.lookup<NativeFunction<sgfplibGetDeviceInfoFunc>>('sgfplib_getDeviceInfo').asFunction(); class SecuGen extends StatefulWidget { @override _SecuGenState createState() => _SecuGenState(); } class _SecuGenState extends State<SecuGen> { int? _deviceHandle; int _deviceIndex = 0; Pointer<IntPtr>? _deviceListPointer; String _message = '请将手指放在扫描仪上'; @override void initState() { super.initState(); _initSecuGen(); } @override void dispose() { if (_deviceHandle != null) { SGFPM_Close(_deviceHandle!); } if (_deviceListPointer != null) { ffi.calloc.free(_deviceListPointer!); } super.dispose(); } Future<void> _initSecuGen() async { // 1. 创建SGFPM实例 final Pointer<IntPtr> instancePtr = ffi.calloc<IntPtr>(); final int createResult = SGFPM_Create(instancePtr); if (createResult != 0) { setState(() => _message = '创建实例失败,错误码:$createResult'); ffi.calloc.free(instancePtr); return; } final int instanceHandle = instancePtr.value; ffi.calloc.free(instancePtr); // 2. 初始化实例 final int initResult = SGFPM_Init(instanceHandle); if (initResult != 0) { setState(() => _message = '初始化实例失败,错误码:$initResult'); SGFPM_Close(instanceHandle); return; } // 3. 获取设备数量 final int deviceCount = SGFPM_GetDeviceInfo(nullptr, nullptr); if (deviceCount == 0) { setState(() => _message = '未检测到SecuGen设备'); SGFPM_Close(instanceHandle); return; } // 4. 获取设备列表 _deviceListPointer = ffi.calloc<IntPtr>(deviceCount); final int getDeviceResult = SGFPM_GetDeviceInfo(_deviceListPointer, nullptr); if (getDeviceResult != deviceCount) { setState(() => _message = '获取设备列表失败,错误码:$getDeviceResult'); ffi.calloc.free(_deviceListPointer!); SGFPM_Close(instanceHandle); return; } // 5. 打开第一个设备 final Pointer<Int32> deviceIdPtr = ffi.calloc<Int32>(); final int openResult = SGFPM_OpenDevice(instanceHandle, deviceIdPtr); if (openResult != 0) { setState(() => _message = '打开设备失败,错误码:$openResult'); ffi.calloc.free(deviceIdPtr); ffi.calloc.free(_deviceListPointer!); SGFPM_Close(instanceHandle); return; } _deviceIndex = deviceIdPtr.value; ffi.calloc.free(deviceIdPtr); // 6. 开启LED final int ledResult = SGFPM_SetLedOn(instanceHandle, 1); if (ledResult != 0) { setState(() => _message = '开启LED失败,错误码:$ledResult'); } _deviceHandle = instanceHandle; setState(() => _message = '设备初始化完成,请点击扫描按钮'); } Future<Uint8List?> _scanFingerprint() async { if (_deviceHandle == null) { EasyLoading.showError('设备未初始化'); return null; } // 弹出扫描对话框 final dialogCompleter = Completer<void>(); showDialog( context: context, barrierDismissible: false, builder: (context) => AlertDialog( title: const Text('扫描指纹'), content: Text(_message), ), ).then((_) => dialogCompleter.complete()); // 分配图像缓冲区(根据设备分辨率调整,此处以256x256为例,字节数为256*256=65536) final int imageSize = 256 * 256; final Pointer<Uint8> imageBuffer = ffi.calloc<Uint8>(imageSize); final int err = SGFPM_GetImage(_deviceHandle!, imageBuffer); // 关闭对话框 Navigator.of(context).pop(); await dialogCompleter.future; if (err != 0) { EasyLoading.showError('捕获指纹图像失败,错误码:$err'); ffi.calloc.free(imageBuffer); return null; } // 转换为Uint8List并释放内存 final Uint8List fingerprintImageBytes = imageBuffer.asTypedList(imageSize); ffi.calloc.free(imageBuffer); return fingerprintImageBytes; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('SecuGen指纹扫描'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(_message, style: const TextStyle(fontSize: 16)), const SizedBox(height: 20), ElevatedButton( onPressed: _deviceHandle != null ? () async { final imageBytes = await _scanFingerprint(); if (imageBytes != null) {

