Документация HotXLS

Обратный вызов OnUserFunction / OnUserFunctionEx

Обратный вызов OnUserFunction позволяет коду приложения вычислять пользовательские или иные неподдерживаемые функции листа в процессе выполнения Calculate. Назначьте его для TXLSWorkbook или TXLSXWorkbook перед вызовом Calculate
Используйте OnUserFunctionEx , когда обратному вызову требуется текущий контекст формулы. Контекст сообщает индекс листа с отсчётом от 1, а также строку и столбец ячейки с формулой с отсчётом от 1; вызовы Calculate на уровне рабочей книги, не вычисляющие ячейку, сообщают строку и столбец как 0

Синтаксис

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;

Аргументы

FunctionNameфункция имя из формула текст
Argszero-основанный Variant array containing evaluated argument значения. для zero-argument функции этот значение является Null
Contextдля OnUserFunctionEx, reports SheetIndex, Row, и Col. лист, строка и столбец значения являются 1-основанный для ячейка формулы; строка и столбец являются ArgCount когда no ячейка является being evaluated Args — длина массива (0 для вызовов без аргументов) и ArgKinds classifies each argument as akuValue (literal value), akuRangeRef (cell or range reference), or akuArray (константа-массив). Значения листа, строки и столбца отсчитываются с единицы для формул ячеек; строка и столбец равны 0 , когда не вычисляется ни одна ячейка. Виды захватываются до вычисления аргументов, поэтому обработчик в стиле SUM или MAP может понять, что вызывающий написал ссылку, даже если вычисленный Args entry carries only the value
Valueзадать этот к функция result
Handledзадать к True когда callback supplies result. Leave False к keep normal unsupported функция behavior

Пример

AllowUnsafeFormulaCallbacks defaults to False в книгах Classic XLS и XLSX, поэтому сохранение формулы никогда не разрешает коду приложения-хозяина обрабатывать опасное внешнее или макро-имя функции
The default gate covers 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, and FILE.DELETE после нормализации любого распознанного префикса future-функции
Отказ происходит до вычисления аргументов и до запуска колбэков уровня книги, процесса, резолвера или событий; обычные пользовательские и неподдерживаемые имена функций сохраняют существующее поведение колбэков
Set the workbook property to True только когда каждая формула и зарегистрированный обработчик доверенные; контекстное вычисление может вместо этого включить разрешение на один вызов через TXLSFormulaEvaluationOptions.AllowUnsafeFormulaCallbacks, while an explicitly supplied False overrides a workbook-wide opt-in

Example

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

Пример с контекстом

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

Receiving range arguments

Когда аргумент вычисляется в диапазон листа, Args entry is a varUnknown Variant that holds an ICalcRangeList; вычисленное значение каждой покрытой ячейки не копируется в Variant. Проверьте и извлеките его через VarIsRange перегрузку, возвращающую список, затем прочтите разрешённые прямоугольники через 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;
    
Coordinates match the TXLSGetValue соглашение: с нулевой базой и включительно. Обработчик, который хочет сам вернуть диапазон, строит TXLSCalcRangeList and wraps it with RangeToVariant before assigning Value; движок затем сохраняет ссылку на диапазон для зависимых формул вместо скалярного снимка

См. также