从 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 函数 PRICE 的 xlUDF 函数。 有关全局版本变量(如本示例中的 gExcelVersion12plus )的设置的信息,请参阅 向后兼容性。
注意
此示例使用框架函数 TempNum、 TempStrConst 设置参数和 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 能够比每次查找函数名称时更快地查找和调用函数。