IR
irwinrodriguez.dev
Volver a documentacion

Ejemplos

Tres ejemplos completos y listos para usar que demuestran los patrones mas comunes de FoxCore en aplicaciones reales.

Ejemplo 1: Importacion de archivos CSV en segundo plano

Contexto: Importar 1000 filas de un CSV mientras la UI permanece responsiva. La barra de progreso se actualiza cada 10 filas a traves de un Timer.

Procedimiento de tarea (en MyTasks.prg compilado)

* MyTasks.prg
PROCEDURE Task_ImportCSV(loParams, loTask)
    LOCAL lcFile, lnHandle, lcLine, lnRow, lnTotal
    lcFile   = loParams.filePath
    lnTotal  = loParams.totalRows   && caller pre-counts rows
    lnHandle = FOPEN(lcFile)
    IF lnHandle < 0
        loTask.Error = "Cannot open file: " + lcFile
        RETURN
    ENDIF
    lnRow = 0
    * Skip header line
    lcLine = FGETS(lnHandle)
    DO WHILE !FEOF(lnHandle)
        lcLine = FGETS(lnHandle)
        IF EMPTY(lcLine)
            LOOP
        ENDIF
        * Parse CSV columns (simplified)
        LOCAL laFields[1]
        lnRow = lnRow + 1
        * -- insert record into target table --
        * INSERT INTO imports (col1, col2) VALUES (...)
        * Update progress every 10 rows
        IF MOD(lnRow, 10) == 0
            loTask.Progress = INT((lnRow / lnTotal) * 100)
        ENDIF
    ENDDO
    FCLOSE(lnHandle)
    loTask.Progress = 100
    loTask.Result   = TRANSFORM(lnRow) + " rows imported successfully."
ENDPROC

Formulario principal -- iniciar la importacion

* frmImport.Init or button Click handler
LOCAL loParams
THIS.oCore   = CREATEOBJECT("FoxCore.FoxCoreClass")
loParams     = CREATEOBJECT("Empty")
ADDPROPERTY(loParams, "filePath",  "C:dataimport.csv")
ADDPROPERTY(loParams, "totalRows", 1000)
THIS.oTask   = THIS.oCore.Run("Task_ImportCSV", loParams)
* Enable timer to poll progress
THIS.Timer1.Enabled  = .T.
THIS.cmdImport.Enabled = .F.   && disable button while running

Timer del formulario (interval: 500 ms)

PROCEDURE Timer1_Timer
    IF ISNULL(THIS.oTask) OR EMPTY(THIS.oTask.Status)
        RETURN
    ENDIF
    THIS.oProgressBar.Value = THIS.oTask.Progress
    THIS.lblStatus.Caption  = THIS.oTask.Status + " -- " + ;
                              TRANSFORM(THIS.oTask.Progress) + "%"
    DO CASE
    CASE THIS.oTask.Status == "Done"
        THIS.Timer1.Enabled    = .F.
        THIS.cmdImport.Enabled = .T.
        MESSAGEBOX(THIS.oTask.Result, 64, "Import complete")
    CASE THIS.oTask.Status == "Failed"
        THIS.Timer1.Enabled    = .F.
        THIS.cmdImport.Enabled = .T.
        MESSAGEBOX("Error: " + THIS.oTask.Error, 48, "Import failed")
    ENDCASE
ENDPROC

Ejemplo 2: Generacion de reporte en segundo plano

Contexto: Generar un reporte PDF/Excel sin congelar VFP. El handler OnComplete abre el archivo automaticamente cuando termina.

Procedimiento de tarea -- generar el reporte

* MyTasks.prg (continued)
PROCEDURE Task_GenerateReport(loParams, loTask)
    LOCAL lcOutputPath, lcReportFrx
    lcReportFrx  = loParams.reportPath   && .frx file path
    lcOutputPath = loParams.outputPath   && destination PDF path
    loTask.Progress = 10
    * Build the report datasource
    * (open cursors, set relations, etc.)
    loTask.Progress = 30
    * Run the VFP report to file
    * REPORT FORM (lcReportFrx) TO FILE (lcOutputPath) NOCONSOLE PDF
    loTask.Progress = 80
    * Verify output exists
    IF !FILE(lcOutputPath)
        loTask.Error = "Report file was not created: " + lcOutputPath
        RETURN
    ENDIF
    loTask.Progress = 100
    loTask.Result   = lcOutputPath   && pass path back to caller
ENDPROC

Codigo del formulario -- lanzar y configurar callback

* Button: Generate Report
LOCAL loCore, loParams, loTask
loCore  = CREATEOBJECT("FoxCore.FoxCoreClass")
loParams = CREATEOBJECT("Empty")
ADDPROPERTY(loParams, "reportPath",  "C:
eportssales.frx")
ADDPROPERTY(loParams, "outputPath",  "C:
eportssales_" + ;
            TRANSFORM(DATE(), "@YMD") + ".pdf")
loTask = loCore.Run("Task_GenerateReport", loParams)
* Set callback -- FoxCore calls this when done
loTask.OnComplete = "OnReportReady"
loTask.OnFailed   = "OnReportFailed"
* ... UI continues normally ...

PROCEDURE OnReportReady(loTask)
    * Open the generated file with the default PDF viewer
    ShellExecute(0, "open", loTask.Result, "", "", 1)
    MESSAGEBOX("Report ready: " + loTask.Result, 64, "Done")
ENDPROC

PROCEDURE OnReportFailed(loTask)
    MESSAGEBOX("Report generation failed:" + CHR(13) + ;
               loTask.Error, 48, "Error")
ENDPROC

Ejemplo 3: Sincronizacion paralela de 3 APIs remotas

Contexto: Sincronizar datos desde 3 APIs REST distintas simultaneamente. Usar RunAll para lanzarlas en paralelo y recolectar resultados.

Procedimientos de tarea -- uno por API

* MyTasks.prg (continued)
PROCEDURE Task_SyncSalesAPI(loParams, loTask)
    LOCAL loHttp
    loHttp = CREATEOBJECT("WinFx.HttpRequest")
    loHttp.Open("GET", loParams.endpoint)
    loHttp.WithBearer(loParams.apiKey)
    loHttp.Send("")
    loTask.Progress = 50
    IF loHttp.StatusCode == 200
        loTask.Result = loHttp.ResponseText
    ELSE
        loTask.Error  = "HTTP " + TRANSFORM(loHttp.StatusCode) + ;
                        ": " + loHttp.StatusText
    ENDIF
    loHttp = .NULL.
ENDPROC

PROCEDURE Task_SyncInventoryAPI(loParams, loTask)
    * Same pattern as Task_SyncSalesAPI but different endpoint
    LOCAL loHttp
    loHttp = CREATEOBJECT("WinFx.HttpRequest")
    loHttp.Open("GET", loParams.endpoint)
    loHttp.WithBearer(loParams.apiKey)
    loHttp.Send("")
    loTask.Progress = 50
    IF loHttp.StatusCode == 200
        loTask.Result = loHttp.ResponseText
    ELSE
        loTask.Error  = "HTTP " + TRANSFORM(loHttp.StatusCode)
    ENDIF
    loHttp = .NULL.
ENDPROC

PROCEDURE Task_SyncCRMAPI(loParams, loTask)
    * Same pattern as above for CRM endpoint
    LOCAL loHttp
    loHttp = CREATEOBJECT("WinFx.HttpRequest")
    loHttp.Open("GET", loParams.endpoint)
    loHttp.WithBearer(loParams.apiKey)
    loHttp.Send("")
    loTask.Progress = 50
    IF loHttp.StatusCode == 200
        loTask.Result = loHttp.ResponseText
    ELSE
        loTask.Error  = "HTTP " + TRANSFORM(loHttp.StatusCode)
    ENDIF
    loHttp = .NULL.
ENDPROC

Codigo principal -- RunAll y colectar resultados

LOCAL loCore, laNames[3], loResults
LOCAL loP1, loP2, loP3

loCore = CREATEOBJECT("FoxCore.FoxCoreClass")
loCore.MaxWorkers = 3   && allow all 3 to run truly in parallel

* Build parameter objects
loP1 = CREATEOBJECT("Empty")
ADDPROPERTY(loP1, "endpoint", "https://sales-api.example.com/sync")
ADDPROPERTY(loP1, "apiKey",   "sk_sales_abc123")

loP2 = CREATEOBJECT("Empty")
ADDPROPERTY(loP2, "endpoint", "https://inventory-api.example.com/sync")
ADDPROPERTY(loP2, "apiKey",   "sk_inv_xyz789")

loP3 = CREATEOBJECT("Empty")
ADDPROPERTY(loP3, "endpoint", "https://crm-api.example.com/sync")
ADDPROPERTY(loP3, "apiKey",   "sk_crm_def456")

* RunAll accepts procedure names only; params are supplied per-task
* via individual Run() calls collected into an array
LOCAL loT1, loT2, loT3
loT1 = loCore.Run("Task_SyncSalesAPI",     loP1)
loT2 = loCore.Run("Task_SyncInventoryAPI", loP2)
loT3 = loCore.Run("Task_SyncCRMAPI",       loP3)

* Wait for all three (30 second total timeout)
loCore.WaitFor(loT1, 30000)
loCore.WaitFor(loT2, 30000)
loCore.WaitFor(loT3, 30000)

* Collect and report results
LOCAL lcSummary
lcSummary = ""
IF loT1.Status == "Done"
    * Process loT1.Result (JSON from sales API)
    lcSummary = lcSummary + "Sales: OK" + CHR(13)
ELSE
    lcSummary = lcSummary + "Sales: FAILED (" + loT1.Error + ")" + CHR(13)
ENDIF
IF loT2.Status == "Done"
    lcSummary = lcSummary + "Inventory: OK" + CHR(13)
ELSE
    lcSummary = lcSummary + "Inventory: FAILED (" + loT2.Error + ")" + CHR(13)
ENDIF
IF loT3.Status == "Done"
    lcSummary = lcSummary + "CRM: OK"
ELSE
    lcSummary = lcSummary + "CRM: FAILED (" + loT3.Error + ")"
ENDIF
MESSAGEBOX(lcSummary, 64, "Sync complete")

Ejemplo 4: Multiples tareas en paralelo (RunMultiple)

Ejecuta un array de scripts simultaneamente y espera a que todos terminen con WaitAll.

DO "ruta\FoxCore-VFP9-v1.0.app"

LOCAL ARRAY laScripts[3]
TEXT TO laScripts[1] NOSHOW
    LOCAL lnSum, i
    lnSum = 0
    FOR i = 1 TO 1000000
        lnSum = lnSum + i
    ENDFOR
    RETURN "Suma: " + TRANSFORM(lnSum)
ENDTEXT

TEXT TO laScripts[2] NOSHOW
    WAIT WINDOW "Procesando archivo..." TIMEOUT 3
    RETURN "Archivo procesado"
ENDTEXT

TEXT TO laScripts[3] NOSHOW
    WAIT WINDOW "Conectando red..." TIMEOUT 2
    RETURN "Conexion OK"
ENDTEXT

PUBLIC loHandler, loTasks
loHandler = CREATEOBJECT("TaskHandler")
loTasks   = _screen.FoxCore.RunMultiple(@laScripts)
_screen.FoxCore.AddEventListener("OnTaskComplete", loHandler, "OnComplete")
_screen.FoxCore.AddEventListener("OnTaskFailed",   loHandler, "OnFailed")

IF !_screen.FoxCore.WaitAll(loTasks, 60)
    MESSAGEBOX("Timeout - no todas completadas", 48)
ELSE
    FOR EACH loTask IN loTasks
        ? loTask.GetStatus(), loTask.GetResult()
    ENDFOR
ENDIF

DEFINE CLASS TaskHandler AS CUSTOM
    PROCEDURE OnComplete(toTask, tvResult)
        ? "OK:", TRANSFORM(tvResult)
    ENDPROC
    PROCEDURE OnFailed(toTask, tcError)
        ? "ERROR:", tcError
    ENDPROC
ENDDEFINE

Ejemplo 5: WaitAny — procesar el primero en completarse

Util cuando buscas datos en multiples fuentes y solo necesitas el primer resultado valido.

DO "ruta\FoxCore-VFP9-v1.0.app"

LOCAL ARRAY laScripts[3]
TEXT TO laScripts[1] NOSHOW
    WAIT WINDOW "Fuente 1 (lenta)..." TIMEOUT 4
    RETURN .NULL.  && sin resultado
ENDTEXT
TEXT TO laScripts[2] NOSHOW
    WAIT WINDOW "Fuente 2 (rapida)..." TIMEOUT 2
    RETURN "Resultado encontrado en fuente 2"
ENDTEXT
TEXT TO laScripts[3] NOSHOW
    WAIT WINDOW "Fuente 3 (media)..." TIMEOUT 3
    RETURN "Resultado encontrado en fuente 3"
ENDTEXT

PUBLIC loTasks
loTasks = _screen.FoxCore.RunMultiple(@laScripts)

LOCAL lnIdx, lvResult
lvResult = .NULL.

DO WHILE ISNULL(lvResult)
    lnIdx = _screen.FoxCore.WaitAny(@loTasks, 10)
    IF lnIdx > 0
        lvResult = loTasks[lnIdx].GetResult()
        IF !ISNULL(lvResult)
            ? "Primera respuesta valida (fuente " + TRANSFORM(lnIdx) + "):", TRANSFORM(lvResult)
            * Cancelar las restantes
            LOCAL i
            FOR i = 1 TO ALEN(loTasks)
                IF i <> lnIdx AND loTasks[i].GetStatus() = "Running"
                    loTasks[i].Cancel("Ya tenemos resultado")
                ENDIF
            ENDFOR
        ENDIF
    ELSE
        ? "Timeout - ninguna fuente respondio"
        EXIT
    ENDIF
ENDDO

Ejemplo 6: Pasar variables a una tarea (SetVariable)

Las variables pasadas con SetVariable estan disponibles directamente en el contexto de ejecucion de la tarea.

DO "ruta\FoxCore-VFP9-v1.0.app"

LOCAL lcRuta, lnFiles, lcPrefix
lcRuta   = "C:\datos\"
lnFiles  = 5
lcPrefix = "reporte_"

TEXT TO lcScript NOSHOW
    * lcRuta, lnFiles, lcPrefix estan disponibles aqui
    LOCAL i, lcFile
    FOR i = 1 TO lnFiles
        lcFile = lcRuta + lcPrefix + TRANSFORM(i) + ".txt"
        STRTOFILE("Contenido " + TRANSFORM(i), lcFile)
        Task.Progress("Creando archivo " + TRANSFORM(i), i/lnFiles*100)
    ENDFOR
    RETURN "Se crearon " + TRANSFORM(lnFiles) + " archivos en " + lcRuta
ENDTEXT

LOCAL loTask
loTask = _screen.FoxCore.NewTask(lcScript)
loTask.SetVariable("lcRuta",   lcRuta)
loTask.SetVariable("lnFiles",  lnFiles)
loTask.SetVariable("lcPrefix", lcPrefix)
loTask.Run()

IF loTask.Wait(30)
    ? "Resultado:", loTask.GetResult()
ENDIF

Ejemplo 7: Tareas secuenciales (RunMultipleSequential)

Ejecuta un array de scripts en orden, donde cada tarea puede leer el resultado de la anterior via gvPreviousTaskResult.

DO "ruta\FoxCore-VFP9-v1.0.app"

LOCAL ARRAY laScripts[3]
TEXT TO laScripts[1] NOSHOW
    * Paso 1: obtener datos
    RETURN "datos_obtenidos"
ENDTEXT

TEXT TO laScripts[2] NOSHOW
    * Paso 2: procesar (gvPreviousTaskResult = "datos_obtenidos")
    RETURN "procesado_desde_" + TRANSFORM(gvPreviousTaskResult)
ENDTEXT

TEXT TO laScripts[3] NOSHOW
    * Paso 3: exportar
    RETURN "exportado: " + TRANSFORM(gvPreviousTaskResult)
ENDTEXT

PUBLIC loResults
loResults = _screen.FoxCore.RunMultipleSequential(@laScripts, .F.)  && .F. = detener ante error

_screen.FoxCore.WaitAll(loResults, 120)

FOR EACH loTask IN loResults
    ? loTask.GetStatus(), loTask.GetResult()
ENDFOR

Ejemplo 8: Monitoreo con estadisticas en tiempo real

Bucle de monitoreo que muestra el estado de todas las tareas mientras se ejecutan en paralelo.

DO "ruta\FoxCore-VFP9-v1.0.app"

* (preparar laScripts y loTasks como en el Ejemplo 4)
LOCAL loStats, loSummary, lnStart
lnStart = SECONDS()

DO WHILE !_screen.FoxCore.WaitAll(loTasks, 0.5)
    CLEAR
    loStats   = _screen.FoxCore.GetSystemStats()
    loSummary = _screen.FoxCore.GetTasksSummary()
    ? "Tiempo transcurrido: " + TRANSFORM(INT(SECONDS()-lnStart)) + "s"
    ? "Procesadores logicos: " + TRANSFORM(loStats.LogicalProcessors)
    ? "Tareas activas: "       + TRANSFORM(loStats.ActiveTasks) + "/" + TRANSFORM(loStats.MaxTasks)
    ? "Progreso general: "     + TRANSFORM(_screen.FoxCore.GetProgress()) + "%"
    ? "Completadas/Fallidas: " + TRANSFORM(loSummary.completed) + "/" + TRANSFORM(loSummary.failed)
ENDDO

loSummary = _screen.FoxCore.GetTasksSummary()
? "=== FINAL ==="
? "Total:", loSummary.total, "  OK:", loSummary.completed, "  Error:", loSummary.failed

Volver a la referencia: Referencia API →