#16 モジュールにコードを挿入する

T'sKit コード一括挿入ツールの画面T'sKitの「コード一括挿入」ツールでは、単一または複数のフォーム・レポートのクラスモジュールや標準モジュールに対して、同じコードを同じ"位置"に一括して挿入することができます。ここでいう"位置"とは、各モジュールの Declarations セクションに変数や定数を挿入する場合もありますし、同名のプロシージャ、例えば Form_Load イベントプロシージャに共通のステートメントを追加する場合もあります。また、Form_Load イベントプロシージャそのものを挿入して、いくつかのフォームで共通の開くときの処理を追加する場合もあるでしょう。これら挿入対象や挿入するコードの違いはあっても、その手段はどれも同じです。既存のモジュールにコードを挿入するには、Module オブジェクトの InsertLinesメソッド または InsertTextメソッド を使います(注:ただしイベントプロシージャの場合には、本来はCreateEventProcメソッドを使います)。おそらく、これまでいくつものデータベースアプリケーションを作ってきた人でさえ、このメソッドを知らない人は少なくないはずです。なぜなら、通常のアプリケーションでは、その機能や動作として自分自身のコードを書き換えることはないでしょうし、それが必要となる場合もないはずです。そもそもプログラムが走っている最中に自分自身を書き換えるということはできません。まさしくこれらのメソッドはアドインのような開発ツールのためのメソッドといえると思います。
 
れでは実際のT'sKitでの使用例を見ていきましょう。
InsertCode:
  If Me!fraInsertPosition = 3 Then
    '新規プロシージャとして挿入するときはモジュールの末尾にコードを挿入
    mdl.InsertText vbCrLf & strInsertCode
  ElseIf strProcName = "(Declarations)" Or strProcName = "" Then
    'Declarationsへ挿入するとき
    lngEndDeclaration = mdl.CountOfDeclarationLines
    If Me!fraInsertPosition = 1 Then
      'Declarationsセクションの先頭に挿入
      mdl.InsertLines 1, strInsertCode
    Else
      'Declarationsセクションの最後に挿入
      mdl.InsertLines lngEndDeclaration + 1, strInsertCode
    End If
  Else
    'プロシージャに挿入するとき
    With mdl
      'プロシージャの行数
      lngCount = .ProcCountLines(strProcName, vbext_pk_Proc)
      'プロシージャ全体の開始行番号
      lngStartLine = .ProcStartLine(strProcName, vbext_pk_Proc)
      'プロシージャ宣言行の行番号
      lngBodyLine = .ProcBodyLine(strProcName, vbext_pk_Proc)
      'プロシージャの最終行
      lngEndProc = (lngBodyLine + lngCount - 1) - Abs(lngBodyLine - lngStartLine)
      If Me!fraInsertPosition = 1 Then
        'プロシージャの先頭に挿入
        .InsertLines lngBodyLine + 1, strInsertCode
      Else
        'プロシージャの最後に挿入
        .InsertLines lngEndProc, strInsertCode
      End If
    End With
  End If
  Return
このサンプルコードは、今回の話しの中心である"モジュールにコードを挿入する"処理の中心となるサブルーチンだけを抜き出したものです。この中で "mdl" は Moduleオブジェクト変数 です。この変数を使うにはその宣言(Dim mdl As Module)はもちろんですが、あらかじめフォームや標準モジュールを開いた上でこの変数への代入を行わなければなりません。これについては「#04 モジュールのプロシージャをリストアップ」で触れていますので、そちらを参照してください。
ずこのコードで使われているModuleオブジェクトのいくつかのプロパティについて簡単に説明します。

CountOfDeclarationLines プロパティ
このプロパティは、Declarationsセクションに記述されたコードの行数を返します。図の例では 5 が返されます。

ProcCountLines プロパティ
このプロパティは、最初の引数に指定したプロシージャのコードの行数を返します。これには"Function xxxx()"という宣言行や"End Function"などの行、さらに宣言行の前のコメント行や空行も含まれます。これは、モジュールウィンドウを連続表示にしたとき各プロシージャの境目に横線が引かれますが、この線と線に囲まれている行数と考えてください。図の例では 12 が返されます。なお、2つ目の引数にはプロシージャの種類を指定する組み込み定数を与えます。SubまたはFunctionプロシージャの場合は vbext_pk_Proc です。

ProcStartLine プロパティ
プロパティ名の単語からも想像できるように、指定のプロシージャの記述(コメント行や空行も含みます)が始まる行の番号を返します。この行番号とは、Declarationsセクションの最も上の行を"1"とするモジュール全体から見た番号です。2つ目の引数には[ProcCountLines]プロパティと同じく、プロシージャの種類を指定する組み込み定数を与えます。図の例の"IsLoaded"プロシージャでは 6 が返されます。

ProcBodyLine プロパティ
このプロパティは、指定のプロシージャの"Function xxxx()"のような宣言行の行番号(これもモジュール全体から見た番号です)を返します。図の例の"IsLoaded"プロシージャでは 9 が返されます。


プロパティ説明用のモジュールウィンドウ
いて、今回の重要ポイントであるInsertLinesメソッドInsertTextメソッドの構文を確認しておきましょう。

  [Moduleオブジェクト変数].InsertLines <挿入先行番号>, <挿入するコード(文字列)>

ここで"挿入先行番号"は、前述の、モジュール全体から見た行番号です。したがって、もしあるプロシージャの先頭に変数の宣言を挿入したいような場合には、まずそのプロシージャがモジュール全体の何行目から始まるかを調べる必要があるわけです。また、挿入するコードは1行だけのこともあるでしょうが、複数の行をまとめて挿入したい場合にはこのメソッドを行数分繰り返す必要はなく、改行コード(定数 vbCrLf)を使えば1回で済ませることができます。なおこのメソッドを実行すると、もともと挿入先の行番号以降にあったコードは挿入された行数分下へシフトされます。

  [Moduleオブジェクト変数].InsertText <挿入するコード(文字列)>

InsertTextメソッドはInsertLinesメソッドのような挿入行番号の引数は用いません。なぜなら、そのモジュール全体の一番最後に追加挿入するものだからです。新しいプロシージャなどをまとめて挿入したい場合には、InsertLinesメソッドでもできないことはありませんが、行番号の計算が要らない分、こちらのメソッドを使った方が楽でしょう。
れでは、T'sKitで使っているサンプルコードに戻って、その手順を説明していきましょう。

まず「挿入先プロシージャ」のオプショングループ"fraInsertPosition" の値や挿入先の「プロシージャ名」によって処理を分岐します。"3"は「新規プロシージャ」のオプション値です。また変数strProcNameには、あらかじめテキストボックス「プロシージャ名」への入力値がセットされています。ここではコードを新規プロシージャとして挿入するか、Declarationsセクションに挿入するか、あるいは既存のプロシージャの一部として挿入するかによって処理が分かれることになります。

新規プロシージャとして挿入する場合には、前のInsertTextメソッドのところで説明した通り、テキストボックス「挿入するコード」の文字列だけを引数としてそのメソッドを実行すれば処理は完了です。

続いてDeclarationsセクションに挿入する場合には、まず[CountOfDeclarationLines]プロパティを使ってセクション全体の行数を調べ、変数lngEndDeclarationにセットします。そして、挿入先がプロシージャの「先頭(オプション値=1)」の場合には1行目に、「最後(オプション値=2)」の場合には lngEndDeclaration + 1 行目、つまりDeclarationsセクションの一番下の行の次の行をターゲットにInsertLinesメソッドを実行します。

既存のプロシージャに挿入する場合もやり方はいっしょですが、挿入先の行番号の計算がちょっと面倒です。前述のプロシージャ関連の情報を取得するためのプロパティを使って、指定プロシージャの全行数、コメント行や空行を含めた全体の開始行番号、宣言行の開始行番号、そしてそれらの値から"End Function"などのプロシージャの最終行の行番号を算出して、それぞれ変数にセットします。そして最後にそれらの変数をInsertLinesメソッドの引数として実行します。
上のように、AccessのVBAを使えばモジュール自体に自動的にコードを挿入することも可能となります。データベースアプリケーションそのものでは使い道はないかもしれませんが、VBAによるコーディング作業の効率化のために、開発時だけのオリジナルプロシージャなどで利用してみてはいかがでしょうか?。
| Index | Prev | Next |

 

Copyright © T'sWare All rights reserved