本节中将介绍几个对于 DLL 和 XLL 开发人员来说十分重要的回调函数,xlfRegister 函数是可用于注册函数,使得 Excel 可以直接访问 DLL 和 XLl 中的函数。
xlfUnregister 和 xlfSetName 函数的作用和 xlfRegister 相反,用于反注册已经注册过的函数。
当你开发 XLL时,可以使用许多由 C API 暴露出的 Excel 功能。它们相当于 从 XLM 宏表获取的 Excel 工作表函数、函数和命令。
xlfCaller
返回当前正在运行的关于单元格、单元格区域、菜单命令、工具栏工具、或对象调用的 DLL 命令或函数。
代码来自于 | 返回 |
---|---|
DLL | 注册的ID. |
单个单元格 | 单个单元格和. |
多个单元格数组公式 | 多个单元格引用. |
条件格式表达式 | 应用条件格式表达式引用的单元格。 |
菜单 | 4个元素的一维数组:
|
工具栏 | 一维二个元素的数组:
|
图形对象 | 对象标识符(对象名称) |
xlcOnEnter, ON.ENTER, 事件捕获关联的命令 | 输入引用的单元格或单元格区域。 |
xlcOnDoubleclick, ON.DOUBLECLICK, event trap.事件跟踪。 | 双击这个单元格 (不是必要的激活单元格). |
Auto_Open, AutoClose, Auto_Activate or Auto_Deactivate 宏 | 调用的表格名称. |
其它方法 | #REF! 错误. |
1.1 用法
Excel12(xlfCaller, (LPXLOPER12) pxRes, 0);
1.2 属性值 / 返回值
返回值是 XLOPER/XLOPER12 数据类型中的一种:xltypeRef、xltypeSRef、xltypeNum、xltypeStr、xltyperErr、xltypeMulti。由于3种类型指针指向分配的内存, 当不在需要 xlfCaller 返回值时,需要调用 xlFree 函数来释放。
1.3 备注
此函数是唯一可以从 DLL/XLL 工作表函数调用的非工作表函数。其它的 XLM 信息函数,只能从命令或函数表等效命令调用。
1.4 实例
\SAMPLES\EXAMPLE\EXAMPLE.C. 这个函数调用一个命令宏 (xlcSelect),只能从宏表调用函数时,才能正常工作。
short WINAPI CallerExample(void)
{
XLOPER12 xRes;
Excel12(xlfCaller, &xRes, 0);
Excel12(xlcSelect, 0, 1, (LPXLOPER12)&xRes);
Excel12(xlFree, 0, 1, (LPXLOPER12)&xRes);
return 1;
}
xlfEvaluate
用于 Excel 分析 和 评估任意工单表单元格中的表达式。
原型
Excel12(xlfEvaluate, LPXLOPER12 pxRes, 1, LPXLOPER12 pxFormulaText);
参数
pxFormulaText(xltypeStr)
要评估的字符串,起始处的 等于号(=)可以省略。工作表和宏表单元格中可以输入的有效字符。
属性值 / 返回值
返回评估结果,它可以是 xltypeNum, xltypeStr, xltypeBool, xltypeErr, xltypeNil, xltypeMulti 中的任意一种数据类型。
备注
此字符串可以仅包含函数,不使用 命令。等效于在公式栏中按 F9。如果 xlfEvaluate 是从 XLL 工作表函数中调用的,并且此函数被注册为 线程安全函数,那么表达式只能为线程安全函数。
xlfEvaluate 函数的主要用途,是允许 DLL 查找表格中或DLL中所定义的名称。注意 包含在 DLL/XLL 中的工作表名称 ,必需以! 作为表名的 结尾。
xlfEvaluate 不能引用没有打开的外部表格。
实例
此实例,使用 xlfEvaluate 强制 “!B38" 转换成 B38 单元格内容。
\SAMPLES\EXAMPLE\EXAMPLE.C. 这个函数调用 命令宏 (xlcAlert)只会在宏表或宏命令中正常执行。
short WINAPI EvaluateExample(void)
{
XLOPER12 xFormulaText, xRes, xRes2, xInt;
xFormulaText.xltype = xltypeStr;
xFormulaText.val.str = L"\004!B38";
Excel12(xlfEvaluate, &xRes, 1, (LPXLOPER12)&xFormulaText);
xInt.xltype = xltypeInt;
xInt.val.w = 2;
Excel12(xlcAlert, &xRes2, 2, (LPXLOPER12)&xRes, (LPXLOPER12)&xInt);
Excel12(xlFree, 0, 1, (LPXLOPER12)&xRes);
Excel12(xlFree, 0, 1, (LPXLOPER12)&xRes2);
return 1;
}
xlfRegister (形式1)
可以从Excel正在使用的 DLL 或 XLL 中调用此命令。这个函数等效于 Excel XLM 宏函数 REGISTER。
xlfRegister 可以用下面两种形式调用:
- 形式1:注册单个的命令或函数
- 形式2:读取或激活 XLL
使用第一种形式,这个函数可以让某一个DLL函数或命令对于Excel是可用的,并设置它的计数器 加 1。并返回一个注册ID,此ID可以用于 xlUDF 或 xlfCall 函数。同时此 ID 还用于 xlfUnregister (形式1)函数。如果函数已经注册,会将计数器在加1.
此形式还定义了一个隐藏名称,它表示了函数的文本参数,pxFunctionText、以及评估 函数或命令的注册ID。当你反注册此函数,使用 xlfSetName 声明要删除的名称。
原型
Excel12(xlfRegister, LPXLOPER12 pxRes, int iCount,
LPXLOPER12 pxModuleText, LPXLOPER12 pxProcedure,
LPXLOPER12 pxTypeText, LPXLOPER12 pxFunctionText,
LPXLOPER12 pxArgumentText, LPXLOPER12 pxMacroType,
LPXLOPER12 pxCategory, LPXLOPER12 pxShortcutText,
LPXLOPER12 pxHelpTopic, LPXLOPER12 pxFunctionHelp,
LPXLOPER12 pxArgumentHelp1, LPXLOPER12 pxArgumentHelp2,
...);
参数
pxModuleText (xltypeStr)
表示包含了注册的函数的 DLL 名称。如果这个函数存在于当前正在执行的DLL中,可以使用 XLL 函数 xlGetName 获取 DLL 名称。
pxProcedure (xltypeStr or xltypeNum)
这里可以使用 DEF 中输出的函数名称,也可以使用序号,但通常使用函数名称,这样代码更容易理解。
pxTypeText (xltypeStr)
这是一个可选字符串,指明了所有函数的参数值类型和返回值类型。但多信息查看 “备注” 一节。这个函数在只包含了 xlAutoRegister 函数 或 xlAutoRegister12 函数的 DLL(XLL)中可以省略。
注意 xlAutoRegister12 只支持 2007 及其后续版本。
pxCategory (xltypeStr 或 xltypeNum)
这是一个可选参数,可以让你指定函数或命令的类型。函数向导通过类型划分了函数。你可以指定类型名称或数字,数字表示函数向导中显示的函数类型的位置。更多信息查到 “类型名称” 一节。如果省略了此参数,那么就会默认它是一个用户定义类型。
pxShortcutText (xltypeStr)
一个有大小写之分的字符,表示与此命令相关的控制键。例如,“A” ,表示 CONTROL+SHIFT+A。这个参数是可选的,只能用于 命令,不可以用于函数。
pxHelpTopic (xltypeStr)
这是一个可选参数,用户点击帮助按钮后要显示要引用的帮助文件(要使用包含路径的完整文件名)
pxFunctionHelp (xltypeStr)
可选字符串,用于在函数向导中显示函数的相关信息。
pxArgumentHelp1 (xltypeStr)
可选参数,第一个字符串,用于在函数向导中显示选择函数参数的相关信息。到 Excel 2003 版本,xlfRegister 可以带有30参数,因此,你可以提供这种帮助的前20个参数的帮助。因此你可以为你的函数前20个参数显示帮助信息。到 Excel 2007 版本,xlfRegister 可以提供 255 个参数,因此你可以为 245 个参数提供帮助信息。
属性值 / 返回值。
数据类型
pxTypeText 参数用于指定 DLL函数或代码资源中所有函数的参数和返回值类型。第一字符表示返回值类型。剩余的其它字符表示所有参数的类型。例如,一个DLL函数返回一个 floating-point 数字 以及 带有 integer 和 floating-point 类型的参数,那么参数就要写为 "BIB"。
下面第一个表格中的数据类型,被所有版本的 Excel 支持,包括 Excel 2007。
Data type | Pass by value | Pass by ref (pointer) | Comments |
---|---|---|---|
Boolean | A | L | short [int] (0=false or 1=true) |
double | B | E |
|
char * |
| C, F | Null-terminated ASCII byte string |
unsigned char * |
| D, G | Counted ASCII byte string |
unsigned short [int] | H |
| 16-bit WORD |
[signed] short [int] | I | M | 16-bit signed integer |
[signed long] int | J | N | 32-bit signed integer |
FP |
| K | Floating-point array structure |
Array |
| O | Three arguments are passed: unsigned short int * unsigned short int * double [] |
XLOPER |
| P | Variable-type worksheet values and arrays |
|
| R | Values, arrays, and range references |
Excel 2007 还支持下表中的一些类型,它们用于支持 大表格和 长的Unicode 字符串
Data type | Pass by value | Pass by ref (pointer) | Comments |
---|---|---|---|
unsigned short * |
| C%, F% | Null-terminated Unicode wide-character string |
unsigned short * |
| D%, G% | Counted Unicode wide-character string |
FP12 |
| K% | Larger grid floating-point array structure |
Array |
| O% | Three arguments are passed:signed int * / RW * signed int * / COL * double [] |
XLOPER12 |
| Q | Variable-type worksheet values and arrays |
|
| U | Values, arrays, and range references |
字符串类型 F, F%, G 和 G% 用于参数。
当你使用上面的这些数据类型时,必需注意以下几点:
- C语言声明,假设你编译器默认使用的是 8-byte doubles, 2-byte short integers, 和 4-byte long integers
- DLL 中的所有函数和代码资源使用 __stdcall 调用协议。
- 任意函数通过引用返回一个数据类型,它返回一个指针,也可以安全返回一个 NULL 指针。Excel 会将 null 指针解释为 #NUM@! 错误。
附加数据类型信息
本节包含了关于 E, F, F%, G, G%, K, O, P, Q, R 和 U 数据类型的详细信息,以及关于 pxTypeText 参数的其它信息。
E 数据类型
Excel 规定 在堆栈中,DLL 通过 E 数据类型指针,指向 floating-point 数字类型。这会导致一些程序设计语言开发的 XLL 会产生问题(例如:Borland C++,就要求在 coprocessor emulator stack 上传送数值)。工作区在 coprocessor stack 上传送一个 数值指针。接下来显示在 Borland C++ 中怎样返回 double
E 数据类型
Excel 规定 在堆栈中,DLL 通过 E 数据类型指针,指向 floating-point 数字类型。这会导致一些程序设计语言开发的 XLL 会产生问题(例如:Borland C++,就要求在 coprocessor emulator stack 上传送数值)。工作区在 coprocessor stack 上传送一个 数值指针。接下来显示在 Borland C++ 中怎样返回 double
[C++]
typedef double * lpDbl;
extern "C" lpDbl __stdcall AddDbl(double D1,
double D2, WORD npDbl)
{
lpDbl Result;
Result = (lpDbl)MK_FP(_SS, npDbl);
*Result = D1 + D2;
return (Result);
}
F, F%, G, 和 G% 数据类型
F, F%, G 和 G% 数据类型,函数可以编辑 Excel 分配的 string buffer。如果返回值的类型是它们中的一个,Excel 就将忽略掉函数返回值。然后,Excel 为第一个匹配的数据类型(F, F%, G, 或 G%)找函数参数列表,并将当前分配的字符串缓存内容做为返回值。
所有版本的 Excel 都为 F 和 G ASCII 字符串分配 256 个字节, Excel 2007 为 F% 和 G% 分配 65,536 个字节,足足有 32,768 个 Unicode 字符。
K 和 K% 数据类型
K 和 K% 数据类型使用指针指向一个可变长度的 FP 和 FP12 结构。这个结构在 XLLCALL.H 文件中定义
O 和 O% 数据类型
O 和 O% 数据类型只能用于参数,不能用于返回值,尽管可以返回编辑的 O 或 O%类型的参数。
P 和 Q 数据类型
当 DLL 函数参数注册为 P XLOPER 或 Q XLOPER12 类型,Excel 将转换参数中的单个的单元格引用为单一值,多单元格引用为数据。换句话说,P 和 Q 类型传送到你的函数中时,总是使用以下数据类型: xltypeNum, xltypeStr, xltypeBool, xltypeErr, xltypeMulti, xltypeMissing, or xltypeNil。但不能是 xltypeRef 或 xltype 类型,因为它们总是被间接引用。 XLOPER12 是 Q 类型,只被 Excel 2007 支持。
易失函数和重计算
在pxTypeText最后 添加感叹号,将函数注册为易失函数。例如 "J!"
修改位置:函数声明为 Void
你可以使用单位数字作为 pxTypeText 参数的返回类型代码,数字的取值范围是 1 到 9。它将让 第n个参数值作为返回值。这也被称为修改。这 N 个参数必需传送引用类型(C, D, E, F, F%, G, G%, K, K%, L, M, N, O, O%, P, Q, R, or U)。这个DLL函数使用 void 关键字声明(在 C/C++ 语言)。
例如,一个 DLL函数带有一个以空字符结尾的字符串和2个整型参数。使用 “1FMM" 作为 pxTypeTextargument 参数值,函数使用 void 声明。
注册 工作表函数为宏表函数
在 pxTypeText 参数最后放置 “#” 符号,就可以让此函数在宏表中也可以使用。
注册工作表函数为线程安全函数
Excel 2007 可以执行多线程重计算。大多数 Excel 2007 工作表函数都是线程安全函数。Excel 2007 允许 XLL 注册为线程安全函数,只需要在 pxTypeText 参数最后加上 "$" 符号。
只有工作表函数可以注册为线程安全的,宏表函数不同。 因此你不能同时在参数 pxTypeText 中使用 # 和 $ 符号。
类别名称
这儿提供了一些分类指导,告诉你将函数分配在那个类别中。
- 如果用户执行的操作是对针对用户界面的,你应该将其放在 Commands 类别中。
- 如果函数返回的信息是关于 外接程序的状态,或其它信息的话,你应该放在 信息类别中。
- 千万不要将函数和命令添加到 用户定义类别 (##User Defined##),这个类型是给最终用户使用的。
类别用于 xlfRegister 命令的 pxCategory 参数。它使用的是规定好的数字或文本来表示。或是 DLL 中指定的新类别。如果文本不存在,Excel 会创建一个新的类型。
下面显示了在粘贴函数对话框中使用的标准类型:
Number | Text |
---|---|
1 | Financial |
2 | Date & Time |
3 | Math & Trig |
4 | Text |
5 | Logical |
6 | Lookup & Reference |
7 | Database |
8 | Statistical |
9 | Information |
14 | User Defined |
| Engineering (new in Excel 2007) |
| Cube (new in Excel 2007) |
这些类型,显示在宏表中。
Number | Text |
---|---|
10 | Commands |
11 | DDE/External |
12 | Customizing |
13 | Macro Control |
实例
实例在 \SAMPLES\GENERIC\GENERIC.C.
xlfRegister (Form 2)
可以从 DLL 或 XLL 命令调用。然后被 Excel 调用。它等效于 宏表中的 REGISTER 函数。
xlfRegister 可以使用两种形式调用:
- 注册独立的命令和函数
- 载入和激活 XLL
第二种方法,函数只能用于包含了 xlAutoOpen 的XLL。
原型
Excel12(xlfRegister, LPXLOPER12 pxRes, 1, LPXLOPER12 pxModuleText);
参数
pxModuleText (xltypeStr)
要载入和激活的 DLL。
属性值和返回值
如果成功,就返回 DLL 名称。其它情况下会返回 #VALUE! 错误。
xlfRegisterId
可以由 Excel 已经载入的 DLL 调用。如果函数已经注册,它返回一个注册ID,如果函数没有再次注册的话。如果函数还没有注册,它将注册函数,并返回函数的注册ID。
原型
Excel12(xlfRegisterId, LPXLOPER12 pxRes, 3, LPXLOPER12 pxModuleText,
LPXLOPER12 pxProcedure, LPXLOPER12 pxTypeText);
参数
pxModuleText (xltypeStr)
包含函数的 DLL 名称
pxProcedure (xltypeStr or xltypeNum)
要调用的函数的名称,也可以用序号数表示。通常为了更容易识别,都是使用的名称。
pxTypeText (xltypeStr)
一个可选的字符串,指定函数的返回值和参数类型。
属性值和返回值
返回函数的注册ID,此ID可用于随后的 xlfUnregister 函数。
备注
这个函数通常在你不需要担心维护注册ID,但之后要反注册的情况下使用。它通常用于当你在DLL中需要访问菜单,工具以及按钮时使用。
当 DLL 或 XLL 函数使用 xlfRegister 注册,但应用了有效的 pxFunctionText 参数时,它的注册ID可以通过传送 pxFunctionText 参数给 xlfEvaluate 获取。