![](/img/trans.png)
[英]Interesting issue with ADODB connection: UDF using ADODB works fine when called from VBA code, but it returns error when called from EXCEL cell
[英]Excel VBA: UDF results in #NAME? error when called from cell
我從本指南中復制了一些符合我目的的 UDF function 代碼,據說這些代碼對其他人有用。 我並沒有真正改變代碼,但為了透明,這里是我在工作簿中作為模塊的確切代碼:
Function IsExtWorkBookOpen(Name As String) As Boolean
Dim xWb As Workbook
On Error Resume Next
Set xWb = Application.Workbooks.Item(Name)
IsExtWorkBookOpen = (Not xWb Is Nothing)
End Function
現在,當我在工作簿的單元格中輸入 function 時,function 將作為選項出現在下拉列表中。 我按下制表符自動填充 UDF 的全名,以確保正確鍵入 function 名稱。 然后,我在不同的單元格中多次調用 function 並使用不同的文件名/路徑作為字符串,例如:
=IsExtWorkBookOpen("C:\Computer\Fake\filepath\name\CORRECTLY SPELLED FULL FILENAME.xlsm")
=IsExtWorkBookOpen("C:\Computer\Fake\filepath\name\[CORRECTLY SPELLED FULL FILENAME].xlsm")
=IsExtWorkBookOpen("[CORRECTLY SPELLED FULL FILENAME]")
嘗試使用或不使用文件名周圍的括號。 而且我已經在這里編輯了文件路徑/名稱,它是我代碼中的實際文件路徑和文件名。 請注意,我的代碼中的文件路徑指向的驅動器是網絡目錄,而不是 PC 硬件中的本地目錄。
還嘗試添加以下內容作為第二個參數: Optional VolatileParameter As Variant
並調用 NOW() 作為第二個參數,以查看它是否與需要 volatile 的 UDF 有關。 令我沮喪的是,似乎沒有任何效果,因為單元格中的結果值始終是#NAME。
不過這很奇怪,因為我在 VBA 編輯器中測試了我的代碼,方法是插入一個過程,在過程中調用 UDF,在 UDF 中放置斷點並運行該過程。 這是代碼:
Public Sub Test1()
Dim x
x = IsExtWorkBookOpen("EXTERNAL WORKBOOK.xlsm")
MsgBox (x)
End Sub
該過程完美運行,並返回 FALSE 值。 在斷點期間無法注意到注冊表中的任何內容。 盡管我確實注意到即使我正在檢查的外部工作簿實際上是打開的,它似乎也會返回 FALSE ......所以這可能是一個比試圖弄清楚為什么 function 在輸入單元格時無法工作更大的問題。
更奇怪的是,我第一次將 function 輸入到單元格中,它確實返回並顯示 FALSE,但只是第一次。 自從#NAME。
我嘗試爬取 web 尋找類似的編程錯誤,我發現最接近的是這個論壇帖子。 似乎與這個用戶的 UDF 一樣,我的甚至沒有執行,因為 excel 從一開始就不知道如何執行它?
最后,我注意到“喬”在第一個網頁上的以下評論,我從那里復制了代碼,其中指出:
只是想確保每個人都知道,“IsWorkBookOpen”function 將只能判斷當前 Excel 實例中是否打開了工作簿。 如果您打開了多個實例,則需要在每個實例上運行它,以確保工作簿(未)打開,僅使用此代碼。
閱讀此評論,此代碼是否注定從一開始就為我的目的工作? 我仍然對此表示懷疑,因為即使我嘗試使用當前工作簿(不是外部工作簿)(VBA 模塊所在的工作簿)的正確拼寫文件名調用 UDF,也會發生 #NAME 錯誤,這讓我相信這個錯誤是代碼功能的其他地方。
如果是這樣,任何人都可以提示我需要什么代碼才能成功執行我的 function 以檢查是否在同一本地 PC/桌面中打開了另一個工作簿?
該 UDF 對我來說很好,但請注意Application.Workbooks.Item()
需要工作簿名稱而不是完整路徑,所以
=IsExtWorkBookOpen("tempo3.xlsb")
返回 TRUE 但
=IsExtWorkBookOpen("C:\Temp\tempo3.xlsb")
給出錯誤。
請注意,如果您想了解工作簿是否在同一實例或 Excel 的不同實例中打開,您可以使用GetObject
采取不同的方法(注意這里您將傳遞完整路徑):
Function IsExtWorkBookOpen2(Name As String) As Boolean
Dim xWb As Object
On Error Resume Next
Set xWb = GetObject(Name)
If Not xWb Is Nothing Then Debug.Print xWb.Name
IsExtWorkBookOpen2 = (Not xWb Is Nothing)
End Function
我建議你重寫 function 如下:
Option Explicit
Function IsWorkbookOpenByName(name As String) As Boolean
Dim wb As Workbook
For Each wb In Application.Workbooks ' Loop through all open workbooks
If wb.Name = name Then ' If a workbook is found with specified name (name + extension)...
IsWorkbookOpenByName = True ' ... return true...
Exit For ' ... and exit loop.
End If
Next
End Function
Function IsWorkbookOpenByFullName(fullName As String) As Boolean
Dim wb As Workbook
For Each wb In Application.Workbooks ' Loop through all open workbooks
If wb.FullName = fullName Then ' If a workbook is found with specified fullName (path + name + extension)...
IsWorkbookOpenByFullName = True ' ... return true...
Exit For ' ... and exit loop.
End If
Next
End Function
上面的代碼已經過測試並且可以工作。
如果您只想將這些函數組合在一個中,只需將第一個 function 中的If
語句更改為If wb.Name = name or wb.FullName = name
:
Option Explicit
Function IsWorkbookOpen(name As String) As Boolean
Dim wb As Workbook
For Each wb In Application.Workbooks ' Loop through all open workbooks
If wb.Name = name or wb.FullName = name Then ' If a workbook is found with specified name or fullname...
IsWorkbookOpen = True ' ... return true...
Exit For ' ... and exit loop.
End If
Next
End Function
使用最后一個 function,您可以傳遞名稱或全名(名稱 + 路徑 + 擴展名)。
注 1:我強烈建議您對所有 VBA 代碼使用Option Explicit
。 此預處理器命令強制 VBA 解釋器(請記住 VBA 並未真正編譯)要求所有變量聲明。 這可以防止拼寫錯誤,並且可以為您節省數小時的調試時間來尋找某個變量名中缺少的字符。 此外,它將使您的代碼更可靠,這是一個健康的習慣。
注意 2:如果可能,請避免使用On Error Resume Next
語句,因為它可能有害。 即使發生錯誤,該語句“授權”代碼繼續執行,因此您可能會從代碼中獲得意外結果,並且如果它是復雜的 function,則可能難以調試。
我這么說是因為 VBA 是我的第一個編程語言,不幸的是沒有人告訴我這些方面。 我了解到改變壞習慣比按時學習好習慣更難:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.