2014年6月15日日曜日

VBAで動的にコード生成&実行

【概要】

CodeModuleのプロパティメソッドを利用すると、VBAで、VBAのコードを動的に書き換える(生成する)ことができるのですが、その場合の注意点として
という話がありまして、実際、コードを動的に生成するプロシージャを含むモジュール(コードジェネレータ)内に、コードを生成した場合には、そのまま実行できません。

なのですが、下記blogに記載のように、コードジェネレータとは、別のモジュールにコードを生成した場合は、そのまま実行できました。
上記サンプルコードでは、コードが生成されるモジュールが、Module1.basに固定されていたので、この辺をもうちょいフレキシブルに対応できるようにしてみました。

【実装したコード】


実装したコードの概要

  • GenerateSub にて新たにモジュールを追加して、そのモジュールにSubMethodなるプロシージャを生成
  • Application.Run を用いてSubMethodを実行
  • GenerateSubで追加したモジュールを削除

オリジナルからの変更点

VBProject.VBComponents.Addメソッドは、新たに追加したコンポーネント(VBComponet型)を返り値として返してくれるので、以降はこれに対して操作を行うよう変更しています。これで、Module1.basが既にある場合でも、自動的に異なる名前のModuleが追加されるので問題なしです。

オリジナルのコードでは、自動生成したプロシージャの呼び出しを間接的に行う(自動生成したプロシージャを呼び出すだけのプロシージャを用意する)ことで、実行時のエラーを回避するようになっていました。が、これだと、VBEのオプションで「順次コンパイル」がONになっていることが前提になってしまうので、Application.Runを用いる方法に変えています。

【余談】

コードジェネレータ内に、コードを生成した場合でも、出来るときもあるような方法があるにはありそうなのですが、Excelの動作が不安定になったりするので、たぶん正攻法では無理っぽい…のかな。

VBA実行時に生成される中間コード(Op-codeやP-code/EX-code)が影響しているんじゃないのかなぁと思うのですが、いかんせん資料がなさ過ぎてわかりません。

VBAの(p-codeへの)コンパイルタイミングって実際のところどうなってるんでしょうか…。