2014年4月2日水曜日

新たに見つかったExcel VBAの闇について

【概要】

VBAの中でも、Word VBAやAccess VBAでは発生せず、Excel VBAでのみ発生する謎の挙動が見つかったので記念にメモします。

例によって、元カリスマVBA-erの@igetaさんが問題を特定して下さいました。

以下では、説明の都合上、Wordで用いるVBAを「Word VBA」、Accessで用いるVBAを「Access VBA」といったように記載しています。実際には、「VBA」という言語自体は、Officeソフトを問わず同一仕様です。

※ 一応補足説明。WordやAccessなどで、初期状態で呼び出せる関数が違うので、アプリケーションによってVBAの仕様が異なると誤解されている方がいるかもしれませんが、これは、単にデフォルトの参照設定が異なっているために「暗黙的に」呼び出せる関数に差が出ているだけです。

【想定する読者】


  • VBAの仕様書にない仕様・挙動まで知っておきたい方
  • VBAを極めたい方

知っておいても損はないと思うけど、実務上、今回の話が問題になることは正直ないと思います。(Officeアプリケーションをまたいで動作をするVBAコードを書くような 特殊な状況でしか役に立ちません。)

【謎の挙動】

Word VBA, Access VBAの場合は、各Applicationオブジェクトに存在しないプロパティ、メソッドを呼び出そうとすれば、コンパイルエラーが発生する。(これが当たり前)

一方、Excel VBAにおいては、Applicationオブジェクトを呼び出すコードを書いた際、存在しないプロパティ、メソッドを呼び出していても、コンパイルエラーが発生しない。(実行時エラーは発生する。)

【VBAの仕様について】



によると、

  • VBAコード → op-code → P-Code/EX-Code → バイナリ

と段階的に変換されるそうです。このうち、op-codeは、入力時のエラーチェックに用いられる模様です。P-Codeというのは、ユーザがメニューから指定しない限りは、実行時にコンパイルされ生成される中間コードのようです。

VBAは、実行時にP-Codeを解釈しながら逐次実行する仕組みのようです。

ただし、上記資料以外からは裏付けが取れなかったため、上記説明が正しいかどうかはわかりません。

【内部仕様に関する推測】

@igetaさん曰く、Excel VBAの場合、内部的にApplicationをObject型変数として取り扱っているように見える。(本来は、Excel.Applicationクラスのオブジェクト)

にも関わらず、IDE (VBE)が、Excel.Applicationクラスとみなして補完候補を表示する。

要するに、Excelの場合だけ、

  • コード入力時に生成されるop-codeでは、Excel.Applicationクラスに変換しているのだけど、
  • コンパイル時に生成されるP-codeの段階で、Object型にキャストしている

ということではないかと推測されます。