Application.Run()の謎挙動
Application.Run()の謎挙動
みんな大好きApplication.Run()の変な挙動に気づいたので報告します。
VBA歴10年を超える私ほどの剛の者(ダニング・クルーガー効果)ですら知らなかったのですから、きっと世紀の発見なのだと思います。
Application.Run()とは
Call Application.Run(<プロシージャ名>[, <引数1>, <引数2>, ... ])
の形で、プロシージャを実行することができる面白いメソッドです。
通常の呼び出し

プロジェクトは、このような構成です。
標準モジュールStd01とStd02を挿入しています。
リスト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モジュールからは〝見えない〟はず、つまり、Std01のtest01()の実行には影響しないはずです。
ところが……。
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()は、スコープを無視して名前解決をしようとする、というバグ(まさか、〝仕様〟じゃないっすよね……?)のお話でした。