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

WinBio指纹池计数错误及指纹验证异常技术求助

问题描述

我在系统指纹池(system pool)中已录入4个指纹:2个通过代码的EnrollSysPool函数录入,2个通过系统UI录入。但GetFingerprintCount()函数始终返回1,无法正确统计指纹数量;此外,系统允许用全部4个指纹登录,但通过Python代码验证时,仅能验证第一个通过系统UI录入的指纹,其余指纹均无法通过验证。需要解决计数错误问题,并获取指纹验证功能的实现指导。

相关代码
import ctypes
import msvcrt
from ctypes import Structure, c_ulong, POINTER

# Constants
WINBIO_TYPE_FINGERPRINT = 0x00000008
WINBIO_POOL_SYSTEM = 0x00000001
WINBIO_FLAG_DEFAULT = 0x00000000
WINBIO_ID_TYPE_SID = 3
WINBIO_E_BAD_CAPTURE = 0x80098003
WINBIO_E_NO_MATCH = 0x80098005
WINBIO_I_MORE_DATA = 0x40098002

# Load the winbio.dll library
lib = ctypes.WinDLL(r"C:\Windows\System32\winbio.dll")

# Define WINBIO_REJECT_DETAIL structure
class WINBIO_REJECT_DETAIL(ctypes.Structure):
    _fields_ = [
        ("RejectDetailSize", ctypes.c_ulong),
        # Add other fields if needed
    ]

# Function prototypes
lib.WinBioOpenSession.argtypes = [
    ctypes.c_uint32,                      # Factor
    ctypes.c_uint32,                      # PoolType
    ctypes.c_uint32,                      # Access
    ctypes.POINTER(ctypes.c_void_p),       # Array of unit IDs
    ctypes.c_ulong,                       # Unit count
    ctypes.POINTER(ctypes.POINTER(ctypes.c_void_p)),  # Database ID
    ctypes.POINTER(ctypes.POINTER(ctypes.c_void_p))  # Session handle
]

lib.WinBioEnumBiometricUnits.argtypes = [
    ctypes.c_uint32,  # Biometric type
    ctypes.POINTER(ctypes.POINTER(ctypes.c_void_p)),  # Array of unit schema
    ctypes.POINTER(ctypes.c_ulong),  # Count of unit schema
]

lib.WinBioCloseSession.argtypes = [
    ctypes.c_void_p  # Session handle
]

lib.WinBioLocateSensor.argtypes = [
    ctypes.c_void_p,  # Session handle
    ctypes.POINTER(ctypes.c_void_p)  # Unit ID
]

lib.WinBioEnrollBegin.argtypes = [
    ctypes.c_void_p,  # Session handle
    ctypes.c_uint32,  # Finger to create template for
    ctypes.c_void_p   # Biometric unit ID
]

lib.WinBioEnrollCapture.argtypes = [
    ctypes.c_void_p,  # Session handle
    ctypes.POINTER(WINBIO_REJECT_DETAIL)  # Failure information
]

lib.WinBioEnrollCommit.argtypes = [
    ctypes.c_void_p,  # Session handle
    ctypes.POINTER(ctypes.c_void_p),  # WINBIO_IDENTITY object for the user
    ctypes.POINTER(ctypes.c_bool)  # Is this a new template
]

lib.WinBioEnrollDiscard.argtypes = [
    ctypes.c_void_p  # Session handle
]

def GetFingerprintCount():
    unitSchema = ctypes.POINTER(ctypes.c_void_p)()
    unitCount = ctypes.c_ulong()

    # Enumerate the biometric units of the specified type (fingerprint)
    hr = lib.WinBioEnumBiometricUnits(WINBIO_TYPE_FINGERPRINT, ctypes.byref(unitSchema), ctypes.byref(unitCount))
    if hr != 0:
        print("WinBioEnumBiometricUnits failed. hr = 0x%x" % hr)
        return 0

    return unitCount.value

def EnrollSysPool(discardEnrollment, subFactor):
    hr = 0
    identity = ctypes.c_void_p()
    sessionHandle = ctypes.POINTER(ctypes.c_void_p)()  # Updated argument type
    unitId = ctypes.c_void_p()  # Updated variable type
    rejectDetail = WINBIO_REJECT_DETAIL()
    isNewTemplate = ctypes.c_bool(True) 

    # Connect to the system pool.
    hr = lib.WinBioOpenSession(WINBIO_TYPE_FINGERPRINT,  # Service provider
                            WINBIO_POOL_SYSTEM,  # Pool type
                            WINBIO_FLAG_DEFAULT,  # Configuration and access
                            None,  # Array of biometric unit IDs
                            0,  # Count of biometric unit IDs
                            None,  # Database ID
                            # ctypes.byref(sessionHandle)  # [out] Session handle
                            sessionHandle)
    
    if hr != 0:
        print("WinBioOpenSession failed. hr = 0x%x" % hr)
        return hr

    # Locate a sensor.
    print("\nSwipe your finger on the sensor...")
    hr = lib.WinBioLocateSensor(sessionHandle, ctypes.byref(unitId))
    if hr != 0:
        print("WinBioLocateSensor failed. hr = 0x%x" % hr)
        return hr

    # Begin the enrollment sequence.
    print("\nStarting enrollment sequence...")
    hr = lib.WinBioEnrollBegin(sessionHandle, subFactor, unitId)
    if hr != 0:
        print("WinBioEnrollBegin failed. hr = 0x%x" % hr)
        return hr

    # Capture enrollment information by swiping the sensor with
    # the finger identified by the subFactor argument in the
    # WinBioEnrollBegin function.
    swipeCount = 1  
    rejectDetail = WINBIO_REJECT_DETAIL()
    while True:
        print("Swipe the sensor to capture %s sample." % ("the first" if swipeCount == 1 else "another"))
        hr = lib.WinBioEnrollCapture(sessionHandle, ctypes.byref(rejectDetail))
        print("Sample %d captured from unit number %d." % (swipeCount, ctypes.cast(unitId, ctypes.c_void_p).value))
        print("Thisis WINBIO_I_MORE_DATA value:",WINBIO_I_MORE_DATA)

        if hr == 0x90001:
            print("More data required.")
            swipeCount += 1
            continue
        elif hr != 0:
            if hr == WINBIO_E_BAD_CAPTURE:
                print("Error: Bad capture; reason: %d" % rejectDetail)
                continue
            else:
                print("WinBioEnrollCapture failed. hr = 0x%x" % hr)
                return hr
        else:
            print("Template completed.")
            break

    # Discard the enrollment if the appropriate flag is set.
    # Commit the enrollment if it is not discarded.
    if discardEnrollment:
        print("\nDiscarding enrollment...\n")
        hr = lib.WinBioEnrollDiscard(sessionHandle)
        if hr != 0:
            print("WinBioEnrollDiscard failed. hr = 0x%x" % hr)
    else:
        print("\nCommitting enrollment...")
        hr = lib.WinBioEnrollCommit(sessionHandle, ctypes.byref(identity), ctypes.byref(isNewTemplate))
        if hr != 0:
            error_msg = ctypes.create_string_buffer(256)  # Buffer to hold the error message
            lib.WinBioHresultToString(hr, error_msg, 256)
            print("WinBioEnrollCommit failed. hr = 0x%x. Error message: %s" % (hr, error_msg.value))

    # Close the session handle
    lib.WinBioCloseSession(sessionHandle.contents)  # Dereference the pointer
    print("Press any key to continue...")
    msvcrt.getch()
    return hr

def main():
    discardEnrollment = False  # Set to True if you want to discard the enrollment, False otherwise
    subFactor = 1  # Set the appropriate finger value, e.g., 0 for the first finger

    hr = EnrollSysPool(discardEnrollment, subFactor)

    if hr == 0:
        print("Enrollment successful.")
    else:
        print("Enrollment failed. hr = 0x%x" % hr)

    fingerprintCount = GetFingerprintCount()
    print("Number of fingerprints in the system pool:", fingerprintCount)

if __name__ == "__main__":
    main()
解决方案

一、修复指纹计数错误

你的GetFingerprintCount()调用的WinBioEnumBiometricUnits是用来枚举指纹传感器硬件数量的,不是统计用户录入的指纹模板数量,所以返回1是因为你只有一个指纹传感器。

要统计用户在系统池中的指纹数量,需要用WinBioEnumEnrollments API,以下是修正后的计数函数:

1. 添加必要的函数原型

# 添加新函数的原型
lib.WinBioGetUserIdentity.argtypes = [
    ctypes.c_void_p,  # Session handle
    ctypes.c_uint32,  # ID type
    ctypes.POINTER(ctypes.c_void_p)  # Identity
]

lib.WinBioEnumEnrollments.argtypes = [
    ctypes.c_void_p,  # Session handle
    ctypes.POINTER(ctypes.c_void_p),  # User identity
    ctypes.c_uint32,  # Biometric type
    ctypes.POINTER(ctypes.POINTER(ctypes.c_uint32)),  # Subfactors array
    ctypes.POINTER(ctypes.c_ulong)  # Enrollment count
]

lib.WinBioFree.argtypes = [ctypes.c_void_p]  # 释放API分配的内存

2. 修正后的计数函数

def GetUserFingerprintCount():
    hr = 0
    session_handle = ctypes.POINTER(ctypes.c_void_p)()
    identity = ctypes.c_void_p()
    enrollment_count = ctypes.c_ulong()
    sub_factors = ctypes.POINTER(ctypes.c_uint32)()

    # 打开系统池会话
    hr = lib.WinBioOpenSession(
        WINBIO_TYPE_FINGERPRINT,
        WINBIO_POOL_SYSTEM,
        WINBIO_FLAG_DEFAULT,
        None,
        0,
        None,
        ctypes.byref(session_handle)
    )
    if hr != 0:
        print(f"WinBioOpenSession 失败,hr = 0x{hr:X}")
        return 0

    # 获取当前用户身份标识
    hr = lib.WinBioGetUserIdentity(session_handle, WINBIO_ID_TYPE_SID, ctypes.byref(identity))
    if hr != 0:
        print(f"WinBioGetUserIdentity 失败,hr = 0x{hr:X}")
        lib.WinBioCloseSession(session_handle.contents)
        return 0

    # 枚举用户的所有指纹录入项
    hr = lib.WinBioEnumEnrollments(
        session_handle,
        ctypes.byref(identity),
        WINBIO_TYPE_FINGERPRINT,
        ctypes.byref(sub_factors),
        ctypes.byref(enrollment_count)
    )
    if hr != 0:
        print(f"WinBioEnumEnrollments 失败,hr = 0x{hr:X}")
        lib.WinBioCloseSession(session_handle.contents)
        return 0

    # 释放API分配的内存
    lib.WinBioFree(sub_factors)
    # 关闭会话
    lib.WinBioCloseSession(session_handle.contents)

    return enrollment_count.value

二、指纹验证功能实现

你的验证问题是因为原逻辑没有遍历用户所有录入的指纹,以下是完整的验证实现:

1. 添加验证函数原型

# 添加WinBioVerify的函数原型
lib.WinBioVerify.argtypes = [
    ctypes.c_void_p,  # Session handle
    ctypes.POINTER(ctypes.c_void_p),  # Target identity(传None验证当前用户)
    ctypes.POINTER(ctypes.c_uint32),  # Matched subfactor
    ctypes.POINTER(ctypes.c_void_p)  # Result identity
]

2. 实现验证函数

def VerifyFingerprint():
    hr = 0
    session_handle = ctypes.POINTER(ctypes.c_void_p)()
    unit_id = ctypes.c_void_p()
    reject_detail = WINBIO_REJECT_DETAIL()
    sub_factor = ctypes.c_uint32()
    identity = ctypes.c_void_p()

    # 打开系统池会话
    hr = lib.WinBioOpenSession(
        WINBIO_TYPE_FINGERPRINT,
        WINBIO_POOL_SYSTEM,
        WINBIO_FLAG_DEFAULT,
        None,
        0,
        None,
        ctypes.byref(session_handle)
    )
    if hr != 0:
        print(f"WinBioOpenSession 失败,hr = 0x{hr:X}")
        return hr

    # 定位指纹传感器
    print("\n请在传感器上按压指纹...")
    hr = lib.WinBioLocateSensor(session_handle, ctypes.byref(unit_id))
    if hr != 0:
        print(f"WinBioLocateSensor 失败,hr = 0x{hr:X}")
        lib.WinBioCloseSession(session_handle.contents)
        return hr

    # 执行指纹验证(自动匹配当前用户的所有指纹)
    print("\n正在验证指纹...")
    hr = lib.WinBioVerify(
        session_handle,
        None,  # 传None表示验证当前登录用户的所有指纹
        ctypes.byref(sub_factor),
        ctypes.byref(identity)
    )
    
    # 处理采集失败的情况,允许用户重试
    while hr == WINBIO_E_BAD_CAPTURE:
        print("指纹采集不清晰,请重新按压...")
        hr = lib.WinBioVerify(
            session_handle,
            None,
            ctypes.byref(sub_factor),
            ctypes.byref(identity)
        )

    # 输出验证结果
    if hr == 0:
        print(f"验证成功!匹配的手指编号:{sub_factor.value}")
    elif hr == WINBIO_E_NO_MATCH:
        print("验证失败:未匹配到有效指纹")
    else:
        print(f"WinBioVerify 失败,hr = 0x{hr:X}")

    # 关闭会话
    lib.WinBioCloseSession(session_handle.contents)
    return hr

3. 调用验证函数

在main函数中添加调用:

def main():
    # ... 原有代码 ...
    fingerprintCount = GetUserFingerprintCount()
    print("系统池中当前用户的指纹数量:", fingerprintCount)

    # 调用验证函数
    VerifyFingerprint()

内容的提问来源于stack exchange,提问作者Abhijeet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 09:09:56