【VBA】事前バインディング(参照設定)VS 実行時バインディング(CreateObject)

VBAで外部のActiveXオブジェクトを参照する際に、事前バインディングと実行時バインディングがあります。

FileSystemObjectやDictionaryは使うことが多いので、ご存じの方も多いかと思います。

事前バインディングと実行時バインディングはどちらを使うほうが良いのかについて、記載をしてみたいと思います。

事前バインディングと実行時バインディングとはなにか

簡単に言うと外部のActiveXオブジェクトの参照をいつやるかです。

事前バインディングの場合

VBEを開き、ツール→参照設定から参照したいファイルを指定します。

この参照設定で直接オブジェクトを呼び出せるようになります。

Dim fso As New FileSystemObject

実行時バインディングの場合

CreateObject関数を指定して、コード実行時にファイルを参照します。

Dim FSO As Object
Set FSO = CreateObject("Scripting.FileSystemObject")

基本的には事前バインディングの方が良い

「事前バインディング」でGoogle検索をかけたところ、事前バインディングと実行時バインディングを比較しているサイトがかなり見つかりました。

検索結果1ページ目の内容を拝見すると…

可能な限り、事前バインディングされたオブジェクトを使用してください。

https://excel-ubara.com/excelvba4/EXCEL227.html

これで、CreateObject関数を使う必然性はなくなりました。つまりこれは、コードの実行時にオブジェクトの型を解釈する必要がないということですので、当然、コードのパフォーマンスも向上します。これが、事前バインディングなのです。

http://www.shoeisha.com/book/hp/pc/office/Word/files/text3.html

コンパイラが効率の高いアプリケーションを生成するための重要な最適化を行うことができるため、可能であれば、事前バインディングされたオブジェクトを使用する必要があります。 

https://docs.microsoft.com/ja-jp/dotnet/visual-basic/programming-guide/language-features/early-late-binding/

ほぼ事前バインディング押しという結果になっていました。

私も全く同意見で、特に理由がなければ事前バインディングを指定するべきだと考えています

理由としては、実行時バインディングの場合、実行されるまでオブジェクトの型が決まらないため、インテリセンスによるオートコンプリートが使用できないからです

事前バインディングはオートコンプリートされる↓

実行時バインディングはオートコンプリートされない↓

オートコンプリートされないとコーディングのスピードも落ちてしまいます。

何よりミスが有ってもコンパイルエラーになりません。ホワイトボックステストに漏れがあったりしたら終了です。

更に、 実行時バインディングの方が処理が遅いらしいです。今回の記事のために他のサイトを見なければ知りませんでした。

事前バインディングの方はアプリケーション開始時に1回読み込めばいいだけのため、内部的に早くなるのでしょうか?

まあ、ほとんど体感できない差だとは思いますが、性能面でも事前バインディングに軍配が上がるようです。


実行時バインディング のメリット

探し方が甘いかもしれませんが、実行時バインディングのメリットについて書かれているサイトは見受けられませんでした。

私も「特に理由がなければ事前バインディングを指定するべき」と書いたのですが、特に理由がある場合も結構あります。

実行時バインディング を使用するメリットとしては

  • エラーハンドリングがしやすい
  • 環境依存のエラーが起こりにくい

ということです。1つずつ詳細に記載をしていこうと思います。

エラーハンドリングがしやすい

実行時バインディングの場合は、 実行時までファイルが参照されないため、その ActiveXオブジェクトが存在しない端末で動かされたときのハンドリングがしやすいです。

これまで例として出してきたFileSystemObjectのscrrun.dllが存在しないことはまず考えられないのですが、自作のdll等の場合はエラーハンドリングをしておきたいところです。

Sub test()
Dim HOGE As Object

On Error GoTo errorproc
Set HOGE = CreateObject("HOGE")
Exit Sub

errorproc:
MsgBox "HOGEがありません"

End Sub

こんな感じでオブジェクトが存在しないことをメッセージで通告することもできます。

一方で事前バインディングの場合には、マクロ有効ブックを開いた瞬間にエラーとなってしまうため、ハンドリングが難しく独自のメッセージを挟みにくいです。

環境依存のエラーが起こりにくい

事前バインディング をする場合と実行時バインディングをする場合でファイルを参照する動きが違います。

  • 事前バインディング→CLSIDを元にファイルを特定する
  • 実行時バインディング→クラス名を元にファイルを特定する

クラス名というのは、”Scripting.FileSystemObject”という文字列です。実行時バインディングはこれを元にレジストリを参照しファイルの場所を特定します。

事前バインディングのCLSIDとは…

上記のようにクラスごとに割り当てられている識別子です。

このCLSIDは厄介な点があります。

「特に意識せずに ActiveXオブジェクトをコンパイルするとCLSIDが変更されてしまう。」という点です。

関数のインターフェースとかが変更になった時はもちろんですが、互換性を保つようなコンパイルをしないと、ソースの変更がなくてもCLSIDが変わったはずです。

それは具体的に、どういう悪いことが起きるのか…?

仮にhoge.dllというオブジェクトを参照するVBAプロジェクトを作成したとして

A君の端末では、hoge.dllのバージョンが1.1

B君の端末では、hoge.dllのバージョンが1.0

上記のような条件の場合、 A君の端末とB君の端末でCLSIDが異なるため、A君が作成したVBAをB君の端末で動かすことができません。

つまり環境が全く同じという担保が取れない場合は、実行時バインディングのほうが安全だったりします。

(想定しているバージョンじゃないのに、そのまま動かしてよいかという議論もあるかと思いますが…)

まとめ

まとめると特に理由がなければ事前バインディングを指定するべきです

しかし、以下のような条件の場合には、実行時バインディングも検討に入ってくるかなと思います。

  • 環境の異なる複数ユーザーにマクロを配る時
  • 自作したActiveXオブジェクトを参照する時


1 個のコメント

  • コメントを残す

    メールアドレスが公開されることはありません。

    日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)