Dokumentace HotXLS

Zpětné volání OnUserFunction / OnUserFunctionEx

Zpětné volání OnUserFunction umožňuje kódu aplikace vyhodnocovat vlastní nebo jinak nepodporované funkce listu během Calculate. Přiřaďte jej na TXLSWorkbook nebo TXLSXWorkbook před voláním Calculate
Použijte OnUserFunctionEx, když zpětné volání potřebuje aktuální kontext vzorce. Kontext hlásí index listu (1-based) plus řádek a sloupec buňky se vzorcem (1-based); volání Calculate na úrovni sešitu, která nevyhodnocují žádnou buňku, hlásí řádek a sloupec jako 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;

Argumenty

FunctionName Název funkce z textu vzorce
Args Pole Variant s indexací od nuly obsahující vyhodnocené hodnoty argumentů. Pro funkce bez argumentů je tato hodnota Null
Context Pro OnUserFunctionEx hlásí SheetIndex, Row a Col, plus deskriptory argumentů: ArgCount odpovídá délce pole Args (0 pro volání bez argumentů) a ArgKinds klasifikuje každý argument jako akuValue (literální hodnota), akuRangeRef (reference na buňku či oblast) nebo akuArray (konstanta pole). Hodnoty listu, řádku a sloupce jsou u buněčných vzorců 1-based; řádek a sloupec jsou 0, když se nevyhodnocuje žádná buňka. Druhy (kinds) se zachytí před vyhodnocením argumentů, takže handler ve stylu SUM či MAP pozná, že volající napsal referenci, i když vyhodnocená položka Args nese jen hodnotu
Value Nastavte toto na výsledek funkce
Handled Nastavte na True, když callback poskytuje výsledek. Nechte False, chcete-li zachovat běžné chování pro nepodporovanou funkci

Bezpečnostní politika callbacků

AllowUnsafeFormulaCallbacks má u Classic XLS i XLSX sešitů výchozí hodnotu False, takže samotné zachování vzorce nikdy neautorizuje kód hostitelské aplikace k obsluze nebezpečného externího či makro-style názvu funkce
Výchozí brána pokrývá 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 a FILE.DELETE po normalizaci jakékoli rozpoznané future-function předpony
Odmítnutí proběhne dřív, než se vyhodnotí argumenty a dřív, než se spustí workbook-lokální, process-wide, resolver či event callbacky; obyčejné vlastní a nepodporované názvy funkcí si ponechávají stávající chování callbacků
Vlastnost sešitu nastavte na True jen tehdy, když je každý vzorec i registrovaný handler důvěryhodný; kontextové vyhodnocení se místo toho může pro jedno volání přihlásit přes TXLSFormulaEvaluationOptions.AllowUnsafeFormulaCallbacks, přičemž explicitně dodané False přebíjí opt-in na úrovni celého sešitu

Příklad

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

Kontextový příklad

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

Přijímání argumentů typu range

Když se argument vyhodnotí na range listu, položka Args je Variant typu varUnknown držící ICalcRangeList; vyhodnocená hodnota každé překryté buňky se do Variantu nekopíruje. Otestujte jej a extrahujte pomocí overloadu VarIsRange, který vrací seznam, a poté přečtěte rozřešené obdélníky přes 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;
    
Souřadnice dodržují konvenci TXLSGetValue: indexované od nuly a inkluzivní. Handler, který chce sám vrátit range, si sestaví TXLSCalcRangeList a před přiřazením do Value jej zabalí pomocí RangeToVariant; engine pak pro závislé vzorce ponechá referenci na range místo skalárního snímku

Viz také