VBAプログラムによって生成するワークブックにVBAコードを追加したい場合があります。例えば,生成するワークブックの標準モジュールに定義した独自のワークシート関数を使用している場合や,ワークブック独自のメニューコマンドなどをVBAコードにより記述している場合などです。特に,プログラムとデータの分離で議論しているようにコード更新の反映が問題になるようなケースでは,同一VBAアプリケーションを多くのユーザーに配布していたり,ソースデータが更新される毎に頻繁にワークシートを作り直さなければならなかったりするので,初めからVBAコードが付加されたワークブックを自動生成したいという需要があることが多いのです。

VBEオブジェクトの使用準備

VBAプログラムによってワークブックのVBAコードを変更するためには,Application.VBEオブジェクトを使用します。VBEオブジェクトを使用するには,次の2つの準備が必要です。
  1. VBEにおいてMicrosoft Visual Basic for Applications Extensibilityへの参照を追加する。
  2. 「VBAプロジェクト オブジェクトモデルへのアクセスを信頼する」オプションを指定する。
Microsoft Visual Basic for Applications Extensibilityは,VBEのツール(T)→参照設定(R)で参照設定ウィンドウを開き,リスト中の「Microsoft Visual Basic for Applications Extensibility」左のチェックボックスをチェックすることで参照されるようになります。
VBE参照設定ウィンドウ
次に,「VBAプロジェクト オブジェクトモデルへのアクセスを信頼する」オプションの設定をExcelから行います。この設定が必要な理由は,標準ではセキュリティ上の理由によりVBAプログラムからVBAコードを操作することが許されていないためです。実際の運用においても,このオプションを有効にするのはVBAコード付きのExcelワークブックを生成するプログラムを実行するPCに限定すべきでしょう。 (このオプションをVBAコードから設定することはできません。悪用される危険のある機能を有効にするかどうかユーザーの明示的な判断を仰いでいるのですから当たり前ですね。)

Excel 2007以降では,開発タブのマクロのセキュリティメニューを選択するとセキュリティ センターウィンドウの当該ページが開くので,チェックボックスをチェックします。
VBプロジェクトへのアクセスを信頼するオプション(Excel 2010)
Excel 2003では,ツール(T)→マクロ(M)→セキュリティ(S)でセキュリティダイアログボックスを開き,「信頼できる発行元」タブを選択します。そして,「Visual Basicプロジェクトへのアクセスを信頼する」をチェックします。
VBプロジェクトへのアクセスを信頼するオプション(Excel 2003)

VBEオブジェクトの構造

VBEオブジェクトは,VBAの開発環境に対応するオブジェクトです。VBEオブジェクトはVBProjectsコレクションプロパティを持ち,その各VBProjectオブジェクトがオープン中の各VBAプロジェクトに対応するVBProjectオブジェクトを管理します。そして,VBProjectオブジェクトのVBComponentsコレクションが各種モジュールに対応するVBComponentオブジェクトを管理します。VBComponentオブジェクトは1つのCodeModuleオブジェクトを持ち,これがモジュールのVBコードに対応します。
VBコード編集に関わるオブジェクトの階層構造
したがって,個々のVBProjectオブジェクトにアクセスするにはApplication.VBE.VBProjects(1)などと記述することになります。しかし,VBAプロジェクトはワークブックと1対1対応するため,WorkbookオブジェクトのVBProjectプロパティを使用して,Workbooks("Book1.xls").VBProjectのようにする場合がほとんどです。

モジュールの追加

VBComponentオブジェクトは,プロジェクト(=ワークブック)に含まれる個別オブジェクトモジュールに対応します。Typeプロパティはvbext_ComponentType列挙型の値を取り,モジュールの種別を表します。

vbext_ComponentType モジュール種別
vbext_ct_StdModule 1 標準モジュール
vbext_ct_ClassModule 2 クラスモジュール
vbext_ct_MSForm 3 ユーザーフォーム
vbext_ct_ActiveXDesigner 11 ActiveXデザイナ
vbext_ct_Document 100 Excelオブジェクト
※ これらのうちActiveXデザイナは特殊で,標準の開発環境では使われません。

新規モジュールを追加するには,VBComponentsコレクションのAddメソッドを使います。引数として上記vbext_ComponentType型の値を渡すことで,追加するモジュールの種別を指定します。あるいは,事前にエクスポートしておいたテキストファイルをImportメソッドで読み込むことで完成されたモジュールを追加することもできます。ただし,追加できるのは標準モジュール,クラスモジュールとユーザーフォームのみです。

Addメソッド
VBComponentsコレクションに新たなVBComponentオブジェクトを追加します。

構文
VBComponentObject = object.Add(type)

指定項目 内容
object VBComponentsコレクションオブジェクトを指定します。
type 追加するVBComponentオブジェクトの種別をvbext_ComponentType型で指定します。vbext_ct_StdModule,vbext_ct_ClassModule,vbext_ct_MSFormが指定可能です。
Addメソッドは,追加されたVBCoponentオブジェクトへの参照を返します。


Importメソッド
ファイルから読み込んだ新たなVBComponentオブジェクトをVBComponentsコレクションに追加します。

構文
VBComponentObject = object.Import(filename)

指定項目 内容
object VBComponentsコレクションオブジェクトを指定します。
filename VBComponentsコレクションに追加するオブジェクトモジュールを定義するテキストファイルのパスを指定します。
Importメソッドは,追加されたVBCoponentオブジェクトへの参照を返します。


追加したモジュールの名前を設定するにはVBComponentオブジェクトのNameプロパティを使用します。

Nameプロパティ
VBComponentオブジェクトの名前を取得または設定します。

構文
object.Name = NewName

指定項目 内容
object VBComponentsコレクションオブジェクトを指定します。
NewName VBComponentオブジェクトの新しい名前を指定します。

コードの付加

追加したモジュールにコードを追加するには,VBComponentオブジェクトが持つCodeModuleオブジェクトを使用します。CodeModuleオブジェクトには様々なプロパティやメソッドが用意されており,たとえばProcBodyLineプロパティは指定したプロシージャやプロパティの先頭行を取得することができます。既存のコードを細かく修正する場合にはこれらの機能が役に立ちますが,新規モジュールにコードを追加するのであれば,基本的にはInsertLinesメソッドさえあれば十分です。

InsertLinesメソッド
モジュールの指定した行にコードを追加します。

構文
object.CodeModule.InsertLines(LineNo, CodeText)

指定項目 内容
object VBComponentオブジェクトを指定します。
LineNo コードを挿入する行番号を指定します。最初の行が1行目となります。
CodeText 追加するコードを文字列で指定します。

新規モジュールにInsertLinesメソッドによりコードを追加する場合,必ずしもLineNoに1を指定すればよいとは限らないことに注意が必要です。なぜなら,オプションダイアログボックスにおいて「変数の宣言を強制する」オプションが指定されていると,コードの1行目には常にOption Explicitというステートメントが自動的に挿入されるからです。そして,Option Explicitはどのプロシージャよりも前に記述されないとエラーとなってしまいます。そこで,InsertLinesメソッドの実行前にCountOfLinesプロパティでモジュールに含まれる行数を取得し,既存コードの次にコードを挿入するようにします。

以下のプロシージャは,新規ワークブックを作成して,そこにVBAコードを付加し,直後にそのコードを実行します。

Public Sub TestAddCode()
    Dim bk As Workbook
    Set bk = Workbooks.Add

    ' Adding code to a new Standard module.
    With bk.VBProject.VBComponents.Add(vbext_ComponentType.vbext_ct_StdModule)
        .CodeModule.InsertLines _
            (.CodeModule.CountOfLines + 1) _
          , "Public Sub ProcInStdModule()" & vbCrLf & _
            "    Msgbox ""Executing ProcInStdModule()""" & vbCrLf & _
            "End Sub"
    End With

    ' Adding code to ThisWorkbook object module.
    With bk.VBProject.VBComponents("ThisWorkbook")
        .CodeModule.InsertLines _
            (.CodeModule.CountOfLines + 1) _
          , "Public Sub ProcInThisWorkbook()" & vbCrLf & _
            "    Msgbox ""Executing ProcInThisWorkbook()""" & vbCrLf & _
            "End Sub"
    End With

    ' Calling procedure in Standard module
    Application.Run bk.Name & "!ProcInStdModule"
    ' Calling procedure of ThisWorkbook module.
    bk.ProcInThisWorkbook
End Sub
新規ワークブックにコードを追加し,即実行するコード(標準モジュール)
まず,6~12行目は新しく追加した標準モジュールにコードを追加します。次の15~21行目では,ThisWorkbookモジュールにコードを追加します。初めから存在するThisWorkbookモジュールにアクセスするには,VBComponentsコレクションにおいてキーとしてモジュール名を指定します。

24行目と26行目で2つのモジュールに追加したプロシージャを呼び出しますが,標準モジュールのプロシージャを呼び出すのとExcelオブジェクト(ThisWorkbook)モジュールに追加したプロシージャを呼び出すのとでは方法が異なります。ThisWorkbookオブジェクトのプロシージャの呼び出しは,通常のオブジェクトメソッド呼び出しと同じですが,外部プロジェクトの標準モジュールのプロシージャ呼び出しにはApplication.Runメソッドを使用します。Runメソッドの文法は以下の通りで,ワークブック名とプロシージャ名との連結には,Excelの数式内で外部ワークブックを参照するときと同じ"!"を用います。

Application.Runメソッド
指定したマクロを呼び出します。

構文
RetValue = Application.Run(macro, arg1, arg2, ... , arg30)

指定項目 内容
macro 実行するマクロを以下のフォーマットの文字列として指定します。
"(ワークブック名)!(マクロ名)"
arg1 ~ arg30 マクロに引き渡す最大30個の引数
Application.Runメソッドは,実行したプロシージャから返された値を返します。


この例では,別のプロジェクト(ワークブック)にコードを追加しましたが,プログラムを実行しているプロジェクト自身のコードを変更することも可能です。ただし,そのような処理はエラーを引き起こしたり,Excel自身の動作を不安定にしたりする場合もありますので,あまり安易に使用しない方が無難です。
web拍手 by FC2
inserted by FC2 system