IR
irwinrodriguez.dev
Back to docs

Examples

Three complete, ready-to-use examples demonstrating the most common FoxCore patterns in real applications.

Example 1: Background CSV file import

Context: Import 1000 rows from a CSV while the UI stays responsive. The progress bar updates every 10 rows via a Timer.

Task procedure (in compiled MyTasks.prg)

* 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

Main form -- start the import

* 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

Form Timer (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

Example 2: Background report generation

Context: Generate a PDF/Excel report without freezing VFP. The OnComplete handler automatically opens the file when done.

Task procedure -- generate the report

* 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

Form code -- launch and set up 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

Example 3: Parallel sync of 3 remote APIs

Context: Synchronize data from 3 different REST APIs simultaneously. Use RunAll to launch them in parallel and collect results.

Task procedures -- one per 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

Main code -- RunAll and collect results

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")

Example 4: Multiple tasks in parallel (RunMultiple)

Runs an array of scripts simultaneously and waits for all to finish with 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

Example 5: WaitAny — process whichever finishes first

Useful when searching multiple sources and you only need the first valid result.

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

Example 6: Passing variables to a task (SetVariable)

Variables passed with SetVariable are available directly in the task execution context.

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

Example 7: Sequential tasks (RunMultipleSequential)

Runs an array of scripts in order. Each task can read the previous result 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

Example 8: Real-time monitoring with statistics

Monitoring loop that shows the status of all tasks while they run in parallel.

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

Back to reference: API Reference →