现在的位置: 首页 > Excel 杂记 > 正文

特殊隐藏名称(Name) 在 Excel 中的妙用

2014年07月24日 Excel 杂记 ⁄ 共 2909字 ⁄ 字号 暂无评论 ⁄ 阅读 5,077 次

  

前两天我们有一篇文章讲了Excel 名称(Name)及其 VBA 中的使用,  其实在 Excel 中还有一个更为神奇的名称空间,这个被隐藏的名称空间存在于 Excel 应用程序当前实例的一块内存区域中,动态链接库加载项(即 Xll)能够在这块区域中存储临时的名称。通过这个区域,Xll 加载项甚至可以在没有可用宏表的情况下来定义名称。

要操作这个隐藏名称我们需要用到宏表函数中的 SET.NAMEGET.NAME EVALUATE 这三个函数。当 SET.NAME 被应用于宏表中时,创建的名称是工作表级别的(局部名称),而在 Xll 中使用 SET.NAME 所定义的名称是应用程序级别的(注意:不只是工作簿级别的,而是可用于所有工作簿的超全局名称)并且储存在一个隐藏的区域中。

正式以上原因使得定义在被隐藏区域的名称有一些特殊的功能,这使得它们与标准工作簿名称有很大的不同。这些功能我们将在后面进行说明。

   

一、与隐藏着的名称相关的可用 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): 删除xName(忽略第二个参数)。

 

二、在VBA中访问被隐藏的名称空间

  
1、创建一个隐藏的名称

下面的语句创建一个包含字符串“OK”的名为Test的隐藏名称:

Application.ExecuteExcel4Macro "SET.NAME(""Test"",""OK"")"

2、获取一个隐藏名称所代表的内容

为了获取名称Test所代表的内容,使用下面的代码:

TestVal = Application.ExecuteExcel4Macro("Test")

注意,只使用名称本身作为ExecuteExcel4Macro的参数。

3、删除一个隐藏的名称

为了删除名称Test,使用下面的语句:

Application.ExecuteExcel4Macro "SET.NAME(""Test"")"

注意,忽略了SET.NAME中的第二个参数。

    

三、被隐藏的名称空间的特征

   
在被隐藏的名称空间中所定义的名称的主要特征是:它们不属于任何工作簿,而属于应用程序本身,这意味着:

 

1、在 Excel 中的任何地方可以直接访问这些名称

无论在哪个工作簿中创建了这种名称,在任何工作簿中的任何 VBA 模块、工作表 或 宏工作表(和任何DLL加载项)中直接都能直接读取和修改它们。

  

2、它生存周期和当前 Excel 会话一致

如果在工作簿Wbk1.xls中的某个VBA模块中创建了一个名称,然后关闭了这个工作簿,那么该名称仍然存储在被隐藏的命名空间中。如果接着打开另一个工作簿Wbk2.xls,那么这个工作簿的VBA过程仍能获取和修改刚才在Wbk1.xls中所创建的名称。在没有被任何VBA加载项所限制的情况下,在被隐藏的名称空间中所定义的名称能作为永久的“公共变量”访问。

对于这些属于应用程序的隐藏的名称,关闭所有工作簿和加载项不会销毁它们。通过对SET.NAME(没有第二个参数)明确的调用或者退出并重启Excel,才能销毁它们。在这种情况下,这些名称能作为一种Excel的环境变量来使用。

  

3、它们是“完全隐藏的”

当一个受保护的加载项使用这个隐藏的名称空间时, 其他的任何 VBA 模块和用户都不可能在不知道这个名称空间的具体名字的情况下来读取和使用这个名称空间,因为没有任何方法来列出这些被定义在隐藏命名空间中的名称。

这些隐藏的名称和标准的隐藏名称(即将工作簿或工作表名称的 Visible 属性设置为 False)有很大的区别。标准的工作簿/表级的名称不是被真正的被隐藏,因为它们可以通过使用 Application.Names 集合来获取和修改,如下面的代码所示:

    Dim CName As Name
    For Each CName In Workbooks("Wbks1.xls").Names
        If CName.Hidden Then
            MsgBox CName.Name & " deleted"
            CName.Delete
        End If  
    Next CName

上面的代码在工作簿Wbks1.xls所有隐藏的名称中循环并删除它们,但是这些代码不能发现存储在被隐藏的命名空间中的名称,因为这些名称不属于Application.Names集合,因此,它们被保护以反对任何恶意的访问或修改。

 

四、具体示例

 

 下面的代码演示了在受保护的 VBA 加载项中隐藏着的命名空间的可能用途。它限制用户在相同的 Excel 会话中执行加载项主过程超过3次。允许剩余执行次数的计数器没有存储在模块级的变量中,也没有存储在依赖加载项的名称中,而是存储在隐藏的命名空间里。通过排除了传统方法的下列缺点,隐藏的命名空间阻止了用户能够中止保护。

1、像所有变量一样,存储在VBA中的计数器变量能在VBE中手动清除。

2、同样的方式,任何外部过程通过在加载项的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

给我留言

您必须 [ 登录 ] 才能发表留言!