Lector de pasaportes y DNI

Post Reply
groiss
Posts: 206
Joined: Tue Sep 01, 2009 7:55 am
Location: Plasencia - ESPAÑA

Lector de pasaportes y DNI

Post by groiss »

Tengo que conectar una de mis aplicaciones a un escáner de pasaportes, para automatizar la entrada de datos de filiación, el aparato viene con un completo SDK, pero el problema es que no se por donde meterle mano al tema, aquí pongo el código en C del SDK para hacer la lectura de los datos MRZ

Code: Select all

/** \file *********************************************************************
 *
 * pr_recognize - Passport Reader sample program
 *
 * 2006-2010 (c) ARH Inc. (http://www.arhungary.hu)
 ******************************************************************************/

/**
 * Advanced image capturing and processing
 *
 * Purpose:
 *      Show how to capture and recognize images.
 *
 * Description:
 *
 *      Capture images after successful startup.
 *      Read the recognized field data, the calculated checksum, and display the result.
 *
 */

#include "prapi.h"
#include "gxsdldr.c"

#include "../__lib__.h"

/**
 * Main Function
 */
int main() {
    char *ec[]={"Ok","Warning","Error"};
    gxVARIANT img;
    gxIMAGE *gim;
    gxVARIANT pdoc;

    /* Opening the PR system */
    gxHANDLE hpr;   /* handle for the PR system */
    lib_function_start("Opening system files");
    if (gx_openmodulea(&hpr,"prapi","default")) lib_function_end();
    else {
        lib_displ_err();
        return 0;
    }

    /* Connecting to the first device */
    lib_function_start("Connecting to the first device");
    if (pr_usedevicen(hpr,0,PR_UMODE_FULL_CONTROL)) {
        lib_function_end();
    } else {
        lib_displ_err();
        gx_closehandle(&hpr);
        return 0;
    }

    while(!lib_kbhit()) {
        int code;
        int status;
        int id = PRV_FIELDLIST;
        gxVARIANT fieldlist;
        int i;
        char path[100], text[100];
        int stext;


        lib_process_start("Processing document");

        /* Capturing images */
        lib_function_start("Capturing images");
        if (!pr_capture(hpr)) {
            lib_displ_err();
        } else {
            lib_function_end();

            /* Getting document data */
            lib_function_start("Recognizing.");
            if (pr_recognize(hpr,0,&pdoc)) {
                lib_function_end();
            } else {
                lib_displ_err();
            }

            if (!pdoc) {
                lib_write_line("No data found!");
            } else {

                /* Displaying document type */
                if (pr_getdocumentstatus(hpr, pdoc, &code, &status)) {
                    lib_write_line("Document type: %i, status: %s", code, ec[status/100]);
                } else {
                    lib_displ_err();
                }

                /* Reading some fixed fields and displaying them */
                stext = sizeof(text);
                if (pr_getfieldfromdoca(hpr, pdoc, PR_DF_NAME, text, &stext, &status, 0)) {
                    if (*text) lib_write_line("NAME \"%s\" [%s]", text, ec[status/100]);
                } else {
                    lib_displ_err();
                }

                stext = sizeof(text);
                if (pr_getfieldfromdoca(hpr, pdoc, PR_DF_DOCUMENT_NUMBER, text, &stext, &status, 0)) {
                    if (*text) lib_write_line("DOCUMENT NUMBER \"%s\" [%s]",text,ec[status/100]);
                } else {
                    lib_displ_err();
                }

                stext = sizeof(text);
                if (pr_getfieldfromdoca(hpr, pdoc, PR_DF_EXPIRY_DATE, text, &stext, &status, 0)) {
                    if(*text) lib_write_line("EXPIRY DATE \"%s\" [%s]",text,ec[status/100]);
                } else {
                    lib_displ_err();
                }

                /* Searching for the fields and displaying them */
                if(gx_getvariantchild(pdoc,GX_VARIANT_BY_ID, &id, 0, &fieldlist)) {
                    int nitems = 0;
                    /* Get the number of recognized fields */
                    if(gx_getvariant(fieldlist, 0, 0, 0, &nitems, 0)) {
                        for (i=0; i<nitems; i++) {
                            int field_code = 0;
                            int sz = sizeof(int);
                            int n = 0;
                            gx_snprintf(path, sizeof(path), "L,X=%d", i);
                            if(gx_convertvariantbypatha(fieldlist, path, 0, GX_VARIANT_INT, &sz, &n, &field_code, sizeof(field_code))) {
                                /* Get the field text */
                                stext = sizeof(text);
                                if (pr_getfieldfromdoca(hpr,pdoc,field_code,text,&stext,&status,0)) {
                                    if (*text) {
                                        /* Converting the data for displaying on console */
#ifdef WIN32
                                        CharToOem(text,text);
#endif
                                        lib_write_line("[%5i] \"%s\" [%s]", field_code, text, ec[status/100]);
                                    }
                                } else {
                                    lib_displ_err();
                                }

                                if(field_code >= PR_DF_FORMATTED) continue;

                                /* Get the field image */
                                gx_snprintf(text, sizeof(text), "%i.jpg",field_code);
                                if(pr_getfieldimage(hpr,pdoc,field_code,0,&img) &&
                                    gx_imagefromvariant(gx_direct(GX_CALL_GROUP_GX_IMAGE), &gim, img) &&
                                    gx_saveimagea(gx_direct(GX_CALL_GROUP_GX_IMAGE), gim, text, GX_JPEG) &&
                                    gx_unrefimage(gx_direct(GX_CALL_GROUP_GX_IMAGE), gim) &&
                                    gx_disposevariant(&img)
                                    )
                                {
                                } else {
                                    lib_displ_err();
                                }
                            } else {
                                lib_displ_err();
                            }
                        }
                    }
                    if (!gx_disposevariant(&fieldlist)) lib_displ_err();
                }
                if (!gx_disposevariant(&pdoc)) lib_displ_err();
            }
        }

        lib_process_end();
        lib_wait_for_sec(3);
    }

    /* Closing the device */
    lib_function_start("Closing the device");
    if (pr_closedevice(hpr)) {
        lib_function_end();
    } else {
        lib_displ_err();
    }

    /* Closing the PR system */
    lib_function_start("Closing the PR system");
    if (gx_closehandle(&hpr)) {
        lib_function_end();
    } else {
        lib_displ_err();
    }

    return lib_print_stat();
}
 
esto carga además

Code: Select all

******************************************************************************
 * GXSD Loader file - V7.2.10
 *
 * 2004-2011 (c) ARH Inc. (http://www.arhungary.hu)
 ******************************************************************************/
/** \file
 * <b> GX system loader </b>
 *
 * The GX is the base system for the majority of the ARH Inc. products.
 * It is a collection of loadable modules and library functions and gives an easy to program
 * interface to the hardware devices.
 *
 * The applications reaches the GX system modules through a defined interface.
 * This interface is a common interface implemented in the \c libgxsd.so on Linux
 * and \c gxsd.dll on Windows systems. The module openings are made using the
 * general dynamic loader functions.
 *
 * Windows example:
 * \verbatim

    HMODULE module = (HMODULE)LoadLibraryA("gxsd7.dll");
    ...
    gx_call = GetProcAddress(module, "gx_call");
    ...
    FreeLibrary(module);

   \endverbatim
 *
 * Linux example:
 * \verbatim

    void *module = dlopen("/usr/lib32/libgxsd.so.7", RTLD_NOW | RTLD_GLOBAL);
    ...
    gx_call = dlsym(module, "gx_call");
    ...
    dlclose(module);

   \endverbatim
 *
 * The \a gxsdldr.c(pp) file is a loader that loads the gxsd.dll (libgxsd.so) file.
 *
 * Recomended usage:
 *
 *  -  Including it in the main source file. (\a \#include \a "gxsdldr.c(pp)")
 *  -  Copying this file in the source directory, compiling and linking with the other object files.
 */
/******************************************************************************/
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include "gxsd.h"
/******************************************************************************/
#ifdef ANDROID
extern void LOG(const char* msg,...);
#endif

#ifdef GX_NAMESPACES
    namespace gx {
#endif
#ifdef GX_DOTNET
    /* Unmanaged code for .net */
    #pragma unmanaged
#endif
/******************************************************************************/
/** Type of the gx_call function. @see gx_call */
typedef int GXAPI gxldr_callfunc_t(struct gxHANDLE handle, int function, void *params);
/******************************************************************************/
#ifdef LINUX
    #include <dlfcn.h>

    #ifdef __cplusplus
        extern "C" void gxsdldr_init(void) __attribute__((constructor));
        extern "C" void gxsdldr_destroy(void) __attribute__((destructor));
    #else
        void gxsdldr_init(void) __attribute__((constructor));
        void gxsdldr_destroy(void) __attribute__((destructor));
    #endif
#endif
/******************************************************************************/
#ifdef WIN32
    #include <windows.h>

    #ifdef __cplusplus
        extern "C" bool gxsdldr_init(gxldr_callfunc_t** gxsdldr_call);
    #else
        bool gxsdldr_init(gxldr_callfunc_t** gxsdldr_call);
    #endif
#endif
/******************************************************************************/
#ifdef __BORLANDC__
    #pragma warn -amp
#endif
/******************************************************************************/
/** Name of the library. */
extern const char *gxsdldr_modulename;

/** Error buffer. */
static char gxsdldr_errstr[256];

/** Main function pointer. */
#ifdef LINUX
    gxldr_callfunc_t *gxsdldr_call = 0;
#endif
/******************************************************************************
 * Common section
 ******************************************************************************/
/** Calls a module process with the specified parameters.
 *
 * The functions and parameters usable inside the modules can be found in the
 * documentation of the modules. The headers given with the modules contain
 * inline functions, that make the access to the functions of the module easier.
 *
 * @see gx_openmodule() gx_closehandle() gx_direct()
 *
 * @param handle    Handle of an opened module or special system handle ( see gx_direct() ).
 * @param function  Identifier of the function (GX_CALL_xxx).
 * @param params    Parameters to give for the function (GX_PARM_xxx).
 * @return Module defined, usually non-zero on success. */
int GXAPI
#if defined GX_ALLOW_GX_CALL_EXPORT
__declspec(dllexport)           /* to allow of building an import library */
#endif
gx_call(struct gxHANDLE handle, int function, void *params) {
#ifdef WIN32
static gxldr_callfunc_t *gxsdldr_call = 0;
    if (!gxsdldr_call)
    {
        /* Call the init function if the gx_call() is not found */
        gxsdldr_init(&gxsdldr_call);
    }
#else
    if(!gxsdldr_call) gxsdldr_init();
#endif
    if (gxsdldr_call) return gxsdldr_call(handle, function, params);    /* GXSD library is loaded */

    /* GXSD library not loaded */
    switch(function) {
        case GX_CALL_GETERROR:  /* gx_geterror() function - Unicode mode */
            {
                if(params){
                    struct GX_PARM_GETERROR *mp = (struct GX_PARM_GETERROR *)params;
                    mp->code = ENOENT;
                    if(mp->string && mp->maxlen>0) {
                        gx_snwprintf(mp->string, mp->maxlen, L"gxsdldr: open error in %hs (%hs)",
                            gxsdldr_modulename, gxsdldr_errstr);
                        mp->string[mp->maxlen-1] = 0;
                    }
                }
                return ENOENT;
            }
#ifndef ANDROID
        case GX_CALL_GETERRORA: /* gx_geterror() function - ASCII mode */
            {
                if(params){
                    struct GX_PARM_GETERRORA *mp = (struct GX_PARM_GETERRORA *)params;
                    mp->code = ENOENT;
                    if(mp->string && mp->maxlen>0) {
                        gx_snprintf(mp->string, mp->maxlen, "gxsdldr: open error in %s (%s)",
                            gxsdldr_modulename, gxsdldr_errstr);
                        mp->string[mp->maxlen-1] = 0;
                    }
                }
                return ENOENT;
            }
#endif
        default:
            /* Unknown function */
            break;
    }

    /* Unknown function */
    errno = EINVAL;
    return 0;
}

/******************************************************************************
 * Linux specific section
 ******************************************************************************/
#ifdef LINUX

/** Name of the library. */
#ifdef GX64
    const char *gxsdldr_modulename = "/usr/lib64/libgxsd.so.7";
#else
    #ifdef ANDROID
        const char *gxsdldr_modulename = "/vendor/lib/libgxsd.so";
    #else
        const char *gxsdldr_modulename = "/usr/lib32/libgxsd.so.7";
    #endif
#endif

/** Handle of the opened gxsd library. */
void *gxsdldr_handle = (void *)0;

/** Init function. */
void gxsdldr_init(void) {
    //LOG("gxsdldr_init\n");
    if(!gxsdldr_handle) {
#ifndef ANDROID
        //LOG("dlopen(libgxsd.so.7)\n");
        gxsdldr_handle = dlopen("libgxsd.so.7", RTLD_NOW | RTLD_GLOBAL);
        if(!gxsdldr_handle) {
            //LOG("dlopen(%s)\n",gxsdldr_modulename);
            gxsdldr_handle = dlopen(gxsdldr_modulename, RTLD_NOW | RTLD_GLOBAL);
        }
#else
        //LOG("dlopen(%s)\n",gxsdldr_modulename);
        gxsdldr_handle = dlopen(gxsdldr_modulename, RTLD_NOW | RTLD_GLOBAL);
#endif
    }
    //LOG("gxsdldr_handle: %p\n",gxsdldr_handle);

    if(!gxsdldr_handle) {
        gxsdldr_errstr[sizeof(gxsdldr_errstr)-1] = 0;
        strncpy(gxsdldr_errstr, dlerror(), sizeof(gxsdldr_errstr)-1);
        //LOG("Error 1: %s\n",gxsdldr_errstr);
        return;
    }

    //LOG("dlsym(gx_call)\n");
    gxsdldr_call = (gxldr_callfunc_t *)dlsym(gxsdldr_handle, "gx_call");
    //LOG("gxsdldr_call: %p\n",gxsdldr_call);
    if(!gxsdldr_call) {
        gxsdldr_call = 0;
        gxsdldr_errstr[sizeof(gxsdldr_errstr)-1] = 0;
        strncpy(gxsdldr_errstr, dlerror(), sizeof(gxsdldr_errstr)-1);
        dlclose(gxsdldr_handle);
        gxsdldr_handle = 0;
        //LOG("Error 2: %s\n",gxsdldr_errstr);
        return;
    }

    //LOG("dlsym(gxmoduleinfo)\n");
    int* vi = (int*) dlsym(gxsdldr_handle, "gxmoduleinfo");
    //LOG("gxmoduleinfo: %p\n",vi);

    if(vi && (vi[2]<0x07000000)) {
        gxsdldr_call = 0;
        snprintf(gxsdldr_errstr, sizeof(gxsdldr_errstr), "Old version of %s.", gxsdldr_modulename);
        gxsdldr_errstr[sizeof(gxsdldr_errstr)-1] = 0;
        dlclose(gxsdldr_handle);
        gxsdldr_handle = 0;
        //LOG("Error 3: %s\n",gxsdldr_errstr);
        return;
    }

    /* OK */
    struct GX_PARM_SENDCOMPVERSION compversion;
    compversion.version = GX_CURRENT_VERSION;
    struct gxHANDLE nullhandle = { 0 };
    //LOG("GX_CALL_SENDCOMPVERSION( %x)\n",GX_CURRENT_VERSION);
    gx_call(nullhandle, GX_CALL_SENDCOMPVERSION, &compversion);
    //LOG("gxsdldr_init end\n");
}

/** Clean up function. */
void gxsdldr_destroy(void) {
    gxsdldr_call = 0;   /* Restore the pointer */
    if(gxsdldr_handle) {
        dlclose(gxsdldr_handle);        /* Close the module */
        gxsdldr_handle = 0;
    }
}

#endif

/******************************************************************************
 * Windows specific section
 ******************************************************************************/
#ifdef WIN32

/** Name of the library. */
const char *gxsdldr_modulename = "gxsd7.dll";

/** Handle of the opened gxsd library. */
HMODULE gxsdldr_handle = (HMODULE)0;

/** Init function
 *
 * @param gxsdldr_call  Buffer for the main calling function pointer. */
bool gxsdldr_init(gxldr_callfunc_t** gxsdldr_call) {
    int *vi;
    struct GX_PARM_SENDCOMPVERSION compversion;
    struct gxHANDLE nullhandle = { 0 };

#ifdef _DEBUG
    char errbuf[1024];
#endif
    for(;;) {
        gxsdldr_handle = (HMODULE)LoadLibraryA(gxsdldr_modulename);
        if(gxsdldr_handle) break;
        gx_snprintf(gxsdldr_errstr, sizeof(gxsdldr_errstr), "Could not load: %hs", gxsdldr_modulename);
        gxsdldr_errstr[sizeof(gxsdldr_errstr)-1] = 0;
#ifdef _DEBUG
        gx_snprintf(errbuf, sizeof(errbuf),
            "GXSD Loader: Could not load: %hs", gxsdldr_modulename);
        errbuf[sizeof(errbuf)-1] = 0;
        if(MessageBoxA(0, errbuf, "GXSD Loader",
            MB_RETRYCANCEL | MB_TASKMODAL | MB_ICONERROR) == IDCANCEL) return 0;
#else
        return 0;
#endif
    }
    gxsdldr_errstr[0] = 0;

    (*gxsdldr_call) = (gxldr_callfunc_t *)GetProcAddress(gxsdldr_handle, "gx_call");
    if(!(*gxsdldr_call)) {
        (*gxsdldr_call) = 0;
        FreeLibrary(gxsdldr_handle);
        gxsdldr_handle = 0;
        gx_strncpy(gxsdldr_errstr,"No 'gx_call' entry found.",255);
#ifdef _DEBUG
        MessageBoxA(0, "GXSD Loader: No 'gx_call' entry found.",
            "GXSD Loader", MB_OK | MB_TASKMODAL | MB_ICONERROR);
#endif
        return 0;
    }

    vi=(int*)GetProcAddress(gxsdldr_handle,"gxmoduleinfo");

    if(vi && (vi[2]<0x07000000)) {
        (*gxsdldr_call) = 0;
        FreeLibrary(gxsdldr_handle);
        gxsdldr_handle = 0;
        gx_snprintf(gxsdldr_errstr, sizeof(gxsdldr_errstr), "Old version of %hs.", gxsdldr_modulename);
        gxsdldr_errstr[sizeof(gxsdldr_errstr)-1] = 0;
#ifdef _DEBUG
        gx_snprintf(errbuf, sizeof(errbuf),
            "GXSD Loader: Old version of %hs.", gxsdldr_modulename);
        errbuf[sizeof(errbuf)-1] = 0;
        MessageBoxA(0, errbuf, "GXSD Loader", MB_OK | MB_TASKMODAL | MB_ICONERROR);
#endif
        return 0;
    }

    gxsdldr_errstr[0] = 0;

    compversion.version = GX_CURRENT_VERSION;
    gx_call(nullhandle, GX_CALL_SENDCOMPVERSION, &compversion);
    return 1;
}

#endif
/******************************************************************************/
#ifdef __BORLANDC__
    #pragma warn .amp
#endif
/******************************************************************************/
#ifdef GX_NAMESPACES
    };
#endif
/******************************************************************************/
 
Agradecería una ayudita para poder prescindir del C y hacer las llamadas desde harbour Fivewin.
Muchas gracias y disculpad por el abuso
hmpaquito
Posts: 1200
Joined: Thu Oct 30, 2008 2:37 pm

Re: Lector de pasaportes y DNI

Post by hmpaquito »

Hola,


¿ Has pensado en hacer una oferta de trabajo por un importe cerrado ?

Hay muchos foros donde esto sucede y nadie se extraña por ello. En _ el contratador, después de pagar el trabajo, lo cede a la comunidad.
Es impresionante lo que estos sistemas ayudan al áuge de esos foros y de sus herramientas.

Me pareciera a mi, a riesgo de equivocarme, que los foros del todo gratis flaquean por falta de compromiso.

Con la mejor de las intenciones.

PD. Hace tiempo leí una idea que me pareció muy acertada. Mucho más que con sus filantrópicas obras, Bill Gates ha aportado más al mundo cuando ha cobrado por el trabajo realizado. Concretamente lo leí aquí http://homominimus.com/2015/12/14/no-ti ... -sociedad/
groiss
Posts: 206
Joined: Tue Sep 01, 2009 7:55 am
Location: Plasencia - ESPAÑA

Re: Lector de pasaportes y DNI

Post by groiss »

Hmpaquito, gracias
No quiero que nadie me haga el trabajo, simplemente busco la forma de entender, el procedimiento, para hacerlo desde fivewin:
Cargar la DLL
Cargar el módulo que me interesa
Hacer las distintas llamadas a las funciones del modulo
Gestionar los errores en cada paso

Un saludo
hmpaquito
Posts: 1200
Joined: Thu Oct 30, 2008 2:37 pm

Re: Lector de pasaportes y DNI

Post by hmpaquito »

groiss,

En general, creo yo, en todo lo relacionado con el desktop, en este foro se puede encontrar informacion. Por ejemplo, http://forums.fivetechsupport.com/viewt ... &hilit=sdk podria ser un buen ejemplo de de creacion de un wrapper a un sdk C.

Mi post iba por el hecho de que quizá un experto te lo solucione por unos pocos dólares, la tarea que para un neófito puede llevar muchas horas, y teniendo en cuenta que no es una tarea que vuelva a repetir, al menos en mucho tiempo, resulta que si saca cuentas y suma horas consumidas por la tarea, resulta que pierde dinero por no haberlo contratado... no sé si me explico.

Creo que eso nos pasa mucho a todos.

Un saludo
User avatar
José Vicente Beltrán
Posts: 279
Joined: Mon Oct 10, 2005 8:55 am
Location: Algeciras, España
Contact:

Re: Lector de pasaportes y DNI

Post by José Vicente Beltrán »

Groiss
No se si es lo que buscas, pero te adjunto un lector de pasaportes hecho completamente con FW.
Implementar el lector de DNI es igual de sencillo.

1. Ejecuta la aplicacion
2. Cursor en el campo de toma de datos
3. Pasar el pasaporte por el escaner
4. Y ya tienes los datos
5. Puedes imprimir la ficha para el viajero, en A-4, por delante, por delante y detrás con los datos de la policia (en este caso en arabe)
etc.
etc.

https://www.dropbox.com/s/qbvbu7s2y7a77 ... s.zip?dl=0

Si es de utilidad para ti, ponte en contacto conmigo y te envio los fuentes.
jvbpARROBAgigabit-tiendas.com
elvira
Posts: 462
Joined: Fri Jun 29, 2012 12:49 pm

Re: Lector de pasaportes y DNI

Post by elvira »

Hola,

¿Y quién puede realizar estos encargos de C para conectar APIS a Fivewin?.

Muy agradecida.
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: Lector de pasaportes y DNI

Post by Antonio Linares »

Jose Luis,

En base a estas notas del código que has publicado:
* Windows example:
* \verbatim

HMODULE module = (HMODULE)LoadLibraryA("gxsd7.dll");
...
gx_call = GetProcAddress(module, "gx_call");
...
FreeLibrary(module);

\endverbatim

gx_call(struct gxHANDLE handle, int function, void *params)
*
En FWH se haría asi:

Code: Select all

hDLL = LoadLibrary( "gxsd7.dll" )

MsgInfo( gx_call( hDLL, nFunction, 0 ) )

FreeLibrary( hDLL )

...

DLL FUNCTION gx_call( nHandle AS LONG, nFunction AS LONG, nPTR AS PTR ) AS LONG LIB hDLL
 
regards, saludos

Antonio Linares
www.fivetechsoft.com
groiss
Posts: 206
Joined: Tue Sep 01, 2009 7:55 am
Location: Plasencia - ESPAÑA

Re: Lector de pasaportes y DNI

Post by groiss »

José Vicente:
El escáner que me han traido al trabajo, es un _, y parece que tu programa no lo detecta, pues no hace nada, pero es interesante tu trabajo, ya me comentarás que debo hacer con el escáner o con que tipo de escaner

Antonio:
Eso es mas o menos lo que quiero saber manejar, se trataría de pasar eso que hay en C a fivewin/harbour, que creo que no es mucho.
Cargar la librería
Detectar el dispositivo
Hacer captura
Leer datos MRZ
Pasar _
Devolver los datos de _
Liberar la librería

Voy a ver como sigo con ello
Muchas gracias
User avatar
thefull
Posts: 720
Joined: Fri Oct 07, 2005 7:42 am
Location: Barcelona
Contact:

Re: Lector de pasaportes y DNI

Post by thefull »

Buenas

Mira si tiene soporte por OCX ( ActiveX ).
Si lo tiene, que seguro que si, te será mucho más sencillo.
Saludos
Rafa Carmona ( rafa.thefullARROBAgmail.com___quitalineas__)
groiss
Posts: 206
Joined: Tue Sep 01, 2009 7:55 am
Location: Plasencia - ESPAÑA

Re: Lector de pasaportes y DNI

Post by groiss »

Rafa:
Si tiene soporte OCX, pero ahí se me hace más engorroso, no lo he manejado nunca, y los ejemplos que vienen están todos para visual basic.
Un saludo
Post Reply