HotXLS Docs

OnUserFunction / OnUserFunctionEx 回调

The 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来自公式文本的函数名称
Args包含已计算参数值的、基于 0 的 Variant 数组 对于无参数函数,此值为 Null
Context对于 OnUserFunctionEx,报告 SheetIndex、 Row和 Col。对于单元格公式,工作表、行和列的值基于 1;当没有单元格被计算时,行和列为 ArgCount matches the Args 数组长度(零参数调用为 0),以及 ArgKinds classifies each argument as akuValue (literal value), akuRangeRef (cell or range reference), or akuArray (数组常量)。单元格公式的 Sheet、行、列值从 1 开始;行和列为 0 (未在求值任何单元格时)。类别在参数求值之前捕获,因此 SUM 或 MAP 风格的处理函数能看出调用方写的是引用,即使被求值的 Args entry carries only the value
Value将此设置为函数结果
Handled当回调提供结果时设为 True 。保持 False 以维持正常的不受支持函数处理行为

示例

AllowUnsafeFormulaCallbacks 默认为 False ,因此保留公式并不意味着授权宿主应用程序代码去处理危险的外部或宏风格函数名
在归一化所有可识别的 future-function 前缀之后,默认拦截名单覆盖 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和 FILE.DELETE (在归一化任何可识别的 future-function 前缀之后)
拦截发生在参数求值之前,也发生在工作簿级、进程级、解析器或事件回调运行之前;普通的自定义函数名和不受支持的函数名仍保持原有的回调行为
只有当所有公式和已注册的处理器都可信时,才把工作簿属性设为 True ;单次上下文求值也可以通过 TXLSFormulaEvaluationOptions.AllowUnsafeFormulaCallbacks单独开启,而显式提供的 False 会覆盖工作簿级的开启

示例

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

请参阅

IXLSWorkbook.Calculate 方法 Args TXLSWorksheet.Calculate 方法 varUnknown TXLSXWorkbook 类 ICalcRangeListTXLSXWorksheet 类 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;
    
坐标遵循 TXLSGetValue 约定:从 0 开始且包含端点。处理器若想自己返回一个区域,可以先构建 TXLSCalcRangeList ,用 RangeToVariant 包装后再赋给 Value;引擎会为依赖公式保留区域引用,而不是标量快照

请参阅