excel表格名称的秘密
名称是Excel中的一项强大功能,无论是在公式中还是在VBA中运用名称,都能带来极大的便利。
本文主要谈谈在Excel中不被注意到的一些名称的使用。
Excel内置的名称
Excel有一些内置的名称,它们会在特定的环境下自动使用。
例如,设置打印区域后,Excel会自动命名打印区域为Print_Area,如下图1所示。
图1
如果设置打印标题,则Excel会创建名称Print_Titles。
又如,在使用高级筛选获取不重复值列表时,Excel会自动创建名称Extract,如图2所示。
图2
如果在使用高级筛选时,使用了条件,除了名称Extract外,Excel还会自动将条件区域命名为Criteria,如图3所示。
图3
Excel还有其它一些内置名称,例如:Consolidate_Area、Database、FilterDatabase、Sheet_Title,等等。
因此,在VBA代码中,如果出现了上述名称,你不必感到奇怪。例如,下面的语句删除当前工作表中已经设置的打印区域:
ActiveSheet.Names(“Print_Area”).Delete
在《经典代码解析5:查找并显示部分匹配的数据》中,VBA代码将名称“Extract”定义为常量,在筛选完成后,再将该名称代表的区域删除,即作为临时数据区域。
Excel中隐藏的名称空间
认识Excel隐藏的名称空间
Excel隐藏的名称空间是一个属于当前Excel实例的内存区域,该区域加载项DLLS(“XLLS”)能够存储临时的名称。使用这个区域,即便没有可利用的宏工作表,XLLs也能够定义名称。
隐藏着的名称操作基于XLM函数SET.NAME、GET.NAME和EVALUATE。当在XLM宏工作表中使用时,SET.NAME定义一个标准的工作表级名称;当它在XLL中被调用时,创建一个应用程序级名称并且将其存储在一个被隐藏的区域中。
与隐藏着的名称相关的可用的C API命令如下:
Excel4(xlfSetName,&xResult,2,&xName,&xValue);
定义包含xValue的名称xlName。
Excel4(xlfGetName,&xResult,1,&xName);
获取xlName的定义(例如,“=1”),并将其存储在xResult中。
Excel4(xlfEvaluate,&xResult,1,&xName);
获取xlName的内容(例如,1)并将其存储在xResult中。
Excel4(xlfSetName,&xResult,1,&xName);
删除xlName(忽略第二个参数)。
定义在隐藏区域的名称有一些特殊功能,这使得它们与标准工作簿名称有很大的不同。
隐藏的名称空间的特征
在隐藏的名称空间中所定义的名称不属于任何工作簿,而属于应用程序本身。
在Excel的任何地方可以直接访问这些名称。无论在哪个工作簿中创建了这个名称,在任何工作簿中的任何VBA模块、工作表或宏工作表(和任何DLL加载项)中都能直接读取和修改它们。
隐藏的名称的“生存时间”与当前Excel会话一致。
如果你在工作簿WB1.xlsx中某个VBA模块中创建了一个名称,然后关闭了这个工作簿,那么该名称仍然存储在隐藏的命名空间中。如果你接着打开另一个工作簿WB2.xlsx,那么该工作簿的VBA过程仍能获取和修改这个隐藏的名称,即便它是在WB1.xls中所创建的。如果没有被任何VBA加载项所限制的话,那么在隐藏的名称空间中所定义的名称能被用作永久的“公共变量”访问。
对于这些属于应用程序的隐藏的名称,关闭所有工作簿和加载项不会销毁它们。它们仅能通过对SET.NAME(如果没有第二个参数)明确的调用或者通过退出并重启Excel被销毁。在这种情况下,这些名称能被用作一种Excel的环境变量。
它们是完全隐藏的。当一个受保护的加载项使用这个隐藏的名称空间时,新的名称不能被任何其它的VBA模块读取,也不能被用户读取,除非他们知道它们的身份证书。没有方法“列出”定义在隐藏命名空间中的名称。
这些名称无须与标准的隐藏名称(工作簿或工作表名称的.Visible属性已设置为False)混淆。标准的工作簿级的名称决不会真正的被隐藏,因为它们能通过使用Application.Names集合的任何VBA程序来获取和修改,如下面的代码所示:
Dim CName As Name
For Each CName In Workbooks(“WB1.xlsm”).Names
If CName.Hidden Then
MsgBox CName.Name & ” 被删除”
CName.Delete
End If
Next CName
上面的代码,在工作簿WB1.xlsm的所有名称中循环,并删除它们中隐藏的名称。然而,这些代码不能发现存储在隐藏名称空间中的名称,因为这些名称不属于Application.Names集合。因此,它们被保护以反对任何恶意的访问或修改。
在VBA中访问隐藏的名称空间
创建一个隐藏的名称
下面的语句创建一个包含字符串“OK”的名为Test的隐藏的名称:
Application.ExecuteExcel4Macro”SET.NAME(“”Test””,””OK””)”
获取一个隐藏名称的内容
下面的语句获取名称“Test”所代表的内容:
TestVal = Application.ExecuteExcel4Macro(“Test”)
只是使用名称本身作为ExecuteExcel4Macro的参数。
删除一个隐藏的名称
下面的语句删除名称“Test”:
Application.ExecuteExcel4Macro”SET.NAME(“”Test””)”
忽略了SET.NAME的第二个参数。
在工作表中访问隐藏的名称空间
在工作表中也可以直接访问隐藏的名称,必须使用SET.NAME和EVALUATE与CALL()和API函数Excel4组合在一起。函数SET.NAME和EVALUATE的编号分别是88和257。
创建一个隐藏的名称
下面创建一个包含字符串“OK”的名为Test的隐藏的名称:
=CALL(“Xlcall32″,”Excel4″,”2JRJRR#”,88,,2,”Test”,”OK”)
获取一个隐藏名称的内容
下面获取名为“Test”的名称的内容:
=CALL(“Xlcall32″,”Excel4″,”2JRJR#”,257,,1,”Test”)
删除一个隐藏名称
下面删除名称“Test”:
=CALL(“Xlcall32″,”Excel4″,”2JRJRR#”,88,,1,”Test”)
在工作表公式中直接定义和删除名称是可能的,因为SET.NAME不是一个命令而是一个宏函数。
在宏工作表中能以相同的方式使用隐藏的名称,除了不需要给类型字符串添加数字标志外。
示例
下面的代码演示了在受保护的VBA加载项中隐藏的名称空间的可能的用途。
它限制用户在相同的Excel会话中执行加载项主过程超过3次。没有在一个模块级的变量中存储允许剩余执行的计数器,也没有将其存储在依赖加载项的名称中,而是存储在这个隐藏的命名空间中。
使用名称空间阻止用户中断保护,修复了传统方法的下列缺点:
像所有变量一样,存储在VBA中的计数器可以在VBE中手工清除。
同样,任何外部子过程遍历加载项的Names集合,可以读取、修改和删除中所有隐藏的或者未隐藏的工作簿名称。
隐藏的名称空间避免了这些危险,它也比基于环境字符串的实例、临时文件或注册输入等方法更简单,而且隐藏的名称空间是永久的,用户能关闭和重新打开该工作簿而无须重新设置这个计数器。
在下面的代码中,函数SetHName、GetHName和DelHName允许创建、获取和删除隐藏的名称,而无须直接使用冗长的Application.ExecuteExcel4Macro方法。
Sub Main()
Application.EnableCancelKey = xlDisabled
Dim Count
Count = GetHName(“TswbkCount”)
If IsError(Count) Then
SetHName “TswbkCount”, 3
ElseIf Count = 1 Then
MsgBox “宏被禁止. 你必须重新启动Excel.”, vbInformation
Else
SetHName “TswbkCount”, Count – 1
End If
End Sub
Sub SetHName(Name As String, Value)
Application.ExecuteExcel4Macro _
“SET.NAME(“”” & Name &”””,” & Value & “)”
End Sub
Function GetHName(Name As String)
GetHName = Application.ExecuteExcel4Macro(Name)
End Function
Sub DelHName(Name As String)
Application.ExecuteExcel4Macro”SET.NAME(“”” & Name & “””)”
End Sub