Der OnUserFunction-Rückruf ermöglicht es Anwendungscode, benutzerdefinierte
oder anderweitig nicht unterstützte Tabellenblattfunktionen während
Calculate auszuwerten. Weisen Sie ihn TXLSWorkbook oder
TXLSXWorkbook vor dem Aufrufen von Calculate zu
Verwenden Sie OnUserFunctionEx, wenn der Rückruf den aktuellen Formelkontext benötigt. Der Kontext meldet den 1-basierten Blattindex sowie die 1-basierte Zeile und Spalte der Formelzelle; Aufrufe von Calculate auf Arbeitsmappenebene, die keine Zelle auswerten, melden Zeile und Spalte als 0
Syntax
type
TXLSUserArgKind = (akuValue, akuRangeRef, akuArray);
TXLSUserFunctionContext = record
SheetIndex: Integer;
Row: Integer;
Col: Integer;
ArgCount: Integer;
ArgKinds: array of TXLSUserArgKind;
end;
TXLSUserFunctionEvent = procedure(
Sender: TObject;
const FunctionName: WideString;
const Args: Variant;
var Value: Variant;
var Handled: Boolean) of object;
TXLSUserFunctionExEvent = procedure(
Sender: TObject;
const FunctionName: WideString;
const Args: Variant;
const Context: TXLSUserFunctionContext;
var Value: Variant;
var Handled: Boolean) of object;
property OnUserFunction: TXLSUserFunctionEvent;
property OnUserFunctionEx: TXLSUserFunctionExEvent;
property AllowUnsafeFormulaCallbacks: Boolean;
Argumente
| FunctionName |
Der Funktionsname aus dem Formeltext |
| Args |
Ein nullbasiertes Variant-Array mit den ausgewerteten Argumentwerten. Für Funktionen ohne Argumente ist dieser Wert Null |
| Context |
Bei OnUserFunctionEx meldet er SheetIndex, Row und Col plus den Argument-Deskriptor: ArgCount entspricht der Länge des Args-Arrays (0 bei Aufrufen ohne Argumente), und ArgKinds klassifiziert jedes Argument als akuValue (Literalwert), akuRangeRef (Zell- oder Bereichsreferenz) oder akuArray (Array-Konstante). Blatt-, Zeilen- und Spaltenwerte sind bei Zellformeln 1-basiert; Zeile und Spalte sind 0, wenn keine Zelle ausgewertet wird. Die Kinds werden erfasst, bevor die Argumente ausgewertet werden — ein Handler im Stil von SUM oder MAP erkennt also, dass der Aufrufer eine Referenz geschrieben hat, obwohl der ausgewertete Args-Eintrag nur den Wert trägt |
| Value |
Hier setzen Sie das Funktionsergebnis |
| Handled |
Auf True setzen, wenn der Callback ein Ergebnis liefert. Auf False lassen, um das übliche Verhalten für nicht unterstützte Funktionen beizubehalten |
Sicherheitsrichtlinie für Callbacks
AllowUnsafeFormulaCallbacks steht bei Classic-XLS- und XLSX-Arbeitsmappen standardmäßig auf False — das Erhalten einer Formel autorisiert also nie, dass Code der Hostanwendung einen gefährlichen externen oder makroartigen Funktionsnamen behandelt
Die Standard-Sperre umfasst DDE, CALL, REGISTER, REGISTER.ID, WEBSERVICE, RTD, SQL.REQUEST, EXEC, RUN, CREATE.OBJECT, APP.ACTIVATE, SEND.KEYS, OPEN, SAVE, SAVE.AS, FOPEN, FWRITE, FWRITELN, FCLOSE und FILE.DELETE, nachdem ein erkanntes Future-Functions-Präfix normalisiert wurde
Die Ablehnung passiert vor der Argumentauswertung und bevor arbeitsmappenlokale, prozessweite, Resolver- oder Ereignis-Callbacks laufen; gewöhnliche benutzerdefinierte und nicht unterstützte Funktionsnamen behalten ihr bisheriges Callback-Verhalten
Setzen Sie die Arbeitsmappen-Eigenschaft nur dann auf True, wenn jede Formel und jeder registrierte Handler vertrauenswürdig ist; die kontextbezogene Auswertung kann sich stattdessen für einen einzelnen Aufruf über TXLSFormulaEvaluationOptions.AllowUnsafeFormulaCallbacks anmelden, während ein explizit gesetztes False eine arbeitsmappenweite Anmeldung überschreibt
Beispiel
procedure TForm1.WorkbookUserFunction(Sender: TObject;
const FunctionName: WideString; const Args: Variant;
var Value: Variant; var Handled: Boolean);
begin
if SameText(FunctionName, 'DOUBLEPLUS') then
begin
Value := Double(Args[0]) * 2 + Double(Args[1]);
Handled := True;
end;
end;
Workbook.OnUserFunction := WorkbookUserFunction;
Value := Workbook.Calculate('=DOUBLEPLUS(A1;5)');
Kontextbezogenes Beispiel
procedure TForm1.WorkbookUserFunctionEx(Sender: TObject;
const FunctionName: WideString; const Args: Variant;
const Context: TXLSUserFunctionContext;
var Value: Variant; var Handled: Boolean);
begin
if SameText(FunctionName, 'ROWBONUS') then
begin
Value := Double(Args[0]) + Context.Row + Context.Col;
Handled := True;
end;
end;
Workbook.OnUserFunctionEx := WorkbookUserFunctionEx;
Value := Worksheet.Calculate('=C2');
Bereichsargumente entgegennehmen
Lautet ein Argument auf einen Arbeitsblattbereich, ist der Args-Eintrag ein varUnknown-Variant, der eine ICalcRangeList hält; der ausgewertete Wert jeder abgedeckten Zelle wird nicht in den Variant kopiert. Prüfen und extrahieren Sie ihn mit der VarIsRange-Überladung, die die Liste zurückgibt, und lesen Sie dann die aufgelösten Rechtecke über TXLSCalcRange
type
TXLSCalcRange = class
property row1: Integer; { 0-based, inclusive }
property col1: Integer; { 0-based, inclusive }
property row2: Integer;
property col2: Integer;
property SheetIndex: Integer;
end;
ICalcRangeList = interface
property Count: Integer;
property Item[Index: Integer]: TXLSCalcRange;
end;
function VarIsRange(Value: Variant): Boolean; overload;
function VarIsRange(Value: Variant; var Int: ICalcRangeList): Boolean; overload;
function RangeToVariant(Value: TXLSCalcRangeList): Variant;
Die Koordinaten folgen der TXLSGetValue-Konvention: nullbasiert und inklusiv. Ein Handler, der selbst einen Bereich zurückgeben will, baut eine TXLSCalcRangeList und wickelt sie mit RangeToVariant ein, bevor er Value zuweist; die Engine behält dann die Bereichsreferenz für abhängige Formeln, statt eines skalaren Schnappschusses
Siehe auch