web-dev-qa-db-ja.com

VBAの隠された機能

VBA言語のどの機能が不十分に文書化されているか、または単に頻繁に使用されていませんか?

29
guillermooo

このトリックはAccess VBAでのみ機能し、Excelなどでは許可されません。ただし、モジュール名の前にアンダースコアを付けることで、オブジェクトブラウザから標準モジュールを非表示にすることができます。モジュールは、オブジェクトブラウザを変更して非表示のオブジェクトを表示する場合にのみ表示されます。

このトリックは、VBAのすべてのvb6ベースバージョンのEnumで機能します。 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では、セルを角かっこで囲むことでセルを参照できます。角かっこは 評価コマンド としても機能し、数式構文を評価できます。

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

8進数および16進数リテラルは実際には符号なしの型であり、これらは両方とも-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
32
Oorang

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
18
Swanny

VBA自体は隠された機能のようです。 Office製品を何年も使用している人なら、それがスイートの一部であることすら知りません。

ここに複数の質問でこれを投稿しましたが、オブジェクトブラウザは私の秘密の武器です。忍者のコードをすばやく作成する必要があるが、dllに慣れていない場合、Object Browserを使用すると命が救われます。クラス構造を学ぶことは、MSDNよりはるかに簡単になります。

Localsウィンドウはデバッグにも最適です。コードを一時停止すると、現在のネームスペース内のすべての変数、その名前、現在の値とタイプが表示されます。

そして、誰が私たちの親友イミディエイトウィンドウを忘れることができますか? Debug.Printの標準出力に最適なだけでなく、コマンドを入力することもできます。 VariableXが何であるかを知る必要がありますか?

?VariableX

そのセルの色を知る必要がありますか?

?Application.ActiveCell.Interior.Color

実際、これらのウィンドウはすべて、VBAで生産性を高めるための優れたツールです。

15
mandroid

これは機能ではありませんが、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
13
Dirk Vollmar

隠された機能

  1. 「基本」ですが、OOP-クラスとオブジェクト
  2. API呼び出しを行うことができます
7
Raj More

おそらく、VBAで最もドキュメント化されていない機能は、VBAオブジェクトブラウザーで[非表示のメンバーを表示]を選択することによってのみ公開できる機能です。非表示のメンバーは、VBAにあるがサポートされていない機能です。それらは使用できますが、Microsoftはいつでもそれらを削除する可能性があります。いずれのドキュメントも提供されていませんが、Web上で見つけることができます。おそらく、これらの隠された機能の中で最も話題になっているものは、VBAのポインターへのアクセスを提供します。まともな評価については、チェックしてください。 それほど軽量ではない-Shlwapi.dll

文書化されていますが、おそらく(Excelでは)よりわかりにくいのは、ExecuteExcel4Macroを使用して、特定のブックではなく、Excelアプリケーションインスタンス全体に属する非表示のグローバル名前空間にアクセスすることです。

7
DaveParillo

Implementsキーワードを使用してインターフェースを実装できます。

6
guillermooo

辞書。 VBAはそれらなしでは実質的に価値がありません!

Microsoft Scripting Runtimeを参照し、Scripting.Dictionaryを使用して十分に複雑なタスクを実行し、その後も幸せに生き続けます。

Scripting RuntimeはFileSystemObjectも提供しますが、これも強くお勧めします。

ここから始めて、少し掘り下げて...

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

6
eksortso

VBA.と入力すると、すべての組み込み関数と定数のインテリセンスリストが表示されます。

5
CtrlDot

少しの作業で、次のようなカスタムコレクションを反復処理できます。

' 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
4
guillermooo
  • debug.? xxxの代わりにdebug.print xxxと入力して、キーストローク全体を4回保存します。
  • 他のコードを含むモジュールの先頭にenum foo: me=0: end enumを追加してクラッシュさせます。
4
Alex K.

ローカライズされた値を使用する式を(少なくとも前世紀に)サポートしたローカライズされたバージョンのサポート。 TrueのPravdaやFałszywy(あまり確かではありませんが、少なくとも面白いLがあります)のように、ポーランド語ではFalseになります。ただし、他のローカライズバージョンでは処理できません。

不合格。

3
Arjan

IsDate("13.50")Trueを返しますが、IsDate("12.25.2010")Falseを返します

これは、IsDateをより正確にIsDateTimeと命名できるためです。そして、期間(.)は、日付区切り記号ではなく時刻区切り記号として扱われます。 完全な説明はこちら を参照してください。

2
mwolfe02

VBE(Visual Basic Extensibility)オブジェクトモデルは、あまり知られていない、または十分に活用されていない機能です。 VBAコード、モジュール、プロジェクトを操作するVBAコードを記述できます。モジュールファイルのグループから他のExcelプロジェクトを組み立てるExcelプロジェクトを書いたことがあります。

オブジェクトモデルは、VBScriptおよびHTAからも機能します。一度にHTAを作成して、多数のWord、Excel、およびAccessプロジェクトを追跡できるようにしました。プロジェクトの多くは共通のコードモジュールを使用し、モジュールが1つのシステムで簡単に「成長」し、他のシステムに移行する必要がありました。 HTAを使用すると、プロジェクト内のすべてのモジュールをエクスポートし、それらを共通フォルダー内のバージョンと比較し、更新されたルーチンをマージして(BeyondCompareを使用)、更新されたモジュールを再インポートできます。

VBEオブジェクトモデルは、Word、Excel、およびAccessの間でわずかに異なる動作をし、残念ながらOutlookではまったく動作しませんが、それでもコードを管理するための優れた機能を提供します。

2
Todd

VBAは、2つの値の2進数字(ビット)を比較するためのビット演算子をサポートしています。たとえば、式4 And 7は4(0100)と7(0111)のビット値を評価し、4(両方の数値でオンになっているビット)を返します。同様に、式4 Or 8は4(0100 )および8(1000)および12(1100)、つまりどちらかが真であるビットを返します。

残念ながら、ビット比較演算子は論理比較演算子で同じ名前を持っています:And、Eqv、Imp、Not、Or、およびXor。これはあいまいさ、さらには矛盾した結果につながる可能性があります。

例として、イミディエイトウィンドウを開き(Ctrl + G)、次を入力します。 (2 And 4)2(0010)と4(0100)の間に共通のビットがないため、これはゼロを返します。

1
ph mrnt

Deftypeステートメント

この機能は、おそらく後方互換性のために存在します。または、絶望的に難読化されたスパゲッティコードを書くこと。あなたのピック。

0
mwolfe02