Universidad de Costa Rica Facultad de Ingeniería Escuela de Ingeniería Eléctrica IE – 0502 Proyecto Eléctrico Diseño e implementación de un sistema de registro de personas mediante la identificación a partir de la huella dactilar Por: Luis Alfonso Castro Leiva Ciudad Universitaria Rodrigo Facio Noviembre del 2009 Diseño e implementación de un sistema de registro de personas mediante la identificación a partir de la huella digital Por: Luis Alfonso Castro Leiva Sometido a la Escuela de Ingeniería Eléctrica de la Facultad de Ingeniería de la Universidad de Costa Rica como requisito parcial para optar por el grado de: BACHILLER EN INGENIERÍA ELÉCTRICA Aprobado por el Tribunal: _________________________________ Ing. Rodrigo García León Profesor Guía _________________________________ Ing. Lucky Lochi Yu Lo Profesor lector _________________________________ Ing. Teodoro Willink Castro Profesor lector ii DEDICATORIA A Dios, A mi familia y amigos, que me han acompañado en el largo camino iii RECONOCIMIENTOS Un reconocimiento especial a mis padres por su gran ayuda durante toda mi vida. iv ÍNDICE GENERAL ÍNDICE GENERAL ........................................................................................... v ÍNDICE DE FIGURAS ...................................................................................viii NOMENCLATURA .......................................................................................... ix RESUMEN ........................................................................................................... x CAPÍTULO 1: Introducción ............................................................................. 1 1.1 Introducción ................................................................................................................ 1 1.2 Justificación ................................................................................................................ 2 1.3 Presentación del problema a resolver........................................................................ 3 1.4 Objetivos ..................................................................................................................... 4 1.1.1 Objetivo general ................................................................................................. 4 1.1.2 Objetivos específicos ......................................................................................... 4 1.5 Metodología ................................................................................................................ 5 CAPÍTULO 2: Desarrollo teórico .................................................................... 6 2.1 Principios de reconocimiento biométrico mediante huellas dactilares ................... 6 2.1.1 Características Globales..................................................................................... 6 2.1.2 Características locales........................................................................................ 8 2.2 One Touch® for Windows® SDK C/C++ Edition .................................................. 9 2.3 El API de DigitalPersona. .......................................................................................... 9 2.4 El IDE de desarrollo Visual C++ 2005 ...................................................................12 2.5 El Software WampServer.........................................................................................13 2.5.1 El servidor HTTP, Apache ..............................................................................13 v 2.5.2 El servidor de Bases de datos, MySQL ..........................................................14 2.5.3 El interpretador PHP ........................................................................................14 2.6 El API C de MySQL ................................................................................................14 2.7 AJAX.........................................................................................................................15 CAPÍTULO 3: Trabajo previo al desarrollo del software ......................... 18 3.1 El lector de huellas dactilares U.Are.U 4500 de DigitalPersona...........................18 3.2 Elección la plataforma de Desarrollo......................................................................19 3.3 Elección del entorno integrado de desarrollo .........................................................20 3.4 Visión general del CRB ...........................................................................................21 3.5 Estructura de la base de datos..................................................................................23 CAPÍTULO 4: Cliente de comunicación con el lector de huellas digitales CRB. .................................................................................................................... 25 4.1 Modo de registro de nuevo personal .......................................................................28 4.2 Modo de control de acceso ......................................................................................29 CAPÍTULO 5: Interfaz para la administración de bases de datos CRB. 32 CAPÍTULO 6: Conclusiones y recomendaciones ........................................ 37 6.1 Conclusiones.............................................................................................................37 6.2 Recomendaciones .....................................................................................................38 BIBLIOGRAFÍA............................................................................................... 40 APÉNDICE A: Código del cliente de comunicación con el lector de huellas dactilares. .............................................................................................. 41 A.1. Archivo CRB.cpp .....................................................................................................41 A.2. Archivo Form1.h ......................................................................................................43 A.3. Archivo Verform.h ...................................................................................................47 A.4. Archivo Verform.cpp ...............................................................................................52 vi A.5. Archivo enroll.h........................................................................................................58 A.6. Archivo enroll.cpp....................................................................................................66 APÉNDICE B: Código de la interfaz para administración de bases de datos CRB........................................................................................................... 73 B.1. Archivo cliente.php ..................................................................................................73 B.2. Archivo ajax.js..........................................................................................................75 B.3. Archivo query_name.php.........................................................................................77 B.4. Archivo query_apellido1.php ..................................................................................78 B.5. Archivo query_apellido2.php ..................................................................................79 B.6. Archivo query_cedula.php.......................................................................................80 B.7. Archivo query_marcas.php ......................................................................................81 B.8. Archivo query_eliminar.php....................................................................................82 Apéndice C: Sentencia de SQL para la creación de la base de datos crb_db1. .............................................................................................................. 84 Apéndice D: Funciones del Dispositivo utilizas. ........................................... 85 2.7.1 Funciones de extracción...................................................................................89 2.7.2 Funciones de comparación ..............................................................................91 ANEXOS............................................................................................................. 93 vii ÍNDICE DE FIGURAS Figura 2.1 Ejemplo de área patrón [3]................................................................................... 7 Figura 2.2 Ejemplo de Delta [3]............................................................................................. 7 Figura 2.3 Patrones básicos de huellas.[3] ............................................................................ 8 Figura 3.1. Lector de huellas digitales U.are.U 4500 .........................................................19 Figura 3.2. Diagrama modular de CRB...............................................................................22 Figura 4.1. Ventana principal del CRB. ..............................................................................25 Figura 4.2. Ventana del modo de registro de nuevo personal ............................................26 Figura 4.3. Diagrama de flujo de CRB.cpp.........................................................................27 Figura 4.4. Niveles de abstracción del programa CRB. .....................................................28 Figura 4.5. Diagrama de flujo del almacenamiento de información. ................................29 Figura 4.6. Ventana del modo de control de acceso ...........................................................30 Figura 5.1. Módulos de la Interfaz Web..............................................................................32 Figura 5.2. Resultado mostrado por el navegador Web......................................................33 Figura 5.3. Resultados de búsqueda.....................................................................................34 Figura 5.4. Resultados del Registro de marcas de personal ...............................................35 Figura 5.5. Eliminación de un usuario.................................................................................36 viii NOMENCLATURA IDE Integrated development environment. SDK Software developmet ki.t API Aplication programming interface. HTTP Hypertext Tranfer protocol. PHP PHP: Hypertext preprocessor. GPL General Public License. AJAX Asynchronous JavaSript + XML. RAD Rapid Application development. MingW Minimalist GNU for Windows GCC GNU Compiler Collection. ix RESUMEN En el presente proyecto se aborda la creación de un sistema que registra las entradas y salidas de personal en alguna empresa o institución mediante la identificación de su huella dactilar, siguiendo una metodología de búsqueda de soluciones y elección de la de mejor ajuste a las necesidades y una programación modular. El resultado obtenido es un sistema funcional en sus aspectos más básicos, con los suficientes requerimientos para ser una versión alfa y con la necesidad de darle seguimiento para obtener un producto con mejor acabado. En conclusión, se logró alcanzar la totalidad de los objetivos planteados y se recomienda seguir con un proceso de mejoramiento de los resultados obtenidos. x 1 CAPÍTULO 1: Introducción 1.1 Introducción Cuando los seres humanos interactúan con otras personas, la identificación se realiza por características como su apariencia física. En caso de que una prueba de la identidad de la persona sea requerida, se recurre a algún tipo de tarjeta de identificación, como la cédula de identidad, el pasaporte o incluso la firma. Sin embargo, técnicas de identificación pueden ser fácilmente falsificables. Por este motivo se desarrolló la biometría, ciencia que estudia la identificación de personas por medio de características anatómicas. La gran ventaja de la identificación biométrica radica en que las características analizadas son prácticamente irrepetibles en diferentes seres humanos y la falsificación de las mismas es extremadamente difícil. Por este motivo, el desarrollo de soluciones biométricas en el área digital ha tenido un enorme desarrollo, especialmente en la identificación mediante huellas dactilares, palma de la mano y el iris. Esto trae consigo grandes ventajas en especial en el área de control de acceso y seguridad en empresas e instituciones, además del control de asistencia de personal. 1.2 Justificación Cuando una empresa es de gran tamaño y sus empleados son muchos, la pérdida de diez o quince minutos en la hora de entrada de varios de sus empleados puede contabilizarse en gran cantidad de horas perdidas y retrasos en el inicio de las operaciones de la empresa, lo cual se traduce al final en grandes pérdidas económicas. Además la existencia de ciertos puestos de trabajo que no pueden estar vacantes, ni siquiera por algunos minutos, motiva al control de entradas y salidas de personal a los puestos de trabajo. El desarrollo del país se sustenta en su capacidad para producir y dar respaldo a esta producción, por esto es importante que se motive la creación de soluciones para las necesidades del sector productivo del país por parte del personal calificado existente en nuestro propio territorio. Las soluciones que se pretenden construir en este proyecto buscan potencializar las capacidades de las empresas nacionales y contribuir al desarrollo. Estos motivos son suficientes para justificar el diseño e implementación de un sistema de registro de personas mediante huellas dactilares y dar cabida a la elaboración de este proyecto. 2 1.3 Presentación del problema a resolver El problema que se aborda en este trabajo es la creación de un programa de computadora que permita el control de entradas y salidas de personal a una institución o empresa. Este control se realiza por medio de un hardware especializado capaz de registrar huellas dactilares y realizar comparaciones para determinar si existe concordancia entre huellas guardadas en una base de datos y el personal que pretende hacer ingreso a las instalaciones. Por este motivo el programa desarrollado debe ser capaz de interactuar con este hardware para adquirir la información sobre las huellas digitales del personal y guardarlo junto con la información pertinente dentro de una base de datos. También debe ser capaz de realizar la comparación y tomar decisiones sobre su resultado, ya sea registrar la entrada o salida del personal o no. Por último se busca que el personal encargado de los recursos humanos tenga una forma fácil de accesar a toda la información personal, como nombre o departamento de los trabajadores o de la entrada y salida de los mismos a las instalaciones, y que la forma en que el personal de recursos humanos pueda realizar estas consultas sea por la vía de Internet. Por este motivo, se busca que el programa tenga una orientación modular, y de esta forma poder enfocarse en sectores específicos del programa por separado, siguiendo el viejo adagio “divide y vencerás”. 3 1.4 Objetivos 1.1.1 Objetivo general Conformar un sistema de registro de personas mediante la identificación a partir de la huella dactilar. 1.1.2 Objetivos específicos Realizar un estudio acerca de las tecnologías existentes en la identificación de personas mediante huella dactilar. Estructurar una solución persiguiendo la versatilidad y fácil adopción de empresas o individuos interesados. Programar una aplicación multiplataforma que interactúe con el hardware especializado para la identificación mediante huella dactilar. Implementar una interfaz Web para la administración y consulta del registro de personas. Elaborar manuales e instructivos de capacitación para el uso del sistema. 4 1.5 Metodología Se indagará sobre las opciones que existen en el mercado para soluciones biométricas y el hardware existente para tales fines, en miras de la elección de la mejor opción. Tomando en cuenta precio, factibilidad de uso del hardware para crear nuevas aplicaciones desde código fuente y disponibilidad de compra desde Costa Rica. Se seleccionará y adquirirá el hardware requerido junto con las herramientas de programación necesarias para la creación de nuevas aplicaciones. Se seleccionará la plataforma de operación (sistema operativo) en la cual se creará la aplicación y el IDE sobre el cual se desarrollará la aplicación. Se creará una la aplicación mediante un proceso de pruebas y depuración de errores del código elaborado, que cumpla con necesidades planteadas Se formulará un manual del usuario para la aplicación desarrollada. 5 6 CAPÍTULO 2: Desarrollo teórico 2.1 Principios de reconocimiento biométrico mediante huellas dactilares Los dedos tienen superficies rugosas que permiten a los seres humanos tener más fricción para tomar objetos y sostenerse de superficies sin deslizamientos. Estas rugosidades forman patrones que son prácticamente únicos e irrepetibles en los seres humanos. La identificación de personas se realiza por medio de dos características en estos patrones: características globales y características locales. Las características globales en las huellas dactilares son aquellas que se pueden observar a simple vista, mientras que las características locales son llamadas puntos de minutia. El arreglo bidimensional de la posición de los puntos de minutia es utilizado en los algoritmos de reconocimiento debido a que diferentes personas pueden tener características globales similares, mientras que es muy poco probable que dos personas tengan arreglos de puntos de minutia similares, además de tener la ventaja de que un patrón de este tipo puede ser cuantificable, lo cual hace esta técnica candidata ideal para ser implementada de forma digital. 2.1.1 Características Globales Algunos tipos de características globales son el área patrón, la delta y el patrón básico, aunque existen muchas otras que ayudan a la clasificación manual de las huellas digitales. El área patrón es el área principal donde se incluyen la mayoría de las características globales, un ejemplo de esta área se muestra en la figura 2.1. Figura 2.1 Ejemplo de área patrón [3] La delta es un punto de bifurcación abrupta o encuentro de líneas digitales donde se pueden formar puntos o fragmentos cortos de línea, un ejemplo de una delta se muestra en la figura 2.2. Figura 2.2 Ejemplo de Delta [3] El patrón básico de las huellas es por así decirlo, la forma adoptan las líneas. Entre las más comunes están el arco, el lazo, y el remolino, los cuales se muestran en la figura 2.3 en ese orden respectivo. 7 Figura 2.3 Patrones básicos de huellas.[3] 2.1.2 Características locales. Las líneas que conforman una huella digital no son continuas ni rectas, éstas generalmente se rompen, dividen, interrumpen y cambian de dirección. Los puntos donde las líneas sufren esa clase de cambios y que proveen información distinguible, perdurable y, más importante aún, cuantificable, son los puntos de minutia. Estos puntos tan importantes para el reconocimiento digital se clasifican según su tipo, su orientación, su frecuencia espacial, su curvatura y su posición. Según su tipo los puntos de minutia pueden ser clasificados como: Fin de línea Bifurcación de línea en dos. Isla o punto. Es una línea que empieza y acaba en un trayecto muy corto. Encapsulamiento. Se produce cuando una línea se divide y rápidamente se vuelve a juntar. 8 2.2 One Touch® for Windows® SDK C/C++ Edition A continuación se hará un breve resumen del SDK utilizado para el desarrollo del trabajo, el cual fue escogido por ser la herramienta de software que permite el desarrollo de aplicaciones con el lector de huellas seleccionado después del estudio de tecnologías y posibilidad de implementación en el trabajo. El paquete de desarrollo de software SDK, One Touch® para Windows® C/C++ Edition, versión 1.4, es el paquete que contiene todos los elementos necesarios para el desarrollo de una aplicación que interactúe con los lectores de huellas digitales de DigitalPersona, incluida la interfaz de programación de aplicaciones o API, las librerías estáticas y dinámicas requeridas para comunicarse con el hardware desde un nivel de abstracción más alto (como lo es el lenguaje C++) y los controladores requeridos por el sistema operativo para el control del hardware. La instalación de este paquete se encuentra explicada detalladamente en la guía del desarrollador incluida en el mismo paquete, y es en este mismo documento donde se explica el manejo de las funciones del API y su adecuado uso. 2.3 El API de DigitalPersona. La interfaz de programación de aplicaciones de DigitalPersona es la que realmente facilita la interacción del programador con los lectores de huellas digitales de DigitalPersona. Está constituida por un conjunto de funciones que, de ser llamadas adecuadamente, permiten obtener resultados tangibles en el programa desarrollado. 9 Para hacer uso del API se deben agregar librerías estáticas en el linker del compilador a utilizar, para que las llamadas a estas librerías que se encuentran en los archivos de encabezado, que también deben ser agregados, sean comprendidas por el compilador El API se encuentra dividido en dos: el núcleo y un encapsulamiento que crea una interfaz de usuario del API. Este encapsulamiento (wrapper) consiste en dos funciones DPEnrollUI y DPVerifyUI. Estas dos funciones son usadas para crear una plantilla con información sobre la huella digital y realizar una verificación de una huella contra una plantilla existente. Además, el encapsulamiento incluye una enumeración utilizada en las dos funciones y dos funciones callback. Una función callback consiste en un código ejecutable que es pasado como argumento a otro código, esto permite a una capa inferior de software llamar una subrutina definida en una capa superior. Dependiendo del tipo de aplicación, puede resultar más fácil hacer uso de este encapsulamiento. En soluciones como la elaborada en este proyecto no es ese el caso debido a que se desea tener un alto grado de control sobre el funcionamiento del lector de huellas digitales, en especial para la comparación. En la comparación se debe realizar esta operación interactuando con todo un conjunto de elementos presentes en la base de datos a utilizar y además tomar decisiones que dependen del tiempo, pues se deben registrar entradas o salidas. Por este motivo el núcleo del API fue la herramienta utilizada. 10 El núcleo contiene funciones, estructuras, enumeraciones, definiciones de tipos de variables y constantes. Las funciones contenidas dentro del API pueden ser clasificadas en las siguientes tres categorías: Funciones del dispositivo: Son utilizadas para comunicarse establecer y terminar la comunicación con el lector de huellas dactilares Funciones de extracción: Son utilizadas en el proceso de captura y procesamiento digital de las imágenes, tanto para el proceso de formación de nuevas plantillas como en el proceso de comparación. Forman el llamado módulo de extracción. Funciones de comparación: son las funciones requeridas para la comparación de plantillas y determinación de concordancia entre huellas. Forman el llamado módulo de comparación. En el apéndice D se presenta una explicación breve de algunas estas funciones, especialmente las más relevantes para la creación de la solución propuesta. 11 2.4 El IDE de desarrollo Visual C++ 2005 Por motivos que se explican más adelante en este documento el IDE elegido fue Visual C++ 2005 es por esto que en este apartado se habla brevemente sobre él, y se comentan los aspecto básicos necesarios que se necesitan conocer. Este entorno de desarrollo permite la rápida creación de aplicaciones generando grandes cantidades de código de forma que libera trabajo al programador y le permite centrarse en las necesidades particulares de su aplicación. El punto más importante de mencionar sobre este IDE es el manejo de Common Language Runtime (CLR), el cual es el motor de la plataforma de trabajo (Framework) .NET de Microsoft. Esta plataforma es la responsable de acelerar y simplificar la creación y el manejo de formularios con los cuales se desarrollan aplicaciones para Windows. Esto es una gran ventaja pero a la vez genera un problema con el uso del API de DigitalPersona. Este API está desarrollo en código de C++ estándar, o como lo llaman en la plataforma de desarrollo .Net, código no manejado o nativo. El código CLR es llamado código manejado y tiene grandes dificultades con la interacción de código no manejado, especialmente por el uso de un componente de Visual C++ 2005, llamado el recolector de basura (Garbage Collector), este bloque genera dificultades en especial con el manejo de punteros y pasos por referencia del código nativo. Esto obliga a recurrir a estrategias que han sido desarrolladas para tal fin como colocar pines a los punteros. Estos pines fijan los punteros en direcciones de memoria de forma tal que el colector de basura no generará problemas con el código nativo. 12 2.5 El Software WampServer. Para implementar la parte Web del proyecto de requiere una estructura que dé soporte a la página web, después de una búsqueda de opciones se seleccionó WampServer y es por esto que en este apartado se habla de forma breve sobre él. WampServer es un ambiente de desarrollo Web en Windows que permite crear aplicaciones Web con Apache, PHP y MySQL. Además incluye phpMyAdmin, un software para el manejo de bases de datos. Al igual que cada una de las partes que lo conforma WampServer es un proyecto de código abierto, con licencia GPL. La versión WampServer 2.0i incluye las versiones Apache 2.2.11, MySQL 5.1.36 y PHP 5.3.0. 2.5.1 El servidor HTTP, Apache Apache es una fundación de software libre que da cabida a una gran cantidad de proyectos, entre ellos se encuentra el servidor HTTP Apache. Este proyecto busca el desarrollo y mantenimiento de un servidor HTTP para sistemas operativos modernos como UNIX y Windows NT. El objetivo del proyecto es proveer de una alternativa de servidor, segura, eficiente y extensible que esté acorde con los estándares de HTTP. A través de la interfaz de WampServer se puede iniciar y detener Apache Server, e incluso cambiar algunas de sus características, pero para una configuración más profunda se puede modificar el archivo de configuración de Apache, httpd.conf y manejarlo desde línea de comandos. 13 2.5.2 El servidor de Bases de datos, MySQL MySQL es un gestor de bases de datos, que se encuentra bajo licencia GPL, aunque también es posible comprar una versión licenciada. MySQL permite estructurar bases de datos y realizar consultas a través de lenguaje SQL 2.5.3 El interpretador PHP PHP es un lenguaje interpretado, por lo cual se requiere un programa interpretador que convierta el código a lenguaje máquina cada vez que se desea ejecutar. Esto trae consigo una problemática para las aplicaciones Web: que el código debe ser ejecutado del lado del servidor, en el caso de que el código PHP deba ser ejecutado solo bajo ciertas condiciones o con ciertos parámetros acrecenta la problemática, por la necesidad de una comunicación asincrónica entre cliente y servidor. Para solucionar este problema se ha desarrollado AJAX. Se ha decidido utilizar PHP por la enorme facilidad que tiene para establecer comunicación con MySQL a través de un API para tal fin. Este API ya se encuentra incluido y configurado dentro del paquete WampServer lo cual facilita en gran medida el trabajo. 2.6 El API C de MySQL Se debe comentar también sobre la estructura que da soporte a la base de datos y la mejor opción para esto es MySQL por esto se dedica un apartado para hablar sobre el API de MySQL, pues es la herramienta de conexión entre el software y la base de datos usada. 14 El API C de MySQL es el encargado de dar conectividad entre aplicaciones escritas en C o C++ y una base de datos implementada en MySQL. Para hacer uso de ella se deben incluir un grupo de librerías estáticas al Linker del compilador a utilizar y los encabezados que hacen los llamados a estas librerías estáticas. Dentro de las funciones más relevantes para este trabajo se encuentran: mysql_init(NULL); : inicializa el API mysql_close(connection); : cierra y libera recursos del API mysql_real_connect(connection,host,username,password,dat abase,port, NULL,0): establece la conexión con la base de datos. 2.7 mysql_real_query(query): envía una consulta a la base de datos. mysql_store_result(connection): guarda el resultado de una consulta mysql_free_result(result): libera el resultado de una consulta AJAX AJAX no es una tecnología, es un conglomerado de tecnologías existentes que ha permitido lograr grandes avances en el mundo del Internet. La idea detrás de AJAX es evitar la necesidad de tener que estar cargando una página Web cada vez que el usuario interactúa con ella y se deben generar cambios. Una vez cargada y renderizada la página, AJAX permite una comunicación asincrónica con el servidor, para traer datos que serán usados solo en una nueva re-renderización del sitio, evitando la necesidad de tener que 15 cargar toda la página. El mejor ejemplo que se puede dar del uso de AJAX es Google Maps, donde es claro como es posible dar zoom y ver diferentes puntos de todo el mapa sin la necesidad de refrescar la página. Esto no es de extrañar pues Google ha sido uno de los más fuertes impulsores de AJAX. “AJAX es realmente muchas tecnologías, cada una floreciendo por su propio mérito, uniéndose en poderosas nuevas formas. AJAX incorpora: presentación basada en estándares usando XHTML y CSS; exhibición e interacción dinámicas usando el Document Object Model; Intercambio y manipulación de datos usando XML and XSLT; Recuperación de datos asincrónica usando XMLHttpRequest; y JavaScript poniendo todo junto.” [2] El modelo de transmisión de información queda ejemplificado en la figura 2.4. Aquí se puede ver claramente las enormes ventajas de AJAX respecto a las nuevas posibilidades que brinda. 16 Figura 2.4 Modelo de diseño Web con AJAX. [2] Como se aprecia, en el antiguo modelo cada vez que el cliente requiere nueva información debe realizar una llamada al servidor Web el cual le reenviará toda la información y se deberá volver a cargar toda la página. En contraposición utilizando AJAX se pueden enviar datos sin la necesidad de cargar toda la página, esto se traduce en un aumento de la velocidad pues la cantidad de datos que se transmiten en ambos sentidos se reduce considerablemente. 17 CAPÍTULO 3: Trabajo previo al desarrollo del software 3.1 El lector de huellas dactilares U.Are.U 4500 de DigitalPersona. Para la elaboración de este proyecto fue sumamente importante la elección adecuada del hardware encargado del escaneo de las huellas digitales. Los parámetros de selección son principalmente las posibilidades reales de desarrollo de nuevas aplicaciones con él, el factor económico y la disponibilidad de adquisición. Existen una gran variedad de componentes para escaneo de huellas digitales, inclusive muchos incorporan teclados numéricos y módulos para lectura de tarjetas de tecnología magnética. Estas capacidades incrementan en gran medida la seguridad y se usan principalmente en el caso de restricción de acceso físico a algún lugar, pero debido a la inclusión de mayores capacidades, su precio aumenta en gran medida si se compara con respecto a las soluciones que no incluyen estas opciones. Entre las empresas que venden soluciones de hardware de este tipo se encuentra: Microsoft ® con el DG2-00002, Zvetco con gran variedad de modelos, M2SYS y por supuesto DigitalPersona. El costo de estos equipos con características similares era muy parecido al momento de la elección, en donde el factor económico fue de peso fue en los paquetes de desarrollo de software para cada uno de los dispositivos. Para muchos de ellos el costo podía alcanzar hasta los 600 USD. Por este motivo la opción del lector U.are.U 4500, mostrado en la figura 3.1, de DigitalPersona fue elegida sobre gran cantidad de otras opciones. De la misma página de DigitalPersona se pueden descargar paquetes de desarrollo de software de versiones más 18 antiguas que la que se comercializa en este momento, lo cual permitió el desarrollo del proyecto a un bajo costo. El contra que poseía la elección de este dispositivo fue su disponibilidad, aunque DigitalPersona tiene un socio comercial en Costa Rica, este ya no comercializa sus productos por lo que tuvo que importarse desde los Estados Unidos, con todas las implicaciones que esto conlleva. La hoja de datos del U.are.U 4500 se encuentra en el Apéndice A de este documento. Figura 3.1. Lector de huellas digitales U.are.U 4500 3.2 Elección la plataforma de Desarrollo. Dentro de las opciones de paquetes de desarrollo que se pueden descargar gratuitamente del sitio Web de DigitalPersona se encuentran un paquete para Linux y otro para Windows. Las aspiraciones de este proyecto son utilizar al máximo las opciones de código abierto para la elaboración de las aplicaciones, por lo cual en un primer momento se 19 trató de utilizar las herramientas orientadas para Linux. A pesar de los intentos de utilizar los paquetes de desarrollo para Linux, esto no se pudo concretar debido a que a pesar de haberse logrado actualizar el código fuente de los manejadores de hardware cambiando funciones obsoleta que se encontraban en los mismos, estos controladores solo funcionan para modelos de lectores de huellas digitales iguales o anteriores al U.are.U 4000B, que es anterior al U.are.U 4500 adquirido. Debido a esto se debió utilizar el paquete de desarrollo para Windows XP, el cual contiene manejadores de hardware actualizados para el U.are.U 4500. Fuera de los motivos técnicos, otro fuerte motivo es el mercado meta del software desarrollado. Este posiblemente utilice Windows a pesar del fuerte crecimiento que han venido experimentando el uso de Linux en Costa Rica. 3.3 Elección del entorno integrado de desarrollo Para desarrollar el software se probaron tres opciones de RADs, el primero de ellos wxDev-C++, el cual es una extensión de Dev-C++ utilizando wxWidgets. Este último es un Framework que permite la creación de aplicaciones de Windows basadas en formularios. Esta primera opción fue descartada por ser un proyecto de software libre con poco seguimiento y desarrollo, que contiene algunas pulgas aún. La segunda opción fue CodeBlocks integrado con wxPack. wxPack contiene el Framework wxWidgets anteriormente mencionado, y con este extra CodeBlocks puede desarrollar aplicaciones de Windows, orientadas a formularios. Este IDE incluye Mingo, el 20 cual es un puerto del compilador de GCC de GNU, aunque si se encuentran instalados se puede seleccionar otros compiladores. Esta opción de IDE fue descartada, porque su funcionamiento cuando se llaman funciones del API de DigitalPersona no era el adecuado. Esto se debe a que el API de DigitalPersona fue escrito para el compilador Visual C++ y hace uso de palabras reservadas para este, cuando se llaman funciones de librerías estáticas y dinámicas. Por este motivo se decidió seguir trabajando con la tercera opción Visual C++ 2005, a pesar de que en CodeBlock uno puede elegir utilizar el compilador Visual C++. Es preferible usar el compilador desde el entorno de desarrollo para el cual fue creado y no desde CodeBlocks. 3.4 Visión general del CRB La aplicación que se desarrolló es llamada Control de Registro Biométrico (CRB) y la misma sigue una concepción modular por lo que está organizada en cuatro bloques principales: Un cliente de registro de nuevo personal, y confirmación de las entradas y salidas de personal, que se comunica con el lector de huellas digitales. Un servidor MySQL y una base de datos que cuenta con las tablas y columnas específicas de la aplicación CRB. Un servidor Web Apache que incluye un interpretador PHP y todas las prerrogativas de comunicación entre el interpretador PHP y la base de datos. 21 Y por último la interfaz Web por la cual el usuario tiene acceso a la información de la base de datos. Los bloques anteriormente mencionados se muestran en el diagrama esquemático de la figura 3.2. APACHE y PHP Base de Datos MySQL Cliente de comunicación con el lector de huellas Interfaz Web Usuario Figura 3.2. Diagrama modular de CRB. Los usuarios finales solo tienen acceso a la interfaz Web y al cliente de comunicación con el lector de huellas dactilares, el resto de partes son transparentes al usuario. 22 3.5 Estructura de la base de datos. Debido a que el sistema desarrollado todavía es una versión alfa, se decidió incluir dentro de la base de datos la información básica que puede necesitar una empresa. Así la base de datos, llamada crb_db1, incluye un tabla principal llamada empleados y una tabla por cada empleado que lleva como nombre el número de cédula correspondiente a cada empleado. Dentro de la tabla empleados se han creado las siguientes columnas: Nombre: un espacio tipo char(20). Apellido1: un espacio tipo char(20). Apellido2: un espacio tipo char(20). Cedula: un espacio tipo int. Departamento: un espacio tipo char(20). DataTemplate: un espacio tipo BLOB. cbData: un espacio tipo int. Los primeros cinco espacios contienen como su nombre lo indica la información elemental del empleado. El espacio DataTemplate no es usado en la versión que ha sido desarrollada, pero ha sido incluido como una prevista importante, pues en este momento la información sobre las huellas digitales de los usuarios se guarda de forma independiente en un archivo extensión crbt, aunque lo óptimo sería almacenar la información dentro de la misma base de datos de forma binaria, es por esto que el espacio DataTemplate es tipo 23 BLOB. Por último, el espacio cbData contiene la longitud recomendada para la plantilla de huella dactilar, este valor es generado por una de las funciones del API de DigitalPersona y debe ser usado cuando se lee la plantilla, es por esto que fue almacenado en la base de datos. La sentencia SQL para la generación de la tabla se encuentra en el apéndice C. 24 CAPÍTULO 4: Cliente de comunicación con el lector de huellas digitales CRB. El software encargado de comunicarse con el lector de huellas digitales y almacenar nueva información sobre el registro de personas en la base de datos fue desarrollado en el lenguaje C++. El código de este software se encuentra en el apéndice A de este documento. El software se divide en tres ventanas. La ventana principal permite al usuario cambiar entre accesar a las otras dos ventanas que corresponden a los dos modos de operación del software. En la figura 4.1 se muestra la ventana principal. Además permite al usuario ver la información básica sobre el software CRB y salir del programa, ya sea mediante la secuencia Archivo -> Salir o dando click en el botón cerrar de Windows. Figura 4.1. Ventana principal del CRB. 25 Los dos modos de operación antes mencionados son el modo de registro de control de acceso (ver figura 4.6) y el modo de registro de nuevo personal (ver figura 4.2). Solamente se puede tener uno de ellos activo en un momento dado, esto para independizar ambos procesos. Así el usuario percibe más fácilmente lo que está haciendo y además se facilita la labor de programación, pues se independizan las tareas de almacenamiento de plantillas de huellas dactilares y la comparación de plantillas almacenadas. Desde el punto de vista de programación existen 3 clases, una para cada formulario: la clase Form1 para la ventana principal, la clase Verform para el registro de marcas y la clase enrrol para el registro de personal nuevo. Además el programa inicia con la ejecución de CRB.cpp, que es el archivo principal donde se inicializa el U.are.U 4500, se establece la conexión con la base de datos crb_db1 y se llama a la ventana principal. En la figura 4.3 se muestra el diagrama de flujo que sigue el CRB.cpp. Figura 4.2. Ventana del modo de registro de nuevo personal 26 Inicio Error Inicializar el hardware. DPFPInit Exitoso Error Crear un contexto de extracción FX_init Exitoso Crear un contexto de comparación MC_init Error Exitoso Establecer conexión con MySQL mysql_real_connect. Abrir la ventana principal Continuar con la ejecución desde ahí Liberar recursos, y cerrar la conexión con MySQL. mysql_close, MC_terminate, FX_terminate, DPFPTerm. Figura 4.3. Diagrama de flujo de CRB.cpp. 27 Return 0 En general el programa puede ser analizado desde sus diferentes niveles de abstracción, (ver figura 4.4), este enfoque permite identificar donde están los problemas, si son a nivel de código del programa, a nivel de dependencias de la funciones (encabezados) o a nivel de librerías dinámicas (problemas en el linker). Aplicación desarrollada en C++ API accesado mediante los encabezado Librerias dinámicas agregadas al linker OS y controladores se comunican con el hardware Figura 4.4. Niveles de abstracción del programa CRB. 4.1 Modo de registro de nuevo personal En el modo de registro de nuevo personal posee una ventana que contiene tres líneas de texto sobre el estado actual, espacios para introducir información necesaria para el registro de personal nuevo y dos botones: uno para guardar la información y otro para salir del modo de registro de nuevo personal. La figura 4.1 muestra esta ventana. Es aquí donde se debe almacenar la información sobre la huella digital de la persona en una plantilla. Este proceso tiene la secuencia que se muestra en la figura 4.5, después de haberse creado los contextos de extracción y comparación requeridos por el API de DigitalPersona. 28 Obtener una muestra de huella digital a causa del toque de un dedo en el lector. Este evento es lanzado por el hardware Procesar la muestra para extraer las características y guardarlas en una plantilla de pre-registro en memoria. ¿Existen suficientes plantillas de pre-registro? No Si Guardar las características en una plantilla definitiva y almacenar la información en forma externa al programa Figura 4.5. Diagrama de flujo del almacenamiento de información. Una vez almacenada la información solo queda generar un stream binario para almacenarla en un archivo con extensión crbt codificado con la huella digital de la persona y guardar la información personal en la base de datos. Por este motivo al dar click en guardar se revisa que la información esté completa antes de proceder a guardar todo en memoria externa al programa. 4.2 Modo de control de acceso Este es el modo que tiene interacción directa con todo el personal, aquí deben realizarse las marcas de entrada o salida a la empresa. La ventana de este modo aparece en la figura 29 4.6. La misma posee tres líneas de información, donde se puede ver si el lector de huellas digitales se encuentra conectado o no, si la marca fue realizada exitosamente y si es posible realizar marca en el presente momento. Figura 4.6. Ventana del modo de control de acceso En lo que respecta a programación lo más importante es el algoritmo de búsqueda que se emplea. Por el momento el algoritmo empleado es muy simple y consiste en una comparación uno a uno, principalmente por dos motivos. Primero, se necesita un conocimiento mucho más profundo sobre la forma en que opera el lector de huellas dactilares, aun más allá del manejo del API, para implementar algún tipo de algoritmo más complejo y segundo, el corto tiempo que se tiene para desarrolla un proyecto de forma individual dificulta el concentrar esfuerzos en un punto específico del sistema como este. Es claro que el algoritmo es funcional y eficiente para alguna empresa pequeña, pero 30 conforme va creciendo la cantidad de usuarios del sistema, el algoritmo se va convirtiendo cada vez más ineficiente. 31 CAPÍTULO 5: Interfaz para la administración de bases de datos CRB. Para ver la información sobre entradas y salidas del personal se desarrollo una interfaz Web. Esta interfaz tiene una estructura modular la cual le permite establecer una comunicación asincrónica entre el un servidor Apache y un navegador Web. Los módulos tienen la estructura que se muestra en la figura 5.1 query_name query_apellido1 Código HTML cliente.php query_apellido2 Código JavaScript ajax.js query_cedula Base de datos crb_db1 query_marcas query_eliminar Figura 5.1. Módulos de la Interfaz Web El primer bloque está formado por el archivo cliente.php. Aunque está conformado casi completamente por código html, éste debe ser un archivo de extensión php. Esto se debe a que debe ser preprocesado por el interpretador PHP antes de ser enviado al cliente que lo está accediendo desde algún navegador Web desde cualquier lugar del mundo para 32 que pueda comunicarse adecuadamente con los otros módulos. Una vez recibido el navegador Web lo procesará y se mostrará un resultado como el de la figura 3.2. Figura 5.2. Resultado mostrado por el navegador Web Aquí el usuario puede realizar tres acciones diferentes, buscar la información de una persona, por cuatro criterios de búsqueda diferentes: Nombre, Primer Apellido, Segundo Apellido y Número de Cédula. Los resultados se muestran en el mismo espacio de la tabla por debajo de los criterios de búsqueda como se muestra en la figura 3.3. La operación realizada es la siguiente: un objeto AJAX creado mediante el script ajax.js es usado a través de una función Consulta que se encuentra también en el mismo script. Esta función envía información a cuatro diferentes códigos PHP dependiendo de qué 33 tipo de búsqueda se vaya a realizar. Es por esto que existen cuatro bloques query_, correspondientes a cada una de las búsquedas. Los bloques query_ sea query_name, query_apellido1, query_apellido2 o query_cedula, son ejecutados del lado del servidor, debido a que están escritos en PHP y requieren del interpretador. Una vez procesados, éstos devuelven la información mediante la sentencia echo de PHP y son mostrados como se ve en la figura 3.3. Es importante decir que para versiones posteriores del sistema CRB debe buscarse otra forma de enviar información de regreso a código en JavaScript. Posteriormente la función Consulta se encarga de colocar los resultados en el código HTML y decirle al navegador Web que debe re-renderizar la página. Figura 5.3. Resultados de búsqueda Otra de las operaciones que puede realizar el usuario, y tal vez la más importante, es ver el registro de entradas y salidas del personal. Para ver los datos de una persona se necesita conocer el número de cédula de ella. La búsqueda, al igual que en el modo anterior, se realiza mediante un objeto AJAX, pero este se comunicará esta vez con el bloque de código query_marcas escrito en PHP. La solución utilizada es la misma y la 34 forma en que se presentan lo resultados se muestra en la figura 3.4. Es en este punto de la interfaz donde más se puede avanzar. Deben agregarse bloques que permitan filtrar las marcas de algún usuario o ver los datos de un día en específico. Nuevamente, el corto tiempo de desarrollo fue la principal dificultad. Figura 5.4. Resultados del Registro de marcas de personal La última de las operaciones que puede realizar la interfaz Web, es la eliminación de usuarios vía su número de cédula. Esta operación se ha agregado solamente aquí en esta 35 versión alfa, pero en versiones posteriores debe ser agregada también en la aplicación de escritorio mediante código C++. Se ha agregado aquí principalmente porque la interfaz Web puede ser accesada prácticamente desde cualquier lugar del mundo y no requiere de una presencia física en el sitio de trabajo, como sí sucede con la aplicación de escritorio. En lo que a programación se refiere, se realiza a través del bloque query_eliminar escrito en PHP. Este bloque de código difiere en que realiza dos consultas a la base de datos y no solamente una, como es el caso de todo el resto de bloques query_, pues se debe eliminar tanto la tabla codificada con el número de cédula de la persona como la fila respectiva en la tabla empleados. Como resultado este enviará solamente una línea de texto indicando que la operación fue realiza con éxito, y el código ajax.js en JavaScript se encarga de que la página sea re-renderizada y mostrar un resultado como el que se aprecia en la figura 3.5. Figura 5.5. Eliminación de un usuario El manejo del sistema, en su totalidad por parte del usuario final está documentado en el manual del usuario.Este manual se encuentra en el Anexo de este documento. 36 CAPÍTULO 6: Conclusiones y recomendaciones 6.1 Conclusiones Una búsqueda concienzuda y comparativa fue la que permitió realizar una elección adecuada del hardware a utilizar, lo que a la postre vino a significar facilidades en el proceso de programación y el satisfactorio fin de este trabajo. El seguimiento de una estrategia clara de división modular del problema a resolver fue exitoso y es el responsable del funcionamiento adecuado de un sistema que integra diferentes frentes de trabajo como lo son una aplicación de escritorio y una interfaz Web. De no ser este el enfoque no sería posible manipular la información desde rutas tan diferentes como lo son el Internet y una aplicación de escritorio. Durante la elaboración de este proyecto siempre se buscó que la solución desarrollada tuviera un enfoque abierto el cual pudiera fácilmente ser adoptado en la gran mayoría de casos donde se requiera una aplicación similar, y que a partir de la solución planteada se pueda seguir trabajando para satisfacer las necesidades específicas del usuario final. Esto se concretó, aunque aún se debe seguir trabajando en esta aplicación, especialmente en los puntos que se abordan en las recomendaciones. La interfaz Web desarrollada puede ser accesada desde los múltiples sistemas operativos existentes, e incluso el código está hecho para preveer diferencias entre los navegadores Web más populares del mercado lo cual hace que esta parte del sistema sea multiplataforma. La aplicación de escritorio solo pudo ser desarrollada para Windows por los problemas mencionados en el Capítulo 4. A pesar de esto si se pudiera contar 37 principalmente con los manejadores de hardware actualizados, partes importantes del código desarrollado podría ser exportadas a una aplicación de Linux, pero mientras no se cuente con estos manejadores se tendrá que esperar. Por último la meta general planteada se concretó y todos los requisitos puestos inicialmente para la solución deseada fueron conseguidos, pero es importante recalcar que en esta clase de aplicaciones siempre debe existir una idea de mejoramiento continuo y aún queda trabajo para obtener un producto final de alta calidad. 6.2 Recomendaciones La aplicación desarrollada tiene mucho trabajo por delante antes de poder ser un versión candidata a definitiva, entre los puntos en los que se debe trabajar para mejor el sistema CRB se encuentran los siguientes. Incluir la información de las plantillas de huella digital correspondiente a cada persona dentro de la base de datos como un elemento tipo BLOB pues mejora en gran medida la portabilidad y además facilita enormemente la tarea de respaldar la información. Incluir el manejo de excepciones en el código de programa CRB hecho en C++, para evitar comportamientos inesperados que podrían dañar valiosa información de la base de datos. Estandarizar la interfaz Web de manejo de bases de datos CRB, conforme lo establece la W3C. 38 Buscar una mejor forma de enviar los resultados de la búsqueda en la base de datos del código PHP a la interfaz Web para presentar la información de forma más agradable. Tomar en cuenta todos los posibles fallos del usuario en el ingreso de información. En número de cédula, por ejemplo, se debe tomar medidas en caso de que el usuario del programa no dé el número completo o incluya letras o espacios dentro de la caja de texto establecida para ingresar tal número. Mejorar el algoritmo de búsqueda del modo de control de acceso pues resulta ineficiente conforme crece la cantidad de personal registrado. Crear un programa instalador para la aplicación que pueda dejar el programa funcional sin la intervención de un programador. Incluir seguridad en el sistema, principalmente la implementación de usuarios y la autenticación para el uso del programa, y posteriormente la encriptación de la información que deberá viajar por Internet en la interfaz Web. Debido a que la solución elaborada representa una versión alfa, el manual del usuario elaborado deben ser puesto bajo revisión pues apenas cuentan con la información necesaria para explicar al usuario como manejarse en el sistema pero no prevén los problemas de desarrollo que hayan sido pasados por alto o que todavía no son del conocimiento del desarrollador del sistema CRB. 39 BIBLIOGRAFÍA Artículos de revistas: 1. Jiménez, J.M. Marín J.G. “Sistema de reconocimiento de huellas dactilares”, Mundo Electrónico, España, N° 380, 2006. 2. Zucker, D.F. “What does AJAX mean for you?”, Interactions, Estados Unidos, Volumen 14 N° 5, 2007. Libros: 3. DigitalPersona, Inc.. “One Touch® for Window® SDK C/C++ Edition. Developer Guide”, Estados Unidos, 2009. 4. Deitel, H.M. Deitel, P.J. “C++ Cómo programar” Segunda edición, Prentice Hall, México, 1999. Páginas Web: 5. “PHP Manual”, http://www.php.net/manual/en/ 6. “Versión 2.2 de la documentación del Servidor de HTTP Apache”, http://httpd.apache.org/docs/2.2/ 7. Garretr, J.J. “AJAX: A New Approach to http://adaptivepath.com/ideas/essays/archives/000385.php. 40 Web Application”, APÉNDICE A: Código del cliente de comunicación con el lector de huellas dactilares. A.1. Archivo CRB.cpp /***************************************************************** Universidad de Costa Rica Escuela de Ingenieria Electrica II Semestre 2009 IE-0502 Proyeto Electrico Elaborado por: Luis Castro Leiva A61368 Resumen: CRB.cpp Este archivo contiene el arranque de CRB, se llama la base de datos se inicializa el lector U.are.U 4500 y se llama la ventana principal en caso de error se da aviso y se cierra el programa. ******************************************************************/ #include "stdafx.h" #include "Form1.h" #include "enrrol.h" //Encabezados necesarios para la conexion la base de datos de MySQL #include <Winsock.h> #include <mysql.h> using namespace CRB; #define #define #define #define host "localhost" username "admin" password "crb" database "crb_db1" [STAThreadAttribute] int main(array<System::String ^> ^args){ //Localiza e inicializa los recursos necesarios para el funcionamiento del API if(FAILED(DPFPInit())==TRUE); else{ // Inicializa el módulo de extracción del SDK if (FT_OK == FX_init()) { // Inicializa el módulo de comparación del SDK if (FT_OK == MC_init()) { 41 // Habilita los efectos visuales de XP antes de que los controles sean creados Application::EnableVisualStyles(); Application::SetCompatibleTextRenderingDefault(false); MYSQL *conn = mysql_init(NULL); int code = 0; int port = 3306; //Establece una conexion con MySQL if (mysql_real_connect(conn,host,username,password,database,port,NULL,0) == NULL){ //En caso de falta de conectividad con crb_db1 se cierra el programa MessageBox::Show( "Error en la conexión con la base de datos\nEl programa se cerrará", "Error"); mysql_close(conn); MC_terminate(); FX_terminate(); DPFPTerm (); return 0; } // Se crea la ventana principal y se ejecuta Application::Run(gcnew Form1(conn)); // Libera recursos de la conexion con la base de datos mysql_close(conn); // Libera recursos del módulo de comparación del SDK MC_terminate(); } else { MC_terminate(); FX_terminate(); DPFPTerm (); return 0; } // Libera recursos del módulo de extracción del SDK FX_terminate(); } else { FX_terminate(); DPFPTerm (); return 0; } } DPFPTerm (); return 0; } 42 A.2. Archivo Form1.h /***************************************************************** Universidad de Costa Rica Escuela de Ingenieria Electrica II Semestre 2009 IE-0502 Proyeto Electrico Elaborado por: Luis Castro Leiva A61368 Resumen: Form1.h Este archivo contiene tanto la declaración como el contenido de las funciones de la ventana principal, la cual se encarga de llamar los dos diferentes modos de operación y distribuir información de conexión a MySQL. ******************************************************************/ #pragma once //Encabezados de los modos de operación #include "enrrol.h" #include "Verform.h" //Encabezados necesarios para la conexion la base de datos de MySQL #include <Winsock.h> #include <mysql.h> //Encabezados para la manipulacion de caracteres #include <iostream> #include <fstream> namespace CRB { using namespace System; using namespace System::ComponentModel; using namespace System::Collections; using namespace System::Windows::Forms; using namespace System::Data; using namespace System::IO; public ref class Form1 : public System::Windows::Forms::Form { public: Form1(MYSQL* connlink) { InitializeComponent(); ZeroMemory(&m_RegTemplate, sizeof(m_RegTemplate)); conn = connlink; } protected: ~Form1() 43 { if (components) { delete components; } } private: System::Windows::Forms::Button^ button1; private: System::Windows::Forms::MenuStrip^ menuStrip1; private: System::Windows::Forms::ToolStripMenuItem^ archivoToolStripMenuItem; private: System::Windows::Forms::ToolStripMenuItem^ salirToolStripMenuItem; private: System::Windows::Forms::ToolStripMenuItem^ toolStripMenuItem1; private: System::Windows::Forms::ToolStripMenuItem^ cRBToolStripMenuItem; private: System::Windows::Forms::Button^ button2; private: System::ComponentModel::IContainer^ components; private: DATA_BLOB MYSQL* m_RegTemplate; conn; #pragma region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> void InitializeComponent(void) { System::ComponentModel::ComponentResourceManager^ resources = (gcnew System::ComponentModel::ComponentResourceManager(Form1::typeid)); this->button1 = (gcnew System::Windows::Forms::Button()); this->menuStrip1 = (gcnew System::Windows::Forms::MenuStrip()); this->archivoToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem()); this->salirToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem()); this->toolStripMenuItem1 = (gcnew System::Windows::Forms::ToolStripMenuItem()); this->cRBToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem()); this->button2 = (gcnew System::Windows::Forms::Button()); this->menuStrip1->SuspendLayout(); this->SuspendLayout(); // // button1 // this->button1->Location = System::Drawing::Point(53, 77); 44 this->button1->Name = L"button1"; this->button1->Size = System::Drawing::Size(184, 26); this->button1->TabIndex = 0; this->button1->Text = L"Registrar nuevo personal"; this->button1->UseVisualStyleBackColor = true; this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click); // // menuStrip1 // this->menuStrip1->Items->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^ >(2) {this>archivoToolStripMenuItem, this->toolStripMenuItem1}); this->menuStrip1->Location = System::Drawing::Point(0, 0); this->menuStrip1->Name = L"menuStrip1"; this->menuStrip1->Size = System::Drawing::Size(292, 24); this->menuStrip1->TabIndex = 1; this->menuStrip1->Text = L"menuStrip1"; // // archivoToolStripMenuItem // this->archivoToolStripMenuItem->DropDownItems->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^ >(1) {this>salirToolStripMenuItem}); this->archivoToolStripMenuItem->Name = L"archivoToolStripMenuItem"; this->archivoToolStripMenuItem->Size = System::Drawing::Size(55, 20); this->archivoToolStripMenuItem->Text = L"Archivo"; // // salirToolStripMenuItem // this->salirToolStripMenuItem->Name = L"salirToolStripMenuItem"; this->salirToolStripMenuItem->Size = System::Drawing::Size(105, 22); this->salirToolStripMenuItem->Text = L"Salir"; this->salirToolStripMenuItem->Click += gcnew System::EventHandler(this, &Form1::salirToolStripMenuItem_Click); // // toolStripMenuItem1 // this->toolStripMenuItem1->DropDownItems->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^ >(1) {this>cRBToolStripMenuItem}); this->toolStripMenuItem1->Name = L"toolStripMenuItem1"; this->toolStripMenuItem1->Size = System::Drawing::Size(67, 20); this->toolStripMenuItem1->Text = L"Acerca de"; // // cRBToolStripMenuItem 45 // this->cRBToolStripMenuItem->Name = L"cRBToolStripMenuItem"; this->cRBToolStripMenuItem->Size = System::Drawing::Size(105, 22); this->cRBToolStripMenuItem->Text = L"CRB"; this->cRBToolStripMenuItem->Click += gcnew System::EventHandler(this, &Form1::cRBToolStripMenuItem_Click); // // button2 // this->button2->Location = System::Drawing::Point(53, 141); this->button2->Name = L"button2"; this->button2->Size = System::Drawing::Size(184, 26); this->button2->TabIndex = 2; this->button2->Text = L"Registrar marcas de personal"; this->button2->UseVisualStyleBackColor = true; this->button2->Click += gcnew System::EventHandler(this, &Form1::button2_Click); // // Form1 // this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; this->ClientSize = System::Drawing::Size(292, 266); this->Controls->Add(this->button2); this->Controls->Add(this->button1); this->Controls->Add(this->menuStrip1); this->Icon = (cli::safe_cast<System::Drawing::Icon^ >(resources->GetObject(L"$this.Icon"))); this->MaximizeBox = false; this->MaximumSize = System::Drawing::Size(300, 300); this->MinimumSize = System::Drawing::Size(300, 300); this->Name = L"Form1"; this->StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen; this->Text = L"Control de Registro Biometrico"; this->menuStrip1->ResumeLayout(false); this->menuStrip1->PerformLayout(); this->ResumeLayout(false); this->PerformLayout(); } #pragma endregion private: System::Void button1_Click(System::Object^ System::EventArgs^ e) { this->Hide(); enrrol ^form2 = gcnew enrrol(); form2->GetConnetionLinker(conn); form2->ShowDialog(this); this->Show(); 46 sender, } private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) { this->Hide(); Verform ^form3 = gcnew Verform(); form3->GetConnetionLinker(conn); form3->ShowDialog(this); this->Show(); } private: System::Void salirToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) { if(MessageBox::Show( "¿Desea salir de la aplicación?", "Salir", MessageBoxButtons::YesNo ) == System::Windows::Forms::DialogResult::Yes) Application::Exit(); } private: System::Void cRBToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) { MessageBox::Show( "CRB: Control de Registro Biométrico\n2009\nElaborado por: Luis Castro Leiva", "Acerca de CRB"); } }; } A.3. Archivo Verform.h /***************************************************************** Universidad de Costa Rica Escuela de Ingenieria Electrica II Semestre 2009 IE-0502 Proyeto Electrico Elaborado por: Luis Castro Leiva A61368 Resumen: Verform.h Este archivo contiene declaraciones de las funciones que correponden a la ventana de registro de control de acceso, (ver Verform.cpp) y forma parte del cliente de comunicacion con el lector de huellas digitales U.are.U 4500 ******************************************************************/ #pragma once #pragma warning( disable : 4368) #include "dpRCodes.h" #include "dpDefs.h" #include "DPDevClt.h" 47 #include "dpFtrEx.h" #include "dpMatch.h" #include "DpUIApi.h" //Encabezados necesarios para la manipulacion de caracteres #include <string.h> #include <stdio.h> #include <iostream> #include <fstream> //Encabezados para la conexion con la base de datos #include <Winsock.h> #include <mysql.h> using using using using using using using using using using namespace namespace namespace namespace namespace namespace namespace namespace namespace namespace std; System; System::ComponentModel; System::Collections; System::Windows::Forms; System::Data; System::Drawing; System::Globalization; System::IO; System::Runtime::InteropServices; namespace CRB { public ref class Verform : public System::Windows::Forms::Form { public: Verform(void){ InitializeComponent(); } protected: ~Verform(){ if (components){ delete components; } delete [] m_RegTemplate.pbData; m_RegTemplate.cbData = 0; m_RegTemplate.pbData = NULL; } //codificacion para los eventos generados por el lector private: static const UINT FP_EVENT = (WM_USER+1); // Variables globales necesarias en el proceso de Verificacion private: // Contexto de extraccion FT_HANDLE m_fxContext; // Contexto de comparacion 48 FT_HANDLE m_mcContext; // Handle de la operacion HDPOPERATION m_hOperationVerify; // Objetos binarios donde se almacen las plantillas de huellas dactilares DATA_BLOB m_RegTemplate,r_RegTemplate; // identificador de la comunicacion establecidad con MySQL MYSQL* conn; // Objeto para almacenar los resultados de una consulta a MySQL MYSQL_RES* mysql_res; // Bandera de resultado de comparacion TRUE == huellas concuerdan. FALSE == no concuerdan bool match_flag; private: private: private: private: private: System::Windows::Forms::Label^ label1; System::Windows::Forms::Button^ button1; System::Windows::Forms::Label^ label2; System::Windows::Forms::Label^ label3; System::Windows::Forms::GroupBox^ groupBox1; System::ComponentModel::Container ^components; #pragma region Windows Form Designer generated code void InitializeComponent(void) { System::ComponentModel::ComponentResourceManager^ resources = (gcnew System::ComponentModel::ComponentResourceManager(Verform::typeid)); this->label1 = (gcnew System::Windows::Forms::Label()); this->button1 = (gcnew System::Windows::Forms::Button()); this->label2 = (gcnew System::Windows::Forms::Label()); this->label3 = (gcnew System::Windows::Forms::Label()); this->groupBox1 = (gcnew System::Windows::Forms::GroupBox()); this->groupBox1->SuspendLayout(); this->SuspendLayout(); // // label1 // this->label1->AutoSize = true; this->label1->Location = System::Drawing::Point(46, 54); this->label1->Name = L"label1"; this->label1->Size = System::Drawing::Size(35, 13); this->label1->TabIndex = 0; this->label1->Text = L"label1"; // // button1 // this->button1->Location = System::Drawing::Point(314, 255); this->button1->Name = L"button1"; this->button1->Size = System::Drawing::Size(92, 28); this->button1->TabIndex = 1; 49 this->button1->Text = L"Cerrar"; this->button1->UseVisualStyleBackColor = true; this->button1->Click += gcnew System::EventHandler(this, &Verform::button1_Click); // // label2 // this->label2->AutoSize = true; this->label2->Location = System::Drawing::Point(46, 89); this->label2->Name = L"label2"; this->label2->Size = System::Drawing::Size(35, 13); this->label2->TabIndex = 2; this->label2->Text = L"label2"; // // label3 // this->label3->AutoSize = true; this->label3->Location = System::Drawing::Point(46, 125); this->label3->Name = L"label3"; this->label3->Size = System::Drawing::Size(35, 13); this->label3->TabIndex = 3; this->label3->Text = L"label3"; // // groupBox1 // this->groupBox1->Controls->Add(this->label2); this->groupBox1->Controls->Add(this->label1); this->groupBox1->Controls->Add(this->label3); this->groupBox1->Location = System::Drawing::Point(12, 37); this->groupBox1->Name = L"groupBox1"; this->groupBox1->Size = System::Drawing::Size(394, 212); this->groupBox1->TabIndex = 5; this->groupBox1->TabStop = false; this->groupBox1->Text = L"Estado"; // // Verform // this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; this->ClientSize = System::Drawing::Size(418, 295); this->Controls->Add(this->groupBox1); this->Controls->Add(this->button1); this->Icon = (cli::safe_cast<System::Drawing::Icon^ >(resources->GetObject(L"$this.Icon"))); this->MaximizeBox = false; this->MaximumSize = System::Drawing::Size(426, 329); this->MinimumSize = System::Drawing::Size(426, 329); this->Name = L"Verform"; this->StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen; this->Text = L"Control de entradas y salidas"; 50 this->Load += gcnew System::EventHandler(this, &Verform::Verform_Load); this->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &Verform::Verform_FormClosing); this->groupBox1->ResumeLayout(false); this->groupBox1->PerformLayout(); this->ResumeLayout(false); } #pragma endregion public: System::Void GetConnetionLinker(MYSQL* connlink); public: System::Void LoadRegTemplate(const DATA_BLOB% rRegTemplate); private: System::Void Verform_Load(System::Object^ sender, System::EventArgs^ e); private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e); private: System::Void Verificar(FT_IMAGE_PT pFingerprintImage, int iFingerprintImageSize); private: System::Void Marca_Personal(int match_cedula); private: System::Void Cargar_Templates(FT_IMAGE_PT pFingerprintImage, int iFingerprintImageSize ); private: System::Void Verform_FormClosing(System::Object^ sender, System::Windows::Forms::FormClosingEventArgs^ e); protected: virtual void WndProc(Message %m) override{ if (m.Msg == FP_EVENT){ switch((int)m.WParam) { case WN_COMPLETED: { this->label3->Text = L"Huella digital capturada"; DATA_BLOB* pImageBlob = reinterpret_cast<DATA_BLOB*>((int)m.LParam); //Verificar si hay concordancia this->Cargar_Templates(pImageBlob->pbData, pImageBlob->cbData); break; } case WN_ERROR: { MessageBox::Show( "Existio un error interno del lector", "Error"); break; } case WN_DISCONNECT: this->label2->Text = L"Lector de huellas digitales desconectado"; break; case WN_RECONNECT: this->label2->Text = L"Lector de huellas digitales conectado"; break; case WN_FINGER_TOUCHED: 51 this->label3->Text = L"Huella digital detectada"; break; case WN_FINGER_GONE: this->label3->Text = L"Dedo alejado"; break; case WN_IMAGE_READY: this->label3->Text = L"Huella digital capturada"; break; case WN_OPERATION_STOPPED: this->label3->Text = L"Operacion detenida inadecuadamente"; break; } } Form::WndProc(m); } };//Fin de la clase Verform }//Fin del espacio CRB A.4. Archivo Verform.cpp /***************************************************************** Universidad de Costa Rica Escuela de Ingenieria Electrica II Semestre 2009 IE-0502 Proyeto Electrico Elaborado por: Luis Castro Leiva A61368 Resumen: Verform.cpp Este archivo contiene las funciones que correponden a la ventana de registro de control de acceso, (ver Verform.h) y forma parte del cliente de comunicacion con el lector de huellas digitales U.are.U 4500 ******************************************************************/ #include "StdAfx.h" #include "Verform.h" using namespace CRB; System::Void Verform::GetConnetionLinker(MYSQL* connlink){ conn = connlink; } 52 System::Void Verform::LoadRegTemplate(const DATA_BLOB% rRegTemplate) { // Se eliminan los elementos antiguos que puedan estar en la plantilla. delete [] m_RegTemplate.pbData; m_RegTemplate.pbData = NULL; m_RegTemplate.cbData = 0; // Se copian los datos suministrados dentro de la plantilla de comparacion m_RegTemplate.pbData = new BYTE[rRegTemplate.cbData]; if (!m_RegTemplate.pbData) MessageBox::Show( "No hay una plantilla creada", "Error"); ::CopyMemory(m_RegTemplate.pbData, rRegTemplate.pbData, rRegTemplate.cbData); m_RegTemplate.cbData = rRegTemplate.cbData; } System::Void Verform::Verform_Load(System::Object^ sender, System::EventArgs^ e) { HRESULT hr = S_OK; FT_RETCODE rc = FT_OK; // Se crea un contexto para realizar una extraccion pin_ptr<FT_HANDLE> pm_fxContext = &m_fxContext; if (FT_OK != (rc = FX_createContext(pm_fxContext))) { MessageBox::Show( "Cannot create Feature Extraction Context.", "Error"); } // Se crea un contexto para realizar una comparacion pin_ptr<FT_HANDLE> pm_mcContext = &m_mcContext; if (FT_OK != (rc = MC_createContext(pm_mcContext))) { MessageBox::Show( "Error en MC_createContext", "Error"); } // Iniciar la verificacion // Se utiliza prioridad baja para que se registren las marcas // aun si la ventana no se encuentra activa. DP_ACQUISITION_PRIORITY ePriority = DP_PRIORITY_LOW; HWND pHandle = (HWND)this->Handle.ToPointer(); pin_ptr<HDPOPERATION> pm_hOperationVerify = &m_hOperationVerify; if(S_OK == DPFPCreateAcquisition(ePriority, GUID_NULL,DP_SAMPLE_TYPE_IMAGE,pHandle,FP_EVENT,pm_hOperationVerify)){ if(S_OK == DPFPStartAcquisition(m_hOperationVerify)){ this->label1->Text = L"Inicializacion concluida"; this->label3->Text = L"Puede realizar una marca"; } } } System::Void Verform::button1_Click(System::Object^ System::EventArgs^ e) { 53 sender, //Se detienen y destruyen los procesos de Adquisicion y se cierran los contextos de extraccion y comparacion if (m_hOperationVerify) { DPFPStopAcquisition(m_hOperationVerify); DPFPDestroyAcquisition(m_hOperationVerify); m_hOperationVerify = 0; } if (m_fxContext) { FX_closeContext(m_fxContext); m_fxContext = 0; } if (m_mcContext) { MC_closeContext(m_mcContext); m_mcContext = 0; } this->Close(); } System::Void Verform::Verificar(FT_IMAGE_PT pFingerprintImage, int iFingerprintImageSize) { HRESULT hr = S_OK; FT_BYTE* pVerTemplate = NULL; FT_RETCODE rc = FT_OK; // Se obtiene el tamaño recomendado de las plantillas de prematricula. int iRecommendedVerFtrLen = 0; rc = FX_getFeaturesLen(FT_VER_FTR, &iRecommendedVerFtrLen, NULL); if (FT_OK != rc) MessageBox::Show( "Error en FX_getFeaturesLen", "Error"); FT_IMG_QUALITY imgQuality; FT_FTR_QUALITY ftrQuality; FT_BOOL bEextractOK = FT_FALSE; if (NULL == (pVerTemplate = new FT_BYTE[iRecommendedVerFtrLen])) MessageBox::Show( "Error en iRecommendedVerFtrLen", "Error"); rc = FX_extractFeatures(m_fxContext, extraccion iFingerprintImageSize, imagen escaneada pFingerprintImage, buffer para contener la imagen FT_VER_FTR, Verification Features iRecommendedVerFtrLen, que recibe la informacion de la plantilla 54 // Contexto para la // Tamaño de la // Puntero a algun // Requested // Tamaño del buffer pVerTemplate, donde se almacena la plantilla &imgQuality, calidad de la imagen &ftrQuality, calidad de las caracteristicas &bEextractOK); extracción // Puntero al buffer // Retorna la // Retorna la // Resultado de la if (FT_OK <= rc && bEextractOK == FT_TRUE) { // Plantilla generada exitosamente // Ahora se comparan la plantilla generada y la proveniente de las plantillas almacenadas double dFalseAcceptProbability = 0.0; FT_BOOL bVerified = FT_FALSE; rc = MC_verifyFeaturesEx(m_mcContext, comparación m_RegTemplate.cbData, la plantilla almacenada m_RegTemplate.pbData, la plantilla almacenada iRecommendedVerFtrLen, la plantilla a ser verificada pVerTemplate, la plantilla a ser verificada 0, debe ser 0 NULL, debe ser NULL NULL, debe ser NULL NULL, debe ser NULL &dFalseAcceptProbability, Probabilidad de concordancia falsa &bVerified); de la comparación if (FT_OK <= rc) { if (FT_OK != rc) { WCHAR buffer[101] = {0}; ULONG uSize = 100; } if (bVerified == FT_TRUE) { match_flag = true; this->label3->Text = L"Scan another finger verification again."; WCHAR buffer[101] = {0}; ULONG uSize = 100; } else { 55 // Contexto de // puntero a // tamaño de // tamaño de // Puntero a // Obsoleto, // Reservado, // Reservado, // Reservado, // // resultado to run this->label3->Text = L"Scan another finger to run verification again."; WCHAR buffer[101] = {0}; ULONG uSize = 100; } } else { WCHAR buffer[101] = {0}; ULONG uSize = 100; MessageBox::Show( "Error en la operacion de verificacion", "Error"); this->label3->Text = L"Intente nuevamente"; } } } System::Void Verform::Marca_Personal(int match_cedula){ CultureInfo^ MyCI = gcnew CultureInfo( "en-US",false ); DateTimeFormatInfo^ myDTFI = MyCI->DateTimeFormat; char* cedula = new char[9]; _itoa_s(match_cedula,cedula,10,10); DateTime Marca = DateTime::Now; char* Fecha = (char*)(void*)Marshal::StringToHGlobalAnsi(Marca.Date.ToString("yyyy-MMdd",myDTFI)); char* Hora = (char*)(void*)Marshal::StringToHGlobalAnsi(Marca.ToString("HH:mm::ss",myD TFI)); char sql[100]; strcpy_s(sql,100,"INSERT INTO `crb_db1`.`"); strcat_s(sql,100,cedula); strcat_s(sql,100,"` (`Fecha` ,`Hora` ,`Tipo`)VALUES ('"); strcat_s(sql,100,Fecha); strcat_s(sql,100,"', '"); strcat_s(sql,100,Hora); strcat_s(sql,100,"', '');"); if(!mysql_real_query(conn, sql ,strlen(sql))){ this->label2->Text = L"Marca realizada adecuadamente"; } else{ this->label2->Text = L"Error en la marca, no se pudo realizar"; } mysql_res = mysql_store_result(conn); mysql_free_result(mysql_res); } System::Void Verform::Cargar_Templates(FT_IMAGE_PT pFingerprintImage, int iFingerprintImageSize ){ FT_BYTE* pRegTemplate = NULL; 56 char* MYSQL_ROW sql; row; String^ solicitud = String::Format(CultureInfo::CurrentCulture,"SELECT * FROM empleados"); sql = (char*)(void*)Marshal::StringToHGlobalAnsi(solicitud); int len = 0; len = strlen(sql); if(!mysql_real_query(conn, sql ,len)){ this->label2->Text = L"Consulta exitosa"; } else{ this->label2->Text = L"Error en la consulta"; } mysql_res = mysql_store_result(conn); int match_cedula = 0; while (row = mysql_fetch_row(mysql_res)){ match_flag = false; int iRecommendedRegFtrLen = atoi(row[6]); char archivo[40]; strcpy_s(archivo,40,"d:\\CRB\\CRB\\Templates\\"); strcat_s(archivo,40,row[3]); strcat_s(archivo,40,".crbt"); char* templ = new char[iRecommendedRegFtrLen]; ifstream input(archivo, ios::binary); input.read(templ, iRecommendedRegFtrLen); input.close(); //Borrar la informacion antigua del template delete [] m_RegTemplate.pbData; m_RegTemplate.pbData = NULL; m_RegTemplate.cbData = 0; // Se copian los datos suministrados dentro de la plantilla de comparacion m_RegTemplate.pbData = new BYTE[iRecommendedRegFtrLen]; if (!m_RegTemplate.pbData) MessageBox::Show( "No hay una plantilla creada", "Error"); ::CopyMemory(m_RegTemplate.pbData, templ, iRecommendedRegFtrLen); m_RegTemplate.cbData = iRecommendedRegFtrLen; Verificar(pFingerprintImage, iFingerprintImageSize); if(match_flag == true) match_cedula = atoi(row[3]); } mysql_free_result(mysql_res); if(match_cedula != 0){ Marca_Personal(match_cedula); 57 this->label1->Text this->label2->Text exitosamente"; } else{ this->label1->Text this->label2->Text } } = L"Puede proceder a realizar otra marca"; = L"Bienvenido. Su marca ha sido registrada = L"Su huella no se encuentra registrada"; = L"Intente nuevamente por favor"; System::Void Verform::Verform_FormClosing(System::Object^ System::Windows::Forms::FormClosingEventArgs^ e) { if (m_hOperationVerify) { DPFPStopAcquisition(m_hOperationVerify); DPFPDestroyAcquisition(m_hOperationVerify); m_hOperationVerify = 0; } if (m_fxContext) { FX_closeContext(m_fxContext); m_fxContext = 0; } if (m_mcContext) { MC_closeContext(m_mcContext); m_mcContext = 0; } } sender, A.5. Archivo enroll.h /***************************************************************** Universidad de Costa Rica Escuela de Ingenieria Electrica II Semestre 2009 IE-0502 Proyeto Electrico Elaborado por: Luis Castro Leiva A61368 Resumen: enrroll.cpp Este archivo contiene las declaraciones funciones que correponden a la ventana de registro de nuevo personal, (ver enrrol.cpp) y forma parte del cliente de comunicacion con el lector de huellas digitales U.are.U 4500 ******************************************************************/ #pragma warning( disable : 4368) 58 #pragma once //Encabezados para la conexion con la base de datos #include <Winsock.h> #include <mysql.h> //Encabezados de DigitalPersona #include "resource.h" #include "dpRCodes.h" #include "dpDefs.h" #include "DPDevClt.h" #include "dpFtrEx.h" #include "dpMatch.h" #include "DpUIApi.h" //Encabezados manejo de cadenas de caracteres #include <string.h> #include <stdio.h> #include <iostream> #include <fstream> using using using using using using using using using namespace namespace namespace namespace namespace namespace namespace namespace namespace std; System; System::ComponentModel; System::Collections; System::Windows::Forms; System::Data; System::Runtime::InteropServices; System::Globalization; System::IO; namespace CRB { public ref class enrrol : public System::Windows::Forms::Form{ public: enrrol(void){ InitializeComponent(); ::ZeroMemory(&m_RegTemplate, sizeof(m_RegTemplate)); } protected: ~enrrol(){ if (components){ delete components; } delete [] m_RegTemplate.pbData; m_RegTemplate.cbData = 0; m_RegTemplate.pbData = NULL; } private: static const UINT FP_EVENT = (WM_USER+1); 59 private: // Contexto de extraccion FT_HANDLE m_fxContext; // Contexto de comparacion FT_HANDLE m_mcContext; // Handle de la operacion HDPOPERATION m_hOperationEnroll; // Numero de plantillas de pre-registro int m_NumberOfPreRegFeatures; // Arreglo que contiene las pantillas de pre-registro FT_BYTE** m_TemplateArray; // Indice de la plantilla de pre-registro int m_nRegFingerprint; // Objeto binario donde se almacen las plantillas de huellas dactilares DATA_BLOB m_RegTemplate; // Link a la conexion con MySQL MYSQL* conn; // Puntero a un objeto encargado de almacenar resultados de una consulta MYSQL_RES* mysql_res; // cadena de caracteres con una sentencia SQL CHAR* sql; private: private: private: private: private: private: private: private: private: private: private: private: private: private: private: private: System::Windows::Forms::Label^ System::Windows::Forms::TextBox^ System::Windows::Forms::Label^ System::Windows::Forms::Label^ System::Windows::Forms::TextBox^ System::Windows::Forms::Label^ System::Windows::Forms::TextBox^ System::Windows::Forms::Label^ System::Windows::Forms::Label^ System::Windows::Forms::Button^ System::Windows::Forms::Button^ System::Windows::Forms::TextBox^ System::Windows::Forms::TextBox^ System::Windows::Forms::Label^ System::Windows::Forms::Label^ System::Windows::Forms::GroupBox^ label1; textBox1; label2; label3; textBox2; label4; textBox3; label5; label6; button1; Guar_button; textBox4; textBox5; label7; label8; groupBox1; System::ComponentModel::Container ^components; #pragma region Windows Form Designer generated code void InitializeComponent(void){ System::ComponentModel::ComponentResourceManager^ resources = (gcnew System::ComponentModel::ComponentResourceManager(enrrol::typeid)); this->label1 = (gcnew System::Windows::Forms::Label()); this->textBox1 = (gcnew System::Windows::Forms::TextBox()); this->label2 = (gcnew System::Windows::Forms::Label()); 60 this->label3 = (gcnew System::Windows::Forms::Label()); this->textBox2 = (gcnew System::Windows::Forms::TextBox()); this->label4 = (gcnew System::Windows::Forms::Label()); this->textBox3 = (gcnew System::Windows::Forms::TextBox()); this->label5 = (gcnew System::Windows::Forms::Label()); this->label6 = (gcnew System::Windows::Forms::Label()); this->button1 = (gcnew System::Windows::Forms::Button()); this->Guar_button = (gcnew System::Windows::Forms::Button()); this->textBox4 = (gcnew System::Windows::Forms::TextBox()); this->textBox5 = (gcnew System::Windows::Forms::TextBox()); this->label7 = (gcnew System::Windows::Forms::Label()); this->label8 = (gcnew System::Windows::Forms::Label()); this->groupBox1 = (gcnew System::Windows::Forms::GroupBox()); this->groupBox1->SuspendLayout(); this->SuspendLayout(); // // label1 // this->label1->AutoSize = true; this->label1->Location = System::Drawing::Point(21, 25); this->label1->Name = L"label1"; this->label1->Size = System::Drawing::Size(35, 13); this->label1->TabIndex = 0; this->label1->Text = L"label1"; // // textBox1 // this->textBox1->Location = System::Drawing::Point(54, 193); this->textBox1->Name = L"textBox1"; this->textBox1->Size = System::Drawing::Size(376, 20); this->textBox1->TabIndex = 1; // // label2 // this->label2->AutoSize = true; this->label2->Location = System::Drawing::Point(51, 177); this->label2->Name = L"label2"; this->label2->Size = System::Drawing::Size(44, 13); this->label2->TabIndex = 2; this->label2->Text = L"Nombre"; // // label3 // this->label3->AutoSize = true; this->label3->Location = System::Drawing::Point(51, 340); this->label3->Name = L"label3"; this->label3->Size = System::Drawing::Size(95, 13); this->label3->TabIndex = 3; this->label3->Text = L"Numero de Cédula"; // // textBox2 // 61 this->textBox2->Location = System::Drawing::Point(54, 248); this->textBox2->Name = L"textBox2"; this->textBox2->Size = System::Drawing::Size(376, 20); this->textBox2->TabIndex = 4; // // label4 // this->label4->AutoSize = true; this->label4->Location = System::Drawing::Point(51, 391); this->label4->Name = L"label4"; this->label4->Size = System::Drawing::Size(74, 13); this->label4->TabIndex = 5; this->label4->Text = L"Departamento"; // // textBox3 // this->textBox3->Location = System::Drawing::Point(54, 303); this->textBox3->Name = L"textBox3"; this->textBox3->Size = System::Drawing::Size(376, 20); this->textBox3->TabIndex = 6; // // label5 // this->label5->AutoSize = true; this->label5->Location = System::Drawing::Point(21, 57); this->label5->Name = L"label5"; this->label5->Size = System::Drawing::Size(35, 13); this->label5->TabIndex = 7; this->label5->Text = L"label5"; // // label6 // this->label6->AutoSize = true; this->label6->Location = System::Drawing::Point(21, 89); this->label6->Name = L"label6"; this->label6->Size = System::Drawing::Size(35, 13); this->label6->TabIndex = 8; this->label6->Text = L"label6"; // // button1 // this->button1->Location = System::Drawing::Point(336, 471); this->button1->Name = L"button1"; this->button1->Size = System::Drawing::Size(94, 28); this->button1->TabIndex = 9; this->button1->Text = L"Cerrar"; this->button1->UseVisualStyleBackColor = true; this->button1->Click += gcnew System::EventHandler(this, &enrrol::button1_Click); // // Guar_button // 62 this->Guar_button->Location = System::Drawing::Point(231, 472); this->Guar_button->Name = L"Guar_button"; this->Guar_button->Size = System::Drawing::Size(94, 27); this->Guar_button->TabIndex = 10; this->Guar_button->Text = L"Guardar"; this->Guar_button->UseVisualStyleBackColor = true; this->Guar_button->Click += gcnew System::EventHandler(this, &enrrol::button2_Click); // // textBox4 // this->textBox4->Location = System::Drawing::Point(54, 356); this->textBox4->Name = L"textBox4"; this->textBox4->Size = System::Drawing::Size(376, 20); this->textBox4->TabIndex = 11; // // textBox5 // this->textBox5->Location = System::Drawing::Point(54, 407); this->textBox5->Name = L"textBox5"; this->textBox5->Size = System::Drawing::Size(376, 20); this->textBox5->TabIndex = 12; // // label7 // this->label7->AutoSize = true; this->label7->Location = System::Drawing::Point(54, 232); this->label7->Name = L"label7"; this->label7->Size = System::Drawing::Size(76, 13); this->label7->TabIndex = 13; this->label7->Text = L"Primer Apellido"; // // label8 // this->label8->AutoSize = true; this->label8->Location = System::Drawing::Point(51, 287); this->label8->Name = L"label8"; this->label8->Size = System::Drawing::Size(90, 13); this->label8->TabIndex = 14; this->label8->Text = L"Segundo Apellido"; // // groupBox1 // this->groupBox1->Controls->Add(this->label1); this->groupBox1->Controls->Add(this->label5); this->groupBox1->Controls->Add(this->label6); this->groupBox1->Location = System::Drawing::Point(54, 36); this->groupBox1->Name = L"groupBox1"; this->groupBox1->Size = System::Drawing::Size(376, 122); this->groupBox1->TabIndex = 15; this->groupBox1->TabStop = false; 63 this->groupBox1->Text = L"Estado"; // // enrrol // this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; this->ClientSize = System::Drawing::Size(473, 541); this->Controls->Add(this->groupBox1); this->Controls->Add(this->label8); this->Controls->Add(this->label7); this->Controls->Add(this->textBox5); this->Controls->Add(this->textBox4); this->Controls->Add(this->Guar_button); this->Controls->Add(this->button1); this->Controls->Add(this->textBox3); this->Controls->Add(this->label4); this->Controls->Add(this->textBox2); this->Controls->Add(this->label3); this->Controls->Add(this->label2); this->Controls->Add(this->textBox1); this->Icon = (cli::safe_cast<System::Drawing::Icon^ >(resources->GetObject(L"$this.Icon"))); this->MaximizeBox = false; this->MaximumSize = System::Drawing::Size(481, 575); this->MinimumSize = System::Drawing::Size(481, 575); this->Name = L"enrrol"; this->StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen; this->Text = L"Registro de Personal"; this->Load += gcnew System::EventHandler(this, &enrrol::enrrol_Load); this->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &enrrol::enrrol_FormClosing); this->groupBox1->ResumeLayout(false); this->groupBox1->PerformLayout(); this->ResumeLayout(false); this->PerformLayout(); } #pragma endregion public: System::Void private: System::Void System::EventArgs^ e); private: System::Void iFingerprintImageSize); private: System::Void FT_BYTE* pRegTemplate); private: System::Void System::EventArgs^ e); GetConnetionLinker(MYSQL* connlink); enrrol_Load(System::Object^ sender, AddToEnroll(FT_IMAGE_PT pFingerprintImage, int GuardarArchivo(int iRecommendedRegFtrLen, button1_Click(System::Object^ 64 sender, private: System::Void enrrol_FormClosing(System::Object^ sender, System::Windows::Forms::FormClosingEventArgs^ e); private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e); protected: virtual void WndProc(Message %m) override{ if (m.Msg == FP_EVENT){ switch((int)m.WParam) { case WN_COMPLETED: { this->label5->Text = L"Imagen de la huella capturada"; DATA_BLOB* pImageBlob = reinterpret_cast<DATA_BLOB*>((int)m.LParam); AddToEnroll(pImageBlob->pbData, pImageBlob>cbData); break; } case WN_ERROR: { MessageBox::Show( "Existio un error interno del lector", "Error"); break; } case WN_DISCONNECT: this->label6->Text = L"Lector de huellas digitales desconectado"; break; case WN_RECONNECT: this->label6->Text = L"Lector de huellas digitales conectado"; break; case WN_FINGER_TOUCHED: this->label5->Text = L"Huella dactilar detectada"; break; case WN_FINGER_GONE: this->label5->Text = L"Dedo separado del lector"; break; case WN_IMAGE_READY: this->label5->Text = L"Imagen de la huella dactilar lista"; break; case WN_OPERATION_STOPPED: this->label5->Text = L"Fingerprint Enrollment Operation stopped"; break; } } Form::WndProc(m); } }; } 65 A.6. Archivo enroll.cpp /***************************************************************** Universidad de Costa Rica Escuela de Ingenieria Electrica II Semestre 2009 IE-0502 Proyeto Electrico Elaborado por: Luis Castro Leiva A61368 Resumen: enrrol.cpp Este archivo contiene las funciones que correponden a la ventana de registro de nuevo personal, (ver enrrol.h) y forma parte del cliente de comunicacion con el lector de huellas digitales U.are.U 4500 ******************************************************************/ #include "StdAfx.h" #include "enrrol.h" using namespace CRB; System::Void enrrol::GetConnetionLinker(MYSQL* connlink){ //Almacena el link a la conexion establecida con MySQL conn = connlink; } System::Void enrrol::enrrol_Load(System::Object^ System::EventArgs^ e) { sender, FT_RETCODE rc = FT_OK; HRESULT hr = S_OK; // Se crea un contexto para realizar una extraccion pin_ptr<FT_HANDLE> pm_fxContext = &m_fxContext; if (FT_OK != (rc = FX_createContext(pm_fxContext))) { MessageBox::Show( "Error en FX_createContext", "Error"); } // Se crea un contexto para la comparacion pin_ptr<FT_HANDLE> pm_mcContext = &m_mcContext; if (FT_OK != (rc = MC_createContext(pm_mcContext))) { MessageBox::Show( "Error en MC_createContext", "Error"); } // Se obtiene el numero de pre-plantillas necesarias para la creacion de una plantilla de huella // Se asigna memoria a un arreglo que almacena estas pre-plantillas MC_SETTINGS mcSettings = {0}; if (FT_OK != (rc = MC_getSettings(&mcSettings))) 66 MessageBox::Show( "Error en MC_getSettings", "Error"); m_NumberOfPreRegFeatures = mcSettings.numPreRegFeatures; if (NULL == (m_TemplateArray = new FT_BYTE*[m_NumberOfPreRegFeatures])) MessageBox::Show( "Error en m_TemplateArray", "Error"); ::ZeroMemory(m_TemplateArray, sizeof(FT_BYTE**)*m_NumberOfPreRegFeatures); // Pone el indice del arreglo en cero, donde sera guardada la primera pre-plantilla. m_nRegFingerprint = 0; // Se usa prioridad Normal para que solo se lean huellas cuando la // ventana se encuentra activa DP_ACQUISITION_PRIORITY ePriority = DP_PRIORITY_NORMAL; HWND pHandle = (HWND)this->Handle.ToPointer(); pin_ptr<HDPOPERATION> pm_hOperationEnroll = &m_hOperationEnroll; if(S_OK == DPFPCreateAcquisition(ePriority, GUID_NULL,DP_SAMPLE_TYPE_IMAGE,pHandle,FP_EVENT,pm_hOperationEnroll)){ if(S_OK == DPFPStartAcquisition(m_hOperationEnroll)){ this->label5->Text = L"Inicializacion concluida"; this->label1->Text = L"Coloque el dedo indice derecho para ser escaneado"; } } } System::Void enrrol::AddToEnroll(FT_IMAGE_PT pFingerprintImage, int iFingerprintImageSize){ HRESULT hr = S_OK; FT_BYTE* pPreRegTemplate = NULL; FT_BYTE* pRegTemplate = NULL; // No se generan mas pre-plantillas de las necesarias if (m_nRegFingerprint < m_NumberOfPreRegFeatures) { FT_RETCODE rc = FT_OK; // Se obtiene la cantidad recomendada de las plantillas de pre-registro int iRecommendedPreRegFtrLen = 0; rc = FX_getFeaturesLen(FT_PRE_REG_FTR, &iRecommendedPreRegFtrLen, NULL); if (FT_OK != rc) MessageBox::Show( "Error en FX_getFeaturesLen", "Error"); FT_IMG_QUALITY imgQuality; FT_FTR_QUALITY ftrQuality; FT_BOOL bEextractOK = FT_FALSE; 67 if (NULL == (pPreRegTemplate = new FT_BYTE[iRecommendedPreRegFtrLen])) MessageBox::Show( "Error en pPreRegTemplate", "Error"); rc = FX_extractFeatures(m_fxContext, // Contexto de extraccion iFingerprintImageSize, // tamaño de la imagen de huella digital pFingerprintImage, // Puntero al buffer de imagen FT_PRE_REG_FTR, // Solicitud de extraccion de características iRecommendedPreRegFtrLen, // tamaño de la plantilla de pre-registro pPreRegTemplate, // puntero al buffer que almacena la plantilla de pre-registro &imgQuality, // retorna la calidad de imagen &ftrQuality, // retorna la calidad de las características &bEextractOK); // retorna el resultado de la extraccion // Si la extracción es exitosa se crea una plantilla de preregistro if (FT_OK <= rc && bEextractOK == FT_TRUE) { this->label1->Text = L"Pre-Enrollment feature set generated successfully"; m_TemplateArray[m_nRegFingerprint++] = pPreRegTemplate; pPreRegTemplate = NULL; // Se verifica si existen suficientes plantillas de pre-registro if (m_nRegFingerprint == m_NumberOfPreRegFeatures) { int iRecommendedRegFtrLen = 0; rc = MC_getFeaturesLen(FT_REG_FTR, 0, &iRecommendedRegFtrLen, NULL); if (FT_OK != rc) MessageBox::Show( "Error en MC_getFeaturesLen", "Error"); if (NULL == (pRegTemplate = new FT_BYTE[iRecommendedRegFtrLen])) MessageBox::Show( "pRegTemplate", "Error"); FT_BOOL bRegSucceeded = FT_FALSE; rc = MC_generateRegFeatures(m_mcContext, // Contexto de comparacion 0, // debe ser 0 68 m_NumberOfPreRegFeatures, // numero de plantillas de pre-registro iRecommendedPreRegFtrLen, // tamaño de una plantilla de preregistro m_TemplateArray, // arreglo de plantillas de pre-registro iRecommendedRegFtrLen, // tamaño de la plantilla pRegTemplate, // Pointer to the buffer where the Enrollment template to be stored NULL, // Reservado, debe ser NULL. &bRegSucceeded); plantilla // Resultado de la creacion de la if (FT_OK <= rc && bRegSucceeded == FT_TRUE) { // Plantilla generada exitosamente m_RegTemplate.pbData = pRegTemplate; m_RegTemplate.cbData = iRecommendedRegFtrLen; pRegTemplate = NULL; this->label1->Text = L"Plantilla de registro generada exitosamente"; this->label5->Text = L"Close this dialog and run Verification to verify fingerprint"; } else { this->label1->Text = L"La creacion de la plantilla de registro fallo"; // Existio un error en la creacion de la plantilla // entonces se borran las prematriculas realizadas m_nRegFingerprint = 0; for (int i=0; i<m_NumberOfPreRegFeatures; ++i) if(m_TemplateArray[i]) delete [] m_TemplateArray[i], m_TemplateArray[i] = NULL; } } else { // Continua ejecutandose si no se han terminado la cantidad de plantilla de // pre-matricula requeridas this->label1->Text = L"Coloque el indice derecho nuevamente"; } } else { 69 MessageBox::Show( "Error en la creación de la plantilla de pre-registro.", "Error"); } } else { MessageBox::Show( "Una plantilla de registro ya ha sido creada", "Error"); } } System::Void enrrol::GuardarArchivo(int iRecommendedRegFtrLen, FT_BYTE* pRegTemplate){ if (m_RegTemplate.cbData == 0 || m_RegTemplate.pbData == NULL) { MessageBox::Show( "Debe crearse una plantilla de huella digital antes de registrar una persona", "Error"); } else{ if(this->textBox1->Text != L"" && this->textBox2->Text != L"" && this->textBox3->Text != L"" && this->textBox4->Text != L""&& this>textBox5->Text != L""){ //Almacenamiento en el archivo temporal char archivo[40]; strcpy_s(archivo, 40, "d:\\CRB\\CRB\\Templates\\"); char* cod_ced = new char[9]; cod_ced = (char*)(void*)Marshal::StringToHGlobalAnsi(this>textBox4->Text); strcat_s(archivo,40,cod_ced); strcat_s(archivo,40,".crbt"); ofstream out(archivo,ios::binary); out.write((char*)pRegTemplate,iRecommendedRegFtrLen); out.close(); //Almacenamiento de la informacio del nuevo empleado en la base de datos String^ solicitud = String::Format(CultureInfo::CurrentCulture,\ "INSERT INTO `crb_db1`.`empleados` (`Nombre` ,`Apellido1` ,`Apellido2` ,`Cedula`,`Departamento` ,`DataTemplate`,`cbData`)VALUES ('{0}', '{1}', '{2}', '{3}' ,'{4}','','{5}');"\ ,textBox1->Text,textBox2->Text,textBox3->Text,textBox4>Text,textBox5->Text,iRecommendedRegFtrLen); sql = (char*)(void*)Marshal::StringToHGlobalAnsi(solicitud); int len = 0; len = strlen(sql); if(!mysql_real_query(conn, sql ,len)){ this->label5->Text = L"Informacion guardada exitosamente"; } else{ this->label5->Text = L"Error en la consulta"; } mysql_res = mysql_store_result(conn); 70 mysql_free_result(mysql_res); //Creacion de una Tabla en la base de datos para el nuevo empleado char nueva_tabla[122]; strcpy_s(nueva_tabla, 122, "CREATE TABLE `crb_db1`.`"); strcat_s(nueva_tabla,122,cod_ced); strcat_s(nueva_tabla,122,"` (`Fecha` DATE NOT NULL ,`Hora` TIME NOT NULL ,`Tipo` BOOL NOT NULL) ENGINE = MYISAM ;"); len = strlen(nueva_tabla); mysql_real_query(conn, nueva_tabla ,len); mysql_res = mysql_store_result(conn); mysql_free_result(mysql_res); } else{ MessageBox::Show( "Ninguno de los campos de informacion puede estar vacio", "Error"); } } } System::Void enrrol::button1_Click(System::Object^ System::EventArgs^ e) { this->Close(); } sender, System::Void enrrol::enrrol_FormClosing(System::Object^ sender, System::Windows::Forms::FormClosingEventArgs^ e) { //Se detienen los procesos de acquisicion y se eliminan los contextos //de comparacion y extraccion if (m_hOperationEnroll) { DPFPStopAcquisition(m_hOperationEnroll); DPFPDestroyAcquisition(m_hOperationEnroll); m_hOperationEnroll = 0; } if (m_fxContext) { FX_closeContext(m_fxContext); m_fxContext = 0; } if (m_mcContext) { MC_closeContext(m_mcContext); m_mcContext = 0; } if(m_TemplateArray){ //Se eliminan las plantillas de pre-registro for (int i=0; i<m_NumberOfPreRegFeatures; ++i) if(m_TemplateArray[i]) delete [] m_TemplateArray[i], m_TemplateArray[i] = NULL; delete [] m_TemplateArray; 71 } } System::Void enrrol::button2_Click(System::Object^ sender, System::EventArgs^ e) { this->GuardarArchivo(m_RegTemplate.cbData, m_RegTemplate.pbData); } 72 APÉNDICE B: Código de la interfaz para administración de bases de datos CRB B.1. Archivo cliente.php <!---------------------------------------------------------Universidad de Costa Rica Escuela de Ingenieria Electrica II Semestre 2009 IE-0529 Proyecto Electrico Elaborado por: Luis Castro Leiva A61368 Resumen: cliente.php Este archivo contiene el codigo HTML de la interfaz de administracion de Bases de Datos CRB. -----------------------------------------------------------> <html> <head> <script language="JavaScript" type="text/javascript" src="ajax.js"></script> <title>CRB Data Base Administrator</title> <style type="text/css"> body { font-family: Arial, "Times New Roman", Times, serif; color: #0174DF; background-color: #FFFFFF } h1 { font-family: Helvetica, Geneva, Arial, SunSans-Regular, sans-serif } </style> </head> <body> <h1>Interfaz para administracion de Bases de Datos CRB</h1> <table align = "center" Border = 0 Cellpadding=4> <td> <p>Por medio de esta interfaz se pueden realizar busquedas de sobre la informacion al almacenada en la base de datos de CRB</p> </td> <td> <object type="application/x-shockwave-flash" data="reloj1.swf" height="100"> <param name="movie" value="reloj1.swf"></param> <param name="quality" value="High"></param> <param name="scale" value="ExactFit"></param> <param name="wmode" value="transparent"></param> <param name="loop" value="false"></param> <param name="menu" value="false"></param> </object> 73 width="100" </td> </table> <Table align = "center" Border = 1 Cellpadding=4> <tr> <td> <p>Busqueda de personal por Nombre, Primer y Segundo Apellido y Numero de Cedula</p> <Form Name="crb_form_busqueda" Action="" Methot="GET"> <Table align = "center" Border Cellpadding=4> <tr> <td>Nombre: <INPUT Type="text" Name="nombre" VALUE="" Size=25></td> <td><Input Type=button OnClick="Consultar('query_name.php',this.form); return false" Value="Buscar"></td> </tr> <tr> <td>Primer Apellido: <Input Name="apellido1" Value="" Size=16></td> <td><Input Type=button OnClick="Consultar('query_apellido1.php',this.form); return false" Value="Buscar"></td> </tr> <tr> <td>Segundo Apellido: <Input Name="apellido2" Size=15></td> <td><Input Type=button OnClick="Consultar('query_apellido2.php',this.form); return false" Value="Buscar"></td> </tr> <tr> <td>Cedula: <Input Name="cedula" Size=27></td> <td><Input Type=button OnClick="Consultar('query_cedula.php',this.form); return false" Value="Buscar"></td> </tr> </Table> <p Align = "center"><Input OnClick="document.getElementById('resultado').innerHTML = resultados" Size=27></p> <div id="resultado"></div> ''" Type=button Value="Limpiar </Form> </td> <td rowspan="2"> <p Align = "center">Registro de Marcas de personal por Numero de Cedula</p> <Form Name="crb_form_marcas" Action="" Methot="GET"> <Table align = "center" Border Cellpadding=4> <tr> <td>Cedula: <INPUT Type="text" Name="cedula" VALUE="" Size=25></td> <td><Input Type=button OnClick="ConsultarMarcas('query_marcas.php',this.form); return false" Value="Buscar"></td> </tr> </Table> </Form> <p Align = "center"><Input Type=button OnClick="document.getElementById('marcas').innerHTML = ''" Value="Limpiar resultados" Size=27></p> <div id="marcas"></div> </td> </tr> 74 <tr> <td> <Form> <p align = "center">Eliminacion de Usuarios por numero de Cedula</p> <Table align = "center" Border Cellpadding=4> <tr> <td>Cedula: <Input Name="cedula_eliminar" Size=27></td> <td><Input Type=button OnClick="Eliminar('query_eliminar.php',this.form); return false" Value="Eliminar"></td> </tr> </Table> <p Align = "center"><Input Type=button OnClick="document.getElementById('resultado_eliminar').innerHTML = ''" Value="Limpiar resultados" Size=27></p> <div id="resultado_eliminar"></div> </Form> </td> </tr> </table> <p Align = "center">2009, Sistema CRB</p> </body> </html> B.2. Archivo ajax.js /*********************************************************************** Universidad de Costa Rica Escuela de Ingenieria Electrica II Semestre 2009 IE-0529 Proyecto Electrico Elaborado por: Luis Castro Leiva A61368 Resumen: ajax.js Este archivo contiene el codigo JAVASCRIPT necesario por la de la interfaz de administracion de Bases de Datos CRB. En el se crea un objeto Ajax para establecer comunicacion asincronica con PHP y este en ultimo enlaza con MySQL ***********************************************************************/ //La funcion objetoAjax hace que la aplicación sea transparente al navegador //utilizado debido a que independientemente de cual sea, se crea un objeto ajax function objetoAjax(){ var xmlhttp=false; try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); 75 } catch (e) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (E) { xmlhttp = false; } } if (!xmlhttp && typeof XMLHttpRequest!='undefined') { xmlhttp = new XMLHttpRequest(); } return xmlhttp; } //La función Consultar se encarga de llamar el script de PHP por medio //del objeto ajax creado al llamar la funcion objetoAjax function Consultar(datos,form){ var nombre = form.nombre.value; var apellido1 = form.apellido1.value; var apellido2 = form.apellido2.value; var cedula = form.cedula.value; divResultado = document.getElementById('resultado'); ajax=objetoAjax(); ajax.open("GET", datos+"?nombre="+nombre+"&apellido1="+apellido1+"&apellido2="+apellido2+" &cedula="+cedula); ajax.onreadystatechange=function() { if (ajax.readyState==4) { divResultado.innerHTML = ajax.responseText } } ajax.send(null) } function Eliminar(datos,form){ var cedula_eliminar = form.cedula_eliminar.value; divResultado = document.getElementById('resultado_eliminar'); ajax=objetoAjax(); ajax.open("GET", datos+"?cedula="+cedula_eliminar); ajax.onreadystatechange=function() { if (ajax.readyState==4) { divResultado.innerHTML = ajax.responseText } } ajax.send(null) } function ConsultarMarcas(datos,form){ var cedula = form.cedula.value; 76 divResultado = document.getElementById('marcas'); ajax=objetoAjax(); ajax.open("GET", datos+"?cedula="+cedula); ajax.onreadystatechange=function() { if (ajax.readyState==4) { divResultado.innerHTML = ajax.responseText } } ajax.send(null) } B.3. Archivo query_name.php <!--------------------------------------------------------Universidad de Costa Rica Escuela de Ingenieria Electrica II Semestre 2009 IE-0529 Proyecto Electrico Elaborado por: Luis Castro Leiva A61368 Resumen: query_name.php Este archivo contine el codigo en PHP que realiza busquedas en la base de datos de CRB por el campo nombre y retorna los resultados de la busqueda. -----------------------------------------------------------> <?php //Configuracion de la conexion a base de datos $host = "localhost"; $usuario = "admin"; $password = "crb"; $base = "crb_db1"; $link = mysql_connect($host, $usuario, $password); //Selección de la base de datos a usar mysql_select_db($base, $link); //consulta todos los empleados if($_GET["nombre"]){ $sql=mysql_query("SELECT * FROM `empleados` WHERE Nombre = '".$_GET['nombre']."'",$link); $num_rows = mysql_num_rows($sql); if($num_rows == NULL) echo "<p align =\"center\">No hay resultados de la busqueda por nombre</p>\n"; else echo "<p align =\"center\">Nombre | Primer Apellido | Cedula </p> \n"; while($row = mysql_fetch_array($sql)){ 77 echo "<p align =\"center\">".$row['Nombre']." | ".$row['Apellido1']." | ".$row['Cedula']."</p> \n"; } mysql_free_result($sql); } else{ echo "<p align =\"center\">No hay nombre elegido para realizar la busqueda</p>"; } ?> B.4. Archivo query_apellido1.php <!--------------------------------------------------------Universidad de Costa Rica Escuela de Ingenieria Electrica II Semestre 2009 IE-0529 Proyecto Electrico Elaborado por: Luis Castro Leiva A61368 Resumen: query_apellido1.php Este archivo contine el codigo en PHP que realiza busquedas en la base de datos de CRB por el campo apellido1 y retorna los resultados de la busqueda. -----------------------------------------------------------> <?php //Configuracion de la conexion a base de datos $host = "localhost"; $usuario = "admin"; $password = "crb"; $base = "crb_db1"; $link = mysql_connect($host, $usuario, $password); //Selección de la base de datos a usar mysql_select_db($base, $link); //consulta todos los empleados if($_GET["apellido1"]){ $sql=mysql_query("SELECT * FROM `empleados` WHERE Apellido1 = '".$_GET['apellido1']."'",$link); $num_rows = mysql_num_rows($sql); if($num_rows == NULL) echo "<p align =\"center\">No hay resultados de la busqueda por primer apellido</p>\n"; else echo "<p align =\"center\">Nombre | Primer Apellido | Segundo Apellido | Cedula </p> \n"; while($row = mysql_fetch_array($sql)){ 78 echo "<p align =\"center\">".$row['Nombre']." | ".$row['Apellido1']." | ".$row['Apellido2']." | ".$row['Cedula']."</p> \n"; } mysql_free_result($sql); } else{ echo "<p align =\"center\">No hay un apellido elegido para realizar la busqueda</p>"; } ?> B.5. Archivo query_apellido2.php <!--------------------------------------------------------Universidad de Costa Rica Escuela de Ingenieria Electrica II Semestre 2009 IE-0529 Proyecto Electrico Elaborado por: Luis Castro Leiva A61368 Resumen: query_apellido2.php Este archivo contine el codigo en PHP que realiza busquedas en la base de datos de CRB por el campo Apellido2 y retorna los resultados de la busqueda. -----------------------------------------------------------> <?php //Configuracion de la conexion a base de datos $host = "localhost"; $usuario = "admin"; $password = "crb"; $base = "crb_db1"; //Establece la conexion con MySQL $link = mysql_connect($host, $usuario, $password); //Selección de la base de datos a usar mysql_select_db($base, $link); //consulta en la tabla empleados el campo Apellido2 if($_GET["apellido2"]){ $sql=mysql_query("SELECT * FROM `empleados` WHERE Apellido2 = '".$_GET['apellido2']."'",$link); $num_rows = mysql_num_rows($sql); if($num_rows == NULL) echo "<p align =\"center\">No hay resultados de la busqueda por segundo apellido</p>\n"; else 79 echo "<p align =\"center\">Nombre | Primer Apellido | Segundo Apellido | Cedula </p> \n"; while($row = mysql_fetch_array($sql)){ echo "<p align =\"center\">".$row['Nombre']." | ".$row['Apellido1']." | ".$row['Apellido2']." | ".$row['Cedula']."</p> \n"; } mysql_free_result($sql); } else{ echo "<p align =\"center\">No hay un apellido elegido para realizar la busqueda</p>"; } ?> B.6. Archivo query_cedula.php <!--------------------------------------------------------Universidad de Costa Rica Escuela de Ingenieria Electrica II Semestre 2009 IE-0529 Proyecto Electrico Elaborado por: Luis Castro Leiva A61368 Resumen: query_cedula.php Este archivo contine el codigo en PHP que realiza busquedas en la base de datos de CRB por el campo Cedula y retorna los resultados de la busqueda. -----------------------------------------------------------> <?php //Configuracion de la conexion a base de datos $host = "localhost"; $usuario = "admin"; $password = "crb"; $base = "crb_db1"; $link = mysql_connect($host, $usuario, $password); //Selección de la base de datos a usar mysql_select_db($base, $link); //consulta todos los empleados if($_GET["cedula"]){ $sql=mysql_query("SELECT * FROM `empleados` WHERE Cedula = '".$_GET['cedula']."'",$link); $num_rows = mysql_num_rows($sql); if($num_rows == NULL) echo "<p align =\"center\">No hay resultados de la busqueda por cedula</p>\n"; else 80 echo "<p align =\"center\">Nombre | Primer Apellido | Segundo Apellido | Cedula </p> \n"; while($row = mysql_fetch_array($sql)){ echo "<p align =\"center\">".$row['Nombre']." | ".$row['Apellido1']." | ".$row['Apellido2']." | ".$row['Cedula']."</p> \n"; } mysql_free_result($sql); } else{ echo "<p align =\"center\">No hay un numero de cedula elegido para realizar la busqueda</p>"; } ?> B.7. Archivo query_marcas.php <!--------------------------------------------------------Universidad de Costa Rica Escuela de Ingenieria Electrica II Semestre 2009 IE-0529 Proyecto Electrico Elaborado por: Luis Castro Leiva A61368 Resumen: query_marcas.php Este archivo contine el codigo en PHP que realiza busquedas en la base de datos de CRB de las marcas de acceso de personal y retorna los resultados de la busqueda. -----------------------------------------------------------> <?php //Configuracion de la conexion a base de datos $host = "localhost"; $usuario = "admin"; $password = "crb"; $base = "crb_db1"; $link = mysql_connect($host, $usuario, $password); //Selección de la base de datos a usar mysql_select_db($base, $link); //consulta todos los empleados if($_GET["cedula"]){ $sql=mysql_query("SELECT * FROM `".$_GET['cedula']."`",$link); if($sql != 0){ $num_rows = mysql_num_rows($sql); if($num_rows == NULL) echo "<p align =\"center\">No hay marcas para esta persona</p>\n"; 81 else echo "<p align =\"center\">Fecha | Hora </p> \n"; while($row = mysql_fetch_array($sql)){ echo "<p align =\"center\">".$row['Fecha']." | ".$row['Hora']."</p> \n"; } mysql_free_result($sql); } else{ echo "<p align =\"center\">No se encuentra registrada una persona con esta cedula</p>"; } } else{ echo "<p align =\"center\">Debe llenar el espacio dado para realizar la busqueda</p>"; } ?> B.8. Archivo query_eliminar.php <!--------------------------------------------------------Universidad de Costa Rica Escuela de Ingenieria Electrica II Semestre 2009 IE-0529 Proyecto Electrico Elaborado por: Luis Castro Leiva A61368 Resumen: query_eliminar.php Este archivo contine el codigo en PHP que elimina una fila correspondiente a un numero de cedula suministrado via GET en la base de datos crb_db1 y la tabla de registro de accesos correspondiente a ese numero de cedula -----------------------------------------------------------> <?php //Configuracion de la conexion a base de datos $host = "localhost"; $usuario = "admin"; $password = "crb"; $base = "crb_db1"; //establece conexion con la base de datos MySQL $link = mysql_connect($host, $usuario, $password); //Selección de la base de datos a usar mysql_select_db($base, $link); 82 if($_GET["cedula"]){ $sql1=mysql_query("DELETE FROM `crb_db1`.`empleados` WHERE Cedula=".$_GET['cedula'],$link); $sql2=mysql_query("DROP TABLE `".$_GET['cedula']."`",$link); if (($sql1 == 1) && ($sql2 == 1)){ echo "<p align =\"center\">Se ha eliminado la persona adecuadamente</p"; } } else{ echo "<p align =\"center\">No se encuentra registrada una persona con esta cedula</p>"; } ?> 83 Apéndice C: Sentencia de SQL para la creación de la base de datos crb_db1. CREATE TABLE `crb_db1`.`empleados` ( `Nombre` CHAR( 20 ) NOT NULL , `Apellido1` CHAR( 20 ) NOT NULL , `Apellido2` CHAR( 20 ) NOT NULL , `Cedula` INT NOT NULL , `Departamento` CHAR( 20 ) NOT NULL , `DataTemplate` BLOB NOT NULL , `cbData` INT NOT NULL ) ENGINE = MYISAM ; 84 Apéndice D: Funciones del Dispositivo utilizas. o HRESULT DPFPInit(); Valores de Retorno S_OK operación exitosa S_FALSE librería ya inicializada. 0x800706B3 el servidor RPC no está escuchando, lo que significa que el Servicio Biométrico de Inicialización no ha sido iniciado. Descripción: Inicializa los recursos necesarios y hace las asignaciones de memoria necesarias para empezar la comunicación con el lector de huellas digitales. Debe ser llamado antes de cualquier función del API, con excepción de DPFPBufferFree. o HRESULT DPFPTerm(); Valores de Retorno S_OK operación exitosa Descripción: Libera recursos asignados por DPFPInit(). o HRESULT DPFPCreateAcquisition( DP_ACQUISITION_PRIORITY eAcquisitionPriority, REFGUID DevUID, ULONG uSampleType, 85 HWND hWnd, ULONG uMsg, HDPOPERATION * phOperation); Parametros eAcquisitionPriority: las aplicaciones que se conectan con el lector de huellas digitales pueden elegir entre tres niveles de prioridad: alto, normal y bajo. En el nivel alto de prioridad todos los eventos generados por el U.are.U 4500 serán enviados al cliente suscrito y solo puede existir uno de este tipo. En nivel normal pueden haber varios clientes suscritos pero la información será enviado a que esté como ventana activa. En el nivel más bajo toda la información será enviada a él aunque no se encuentre activo. DevUID: numero de serie del lector a utilizar, GUID_NULL si cualquier lector puede ser utilizado. uSampleType: Este parámetro debe ser DP_SAMPLE_TYPE_IMAGE. hWnd: Handle de la ventana a ser notificada de los eventos. uMsg: Mensaje a ser enviado como la notificación del evento phOperation: puntero al handle de la operación a ser llenado si la operación es creada exitosamente. Valores de Retorno S_OK operación exitosa E_ACCESSDENIED se intenta suscribir una aplicación como cliente pero no se tiene permisos para esto 86 E_INVALIDARG ya existe una aplicación cliente suscrita con prioridad alta. Descripción: Crea una operación de adquisición. o HRESULT DPFPStartAcquisition(HDPOPERATION hOperation); Parametros hOperation: Handle de la operación. Valores de Retorno S_OK operación exitosa Descripción: Suscribe una aplicación cliente para recibir notificación de eventos del hardware. o HRESULT DPFPStopAcquisition(HDPOPERATION hOperation); Parametros hOperation: Handle de la operación. Valores de Retorno S_OK operación exitosa Descripción: Se elimina la suscripción de alguna aplicación cliente para y se liberan recursos asignados para esto. o HRESULT DPFPDestroyAcquisition(HDPOPERATION hOperation); 87 Parametros hOperation: Handle de la operación. Valores de Retorno S_OK operación exitosa Descripción: Elimina la operación creada por DPFPCreateAcquisition y libera los recursos asociados. 88 2.7.1 Funciones de extracción o FX_DLL_INTERFACE FT_RETCODE FX_init(void); Valores de Retorno S_OK operación exitosa FT_ERR_NO_MEMORY no se encontró suficiente memoria para iniciar el módulo de extracción FT_ERR_BAD_INI_SETTING la configuración de inicialización ha sido corrompida. Descripción: Inicializa el módulo de extracción de huellas digitales, inicializa la estructura MC_SETTINGS y las tablas de búsqueda para comparación. Debe ser ejecutada antes que cualquier función del módulo de extracción. o FX_DLL_INTERFACE FT_RETCODE FX_Terminate(void); Valores de Retorno FT_OK FT_WRN_NO_INIT operación exitosa el modulo de extracción no ha sido inicializado. Descripción: Cierra el módulo de extracción y libera los recursos asociados 89 o FX_DLL_INTERFACE FT_RETCODE FX_createContext( OUT FT_HANDLE *fxContext); Parametros fxContext: Puntero a la dirección de memoria donde se localiza el handle del contexto. Valores de Retorno FT_OK operación exitosa FT_ERR_NO_INIT FX_INIT no ha sido llamada FT_ERR_INVALID_CONTEXT no hay suficiente memoria para crear el contexto. Descripción: Crea un contexto de extracción, si la operación es exitosa retorna un HANDLE que apunta al contexto creado. o FX_DLL_INTERFACE FT_RETCODE FX_closeContext( OUT FT_HANDLE* fxContext); Parametros fxContext: handle del contexto a cerrar. Valores de Retorno operación exitosa FT_OK Descripción: Cierra un contexto de extracción. 90 2.7.2 Funciones de comparación o FX_DLL_INTERFACE FT_RETCODE MC_init(void); Valores de Retorno S_OK operación exitosa FT_ERR_NO_MEMORY no se encontró suficiente memoria para iniciar el módulo de comparación FT_ERR_BAD_INI_SETTING la configuración de inicialización ha sido corrompida. Descripción: Inicializa el módulo de comparación extracción de huellas digitales, inicializa. Debe ser ejecutada antes que cualquier función del módulo de extracción. o FX_DLL_INTERFACE FT_RETCODE MC_Terminate(void); Valores de Retorno FT_OK FT_WRN_NO_INIT operación exitosa el modulo de comparación no ha sido inicializado. Descripción: Cierra el módulo de comparación y libera los recursos asociados. 91 o FX_DLL_INTERFACE FT_RETCODE MC_createContext( OUT FT_HANDLE* mcContext); Parametros mcContext: Puntero a la dirección de memoria donde se localiza el handle del contexto. Valores de Retorno FT_OK operación exitosa Descripción: Crea un contexto de comparación, si la operación es exitosa retorna un HANDLE que apunta al contexto creado. o FX_DLL_INTERFACE FT_RETCODE MC_closeContext( OUT FT_HANDLE* mcContext); Parametros mcContext: handle del contexto a cerrar. Valores de Retorno FT_OK operación exitosa Descripción: Cierra un contexto de comparación. 92 ANEXOS Sistema CRB Versión Alfa MANUAL DEL USUARIO 93 Bienvenido a CRB Bienvenido. Este documento pretende ser una guía para el manejo de la versión Alfa del sistema CRB. Aquí encontrará toda la información sobre las capacidades del programa y podrá adquirir los elementos necesarios para hacer uso del mismo. CRB es una aplicación que le permitirá estar al tanto de las horas de entrada y salida del personal a su empresa. Este software cuenta con dos partes fundamentales: una interfaz Web y el programa CRB que registra las marcas del personal y le permite registrar nuevos usuarios. Proceso de Instalación Por el momento, por ser esta una versión alfa, el proceso de instalación no está automatizado por lo cual se requiere la instalación de personal capacitado en el tema. Manejo del Sistema. El programa CRB. Para iniciar con el registro de entradas y salidas abra la aplicación CRB. Una vez abierta podrá ver la ventana principal del programa como se muestra a continuación. En esta ventana puede elegir uno de los dos modos de operación de la aplicación CRB según lo que desee hacer. 94 Figura 1. Ventana principal Si desea registrar un nuevo empleado en la base de datos del programa haga click en “Registrar nuevo personal”, si desea registrar las salidas y entradas de personal a la empresa haga click en “Registrar marcas de personal”. Cómo agregar un nuevo usuario Una vez que dio click en “Registrar nuevo personal” verá la siguiente ventana. 95 Figura 2. Ventana de Registro de nuevo personal. Siga lo siguientes pasos: Introduzca todos los datos solicitados de la persona Solicite a la persona a registrar que coloque el dedo sobre el lector y luego lo retire. Repita el procedimiento anterior tres veces más o hasta que aparezca en la línea superior del área de estado la sentencia: “La plantilla de registro ha sido generada exitosamente” Haga click en el botón Guardar. 96 Revise que en la segunda línea del área de estado se encuentre la sentencia “La información ha sido guardada exitosamente”, en caso de no ser así salga y vuelva a intentar todo el procedimiento. Haga click en el botón salir y vuelva a entrar si se desea registrar un nuevo usuario. Cómo registrar marcas de personal Desde la ventana principal, entre al modo de control de acceso haciendo click sobre el botón “Registrar marcas de personal”. Podrá observar entonces la ventana que se muestra en la siguiente figura: Figura 3. Ventana de control de acceso. Aquí los empleados nada más deben colocar el dedo que fue registrado y asegurarse de que en el área de estado se informe del resultado de la marca. En caso de que se 97 informara de algún error, se debe volver a colocar el dedo hasta que el área de estado notifique lo contrario Interfaz para la administración de bases de datos CRB Aquí el encargado de recursos humanos puede realizar las siguientes tres operaciones: Realizar búsqueda de la información del personal por nombre, apellidos o cédula. Revisar las marcas de alguna persona. Eliminar usuario registrado. Figura 4. Interfaz Web. 98 Solamente se debe acceder al sitio Web habilitado por la empresa para tal fin y llenar los espacios requeridos para realizar las búsquedas, las consultas o la eliminación. Para realizar consultas de las marcas o eliminar usuarios debe conocerse el número de cédula de la persona que se desea sacar del registro principal, y este es el dato que se debe introducir en los espacios asignados para este fin. 99 100