Aquí está el código para leer, guardar y comparar una huella dactilar.
Utilizo el lector biométrico Digital Persona U.are.U 4500.
Persiste el problema del GPF aleatorio; en cuanto tenga tiempo libre intentaré con el SDK propio de Digital Persona.
Code: Select all
#include "FiveWin.ch"
#include "saytimer.ch"
#include "TSButton.ch"
//////////////////////
FUNCTION Main() ///
//////////////////////
LOCAL oWndE , oFont
LOCAL oCODCLI, cCodCli
LOCAL oNom , cNom
LOCAL oNoc , cNoc
LOCAL oImage, cHuella:=""
LOCAL lProcesandoHuella:= .F. , oBmp , oSay
LOCAL ttpt , ttptSize , oFingerX , sensor
LOCAL oIng , nIng:=1 // 1: Ingreso // 2: Salida
LOCAL cArch1:=".\Data\Tabla23.DAT"
LOCAL cArch2:=".\Data\Tabla24.DAT"
LOCAL nArea:=0
USE (cArch1) ALIAS Personal NEW SHARED
nArea:=Select("Personal")
IF nArea==0
msginfo("No se pudo abrir la tabla de Personal","Atención")
RETURN .F.
ENDIF
USE (cArch2) ALIAS IngresoP NEW SHARED
nArea:=Select("IngresoP")
IF nArea==0
msginfo("No se pudo abrir la tabla de Ingresos de Personal","Atención")
RETURN .F.
ENDIF
cCodCli := " "
cNom := " "
cNoc := " "
sysrefresh()
HB_GCAll(.t.) // Aleatoriamente el programa produce un GPF, entonces invoco al colector para ver si se solucionaba el error, pero no.
DEFINE FONT oFont NAME "Times New Roman" BOLD SIZE 24, 24
IF IsActiveX("GrFingerX.GrFingerXCtrl")
DEFINE WINDOW oWndE TITLE "Ingreso de Personal" from 100, 100 to 400, 700 pixel NOMAXIMIZE
@01 , 56.0 BITMAP oBmp OF oWndE SIZE 110,160 ADJUST
// @01 , 36 SAY oCodCli VAR "DNI : " + cCodCli OF oWndE COLOR CLR_BLACK, nrgb(226,208,242)
// @02 , 36 SAY oNom VAR "Nombre : " + cNom OF oWndE COLOR CLR_BLACK, nrgb(226,208,242)
// @03 , 36 SAY oNoc VAR "N. Corto: " + cNoc OF oWndE COLOR CLR_BLACK, nrgb(226,208,242)
@04 , 32 RADIO oIng VAR nIng ITEMS "INGRESO","SALIDA" SIZE 102,22 OF oWndE ON CHANGE (iif(nIng=1,oWndE:settext("Ingreso de Personal"),oWndE:settext("Salida de Personal")))
@16 , 220 SAYTIMER O OF oWndE FONT oFont PIXELS //TRANSPARENT NOBORDER
// AMPM ;
// SHORT ;
// COLOR CLR_WHITE, CLR_HGREEN, CLR_BLUE, CLR_RED
@11 , 075.0 SBUTTON oSalir PROMPT "Salir" COLORS CLR_BLUE, nrgb(112,146,190), nrgb(0,128,255) CRYSTAL SIZE 106,46 ACTION oWndE:End()
oFingerX = TActiveX():New( oWndE, "GrFingerX.GrFingerXCtrl")
//oWndE:oClient = oFingerX
oFingerX:Do("Initialize")
oFingerX:Do("CapInitialize")
oFingerX:bOnEvent = { | event,aParams,pParams | EventInfo2(event,aParams,pParams,oFingerX,oWndE,lProcesandoHuella,oBmp,@ttpt,@ttptSize,;
oCodCli,@cCodCli,oNom,@cNom,oNoc,@cNoc,@sensor,nIng) }
ACTIVATE WINDOW oWndE VALID SalirHuella(oFingerX,sensor)
ELSE
msginfo("Tiene que estar instalado GRFINGER","Atención")
ENDIF
RETURN NIL
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FUNCTION EventInfo2(event,aParams,pParams,oFingerX,oWndE,lProcesandoHuella,oBmp,ttpt,ttptSize,oCodCli,cCodCli,oNom,cNom,oNoc,cNoc,sensor,nIng) ///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Local cEvent , cHora:=""
sysrefresh()
HB_GCAll(.t.) // ya expliqué de porqué invoco al colector
IF .not. lProcesandoHuella
cEvent := cValToChar( event )
IF cEvent == "SensorPlug" .and. aParams[1] != "File"
sensor:=aParams[1]
ENDIF
IF cEvent == "SensorPlug" .or. cEvent == "1"
IF aParams[1] != "File"
oFingerX:Do("CapStartCapture",sensor)
ENDIF
ELSE
IF cEvent == "SensorUnplug"
oFingerX:Do("CapStopCapture",sensor)
ELSE
IF cEvent == "FingerDown" .or. cEvent = "4"
ELSE
IF cEvent == "FingerUp" .or. cEvent = "3"
ELSE
IF cEvent == "ImageAcquired" .or. cEvent = "5"
lProcesandoHuella:= .T.
xLib:= LoadLibrary("GrFinger.dll")
GrInitialize()
ttptSize = 10000
ttpt = SPACE(10000)
ret:= GrExtract( aParams[ 4], aParams[ 2], aParams[ 3], aParams[ 5], @ttpt, @ttptSize, 0 )
GrCapSaveRawImageToFile( aParams[ 4] , aParams[ 2], aParams[ 3], ".\Lectura.bmp", 501) // Aquí se graba la imagen
oBmp:LoadBmp( '.\Lectura.bmp' ) // cargo la imagen guardada en la anterior línea
oBmp:refresh()
select("Personal")
GO TOP
nIdScore:= 0
WHILE !eof()
GrIdentifyPrepare( ttpt, 0 )
nId:= GrIdentify( Personal->Huella, @nIdScore , 0 )
IF nId = 1
cHora := ""
cHora := time()
cCodCli := Personal->DNIPER //; oCodCli : refresh()
cNom := Personal->NOM //; oNom : refresh()
cNoc := Personal->NOC //; oNoc : refresh()
//oWndE:refresh()
select("IngresoP")
APPEND BLANK
GO Lastrec()
IF IngresoP->(rlock())
REPLACE IngresoP->DNIPER WITH cCodCli
REPLACE IngresoP->NOM WITH cNom
REPLACE IngresoP->NOC WITH cNoc
REPLACE IngresoP->FING WITH date()
REPLACE IngresoP->HING WITH cHora
REPLACE IngresoP->TIPO WITH nIng
IngresoP->(dbcommit())
IngresoP->(dbunlock())
ELSE
msginfo("El registro está bloqueado, intente otra vez","Atención")
ENDIF
MsgBeep()
MsgBeep()
msgwait(alltrim(Personal->Nom) + " : " + CRLF + ;
"Hora ingreso:" + cHora, "Grabado con éxito!",1)
EXIT
ELSE
SKIP +1
ENDIF
IF eof()
SndPlaySound("Error.wav",1)
msgwait("Personal no encontrado!","Atención",1)
ENDIF
ENDDO
select("Personal")
SysWait(1)
GrFinalize()
FreeLibrary(xLib)
lProcesandoHuella:= .F.
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
RETURN NIL
////////////////////////////////////////////
FUNCTION SalirHuella(oFingerX,sensor) ///
////////////////////////////////////////////
IF valtype(sensor) ="U" .OR. valtype(sensor) ="u"
ELSE
oFingerX:Do("CapStopCapture",sensor)
oFingerX:Do("CapFinalize")
oFingerX:Do("Finalize")
ENDIF
oFingerX:Do("CapFinalize")
oFingerX:Do("Finalize")
RETURN ( .T. )
DLL32 FUNCTION GrInitialize() AS LONG PASCAL FROM "_GrInitialize@0" LIB xLib
DLL32 FUNCTION GrFinalize() AS LONG PASCAL FROM "_GrFinalize@0" LIB xLib
*DLL32 FUNCTION GrCapInitialize(status AS LPSTR) AS LONG PASCAL FROM "_GrCapInitialize@4" LIB xLib
DLL32 FUNCTION GrExtract( rawImage AS LONG, width AS LONG, height AS LONG, res AS LONG, ttpt AS LPSTR, @ttptSize AS LONG , context AS LONG ) AS LONG PASCAL FROM "_GrExtract@28" LIB xLib
DLL32 FUNCTION GrIdentifyPrepare( ttpt AS LPSTR, context AS LONG ) AS LONG PASCAL FROM "_GrIdentifyPrepare@8" LIB xLib
DLL32 FUNCTION GrIdentify( ttpt AS LPSTR, @Idscore AS LONG, context AS LONG ) AS LONG PASCAL FROM "_GrIdentify@12" LIB xLib
DLL32 FUNCTION GrCapSaveRawImageToFile( rawImage AS LONG, width AS LONG, height AS LONG, qtpt AS LPSTR, n AS LONG ) AS LONG PASCAL FROM "_GrCapSaveRawImageToFile@20" LIB xLib
DLL32 FUNCTION GrVerify( ttpt AS LPSTR, qtpt AS LPSTR, @Idscore AS LONG, context AS LONG ) AS LONG PASCAL FROM "_GrVerify@16" LIB xLib
#include 'saytimer.PRG'
/////////////////////////// Alias: "Personal"
//FUNCTION CreaT23() ///
///////////////////////////
//LOCAL aEstruc:={}
//LOCAL cArch:=".\DATA\"+"Tabla23.DAT"
//AADD(aEstruc,{"DNIPER", "C" , 11 ,00}) // DNI Personal
//AADD(aEstruc,{"CRE" , "L" , 1 ,00}) // Si es sujeto de Crédito
//AADD(aEstruc,{"LCR" , "N" , 10 ,02}) // Límite de Crédito
//AADD(aEstruc,{"SDE" , "N" , 10 ,00}) // Saldo Deudor
//AADD(aEstruc,{"PSE" , "N" , 10 ,00}) // Pago Diario
//AADD(aEstruc,{"NOM" , "C" , 45 ,00}) // Nombre
//AADD(aEstruc,{"DOM" , "C" , 45 ,00}) // Domicilio
//AADD(aEstruc,{"NOC" , "C" , 12 ,00}) // Nombre Corto
//AADD(aEstruc,{"FO1" , "N" , 10 ,00}) // Telefono
//AADD(aEstruc,{"CUM" , "D" , 08 ,00}) // Cumpleaños
//AADD(aEstruc,{"MAI" , "C" , 20 ,00}) // Mail
//AADD(aEstruc,{"WEB" , "C" , 30 ,00}) // WEB
//AADD(aEstruc,{"CON" , "C" , 45 ,00}) // CONTACTO
//AADD(aEstruc,{"FOTO" , "C" , 52 ,00}) // Foto del Personal, mejor dicho la dirección de donde se encuentra en el disco duro
//AADD(aEstruc,{"CORREO", "C" , 26 ,00}) // correo electronico
//AADD(aEstruc,{"SENHA" , "C" , 16 ,00}) // contraseña
//AADD(aEstruc,{"HUELLA", "M" , 10 ,00}) // campo MEMO para guardar la huella dactilar
//DBCREATE(cArch,aEstruc)
//RETURN NIL
/////////////////////////// Alias: "IngresoP"
//FUNCTION CreaT24() ///
///////////////////////////
//LOCAL aEstruc:={}
//LOCAL cArch:=".\DATA\"+"Tabla24.DAT"
//AADD(aEstruc,{"DNIPER", "C" , 11 ,00}) // DNI Personal
//AADD(aEstruc,{"NOM" , "C" , 45 ,00}) // Nombre
//AADD(aEstruc,{"NOC" , "C" , 12 ,00}) // Nombre Corto
//AADD(aEstruc,{"FING" , "D" , 08 ,00}) // Fecha de Ingreso
//AADD(aEstruc,{"HING" , "C" , 08 ,00}) // Hora de Ingreso
//AADD(aEstruc,{"TIPO" , "N" , 01 ,00}) // Para saber= 1 : Ingreso 2: Salida
//DBCREATE(cArch,aEstruc)
//RETURN NIL