Docs HotXLS

Rappel OnUserFunction / OnUserFunctionEx

Le rappel OnUserFunction permet au code d'application d'évaluer des fonctions de feuille de calcul personnalisées ou non supportées pendant Calculate. Assignez-le sur TXLSWorkbook ou TXLSXWorkbook avant d'appeler Calculate
Utilisez OnUserFunctionEx lorsque le rappel a besoin du contexte de formule actuel. Le contexte signale l'index de feuille à base 1 ainsi que la ligne et la colonne à base 1 de la cellule de formule ; les appels Calculate au niveau du classeur qui n'évaluent pas une cellule signalent la ligne et la colonne comme 0

Syntaxe

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;

Arguments

FunctionName Le nom de la fonction provenant du texte de la formule
Args Une matrice Variant à base zéro contenant les valeurs des arguments évalués. Pour les fonctions sans argument, cette valeur est Null
Context Pour OnUserFunctionEx, signale SheetIndex, Row et Col, plus le descripteur d'arguments : ArgCount correspond à la longueur du tableau Args (0 pour les appels sans argument) et ArgKinds classe chaque argument en akuValue (valeur littérale), akuRangeRef (référence de cellule ou de plage) ou akuArray (constante tableau). Les valeurs de feuille, de ligne et de colonne sont à base 1 pour les formules de cellule ; la ligne et la colonne valent 0 lorsqu'aucune cellule n'est évaluée. Les types sont capturés avant l'évaluation des arguments, si bien qu'un gestionnaire de style SUM ou MAP peut savoir que l'appelant a écrit une référence alors que l'entrée Args évaluée ne transporte que la valeur
Value Définissez cette valeur sur le résultat de la fonction
Handled Définissez-le sur True lorsque le rappel fournit un résultat. Laissez False pour conserver le comportement normal des fonctions non supportées

Politique de sécurité des rappels

AllowUnsafeFormulaCallbacks vaut False par défaut sur les classeurs XLS Classic et XLSX, si bien que préserver une formule n'autorise jamais le code de l'application hôte à traiter un nom de fonction externe ou de style macro dangereux
Le verrou par défaut couvre 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 et FILE.DELETE, après normalisation de tout préfixe de future-function reconnu
Le refus intervient avant l'évaluation des arguments et avant l'exécution des rappels locaux au classeur, globaux au processus, de résolveur ou d'événement ; les noms de fonctions personnalisées et non prises en charge ordinaires conservent leur comportement de rappel existant
Ne passez la propriété du classeur à True que lorsque chaque formule et chaque gestionnaire enregistré est de confiance ; l'évaluation contextuelle peut au lieu de cela accepter un appel unique via TXLSFormulaEvaluationOptions.AllowUnsafeFormulaCallbacks, tandis qu'un False explicitement fourni prime sur une acceptation à l'échelle du classeur

Exemple

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)');

Exemple prenant en compte le contexte

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');

Recevoir des arguments de plage

Quand un argument s'évalue en une plage de feuille de calcul, l'entrée Args est un Variant varUnknown qui contient un ICalcRangeList ; la valeur évaluée de chaque cellule couverte n'est pas copiée dans le Variant. Testez-le et extrayez-le avec la surcharge VarIsRange qui renvoie la liste, puis lisez les rectangles résolus via 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;
    
Les coordonnées suivent la convention TXLSGetValue : en base zéro et inclusives. Un gestionnaire qui souhaite renvoyer une plage construit lui-même une TXLSCalcRangeList et l'enveloppe avec RangeToVariant avant d'affecter Value ; le moteur conserve alors la référence de plage pour les formules dépendantes au lieu d'un instantané scalaire

Voir aussi