IR
irwinrodriguez.dev
Volver a documentación

Primeros pasos

De cero a tu primera tarea corriendo en otro proceso de Visual FoxPro, en cinco pasos. Válido para FoxCore.Runtime 3.4.2.

Antes de empezar

  • FoxCore.Runtime 3.4.2 instalado y registrado: el instalador FoxCore.Runtime-Setup-3.4.2.exe lo hace, y trae verify.cmd para comprobarlo. Ver Instalación.
  • Visual FoxPro 9 SP2 registrado como servidor de automatización, que es el proceso que ejecuta las tareas. Desde la 3.1.0 puede ser otro: VFP Advanced, o tu propio .exe.
  • Tu licencia, que es un JWT: se descarga del portal de cliente y se pasa por código. Ver Licencias.

1. Comprueba que el motor está ahí

Antes de nada, que el objeto COM se cree. Si esto falla, es la instalación y no tu código: ninguna de las líneas siguientes va a funcionar.

Crear el runtime y comprobar que responde
LOCAL loRt
loRt = CREATEOBJECT("FoxCore.Runtime")
? loRt.Ping()                             && FoxCore.Runtime 3.4.2

2. Activa la licencia: y comprueba el .T.

Activate() NUNCA lanza por una licencia inválida: devuelve .F. y sigue adelante. Si lo llamas y no miras lo que devuelve, el motor arranca igual y descubres el problema mucho más tarde, cuando la primera tarea nace Failed.

Activar la licencia y comprobar el .T.
LOCAL lcJwt
lcJwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...."   && pega aquí el JWT de tu portal de cliente

IF !loRt.Activate(lcJwt)
    MESSAGEBOX("La licencia de FoxCore no es valida.", 16, "FoxCore")
    RETURN
ENDIF
? loRt.IsLicensed                         && .T.

Si te saltas este paso, el ciclo de vida funciona (Attach, Ping, Shutdown), pero cada tarea nace Failed con este mensaje exacto:

El mensaje de una tarea sin licencia
FoxCore.Runtime: no hay una licencia valida para el producto 'FoxCore', asi que la tarea no se ejecuta. Activala por codigo al arrancar: loRt.Activate(<tu JWT>). Se consigue en https://irwinrodriguez.dev/products/foxcore

3. Engánchate, lanza y bombea

Éste es el ciclo completo, y es el mismo fragmento que abre la Referencia de API. Attach() engancha el runtime AL HILO desde el que lo llamas. RunScript() devuelve el id al instante: el guion ya está corriendo en otro proceso. Y Pump() es lo que atiende a los workers: sin él, se quedan esperando.

El ciclo completo: activar, enganchar, lanzar y bombear
LOCAL loRt, lcId

loRt = CREATEOBJECT("FoxCore.Runtime")
? loRt.Activate(lcJwt)                    && .T. -- tu licencia, como cadena
loRt.Attach(_VFP)                         && engancha el runtime A ESTE hilo
loRt.MaxWorkers = 8

lcId = loRt.RunScript("RETURN 6 * 42", "la primera")   && el guion corre en OTRO proceso VFP

DO WHILE !loRt.IsCompleted(lcId)
    loRt.Pump()                           && Pump() atiende a los workers; sin el, se quedan esperando
    DOEVENTS
ENDDO

? loRt.GetState(lcId)                     && Completed
? loRt.GetResult(lcId)                    && 252
? loRt.GetError(lcId)                     && ""

loRt.Shutdown()                           && SIEMPRE: es lo que mata a los workers
Pump() sólo desde el hilo del Attach: Llamar a Pump() desde otro hilo lanza un error controlado. Y dentro de un handler, un DOEVENTS reentra en Pump(): devuelve 0 sin hacer nada y sin lanzar, así que no atiende. En un formulario, el sitio del Pump() es un Timer.

4. Recoge el resultado

GetResult() devuelve lo que el guion pasó por RETURN. Mientras la tarea no haya terminado bien devuelve .NULL., así que se mira el estado primero.

Recoger el resultado o el error de la tarea
IF loRt.GetState(lcId) == "Completed"
    ? loRt.GetResult(lcId)                && lo que devuelve el guion
ELSE
    ? loRt.GetError(lcId)                 && vacío si no falló
ENDIF

5. Cierra siempre con Shutdown()

Shutdown() es lo que mata a los procesos worker. Es idempotente: llamarlo dos veces no hace daño. Si no lo llamas, quedan procesos vfp9.exe huérfanos ocupando memoria, y esa es la forma más común de romper esto.

Cerrar el runtime y sus workers
loRt.Shutdown()

Y a partir de aquí

  • Patrones: el lote grande, el progreso con barra y botón de cancelar, los handlers, la pizarra, y cómo se rompe esto.
  • Ejemplos: tres programas completos que se pueden copiar y ejecutar.
  • Referencia de API: los seis tipos y todos sus miembros, con qué devuelve cada uno cuando algo falla.
¿Vienes del motor clásico? Si tu código dice CREATEOBJECT("FoxCore.FoxCoreClass"), es el otro motor: sigue existiendo y sigue soportado, pero no es el que describe esta página. La tabla de equivalencias está en «Lo que ya no existe», al final de la Referencia.

Siguiente: Patrones avanzados ->