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
相关产品推荐
相关产品推荐

