【问题标题】:How to make VBA function "VBA only" and disable it as UDF如何使 VBA 功能“仅限 VBA”并将其禁用为 UDF
【发布时间】:2012-06-24 17:39:19
【问题描述】:

我正在编写一个 VBA 函数,我希望在同一文档中的其他 VBA 模块中公开可用,但我不希望它作为 UDF(用户定义的函数)提供。

如果我使用公共访问修饰符,我的函数也可以作为 UDF 公式使用,可以从工作簿中的单元格调用。我不想要这个。

是否有访问修饰符或其他方式可以帮助我获得这种“仅限 VBA”的行为?

亲切的问候

【问题讨论】:

  • 你能更详细地了解这个函数的作用吗?这可能有助于建议使用 VBA 类的方法,这些类仅是 VBA,不能从工作表初始化。至少将预期的输入参数显示为输出值。
  • 检查函数内application.caller的类型名称。尚未对此进行测试,但我认为它应该允许检查是否从单元格调用函数。

标签: excel vba excel-2007 user-defined-functions


【解决方案1】:

如果您在函数出现的模块中使用Option Private Module,则该函数可以声明为Public,并在您的VBA项目中的任何其他模块中使用,但其他应用程序无法访问或项目,包括 Excel 本身。

【讨论】:

    【解决方案2】:

    如果在 Excel 中使用,这将返回 #VALUE 错误。

    Function VBAOnly() As Variant
    
        If TypeName(Application.Caller) <> "Range" Then
            VBAOnly = 1 'or some other return value
        Else
            VBAOnly = CVErr(xlErrValue)
        End If
    
    End Function
    

    【讨论】:

    • xlErrName 会更好:)
    • 谢谢,但我曾希望存在一种机制,使该函数对电子表格不可见。这样该函数仍然可见(例如在自动完成中),它只是返回一个错误。这不是我想的 100%。
    • +1 对迪克的建议。 @Skifozoa 根据 KFleschner 的评论,将其设为 Private Function
    • 我不知道有什么方法可以让它对 UI 完全不可见,但仍然可以从其他模块访问。我对 XLL 知之甚少,但它们可能会提供这种灵活性——可能比它的价值还多。作为最后的努力,您可以向我们展示该功能,也许有人可以想到一些聪明的东西。
    【解决方案3】:

    不要写Function,而是写Sub,并通过ByRef 参数设置返回值。这样,您的函数将对 Excel 不可见(通过 Alt F8 或开发人员选项卡 > 宏除外)并且不会出现在 Excel 的智能感知中。

    代替

    Function Add(Num1 As Double, Num2 As Double)
        Add = Num1 + Num2
    End Function
    

    使用

    Sub AddInvisible(ByRef Result As Double, Num1 As Double, Num2 As Double)
        Result = Num1 + Num2
    End Sub
    

    注意

    1. ByRef 不是绝对必要的(因为参数在 VBA 中默认通过引用),但它可以作为有用的提醒,Result 带有返回值。
    2. 您需要对代码进行必要的更改,例如:

      z = Add(x,y)

    会变成

    AddInvisible z,x,y

    如下所示:

    Sub DemoAddInvisible()
    
        Dim Num1 As Double
        Dim Num2 As Double
        Dim Result As Double 'Result initialises to 0
    
        Num1 = 1
        Num2 = 2
        AddInvisible Result, Num1, Num2
    
        MsgBox Result ' See that Result has become 3
    
    End Sub
    

    所有这些的缺点是新代码有点难以理解。

    【讨论】:

    • @philp Swannell 如果没有定义Result,您将如何调用 AddInVisible 宏?也许展示一个完整的例子?
    • @PGSystemTester 我已经修改了我的答案以显示一个示例。
    • 我明白了。感谢您的澄清。这是一个聪明的主意。但是,我认为它有点失去了功能的“感觉”,您拥有一种机制,您只需将某些东西放入......并获得结果。您需要确保相同的变量范围正确。您还需要在每次运行时将Result 重置为零。无论如何......很酷的想法。即使我永远不会真正使用它,我也给了你一个赞成票?
    【解决方案4】:

    答案之间有点混乱,所以这里有一个更全面的解释:

    技术上...如果输入了准确的公式,则可以调用标准 VBA 模块中的所有函数。 Private Functions 内的偶数公式 Private Modules

    例子

    Option Private Module
    Private Function hiddenEverythingExample() As String
        hiddenEverythingExample= "NOPE!!!"
    End Function
    

    如果单元格有=hiddenEverythingExample(),仍然会返回一个值

    但是,我认为 OP 的目标是避免让 itellisense 在 Excel 公式栏中填充这些函数。

    我最常用的方法是为所有 VBA-Only 函数创建一个特定的模块,并将 Option Private Module 放在模块定义中(函数上方的区域)。

    这确保了该模块中的所有功能都不会出现在 itellisense 中,但仍然可以与 itellisense 一起被其他模块访问。

    定义为Private Function 也可以实现这一点,但是该功能的范围仅限于该模块,这可能是也可能不是要求。

    请注意,YowE3K 推断一个函数必须同时是 Private Function AND Option Private Module,但只有一个 OR 是消除 itellisense 所必需的。 p>

    【讨论】:

      【解决方案5】:

      传递一个参数,该参数只允许函数在“magic*”值被赋予时运行。

      示例 - 这将给出错误 #NAME!,除非您知道 key 是什么:

      Function VBAOnly(key As Long)
      
      If key <> 12345 Then
          VBAOnly = CVErr(xlErrName)
          Exit Function
      End If
      
      VBAOnly = True
      
      End Function
      

      【讨论】:

        【解决方案6】:

        使用Private 修饰符应该只允许在该函数所在的模块中执行。

        【讨论】:

        • 不是这样。粗略测试表明,Private 函数可以从 Excel 访问。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-29
        • 2018-05-23
        相关资源
        最近更新 更多