Documentazione HotXLS

OnUserFunction / OnUserFunctionEx callback

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