You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:使用SecuGen指纹扫描仪与Dart FFI实现指纹扫描失败

排查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) {
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 15:16:16