名稱是Excel中的一項強大功能,無論是在公式中還是在VBA中運用名稱,都能帶來極大的便利。
本文主要談談在Excel中不被注意到的一些名稱的使用。
Excel內置的名稱
Excel有一些內置的名稱,它們會在特定的環境下自動使用。
例如,設置打印區域后,Excel會自動命名打印區域為Print_Area,如下圖1所示。
圖1
如果設置打印標題,則Excel會創建名稱Print_Titles。
又如,在使用高級篩選獲取不重復值列表時,Excel會自動創建名稱Extract,如圖2所示。
圖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