23.2 Excel服务器VBA编程接口
Excel服务器客户端组件是在安装目录下的一个文件----ESClient10.dll,它不是VBA程序,而是一个Com加载项,相当于对Excel附加了功能。Com载加项也是一种对象,我们可以在VBA程序中调用它提供的方法(编程接口)。
若要在VBA程序中调用Excel服务器的功能,首先需要声明对象,通过调用对象的方法来完成想要的功能,最后,还需要释放对象。
如下面的代码片断,第1行声明了一个变量对象oAdd,第2行设置该变量为Excel服务器客户端组件所对应的Com加载项。中间部分具体的操作,最后1行释放对象。
若要通过VBA程序操纵Excel服务器,开头的两行和最后的一行代码都是必需的,所不同的只是中间省略的部分。
Dim oAdd As Object
Set oAdd = Application.COMAddIns("ESClient10.Connect").Object
…….
这里可以调用客户端组件的不同方法
…….
Set oAdd = Nothing
23.2.1 自动保存、连续输入
方法说明
saveCase方法,作用是保存当前正在填报的表单。该方法有五个参数:
参数1:要省略
参数2:布尔型,是否省略保存对话框,默认值为False,也即显示保存对话框。
参数3:布尔型,是否询问继续填写下一张,默认值为True,也即询问是否填下一张。
参数4:tempSave为布尔型 ,表示是否暂存True为暂存,False为保存。
参数5:errMsg 为string型, 表示若暂存出错后的报错。
返回值:布尔型,True表示保存成功,False表示保存失败
示例
我们通常用Excel服务器填报完成一张表单后,需要手工点击【保存】工具栏按钮,或选择“文件 保存”菜单,才能保存。对于有大量表单需连续输入的情况,这种做法需要键盘和鼠标交替操作,效率不高。
我们可以通过在Worksheet_selectionChange事件处理程序中调用saveCase方法,使得录入员只需要操作键盘,当数据录入完成,光标跳转到最后一个数据项出,自动保存,出现新的表单等待输入,过程中不需要使用鼠标。
假设有如下的模版,定义三个数据项:x、y和录入时间,其中录入时间有默认值,x和y需要输入。

图30‑5
我们希望录入员的辅助动作次数最少:
输入x,按回车,输入y,按回车,保存成功,提示是否填下一张,按回车(相当于回答【是】),出现新的一张空白表,光标自动回到C2处。
输入一张单据的过程中辅助动作只有三次回车,没有鼠标动作。下面看一下实现方式。
在模版的设计状态下,打开Visual Basic编辑器,在Worksheet_selectionChange事件处理程序中输入如下代码:(为讲解方便,加上了行号)
1 |
Private Sub Worksheet_SelectionChange ( ByVal Target As Range) |
2 |
Dim oAdd As Object |
3 |
Dim bResult As Boolean |
4 |
|
5 |
Set oAdd = Application.COMAddIns ("ESClient10.Connect").Object |
6 |
|
7 |
If Target.Address = "$C$4" Then |
8 |
bResult = oAdd.saveCase (, True, True ) |
9 |
If bResult = False Then |
10 |
MsgBox " 保存失败! " |
11 |
Else |
12 |
Range("C2").Select |
13 |
End If |
14 |
End If |
15 |
|
16 |
Set oAdd = Nothing |
17 |
End Sub |
第1行,Worksheet_SelectionChange为事件处理程序名,它对应于单元区域被选中这一事件。这个事件处理程序有一个参数Target,它代表被选中的单元区域。
第2行,声明对象变量(必须这样写)
第5行,设置变量oAdd对应于Excel服务器客户端组件(必须这样写)
第7行,判断光标跳到的单元格是不是C4,如果不是,直接转到第16行(什么也没做)
第8行,(光标跳到了C4单元格),调用Excel服务器客户端组件提供的saveCase方法,实际保存当前已填好的表单,不弹出保存对话框,但保存后会询问是否继续填写。
第12行,(保存成功)光标跳转到C2处,等待继续输入。
第16行,释放对象(必须这样写)
本例在示例数据库中。
23.2.2 用按钮执行表间公式
方法
execQuery方法,作用是应用指定的表间公式,它只有一个参数,为字符串类型,其内容是一条或若干条表间公式的名称,若要执行的表间公式不止一条,彼此间需要用逗号分割(英文逗号)。
例如:
execQuery(“查询”),表示要执行当前模版上定义的表间公式“查询”
execQuery(“查询,统计”),表示要连续执行当前模版上定义的表间公式“查询”和“统计”。
示例
复习第9章建立的“销售台帐”模板,我们定义了一个手动执行的表间公式“组合条件查询”。在模板上增加一个按钮,如图:

图30‑6
在按钮的Click事件处理程序中写如下代码:
1 |
Private Sub cmdQry_Click () |
2 |
Dim oAdd As Object |
3 |
|
4 |
Set oAdd = Application.COMAddIns ("ESClient10.Connect").Object |
5 |
|
6 |
Range("C4").select |
7 |
oAdd.execQuery (" 组合条件查询 ") |
8 |
|
9 |
Set oAdd = Nothing |
10 |
End Sub |
第2、4行,声明对象变量、赋值(必须这样写)
第6行,光标放置到明细表的第1行
第7行,执行表间公式
第9行,释放对象(必须这样写)
23.2.3 新建表单
方法
用VBA程序来新建一份表单,需要调用如下的接口方法:
NewReport(<模板名称>)
利用NewReport方法,会针对指定模板建立一份空表单。如果需要在建立表单的同时为表单内容赋值,还需要在newReport之前调用addInitData方法:
AddInitData(<目的字段名>,<赋值表达式>)
其中“赋值表达式”可以是本模板的字段名
示例
假设有如下模板,列举所有客户的信息

图30‑10
当点击【录入订单】按钮之后,会打开一份新订单,并且把当前选中(桔黄底色的那一行)的客户信息,自动传递到新订单上。
为了实现上述目的,我们需要做三件事。
首先,我们要识别当前客户是在哪一个。“当前客户”指的是光标所在行的客户。但是,当用户点击按钮的时候,输入焦点在按钮上,也就是说,在按钮的Click事件中无法读取当前行号,所以,需要在点击按钮之前,就把当前行号记录下来。我们的解决方案是,用J2单元格存放当前行号信息,在workSheet_SelectionChange事件中,把当前行号记录到J2单元格中去。也就是说,每当光标在工作表上移动,J2单元格总是随时反映当前的光标所在行号。
类似地,把当前行的客户编号记录到H2单元格,记录它的目的是定义条件格式,使得当前行的底色总是显示成桔黄色。
第三,在【录入订单】按钮的Click事件中,用VBA代码新建订单,并且把当前行的客户信息传递过去,代码如下:
1 |
Private Sub cmdNewOrder_Click () |
2 |
Dim r As Long |
3 |
r = Range("J2") ' 确定当前行号 |
4 |
|
5 |
' 如果当前行没有数据,什么也不做,返回。 |
6 |
If Range("B" & r) = "" Then Exit Sub |
7 |
|
8 |
' 用当前行的数据新建订单 |
9 |
Dim oAdd As Object |
10 |
Set oAdd = Application.COMAddIns ("ESClient10.Connect").Object |
11 |
|
12 |
oAdd.addInitData " 客户编号 ", Range("B" & r) |
13 |
oAdd.addInitData " 客户名称 ", Range("C" & r) |
14 |
oAdd.addInitData " 地址 ", Range("D" & r) |
15 |
oAdd.addInitData " 电话 ", Range("E" & r) |
16 |
|
17 |
oAdd.newReport " 订单 " |
18 |
|
19 |
Set oAdd = Nothing |
20 |
|
21 |
End Sub |
第3行,确定当前行号r。
第6行,如果当前行的客户编号为空,说明当前行不是有效的客户信息,什么也不做,直接退出。
第9~10行,声明接口对象,并赋值。
第12~15行,指定要传递到新表单上的数据。
第17行,新建订单并打开,同时把12~15行指定的数据传递过去。
第19行,释放接口对象。
23.2.4 修改表单
方法
execUpdate(<回写公式名称列表>)
执行指定的一条或多条回写公式
示例
假设有如下模板,列举所有客户的信息。

图30‑11
在这个模板上定义了一条回写公式,把表格中的客户信息更新到客户登记表中去。通常情况下,回写公式只是在保存的时候才执行,但是我们可以写一段VBA代码,让它在点击【修改客户信息】按钮后执行。
1 |
Private Sub cmdUpd_Click () |
2 |
Dim oAdd As Object |
3 |
Set oAdd = Application.COMAddIns ("ESClient10.Connect").Object |
4 |
If oAdd.execUpdate (" 更新客户信息 ") = True Then |
5 |
MsgBox " 客户信息已更新 " |
6 |
End If |
7 |
Set oAdd = Nothing |
8 |
End Sub |
23.2.5 其它程序员用VBA编程接口
- AddInitData
- AddLink
- AddPicture
- DeleteRow
- DeleteColumn
- ExecProc
- ExecQryProc
- GetByDBFunction
- GetLockState
- GetFieldAddress
- GetInstallPath
- InsertRow
- InsertColumn
- IsNotCaseBook
- PrintReport
- ProtectBook
- ReturnWi
- UnProtectBook
以下一些编程接口,仅专业的软件开发人员利用Excel服务器做二次开发时才需要用到。有的需要使用者拥有编程相关的一些背景知识才能正确使用,非专业用户,一般不建议使用。
AddInitData
AddInitDAta(DestFieldName As String, SrcField)
功能:调用NewReport前,使用此函数做数据初始化,将数据填充到新建的表单上。
参数:
参数 |
类型 |
说明 |
DestFieldName | string | 新报表字段名, <字段名> | <表名>.<字段名> |
SrcField | string | 源报表字段名或者值,<字段名> | <表名>.<字段名> | 值 |
insertRow
insertRow(<sheetId>,<base>,<num>)
功能:向明细表中增加行
参数:
参数 |
类型 |
说明 |
sheetId |
integer |
向当前工作簿的哪个 sheet 上增加行。 例如,向第一个 sheet 上增加行,为 1 |
base |
L ong |
基准行的行号。 例如,假设 base=5 ,则表明要在第 5 行之上增加行 |
N um |
long |
所增加的行数 |
返回值:无
调用举例:
insertRow(2,3,4),表示在当前工作簿的第2个sheet上,在第3行之上,增加4个新行
insertColumn
insertColumn(<sheetId>,<base>,<num>)
功能:向明细表中增加列
参数说明:同insertRow
deleteRow
deleteRow(<sheetId>,<base>,<num>)
功能:在明细表中删除行
参数:
参数 |
类型 |
说明 |
sheetId |
integer |
在当前工作簿的哪个 sheet 上删除行。 例如,在第一个 sheet 上删除行,为 1 |
base |
L ong |
基准行的行号。 例如,假设 base=5 ,则表明要从第 5 行开始删除行 |
N um |
long |
所删除的行数 |
返回值:无
调用举例:
deleteRow(2,3,4),表示在当前工作簿的第2个sheet上,从第3行开始,删除以下的4个行(即所删除的行是3,4,5,6,四行)
deleteColumn
deleteColumn(<sheetId>,<base>,<num>)
功能:在明细表中删除列
参数说明:同deleteRow
ExecProc
ExecProc(<ProcName>,<errMsg>,<Args1>,<Args2>,…<Args15>) As Boolean
功能:执行不返回纪录集的存储过程
返回值:
True 成功
False 出错
参数:
参数 |
类型 |
说明 |
procName | String | 要执行的存储过程名称 |
errMsg | string | 引用传递 |
Args1~Args15 | variant | 存储过程需要的参数,任意类型,按存储过程定义的顺序传递 |
调用举例:
ExecProc("p_NoReturn", sErr, ActiveSheet.Range("D2"), ActiveSheet.Range("D3"))
执行当前应用数据库中一个名为“p_NoReturn”的存储过程,改存储过程需要两个参数,分别是 D2 和 D3 单元格的值,如果该存储过程执行出错,错误信息会赋值到变量 sErr。
ExecQryProc
ExecQryProc(<ProcName>,<rset>,<errMsg>,<Args1>,<Args2>,…<Args15>) As Boolean
功能:执行返回纪录集的存储过程
返回值:
True 成功
False 出错
参数:
参数 |
类型 |
说明 |
procName |
String |
要执行的存储过程名称 |
rset |
recordset |
引用传递 如果执行类别为 1 ,则表示返回结果集的变量名 |
errMsg |
string |
引用传递 如果执行出错,返回的错误信息 |
Args1~Args15 |
Variant |
存储过程需要的参数,任意类型,按存储过程定义的顺序传递 |
调用举例:
ExecQryProc("p_withReturn", oRs, sErr, ActiveSheet.Range("D2"), ActiveSheet.Range("D3"))
执行当前应用数据库中一个名为 p_withReturn 的存储过程,该存储过程需要两个参数,分别用D2 和 D3 单元格的内容给这两个参数赋值;该存储过程是一个查询,查询的结果会写到记录集 oRs 中;如果执行出错,错误信息会赋值到变量 sErr 中。
完整示例在示例数据库中。
GetByDBFunction
GetByDBFunction(<funcName>,<rset>,<errMsg><p1>,<p2>,…<pn>)
功能:执行指定的数据库函数
返回值:
True 成功
False 出错
参数:
参数 |
类型 |
说明 |
funcName |
String |
要执行的数据库函数名称 |
rset |
recordset |
引用传递 表示返回结果集的变量名 |
errMsg |
string |
引用传递 如果执行出错,返回的错误信息 |
p1 ~ n |
可变 |
函数需要的参数 |
GetLockState
功能:获取当前表单的锁定状态
参数:无
返回值:
True 已锁定
False 未锁定
GetFieldAddress
GetFieldAddress(<fieldName>,<address>,<startRow>,<startCol>,<endRow>,<endCol>)
功能:返回当前模板上某字段的地址及行列范围
返回值:
True 成功
False 出错
参数:
参数 |
类型 |
说明 |
fieldName |
string |
字段名 |
address |
string |
引用传递 返回的字段地址,为 Excel 的地址格式,如果字段所在的 Sheet 与 ActiveSheet 不同,则返回的地址中带有 Sheet 名称 |
startRow |
long |
引用传递 返回的字段起始行 |
startCol |
long |
引用传递 返回的字段起始列 |
EndRow |
Long |
引用传递 返回的字段终止行 |
EndCol |
Long |
引用传递 返回的字段终止列 |
GetInstallPath
功能:返回Excel服务器软件在本计算机的安装路径
参数:无
返回值:String类型,为安装路径
ProtectBook
功能:
对当前表单加保护。若当前工作簿不是表单,本函数不起作用。通常和AddRow等函数一起使用。
返回值:布尔型,成功为真,出错为假。
参数:无
UnProtectBook
功能:对当前表单解加保护。若当前工作簿不是表单,本函数不起作用。通常和AddRow等函数一起使用。
返回值:布尔型,成功为真,出错为假。
参数:无
IsNotCaseBook
功能:
判断当前工作簿是不是表单。Excel中的任何工作簿,都是三种情况之一:被打开的模板、正填报的表单、普通的Excel文件。可能用户在模板上,会写一些VBA代码,但是希望这些VBA代码只是在填报状态下执行,模板设计下不要执行,为了做到这一点,可以在VBA代码的开头,用此函数判断当前工作簿是不是表单,不是表单,则直接返回。
返回值:布尔型。若当前工作簿不是表单,返回真,否则返回假。
参数:无
AddLink
AddLink(<fileName>,[sh],[r],[c])
功能:向当前表单的当前单元格(或指定单元格)上加入附件
返回值:无
参数:
参数 |
类型 |
说明 |
fileName |
string |
要加入的附件文件名。注意要带全路径 |
sh |
integer |
目的单元格所在的 sheet 序号,第一个 sheet 的序号为 1 。 可以省略。省略的话,指当前 sheet |
r |
long |
目的单元格的行号,可省略。省略的话,指当前焦点所在的单元格。 |
c |
long |
目的单元格的列号,可省略。省略的话,指当前焦点所在的单元格。 |
AddPicture
AddPicture(<fileName>,[sh],[r],[c])
功能:向当前表单的当前单元格(或指定单元格)上插入图片
返回值:无
参数:
参数 |
类型 |
说明 |
fileName |
string |
要加入的图片文件。注意要带全路径 |
sh |
integer |
目的单元格所在的 sheet 序号,第一个 sheet 的序号为 1 。 可以省略。省略的话,指当前 sheet |
r |
long |
目的单元格的行号,可省略。省略的话,指当前焦点所在的单元格。 |
c |
long |
目的单元格的列号,可省略。省略的话,指当前焦点所在的单元格。 |
ReturnWi
ReturnWi(errMsg)
功能:退回任务
参数:
参数 |
类型 |
说明 |
errMsg |
string |
表示若退回出错后的报错 |
返回值:布尔型,成功为真,出错为假
PrintReport
功能:打印当前表单
参数:
参数 |
类型 |
说明 |
useExcelPrint |
Boolean |
是否使用Excel自带打印。默认为False,不使用,即使用用户自定义打印。 |
调用举例:
PrintReport:用本模板上定义的自定义打印格式,打印当前表单。
PrintReport(true):用Excel自身的打印功能,打印当前表单。
PrintReport(false):用本模板上定义的自定义打印格式,打印当前表单。