从 DLL 调用用户定义的函数

适用于:Excel 2013 | Office 2013 | Visual Studio

从工作表) (UDF 调用用户定义的函数与调用内置函数一样简单:通过单元格公式输入函数。 但是,在 C API 中,没有预定义的函数代码可用于回调。 若要使你能够调用 UDF,C API 导出一个仅限 XLL 的函数 ,即 xlUDF 函数。 函数的第一个参数是函数名称作为字符串,后续参数是 UDF 通常期望的参数。

可以使用带有参数 44 的 xlfGetWorkspace 函数获取当前注册的 XLL 外接程序函数和命令的列表。 这将返回一个三列数组,其中列表示以下内容:

  • XLL 的完整路径和名称

  • 从 XLL 导出的 UDF 或命令的名称

  • 返回和参数代码字符串

注意

从 XLL 导出的名称可能与 Excel 知道 UDF 或命令所依据的注册名称不同。

从 Excel 2007 开始,分析工具库 (ATP) 函数已完全集成,并且 C API 为 PRICE、 xlfPrice 等函数提供了自己的枚举。 在早期版本中,必须使用 xlUDF 来调用这些函数。 如果你的外接程序需要使用 Excel 2003 和 Excel 2007 或更高版本,并且它使用这些函数,则应检测当前版本,然后以适当的方式调用函数。

示例

以下示例演示运行 Excel 版本为 2003 或更低版本时,用于调用 ATP 函数 PRICExlUDF 函数。 有关全局版本变量(如本示例中的 gExcelVersion12plus )的设置的信息,请参阅 向后兼容性

注意

此示例使用框架函数 TempNumTempStrConst 设置参数和 Excel 来调用 C API。

LPXLOPER TempNum(double d);
LPXLOPER TempStrConst(const LPSTR lpstr);
int cdecl Excel(int xlfn, LPXLOPER pxResult, int count, ...);
double call_ATP_example(void)
{
  XLOPER xPrice;
  int xl_ret_val;
  if(gExcelVersion12plus) // Starting in Excel 2007
  {
    xl_ret_val = Excel(xlfPrice, &xPrice, 7,
      TempNum(39084.0), // settlement date 2-Jan-2007
      TempNum(46706.0), // maturity date 15-Nov-2027
      TempNum(0.04), // Coupon
      TempNum(0.05), // Yield
      TempNum(1.0), // redemption value: 100% of face
      TempNum(1.0), // Annual coupons
      TempNum(1.0)); // Rate basis Act/Act
  }
  else // Excel 2003-
  {
    xl_ret_val = Excel(xlUDF, &xPrice, 8,
      TempStrConst("PRICE"),
      TempNum(39084.0), // settlement date 2-Jan-2007
      TempNum(46706.0), // maturity date 15-Nov-2027
      TempNum(0.04), // Coupon
      TempNum(0.05), // Yield
      TempNum(1.0), // redepmtion value: 100% of face
      TempNum(1.0), // Annual coupons
      TempNum(1.0)); // Rate basis Act/Act
  }
  if(xl_ret_val != xlretSuccess || xPrice.xltype != xltypeNum)
  {
// Even though PRICE is not expected to return a string, there
// is no harm in freeing the XLOPER to be safe
    Excel(xlFree, 0, 1, &xPrice);
    return -1.0; // an error value
  }
  return xPrice.val.num;
}

如果调用通过就地修改参数返回值的 XLL 函数, 则 xlUDF 函数仍通过结果 XLOPER/XLOPER12的地址返回值。 换句话说,返回结果的方式就像通过普通返回语句一样。 与用于返回值的参数对应的 XLOPER/XLOPER12 未修改。 例如,请考虑以下两个 UDF。

// Registered as "1E". Returns its argument incremented by 1.
void WINAPI UDF_1(double *pArg)
{
  *pArg += 1.0;
}
// Registered as "QQ". Returns its argument unmodified
// unless it is a number, in which case it increments it
// by calling UDF_1.
LPXLOPER12 WINAPI UDF_2(LPXLOPER12 pxArg)
{
  static XLOPER12 xRetVal; // Not thread-safe
  XLOPER12 xFn;
  xFn.xltype = xltypeStr;
  xFn.val.str = L"\005UDF_1";
  Excel12(xlUDF, &xRetVal, 2, &xFn, pxArg);
  xRetVal.xltype |= xlbitXLFree;
  return &xRetVal;
}

当UDF_2调用UDF_1时,pxArg 的值在调用 Excel12 后保持不变,并且 UDF_1 返回的值包含在 xRetVal 中

以这种方式对 UDF 进行大量调用时,可以先使用 xlfEvaluate 函数来评估函数名称。 生成的数字(与 xlfRegister 函数返回的注册 ID 相同)可以作为 xlUDF 函数的第一个参数传递来代替函数名称。 这使 Excel 能够比每次查找函数名称时更快地查找和调用函数。

另请参阅