Documentación de HotXLS

Callback OnUserFunction / OnUserFunctionEx

El callback OnUserFunction permite al código de la aplicación evaluar funciones de hoja de cálculo personalizadas o no compatibles durante Calculate. Asígnelo en TXLSWorkbook o TXLSXWorkbook antes de llamar a Calculate
Use OnUserFunctionEx cuando el callback necesite el contexto de fórmula actual. El contexto informa el índice de hoja de base 1 más la fila y columna de base 1 de la celda de fórmula; las llamadas a Calculate a nivel de libro de trabajo que no evalúan ninguna celda informan fila y columna como 0

Sintaxis

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;

Argumentos

FunctionName El nombre de la función tal como aparece en el texto de la fórmula
Args Un arreglo Variant de base 0 con los valores de los argumentos ya evaluados. Para funciones sin argumentos este valor es Null
Context Para OnUserFunctionEx, informa SheetIndex, Row y Col, más el descriptor de argumentos: ArgCount coincide con la longitud del arreglo Args (0 en llamadas sin argumentos) y ArgKinds clasifica cada argumento como akuValue (valor literal), akuRangeRef (referencia a celda o rango) o akuArray (constante de matriz). Los valores de hoja, fila y columna son de base 1 en las fórmulas de celda; la fila y la columna son 0 cuando no se evalúa ninguna celda. Los tipos se capturan antes de evaluar los argumentos, de modo que un manejador al estilo de SUM o MAP puede saber que quien escribió la fórmula usó una referencia aunque la entrada Args evaluada lleve solo el valor
Value Asígnelo con el resultado de la función
Handled Asígnelo a True cuando el callback entrega un resultado. Déjelo en False para conservar el comportamiento normal con funciones no compatibles

Política de seguridad de callbacks

AllowUnsafeFormulaCallbacks es False de forma predeterminada en los libros de trabajo XLS clásicos y XLSX, de modo que preservar una fórmula nunca autoriza al código de la aplicación host a manejar nombres de funciones peligrosos de tipo externo o macro
La barrera predeterminada cubre 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 y FILE.DELETE, después de normalizar cualquier prefijo de función futura reconocido
El rechazo ocurre antes de evaluar los argumentos y antes de que se ejecuten los callbacks del libro de trabajo, del proceso, del resolutor o de eventos; los nombres de funciones personalizadas y no compatibles ordinarias conservan su comportamiento de callback existente
Establezca la propiedad del libro de trabajo en True solo cuando confíe en todas las fórmulas y manejadores registrados; la evaluación contextual puede habilitarlo solo para una llamada mediante TXLSFormulaEvaluationOptions.AllowUnsafeFormulaCallbacks, mientras que un False explícito anula una habilitación de todo el libro de trabajo

Ejemplo

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

Ejemplo con contexto

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

Recepción de argumentos de rango

Cuando un argumento se evalúa como un rango de hoja de cálculo, la entrada Args es un Variant varUnknown que contiene un ICalcRangeList; el valor evaluado de cada celda cubierta no se copia en el Variant. Compruébelo y extráigalo con la sobrecarga de VarIsRange que devuelve la lista, y luego lea los rectángulos resueltos a través de 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;
    
Las coordenadas siguen la convención de TXLSGetValue: de base 0 e inclusivas. Un manejador que quiera devolver un rango por sí mismo construye un TXLSCalcRangeList y lo envuelve con RangeToVariant antes de asignar Value; el motor conserva entonces la referencia del rango para las fórmulas dependientes en lugar de una instantánea escalar

Ver también