IR
irwinrodriguez.dev
Zurück zur Dokumentation

API-Referenz

Vollstandige Referenz von FoxCore.Runtime 3.4.2: die sechs COM-Typen, ihre Mitglieder und was jedes liefert, wenn etwas schiefgeht.

Gultig fur FoxCore.Runtime 3.4.2 (2026-09-15). Der Vertrag ist auf sechs Typen eingefroren; Mitglieder wachsen immer am Ende, also andert nichts auf dieser Seite in einer spateren Version Namen oder Signatur.

Die Engine starten

Das Minimum, das funktioniert: erzeugen, Lizenz aktivieren, an den Thread binden, eine Aufgabe starten, während sie läuft pumpen und beenden.

Die Engine starten: von CREATEOBJECT() bis Shutdown()
LOCAL loRt, lcId

loRt = CREATEOBJECT("FoxCore.Runtime")
? loRt.Activate(lcJwt)                    && .T. -- Ihre Lizenz, als Zeichenkette
loRt.Attach(_VFP)                         && bindet die Runtime AN DIESEN Thread
loRt.MaxWorkers = 8

lcId = loRt.RunScript("RETURN 6 * 42", "la primera")   && das Skript läuft in einem ANDEREN VFP-Prozess

DO WHILE !loRt.IsCompleted(lcId)
    loRt.Pump()                           && Pump() bedient die Worker; ohne es warten sie nur
    DOEVENTS
ENDDO

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

loRt.Shutdown()                           && IMMER: es beendet die Worker

Der JWT wird per Code ubergeben: es gibt keine Datei zu kopieren. Woher Sie ihn bekommen und was ohne ihn passiert, steht auf der Seite Lizenzierung.

Die sechs Typen

Drei Klassen und ihre drei Schnittstellen. Einen siebten Typ gibt es nicht, und es wird ihn nicht geben: zweimal sah es so aus, als brauchte es einen - das Ergebnis von TryCall, dann GetStats - und beide Male war die Antwort eine JSON-Zeichenkette.

KlasseSchnittstelleProgIdWas es ist
FoxRuntime IFoxRuntime FoxCore.Runtime Das Objekt, das der Host erzeugt. Es ist die Engine: Lizenz, Optionen, Aufgaben, Pumpen, Ereignisse und Handler.
FoxTaskHandle IFoxTask — Das Handle, das NewTask() liefert. Zucker: es hält keinen Zustand, jede Eigenschaft fragt die Registry.
WorkerBridge IFoxWorker — Die Variable runtime INNERHALB des Skripts. Mehr sieht der Worker vom Hauptprozess nicht.

FoxCore.Runtime

Lebenszyklus

MitgliedLiefertHinweise
Activate(cLicenseKey)LPrueft den JWT. Wirft bei ungultiger Lizenz NIE: liefert .F., und blockiert werden die Aufgaben, nicht der Lebenszyklus.
Attach(oHost, nVersion, cRuntimeMode)—Bindet die Runtime AN DEN THREAD, aus dem sie aufgerufen wird. Normalerweise loRt.Attach(_VFP). Die letzten beiden sind optional.
Shutdown()—Idempotent. ES BEENDET DIE WORKER. Immer aufrufen.
Ping()C"FoxCore.Runtime 3.4.2". Funktioniert in jedem Zustand, auch nach Shutdown().
VersionCNur lesbar.
StateCCreated | Activated | Attached | ShuttingDown | ShutDown. Eine ZEICHENKETTE, kein Enum: kein Zahlenwert quert COM.
IsRunningL.T. zwischen Attach() und Shutdown().
IsLicensedL.T., wenn der JWT gültig ist. Seit 3.4.0 gibt es KEINE Ausnahme nach Modus: auch außerhalb der IDE erforderlich.

Optionen

Alle lesbar und schreibbar. Nach dem Erzeugen des Objekts und vor dem Start von Aufgaben setzen.

EigenschaftStandardWas sie steuert
MaxWorkersmin(nucleos, 8)Gleichzeitige Worker-Prozesse. Bereich 1-64. Faustregel: physische Kerne.
DefaultTimeoutSeconds30Frist pro Aufgabe. Bereich 1-86.400. Nach Ablauf endet die Aufgabe als TimedOut und der Worker stirbt.
WorkerProgId"VisualFoxpro.Application.9"Welcher Prozess als Worker dient: VFP 9, VFP Advanced oder Ihre eigene registrierte EXE. Geprueft wird das FORMAT, nicht die Existenz: ob er taugt, sagt ProbeWorker().
KeepCompletedTasks200Wie viele BEENDETE Aufgaben die Registry behalt, bevor die altesten verworfen werden. Wichtig bei grossen Stapeln.
MaxTasksPerWorker1Wie viele Aufgaben ein Worker bedient, bevor er recycelt wird. 1 = ein Prozess pro Aufgabe, volle Isolation. 0 = ohne Limit.
WorkerInitScript""Skript, das EINMAL PRO WORKER vor seiner ersten Aufgabe läuft. Hier kommt die Umgebung hin.
WorkerResetScript""Skript, das ZWISCHEN AUFGABEN eines wiederverwendeten Workers läuft. Hier wird aufgeraumt.
WorkerInitFailurePolicy"abort"Was bei einem Fehler im Startskript passiert: "abort" bricht ab, "tolerate" lasst dessen eigenes ON ERROR ubernehmen und weitermachen.
PumpMaxItems8Wie viel jedes Pump() abarbeitet.
PumpMaxMilliseconds20Zeitbudget jedes Pump().
RequestTimeoutSeconds15Wie lange ein in Call() blockierter Worker auf ein Timeout wartet. Das verhindert, dass ein Host, der nicht pumpt, einen Worker haengen lässt.
SecurityMode"Safe""Safe" ist der einzige echte Modus.
AuditLevel"basic"off | basic | full.

Aufgaben

MitgliedLiefertHinweise
RunScript(cScript, cTaskName)CErzeugt, reiht ein und liefert die Task-ID. DER NORMALE WEG.
NewTask(cScript, cTaskName)FoxTaskHandleErzeugt OHNE Einreihen, um sie vorher zu konfigurieren (etwa mit SetTaskTimeout).
Start(cTaskId)LReiht eine erzeugte Aufgabe ein. .F., wenn sie nicht existiert oder schon gestartet wurde.
GetState(cTaskId)CCreated | Queued | Running | Completed | Failed | Cancelled | TimedOut, und NotFound für eine unbekannte oder bereits verworfene ID.
GetResult(cTaskId)valorDas RETURN des Skripts. .NULL., solange es nicht erfolgreich beendet ist; leere Zeichenkette bei unbekannter ID.
GetError(cTaskId)CLeere Zeichenkette, wenn kein Fehler; "Task not found." bei unbekannter ID.
IsCompleted(cTaskId)L.T. in jedem Endzustand UND AUCH bei einer nicht existierenden ID - mit Absicht: sonst wurde die kanonische Schleife ewig drehen, sobald die Bereinigung die Aufgabe entfernt.
GetProgress(cTaskId)N0-100. Funktioniert auch, wenn niemand pumpt.
GetProgressMessage(cTaskId)CDie letzte Meldung, sonst leere Zeichenkette.
PollCompleted()CDie seit dem LETZTEN AUFRUF beendeten IDs, durch ";" getrennt. Ein COM-Aufruf pro Runde statt N. LESEN LEERT ES.
SetTaskTimeout(cTaskId, nSegundos)LFrist für EINE Aufgabe. Nur vor dem Start: NewTask + dies + Start. .F., wenn sie schon läuft oder nicht existiert.
Forget(cTaskId)LVergisst eine BEENDETE Aufgabe und gibt ihr Ergebnis frei. .F., wenn sie nicht existiert oder noch läuft.

Abbruch

MitgliedLiefertHinweise
Cancel(cTaskId)LKOOPERATIV: setzt das Flag, das das Skript mit runtime.IsCancelled() liest, und entsperrt sofort jeden laufenden Call. .F., wenn es nichts zu stoppen gibt.
CancelAll()NWie viele abgebrochen wurden.
Kill(cTaskId)LHART: beendet den Prozess per PID. Fur ein Skript, das das Flag nie prueft, der einzige Weg. Endet als Cancelled mit "Killed by host."

Pumpen

MitgliedLiefertHinweise
Pump(nMaxItems, nMaxMs)NBedient zuerst die synchronen Anfragen - hinter jeder steht ein BLOCKIERTER Worker - und danach die Benachrichtigungen. Beide Parameter 0 oder nicht angegeben = die Optionen verwenden.
Drei Regeln zu Pump(): es darf nur aus dem Attach-Thread aufgerufen werden (aus einem anderen gibt es einen kontrollierten Fehler); es ist nicht reentrant - wird es aufgerufen, während schon gepumpt wird, liefert es 0, tut nichts und wirft nicht; und nach Shutdown() liefert es 0, ohne Fehler.

Ereignisse

MitgliedLiefertHinweise
SetEventSink(oSink)LDie Runtime meldet AUS Pump() HERAUS, in Ihrem Thread. Liefert .F. OHNE ZU WERFEN, wenn dem Objekt die Pflichtmethoden fehlen.
ClearEventSink()—Im Destroy des Formulars freigeben: solange die Runtime es hält, bleibt das Formular am Leben.

Der Sink muss OnProgress(tcTaskId, tnPercent, tcMessage) und OnLog(tcTaskId, tcLevel, tcMessage) haben, beide Pflicht, und kann OnTaskCompleted(tcTaskId, tcState) und OnTaskFailed(tcTaskId, tcError) haben, die erkannt werden, wenn sie da sind. Der Sink ist zusätzlich: GetProgress() und GetProgressMessage() funktionieren auch ohne ihn.

Handler - was ein Worker vom Host anfordern kann

MitgliedLiefertHinweise
RegisterHandler(cName, oTarget, cMethodName)LcMethodName ist standardmassig "Invoke". Liefert .F. OHNE ZU WERFEN, wenn der Name leer ist, Leerzeichen enthalt, 64 Zeichen ubersteigt, schon registriert ist, einer der eingebauten ist ODER WENN DAS OBJEKT DIESE METHODE NICHT BIETET - diese letzte Prufung lasst den Fehler im Init des Formulars auftauchen und nicht sechs Stunden spater im Worker.
UnregisterHandler(cName)L.F., wenn er nicht registriert war.
GetHandlerNames()CDie Namen, durch ";" getrennt, alphabetisch. Das ist die VOLLSTANDIGE Flache dessen, was ein Worker anfordern kann. Drei eingebaute sind immer da: echo, upper und add.

Gemeinsame Tafel

Löst "der Worker braucht die Konfiguration des Hosts" ohne Roundtrip und ohne Pump.

MitgliedLiefertHinweise
Publish(cName, uValue)—Veröffentlicht einen Wert, den die Worker mit runtime.GetValue() OHNE Warteschlangen- und Pump-Kosten lesen.
GetValue(cName)valor.NULL., wenn er nicht existiert.

Sonstiges

MitgliedLiefertHinweise
GetStats()CDie Momentaufnahme der Engine als flache JSON-ZEICHENKETTE. Sie liefert eine Zeichenkette und kein Objekt, aus zwei Grunden: ein COM-Objekt kostet einen Roundtrip PRO EIGENSCHAFT, und ein neuer Typ wurde den Vertrag der sechs Typen brechen.
ProbeWorker(cProgId)CTaugt diese ProgId als Worker? Die Antwort kommt vom AUSFÜHREN. Ohne Argument wird die aktuelle WorkerProgId geprüft.
GetAuditPath()CWO das Journal LIEGEN WURDE. Es schreibt nichts.
SetCorrelation(cId, cName, cValue)LEin GESCHLOSSENES Vokabular aus sieben Namen. .F. ohne zu schreiben für alles andere.
GetCorrelation(cId, cName)CLeere Zeichenkette, wenn nicht gesetzt.

Was GetStats() liefert

Eine flache JSON-Zeichenkette, mit jsonfox in einem einzigen Aufruf geparst. Es gibt zwei Familien von Zahlern, und sie zu verwechseln ist teuer:

  • createdEver, finishedEver, completedEver, failedEver, cancelledEver, timedOutEver - sie zahlen, was seit dem Start der Runtime PASSIERT ist, und gehen NIE zurück. Mit ihnen zeichnet man den Fortschritt.
  • total, created, completed, failed, cancelled, timedOut - sie sind die MOMENTAUFNAHME der Registry, und sie gehen zurück: Forget() und die Bereinigung ziehen ab. Mit ihnen sieht man, was gerade lebt.
GetStats() mit einem laufenden Stapel von 30 Aufgaben
{
  "state": "Attached",
  "workerProgId": "VisualFoxpro.Application.9",
  "maxWorkers": 8,
  "queued": 22,
  "running": 8,
  "peakRunning": 8,
  "liveWorkers": 8,
  "createdEver": 30,
  "finishedEver": 0,
  "completedEver": 0,
  "failedEver": 0,
  "cancelledEver": 0,
  "timedOutEver": 0,
  "total": 30,
  "created": 0,
  "completed": 0,
  "failed": 0,
  "cancelled": 0,
  "timedOut": 0,
  "purged": 0,
  "keepCompletedTasks": 200,
  "completedPending": 0,
  "completedDropped": 0,
  "pendingRequests": 0,
  "expiredRequests": 0,
  "pendingNotifications": 3,
  "droppedTelemetry": 0,
  "handlers": 2,
  "requestsHandled": 47,
  "handlerErrors": 0
}
Die Momentaufnahme ist nicht atomar: jeder Zahler wird unter eigenem Lock gelesen. Sie taugt für einen Fortschrittsbalken, nicht für eine Summenprufung. Die Wahrheit über eine einzelne Aufgabe ist immer GetState(id).

FoxTaskHandle

Von NewTask() geliefert. Es hält keinen Zustand: jede Eigenschaft delegiert an die Registry der Engine. Es ist Zucker - alles, was es tut, geht auch mit der taskId und den Runtime-Methoden.

MitgliedTypHinweise
IdCDie taskId. DIE KANONISCHE WAHRHEIT ist diese Zeichenkette: sie quert COM ohne Lebensdauer-Kosten und lässt sich in ein Ticket einfügen.
NameCDer bei der Erzeugung vergebene Name.
StateCDasselbe wie GetState(Id).
ResultvalorDasselbe wie GetResult(Id).
ErrorCDasselbe wie GetError(Id).
IsCompletedLDasselbe wie IsCompleted(Id).
OperationIdCExistiert und ist IMMER eine leere Zeichenkette: Operationen sind nicht implementiert.
Start()LReiht die Aufgabe ein. Dasselbe wie Start(Id).

WorkerBridge - die Variable runtime im Skript

Mehr sieht der Worker vom Hauptprozess nicht, und seine Flache ist auf diese Aufgabe begrenzt. Entscheidend ist die Spalte "Blockiert?": nur Call und TryCallJson warten darauf, dass der Host pumpt, denn nur sie fuhren VFP-Code im Hauptprozess aus.

MitgliedBlockiert?Hinweise
TaskId / TaskNamenoDie ID und der Name DIESER Aufgabe.
ElapsedSecondsnoSekunden seit dem Start der Aufgabe.
Ping()no"pong".
Progress(nPercent, cMessage)noFire-and-forget. Braucht kein Pump und schlägt nicht fehl. Der Prozentwert wird auf 0-100 begrenzt.
Log(cLevel, cMessage)no"info" | "warn" | "error". Fire-and-forget.
IsCancelled()noEine LOKALE Abfrage, sie berührt den Host nicht. Gedacht für jeden Schleifendurchlauf.
GetValue(cName) / SetValue(cName, uValue)noGemeinsame Tafel, lokal, ohne Pump.
Call(cName, arg1..arg8)SIRuft einen Host-Handler auf. Synchron: der Worker wartet, bis der Host pumpt. WIRFT einen OLE-Fehler, wenn der Handler scheitert.
TryCallJson(cName, arg1..arg8)SIWie Call, aber WIRFT NIE. Liefert JSON: {"ok":true,"value":"42","error":"","errorCode":""}. Der Wert reist IMMER als Zeichenkette.

Muster

Die zwei Schleifen, die man kennen muss:

  1. Normaler Stapel: mit RunScript() starten, die IDs behalten und ein DO WHILE drehen, das Pump() und DOEVENTS aufruft, bis IsCompleted() für alle ja sagt.
  2. Großer Stapel (Hunderte oder Tausende): Aufgabe für Aufgabe zu fragen sind N COM-Aufrufe pro Runde. KeepCompletedTasks erhöhen, PollCompleted() einmal pro Runde aufrufen, das Ergebnis der gelieferten IDs lesen und für jede Forget() aufrufen. Der Fortschritt kommt aus finishedEver, nicht aus completed: mit Forget() in jeder Runde bleibt die Momentaufnahme bei null, und das ist richtig.

Beide, mit vollstandigem Code und den jeweiligen Fallen, stehen auf der Seite Muster.

Was es nicht mehr gibt

Wenn Sie von einer Suchmaschine kommen oder von Code, der für die klassische Engine (WinFx.FoxCore) geschrieben wurde: das hat sich geändert. Die klassische Engine existiert weiter und wird weiter unterstützt; sie ist nicht die, die diese Seite beschreibt.

Klassische EngineIn FoxCore.Runtime 3.4.2
CREATEOBJECT("WinFx.FoxCore") / _screen.FoxCoreCREATEOBJECT("FoxCore.Runtime") - ein anderes COM-Objekt, mit anderer ProgId und anderer GUID. Beide konnen gleichzeitig registriert sein.
Run(cProc, oParams)RunScript(cSkript, cName). Es wird nicht mehr der NAME einer Prozedur übergeben, die im Worker existieren muss: übergeben wird das SKRIPT als Text, und der Worker führt es mit EXECSCRIPT() aus.
RunMultiple(@laTareas)Kein Aquivalent, mit Absicht: man ruft RunScript() in einer FOR-Schleife auf und behalt die IDs. Eine Methode, die ein Array per Referenz nimmt, quert COM nicht zuverlassig, und sie lieferte ein Container-Objekt: ein Typ mehr, und der Vertrag sind sechs.
WaitAll() / WaitAny()Kein Aquivalent, und das ist der eigentliche Unterschied: die Schleife schreibt der HOST, mit Pump() und DOEVENTS. Ein blockierendes WaitFor in VFP ist genau die eingefrorene Oberfläche, die dieses Produkt verhindern soll.
GetTasksSummary() / GetSystemStats()GetStats() für die Zahlen (queued, running, liveWorkers) und PollCompleted(), um zu erfahren, wer gerade fertig wurde. Ein Array von Task-Objekten über COM kostet einen Roundtrip pro Eigenschaft und Aufgabe.
CancelTask(loTask)Cancel(cTaskId). Identifiziert über die ID, nicht über das Objekt.
Activate(cClave)Activate(cJwt), gleicher Name, anderer Schlüssel: seit 3.4.0 gibt es keine Datei, die Lizenz ist ein JWT, das per Code übergeben wird.
foxcore.licKein Aquivalent: seit 3.4.0 gibt es keine Lizenzdatei. Siehe die Seite Lizenzierung.
PROCEDURE MiTarea(loParams, loTask)Im Skript gibt es keine Parameter: es gibt eine Variable namens runtime (WorkerBridge). loTask.Progress = 50 wird zu runtime.Progress(50, "...") und loTask.Result = x wird zu RETURN x.

Weiter: Lizenzierung ->