Il callback OnUserFunction consente al codice dell'applicazione di valutare
funzioni personalizzate o comunque non supportate del foglio di lavoro durante
Calculate. Assegnalo a TXLSWorkbook o
TXLSXWorkbook prima di chiamare Calculate
Usa OnUserFunctionEx quando il callback necessita del contesto corrente della formula. Il contesto riporta l'indice del foglio con base 1, oltre alla riga e alla colonna (base 1) della cella della formula; le chiamate Calculate a livello di workbook che non valutano una cella riportano riga e colonna come 0
Sintassi
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;
Argomenti
| FunctionName |
Il nome della funzione dal testo della formula |
| Args |
Una matrice Variant a base zero contenente i valori
degli argomenti valutati. Per le funzioni senza argomenti questo valore è
Null |
| Context |
Per OnUserFunctionEx, riporta SheetIndex, Row e Col, più il descrittore degli argomenti: ArgCount corrisponde alla lunghezza dell'array Args (0 per le chiamate senza argomenti) e ArgKinds classifica ogni argomento come akuValue (valore letterale), akuRangeRef (riferimento a cella o intervallo) o akuArray (costante array). I valori di foglio, riga e colonna hanno base 1 per le formule di cella; riga e colonna sono 0 quando non viene valutata alcuna cella. Le categorie vengono catturate prima della valutazione degli argomenti, così un gestore in stile SUM o MAP può capire che il chiamante ha scritto un riferimento anche se la voce Args valutata contiene solo il valore |
| Value |
Impostalo sul risultato della funzione |
| Handled |
Impostalo su True quando il callback fornisce
un risultato. Lascialo su False per mantenere il normale
comportamento per le funzioni non supportate |
Criterio di sicurezza delle callback
AllowUnsafeFormulaCallbacks è False per default sulle cartelle di lavoro Classic XLS e XLSX, così preservare una formula non autorizza mai il codice dell'applicazione host a gestire un nome di funzione esterno o in stile macro pericoloso
Il gate predefinito copre 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 e FILE.DELETE, dopo la normalizzazione di ogni prefisso di future-function riconosciuto
Il rifiuto avviene prima della valutazione degli argomenti e prima dell'esecuzione delle callback a livello di cartella di lavoro, di processo, di resolver o di evento; i normali nomi di funzione personalizzati e non supportati conservano il loro comportamento di callback esistente
Impostare la proprietà della cartella di lavoro su True solo quando ogni formula e ogni gestore registrato è affidabile; la valutazione contestuale può invece attivarsi per una sola chiamata tramite TXLSFormulaEvaluationOptions.AllowUnsafeFormulaCallbacks, mentre un False fornito esplicitamente prevale su un opt-in a livello di cartella di lavoro
Esempio
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)');
Esempio con contesto
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');
Ricezione di argomenti intervallo
Quando un argomento valuta a un intervallo del foglio di lavoro, la voce Args è un Variant varUnknown che contiene un ICalcRangeList; il valore valutato di ogni cella coperta non viene copiato nel Variant. Verificarlo ed estrarlo con l'overload di VarIsRange che restituisce la lista, poi leggere i rettangoli risolti tramite 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;
Le coordinate seguono la convenzione di TXLSGetValue: a base zero e inclusive. Un gestore che vuole restituire a sua volta un intervallo costruisce una TXLSCalcRangeList e la incapsula con RangeToVariant prima di assegnare Value; il motore mantiene quindi il riferimento all'intervallo per le formule dipendenti invece di un'istantanea scalare
Vedere anche