简体   繁体   English

Excel VBA:UDF 导致#NAME? 从单元格调用时出错

[英]Excel VBA: UDF results in #NAME? error when called from cell

I copied some UDF function code that serves my purpose from this guide which supposedly has worked for others.我从本指南中复制了一些符合我目的的 UDF function 代码,据说这些代码对其他人有用。 I didn't really alter the code much, but for transparency here is the exact code I have in my workbook as a module:我并没有真正改变代码,但为了透明,这里是我在工作簿中作为模块的确切代码:

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

Now when I enter the function in a cell of the workbook, the function appears as an option in the dropdown list.现在,当我在工作簿的单元格中输入 function 时,function 将作为选项出现在下拉列表中。 I pressed tab to autofill the full name of the UDF, to ensure the function name is correctly typed.我按下制表符自动填充 UDF 的全名,以确保正确键入 function 名称。 I then called the function several times in different cells with different filenames/paths as strings, such as:然后,我在不同的单元格中多次调用 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]")

tried with or without the brackets around the filename.尝试使用或不使用文件名周围的括号。 And ofc I've redacted the filepath/name here, its an actual filepath and filename in my code.而且我已经在这里编辑了文件路径/名称,它是我代码中的实际文件路径和文件名。 Note that the filepath in my code directs to a drive that is a network directory, not a local directory in the PC's hardware.请注意,我的代码中的文件路径指向的驱动器是网络目录,而不是 PC 硬件中的本地目录。

Also tried adding the following as a second parameter: Optional VolatileParameter As Variant and calling, NOW() as the second parameter to see if it has something to do with the UDF needing to be volatile.还尝试添加以下内容作为第二个参数: Optional VolatileParameter As Variant并调用 NOW() 作为第二个参数,以查看它是否与需要 volatile 的 UDF 有关。 To my dismay, nothing seems to work, as the resulting value in the cells is always #NAME.令我沮丧的是,似乎没有任何效果,因为单元格中的结果值始终是#NAME。

It gets weird though, because I tested my code in the VBA editor by inserting a procedure, calling the UDF in the procedure, placing breakpoints in the UDF and running the procedure.不过这很奇怪,因为我在 VBA 编辑器中测试了我的代码,方法是插入一个过程,在过程中调用 UDF,在 UDF 中放置断点并运行该过程。 Here's the code for that:这是代码:

Public Sub Test1()
    Dim x
    x = IsExtWorkBookOpen("EXTERNAL WORKBOOK.xlsm")
    MsgBox (x)
End Sub

The procedure runs perfectly, and returns a FALSE value.该过程完美运行,并返回 FALSE 值。 Can't notice anything off in the registries during breakpoints.在断点期间无法注意到注册表中的任何内容。 Although I did notice it seems to return FALSE even if the external workbook I am checking is actually open... so thats probably a bigger problem than trying to figure out why the function won't work when entered into a cell.尽管我确实注意到即使我正在检查的外部工作簿实际上是打开的,它似乎也会返回 FALSE ......所以这可能是一个比试图弄清楚为什么 function 在输入单元格时无法工作更大的问题。

Even weirder, is the very first time I entered the function into a cell, it did return and display FALSE, but only the very first time.更奇怪的是,我第一次将 function 输入到单元格中,它确实返回并显示 FALSE,但只是第一次。 ever since just #NAME.自从#NAME。

I tried crawling the web for similar programming bugs and the closest I found was this forum thread.我尝试爬取 web 寻找类似的编程错误,我发现最接近的是这个论坛帖子。 It seems that maybe, as with this user's UDF, mine is not even executing because excel doesn't know how to execute it from the start?似乎与这个用户的 UDF 一样,我的甚至没有执行,因为 excel 从一开始就不知道如何执行它?

Finally, I noticed the following comment by 'Joe' on the first webpage, from where I copied the code, which stated:最后,我注意到“乔”在第一个网页上的以下评论,我从那里复制了代码,其中指出:

Just want to make sure everyone is aware, the "IsWorkBookOpen" function will only be able to tell if a workbook is open in the current instance of Excel.只是想确保每个人都知道,“IsWorkBookOpen”function 将只能判断当前 Excel 实例中是否打开了工作簿。 If you have multiple instances open you would need to run it on each instance to be sure the workbook is (not) open, using this code alone.如果您打开了多个实例,则需要在每个实例上运行它,以确保工作簿(未)打开,仅使用此代码。

Reading this comment, is this code doomed to work for my purpose from the beginning?阅读此评论,此代码是否注定从一开始就为我的目的工作? I still doubt this because the #NAME error happens even when I tried calling the UDF with the correctly spelled filename of the current workbook (not the external one)(the workbook within which the VBA module is) which leads me to believe the bug is elsewhere in the code functionality.我仍然对此表示怀疑,因为即使我尝试使用当前工作簿(不是外部工作簿)(VBA 模块所在的工作簿)的正确拼写文件名调用 UDF,也会发生 #NAME 错误,这让我相信这个错误是代码功能的其他地方。

If so though, can anyone give me a hint as to what code is needed to successfully perform my function that checks if another workbook is open in the same local PC/desktop?如果是这样,任何人都可以提示我需要什么代码才能成功执行我的 function 以检查是否在同一本地 PC/桌面中打开了另一个工作簿?

That UDF works fine for me, though note that Application.Workbooks.Item() wants the workbook name and not the full path, so该 UDF 对我来说很好,但请注意Application.Workbooks.Item()需要工作簿名称而不是完整路径,所以

=IsExtWorkBookOpen("tempo3.xlsb") 

returns TRUE but返回 TRUE 但

=IsExtWorkBookOpen("C:\Temp\tempo3.xlsb") 

gives FALSE.给出错误。

Note you can take a different approach using GetObject if you want to find out if a workbook is open in the same instance or a different instance of Excel (note here you'd pass in the full path):请注意,如果您想了解工作簿是否在同一实例或 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

I suggest you to rewrite that function as follow:我建议你重写 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

The code above is tested and working.上面的代码已经过测试并且可以工作。

If you want to combine these functions in only one, simply change the If statement into If wb.Name = name or wb.FullName = name in the first 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

With this last function you can pass the name or the fullname (name + path + extension).使用最后一个 function,您可以传递名称或全名(名称 + 路径 + 扩展名)。

Note 1: I highly recommend you using Option Explicit for all your VBA code.注 1:我强烈建议您对所有 VBA 代码使用Option Explicit This preprocessor command forces the VBA interpreter (remember that VBA is not really compiled) to require all variable declarations.此预处理器命令强制 VBA 解释器(请记住 VBA 并未真正编译)要求所有变量声明。 This prevent typos and will save you hours of debugging in search of a missing char in some variable name.这可以防止拼写错误,并且可以为您节省数小时的调试时间来寻找某个变量名中缺少的字符。 Also, it will make your code more reliable and it's a healthy habit.此外,它将使您的代码更可靠,这是一个健康的习惯。

Note 2: When possible, avoid the On Error Resume Next statement because it can be harmful.注意 2:如果可能,请避免使用On Error Resume Next语句,因为它可能有害。 That statement "authorizes" the code execution to continue even if errors occurs, so you could get unexpected result from your code and it could be difficult to debug if it's a complex function.即使发生错误,该语句“授权”代码继续执行,因此您可能会从代码中获得意外结果,并且如果它是复杂的 function,则可能难以调试。

I say this because VBA was my first programming language, and unfortunately no one told me about these aspects.我这么说是因为 VBA 是我的第一个编程语言,不幸的是没有人告诉我这些方面。 I learned that changing bad habits is more difficult than learning good practices on time:)我了解到改变坏习惯比按时学习好习惯更难:)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 ADODB连接的有趣问题:从VBA代码调用时,使用ADODB的UDF可以正常工作,但是从EXCEL单元调用时,它将返回错误 - 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执行之前,是否可以访问单元格的值? - Excel vba: Is it possible to access the value of a cell before the UDF called from that cell executes? 从Excel vs VBA调用时,VBA UDF给出了不同的答案 - VBA UDF gives different answer when called from Excel vs VBA 从Excel VBA UDF调用时,Range.Precedents返回范围,而不是其先例。 有解决方法吗? - When called from an Excel VBA UDF, Range.Precedents returns the range and not its precedents. Is there a workaround? 防止在vba Excel工作表删除/添加上调用UDF - Prevent UDF from being called on vba Excel Sheet Deletion/Addition 在VBA中处理UDF中的长字符串时出现#VALUE错误(excel) - #VALUE error when dealing with long string in UDF in VBA(excel) VBA Excel副本名称从左侧的单元格 - VBA Excel copy name from cell to the left 使用VBA for Excel在UDF中输入的名称无效 - Invalid name entered in UDF with VBA for Excel 在 Excel VBA 中使用 UDF 名称中的数字 - use of numbers within name of UDF in Excel VBA 从Excel VBA / Python调用时C ++ dll返回不同的结果 - C++ dll returns different results when called from Excel VBA/Python
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM