Application.Run()の謎挙動

Application.Run()の謎挙動

みんな大好きApplication.Run()の変な挙動に気づいたので報告します。

VBA歴10年を超える私ほどの剛の者(ダニング・クルーガー効果)ですら知らなかったのですから、きっと世紀の発見なのだと思います。

Application.Run()とは

Call Application.Run(<プロシージャ名>[, <引数1>, <引数2>, ... ])

の形で、プロシージャを実行することができる面白いメソッドです。

通常の呼び出し

プロジェクトは、このような構成です。

標準モジュールStd01Std02を挿入しています。

リスト1
' Std01モジュール
Private Sub test01()
    Debug.Print "ち~ん(笑)"
End Sub

Private Sub TestApplicationRun()
    Call Application.Run("test01")
End Sub

たとえば、標準モジュールStd01リスト1のようにコードを書きます。

TestApplicationRun()を実行すると、Application.Run()メソッドでtest01というプロシージャを実行することができます。

このとおり。

別モジュールに同名のプロシージャがあるとき

では、次に標準モジュールStd02に、test01()という名前のプロシージャを実装(笑)します。

リスト2
Private Sub test01()
    Debug.Print "( ´,_ゝ`)プッ"
End Sub

スコープはPrivateにしているので、基本的にStd01モジュールからは〝見えない〟はず、つまり、Std01test01()の実行には影響しないはずです。

ところが……。

Std01モジュールに戻ってApplicationRun()プロシージャを実行してみると……。

エラーメッセージ

実行時エラー '1004':

マクロ'test01'を実行できません。このブックでマクロが使用できないか、またはすべてのマクロが無効になっている可能性があります。

(゚д゚)ハァ?

なんでやねん……。

ここで、Std01モジュールのtest01()プロシージャをコメントアウトします。

そして、再度Std01モジュールのTestApplicationRun()プロシージャを実行してみます。

なんと、Std01モジュールからは〝見えない〟はずのStd02モジュールのtest01()プロシージャが実行できてしまっています。

何なんすかこれ……。

わけがわかりません。

モジュール名付きで呼び出す

さらにここで、Std01のコードを次のようにします。

リスト3
Private Sub test01()
    Debug.Print "ち~ん(笑)"
End Sub

Private Sub TestApplicationRun()
    Call Application.Run("Std01.test01")
End Sub

test01()プロシージャのコメントアウトを解除した上で、Application.Run()メソッドの引数Macro(第1引数)を<モジュール名>.<プロシージャ名>に変えました。

すると……。

今度はStd01の方のtest01()プロシージャを実行することができました。

つまり、Std01モジュールからStd02モジュールのPrivate test01()は〝見えない〟はずなのに、名前の衝突が起こっていたようです。

名前空間の管理、どないなっとんねん……。

ちなみに……。

リスト4
Private Sub test01()
    Debug.Print "ち~ん(笑)"
End Sub

Private Sub TestApplicationRun()
    Call Application.Run("Std02.test01")
End Sub

このようにすれば、当然Std02モジュールのtest01()プロシージャもフツーに実行できてしまいます。(別モジュールのPrivateなプロシージャなのに!)

おわりに

Application.Run()は、スコープを無視して名前解決をしようとする、というバグ(まさか、〝仕様〟じゃないっすよね……?)のお話でした。