VBA的隐藏功能

时间:2009-07-01 19:21:15

标签: vba hidden-features

VBA语言的哪些功能要么记录不清,要么根本不常用?

16 个答案:

答案 0 :(得分:32)

此技巧仅适用于Access VBA,Excel和其他人不允许使用。但是,您可以通过在模块名称前加下划线来使对象浏览器隐藏标准模块。只有在您更改对象浏览器以显示隐藏对象时,才会显示该模块。

这个技巧适用于所有基于vb6的VBA版本中的Enums。您可以通过在括号中包含它的名称来创建Enum的隐藏成员,然后在其前面添加下划线。例如:

Public Enum MyEnum
    meDefault = 0
    meThing1 = 1
    meThing2 = 2
    meThing3 = 3
    [_Min] = meDefault 
    [_Max] = meThing3 
End Enum

Public Function IsValidOption(ByVal myOption As MyEnum) As Boolean
    If myOption >= MyEnum.[_Min] Then IsValidOption myOption <= MyEnum.[_Max]
End Function

在Excel-VBA中,您可以通过将单元格括在括号中来引用单元格,括号也可以作为evaluate command使用,以便您评估公式语法:

Public Sub Example()
    [A1] = "Foo"
    MsgBox [VLOOKUP(A1,A1,1,0)]
End Sub

此外,您可以通过将LSet与相同大小的用户定义类型相结合来传递原始数据,而无需使用MemCopy(RtlMoveMemory):

Public Sub Example()
    Dim b() As Byte
    b = LongToByteArray(8675309)
    MsgBox b(1)
End Sub

Private Function LongToByteArray(ByVal value As Long) As Byte()
    Dim tl As TypedLong
    Dim bl As ByteLong
    tl.value = value
    LSet bl = tl
    LongToByteArray = bl.value
End Function

Octal&amp; Hex Literals实际上是无符号类型,它们都输出-32768:

Public Sub Example()
    Debug.Print &H8000
    Debug.Print &O100000
End Sub

如上所述,在括号内传递变量会导致它传递ByVal:

Sub PredictTheOutput()
    Dim i&, j&, k&
    i = 10: j = i: k = i
    MySub (i)
    MySub j
    MySub k + 20
    MsgBox Join(Array(i, j, k), vbNewLine), vbQuestion, "Did You Get It Right?"
End Sub

Public Sub MySub(ByRef foo As Long)
    foo = 5
End Sub

您可以将字符串直接分配到字节数组中,反之亦然:

Public Sub Example()
    Dim myString As String
    Dim myBytArr() As Byte
    myBytArr = "I am a string."
    myString = myBytArr
    MsgBox myString
End Sub

“Mid”也是一名运营商。使用它可以覆盖字符串的特定部分而无需VBA众所周知的慢字符串连接:

Public Sub Example1()
    ''// This takes about 47% of time Example2 does:
    Dim myString As String
    myString = "I liek pie."
    Mid(myString, 5, 2) = "ke"
    Mid(myString, 11, 1) = "!"
    MsgBox myString
End Sub

Public Sub Example2()
    Dim myString As String
    myString = "I liek pie."
    myString = "I li" & "ke" & " pie" & "!"
    MsgBox myString
End Sub

答案 1 :(得分:18)

Mid()语句有一个重要但几乎总是错过的功能。这就是Mid()出现在赋值的左侧而不是出现在右侧或表达式中的Mid()函数的位置。

规则是如果目标字符串不是字符串文字,并且这是对目标字符串的唯一引用,并且插入的段的长度与要替换的段的长度匹配,则字符串将被视为可操作的可变。

这是什么意思?这意味着如果您将一个大型报表或一个庞大的字符串列表构建到单个字符串值中,那么利用它将使您的字符串处理更快。

这是一个受益于此的简单课程。它为您的VBA提供了与.Net相同的StringBuilder功能。

' Class: StringBuilder

Option Explicit

Private Const initialLength As Long = 32

Private totalLength As Long  ' Length of the buffer
Private curLength As Long    ' Length of the string value within the buffer
Private buffer As String     ' The buffer

Private Sub Class_Initialize()
  ' We set the buffer up to it's initial size and the string value ""
  totalLength = initialLength
  buffer = Space(totalLength)
  curLength = 0
End Sub

Public Sub Append(Text As String)

  Dim incLen As Long ' The length that the value will be increased by
  Dim newLen As Long ' The length of the value after being appended
  incLen = Len(Text)
  newLen = curLength + incLen

  ' Will the new value fit in the remaining free space within the current buffer
  If newLen <= totalLength Then
    ' Buffer has room so just insert the new value
    Mid(buffer, curLength + 1, incLen) = Text
  Else
    ' Buffer does not have enough room so
    ' first calculate the new buffer size by doubling until its big enough
    ' then build the new buffer
    While totalLength < newLen
      totalLength = totalLength + totalLength
    Wend
    buffer = Left(buffer, curLength) & Text & Space(totalLength - newLen)
  End If
  curLength = newLen
End Sub

Public Property Get Length() As Integer
  Length = curLength
End Property

Public Property Get Text() As String
  Text = Left(buffer, curLength)
End Property

Public Sub Clear()
  totalLength = initialLength
  buffer = Space(totalLength)
  curLength = 0
End Sub

以下是如何使用它的示例:

  Dim i As Long
  Dim sb As StringBuilder
  Dim result As String
  Set sb = New StringBuilder
  For i = 1 to 100000
    sb.Append CStr( i)
  Next i
  result = sb.Text

答案 2 :(得分:15)

VBA本身似乎是一个隐藏的功能。我知道多年来一直使用Office产品的人不知道它甚至是套件的一部分。

我在这里发布了多个问题,但对象浏览器是我的秘密武器。如果我需要忍者快速编写代码,但我不熟悉dll,对象浏览器可以挽救我的生命。它使得学习类结构比MSDN更容易。

Locals Window也非常适合调试。暂停代码,它将显示当前命名空间中的所有变量,名称及其当前值和类型。

谁能忘记我们的好朋友立即窗口?它不仅适用于Debug.Print标准输出,而且您也可以输入命令。需要知道VariableX是什么?

?VariableX

需要知道细胞是什么颜色的?

?Application.ActiveCell.Interior.Color

事实上,所有这些窗口都是使用VBA提高工作效率的好工具。

答案 3 :(得分:13)

这不是一个功能,但是我在VBA(和VB6)中看到过多次错误:在方法调用中添加了括号,它将改变语义:

Sub Foo()

    Dim str As String

    str = "Hello"

    Bar (str)
    Debug.Print str 'prints "Hello" because str is evaluated and a copy is passed

    Bar str 'or Call Bar(str)
    Debug.Print str 'prints "Hello World"

End Sub

Sub Bar(ByRef param As String)

    param = param + " World"

End Sub

答案 4 :(得分:7)

隐藏的功能

  1. 虽然它是“Basic”,但您可以使用OOP - 类和对象
  2. 您可以进行API调用

答案 5 :(得分:7)

可能在VBA中记录最少的功能是您只能通过在VBA对象浏览器上选择“显示隐藏的成员”来公开的功能。隐藏成员是VBA中的那些功能,但不受支持。您可以使用它们,但Microsoft可能会随时消除它们。他们都没有提供任何文件,但你可以在网上找到一些。可能最受关注的这些隐藏功能可以访问VBA中的指针。对于体面的写作,请查看; Not So Lightweight - Shlwapi.dll

已记录,但可能更加模糊(无论如何都是excel)使用ExecuteExcel4Macro来访问属于整个Excel应用程序实例而不是特定工作簿的隐藏全局命名空间。

答案 6 :(得分:6)

您可以使用Implements关键字实现接口。

答案 7 :(得分:6)

词典。没有它们,VBA几乎毫无价值!

参考Microsoft Scripting Runtime,使用Scripting.Dictionary执行任何足够复杂的任务,并且从此过上幸福的生活。

Scripting Runtime还为您提供了FileSystemObject,强烈建议使用它。

从这里开始,然后挖掘一下......

http://msdn.microsoft.com/en-us/library/aa164509%28office.10%29.aspx

答案 8 :(得分:5)

键入VBA.将显示所有内置函数和常量的intellisense列表。

答案 9 :(得分:4)

通过一些工作,您可以迭代这样的自定义集合:

' Write some text in Word first.'
Sub test()
    Dim c As New clsMyCollection
        c.AddItems ActiveDocument.Characters(1), _
            ActiveDocument.Characters(2), _
            ActiveDocument.Characters(3), _
            ActiveDocument.Characters(4)

    Dim el As Range
    For Each el In c
        Debug.Print el.Text
    Next
    Set c = Nothing
End Sub

您的自定义集合代码(在名为clsMyCollection的类中):

Option Explicit

Dim m_myCollection As Collection

Public Property Get NewEnum() As IUnknown
    ' This property allows you to enumerate
    ' this collection with the For...Each syntax
    ' Put the following line in the exported module
    ' file (.cls)!'
    'Attribute NewEnum.VB_UserMemId = -4
    Set NewEnum = m_myCollection.[_NewEnum]
End Property

Public Sub AddItems(ParamArray items() As Variant)

    Dim i As Variant

    On Error Resume Next
    For Each i In items
        m_myCollection.Add i
    Next
    On Error GoTo 0
End Sub

Private Sub Class_Initialize()
    Set m_myCollection = New Collection
End Sub

答案 10 :(得分:4)

  • 通过键入debug.? xxx而不是debug.print xxx来保存4个完整的击键。
  • 通过将enum foo: me=0: end enum添加到包含任何其他代码的模块的顶部来崩溃它。

答案 11 :(得分:3)

支持本地化版本(至少在上个世纪)支持使用本地化值的表达式。像Pravda for True和Fałszywy(不太确定,但至少它确实有滑稽的L)在波兰语中使用False ...实际上,英文版本能够以任何语言读取宏,并在运行中进行转换。其他本地化版本不会处理这个问题。

FAIL。

答案 12 :(得分:2)

VBE(Visual Basic可扩展性)对象模型是一个鲜为人知的和/或未充分利用的特性。它允许您编写VBA代码来操作VBA代码,模块和项目。我曾经写过一个Excel项目,它将从一组模块文件中组装其他Excel项目。

对象模型也适用于VBScript和HTA。我曾经一次写过HTA,以帮助我跟踪大量的Word,Excel和Access项目。许多项目都使用通用代码模块,模块很容易在一个系统中“增长”,然后需要迁移到其他系统。我的HTA允许我导出项目中的所有模块,将它们与公共文件夹中的版本进行比较并合并更新的例程(使用BeyondCompare),然后重新导入更新的模块。

VBE对象模型在Word,Excel和Access之间的工作方式略有不同,遗憾的是根本不能与Outlook一起使用,但仍然提供了管理代码的强大功能。

答案 13 :(得分:2)

IsDate("13.50")返回TrueIsDate("12.25.2010")返回False

这是因为IsDate可以更准确地命名为IsDateTime。并且因为句点(.)被视为时间分隔符而不是日期分隔符。见here for a full explanation

答案 14 :(得分:1)

VBA支持按位运算符,用于比较两个值的二进制数字(位)。例如,表达式4和7计算4(0100)和7(0111)的位值并返回4(两个数字中都打开的位。)类似地,表达式4或8计算4中的位值(0100) )和8(1000)并返回12(1100),即任何一个为真的位。

不幸的是,按位运算符在逻辑比较运算符中具有相同的名称:And,Eqv,Imp,Not,Or和Xor。这可能导致含糊不清,甚至是相互矛盾的结果。

例如,打开立即窗口(Ctrl + G)并输入:     ? (2和4) 这返回零,因为在2(0010)和4(0100)之间没有共同的位。

答案 15 :(得分:0)

Deftype Statements

此功能大概存在于向后兼容性。或者写出绝望的混淆意大利面条代码。你的选择。