HotXLS-documentatie

OnUserFunction / OnUserFunctionEx callback

De OnUserFunction-callback laat applicatiecode aangepaste of verder niet-ondersteunde werkbladfuncties evalueren tijdens Calculate. Wijs hem toe op TXLSWorkbook of TXLSXWorkbook vóór het aanroepen van Calculate
Gebruik OnUserFunctionEx wanneer de callback de huidige formulecontext nodig heeft. De context rapporteert de 1-gebaseerde bladindex plus de 1-gebaseerde rij en kolom van de formulecel; Calculate-aanroepen op werkmapniveau die geen cel evalueren, rapporteren rij en kolom als 0

Syntaxis

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

FunctionNameDe functienaam uit de formuletekst
ArgsEen 0-gebaseerde Variant-array met geëvalueerde argumentwaarden. Voor functies zonder argumenten is deze waarde Null
ContextBij OnUserFunctionEx geeft dit SheetIndex, Row en Col door, plus de argumentdescriptor: ArgCount komt overeen met de lengte van de Args-array (0 bij aanroepen zonder argumenten) en ArgKinds classificeert elk argument als akuValue (letterlijke waarde), akuRangeRef (verwijzing naar cel of bereik) of akuArray (arrayconstante). Sheet-, rij- en kolomwaarden zijn 1-gebaseerd bij celformules; rij en kolom zijn 0 wanneer er geen cel wordt geëvalueerd. De kinds worden vastgelegd vóórdat de argumenten worden geëvalueerd, zodat een SUM- of MAP-achtige handler kan zien dat de aanroeper een verwijzing schreef ook al bevat de geëvalueerde Args-entry alleen de waarde
ValueStel hier het functieresultaat in
HandledZet op True wanneer de callback een resultaat aanlevert. Laat False staan om het normale gedrag voor niet-ondersteunde functies te behouden

Callback-beveiligingsbeleid

AllowUnsafeFormulaCallbacks staat standaard op False voor klassieke XLS- en XLSX-werkmappen, zodat het bewaren van een formule code van de hosttoepassing nooit toestaat om een gevaarlijke externe functienaam of een functienaam in macro-stijl te behandelen
De standaardafschutting dekt 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 en FILE.DELETE , nadat een herkend future-function-prefix is genormaliseerd
Weigering gebeurt vóór de evaluatie van argumenten en vóór het uitvoeren van callbacks op werkmapniveau, procesbrede resolvers of events; gewone aangepaste en niet-ondersteunde functienamen behouden hun bestaande callback-gedrag
Zet de eigenschap van de werkmap alleen op True wanneer elke formule en elke geregistreerde handler vertrouwd wordt; contextuele evaluatie kan in plaats daarvan voor één aanroep meedoen via TXLSFormulaEvaluationOptions.AllowUnsafeFormulaCallbacks, terwijl een expliciet opgegeven False een werkmapbrede opt-in overschrijft

Voorbeeld

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

Context-aware example

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

Bereikargumenten ontvangen

Wanneer een argument evalueert naar een werkbladbereik, is de Args -entry een Variant van type varUnknown die een ICalcRangeListbevat; de geëvalueerde waarde van elke gedekte cel wordt niet in de Variant gekopieerd. Test en extraheer die met de VarIsRange -overload die de lijst teruggeeft, en lees daarna de herleide rectangles 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;
    
De coördinaten volgen de TXLSGetValue -conventie: op nul gebaseerd en inclusief. Een handler die zelf een bereik wil teruggeven, bouwt een TXLSCalcRangeList op en wikkelt die in RangeToVariant voordat Valuewordt toegewezen; de engine houdt dan de bereikverwijzing vast voor afhankelijke formules in plaats van een scalaire momentopname

Zie ook