第7回  「じっくりソースを追いましょう その1」



とりあえずソースを読む

「MaferLite.vbp」をVBで開くと、以下の5つのファイルが右上のウィンドウに表示されます。

frmMaferLite.frm
frmML_FileEdit.frm
MaferLite.bas
EditEngine.bas
StrCtrl.bas

同封の、Readme.txt にも書きましたが、これらはそれぞれ
・メイン画面のフォーム
・ファイル書き換え画面のフォーム
・MaferLite 用の変数・関数の宣言
・ファイル等の書き換え関連の関数の定義
・文字列操作関連の関数の定義
となっています。

まずは、MaferLite 用の変数・関数の宣言部分のプログラムを見ていきましょう。

MaferLite.bas ソースプログラム1
'改造コードファイルの文字列を格納する配列
Public strCodeString(128) As String

'strCodeString の添字
Public lngCodeIndex As Long

'改造コードのみの内容を格納する配列
Public strCodeData(100) As String

'strCodeData の添字
Public intCodeDataIndex As Integer

'書き換えるファイルの名前(フルパスではない)を格納する変数
Public strDataFile As String


ここで、「MaferLite」全体で使用する変数を宣言しています。
このプログラムのように複数のフォームを持ち、なおかつ、それらのフォームの間で共通に使用する変数は
このように標準モジュールに宣言する必要があります。
(詳しくは、VBヘルプ「変数」「変数の適用範囲」「変数の詳細」を参照して下さい)

また、それぞれの変数の内容なんですが、これはコメントに書いてある通りです。
少し補足しておきますと、
「strCodeString」というのは、コードファイルを読みとった内容をそのまま配列に記録するもの。
ただし、「#」で始まらない行はとばします。

「strCodeData」というのは、コードファイルの中でも、改造コードの部分のみを記録するもの。
具体的には、「#Code:10-61」等と書かれている部分。
そして、更にその数値部分のみ抜き出したもの。(上の例では「10-61」)
というように使い分けています。

ちなみに、変数の名前の前に「str」が付いているのは、文字列型の変数を表すために付けた識別子です。
詳しくは、VBちょっといい話を参考にして下さい。

ここで、各配列の添字を、Long型とInteger型で宣言していますが、本来なら両方ともLong型にした方が良いでしょう。
ただ、ファイルの型による識別子の区別を見せたかったので、今回はこのようにしているだけです。

必要であれば、各自で修正しておいて下さい。(しなくても構いません)
型をLongに、変数名を「intCodeDataIndex」→「lngCodeDataIndex」に変更するわけです。
勿論、この宣言部分だけでなく、この変数を使用している場所全てですが。
これは、「編集」メニューの「検索」を実行し、対象を「カレントプロジェクト」に設定すれば、
比較的簡単に行う事ができます。


では、これらの変数の働きを理解したところで、メイン画面のプログラムの説明に移りましょう。


frmMaferLite.frm ソースプログラム1
01>  On Error GoTo ErrHandler
02>  'コードファイルを読み込む
03>  Dim CodeFileName As String  'コードファイルのフルパス名を格納するための変数

04>  With CommonDialog1
05>  .DialogTitle = "コードファイルの選択"
06>  '.InitDir = LastPath
07>  .Filter = "MAFERのファイル(*.mfr)|*.mfr|" & _
08>       "テキストファイル(*.txt)|*.txt|" & _
09>       "すべてのファイル(*.*)|*.*"
10>  .FilterIndex = 2
11>  .FileName = ""
12>  .Flags = cdlOFNHideReadOnly
13>  End With

14>  CommonDialog1.ShowOpen
15>  If CommonDialog1.FileName <> "" Then
16>    CodeFileName = CommonDialog1.FileName
17>  Else
18>    Exit Sub
19>  End If


長くなりましたので、行番号を付けておきました。
以降は、この行番号を使って解説していきます。

1行目は、エラーをトラップするための処理です。
これは、何らかのエラーが生じた場合、「ErrHandler」というラベルにジャンプしろという命令です。
(詳しくは後述します)
VBでは必須といっても良いほどの機能ですので、覚えておきましょう。

3行目で、開くべきコードファイルのフルパス名を格納する変数を宣言します。
4〜13行目の「With」と「End With」で囲まれた部分は、「CommonDialog1」に対する設定をまとめて行っています。
同じオブジェクトに対するプロパティの設定等は、Withステートメントを使うと、まとめて記述できて便利です。

設定の細かい内容については、VBのヘルプを見ていただければすぐに分かります。
例えば、「Filter」という文字にカーソルを合わせてF1キーを押すと、対応するヘルプが表示され、
「Filter」とは、「選択するファイルの種類」を設定するものだと分かりますね。

また、6行目の「InitDir」の行は現在は使用していませんので、コメントにしてあります。
最後に開いたフォルダを記憶し、次回にファイル開く時は、そのフォルダが選択されているようにする。
というような機能が使いたい場合には、ここで設定する事になります。

余談ですが、実行しない行を消してしまわず、コメントにしておく事を「コメントアウト」と言います。
消すのは勿体ないけど、とりあえず実行したくないという場合によく使われます。

14行目で、設定が完了したコモンダイアログを表示しています。
そして、その画面でファイルがオープンされたならば、そのファイルのフルパス名を「CodeFileName」に格納します。
もし、キャンセルボタンを押された場合は、サブルーチンから脱出しメイン画面へと戻ります。

では続いて、開いたファイルの内容を読み込む処理を見ていきましょう。


frmMaferLite.frm ソースプログラム2
01>  Dim FileNumber As Variant   '開くファイルの番号
02>  Dim CodeFile As String     '1行ずつ読み込んだ内容を、一時的に保存するための変数
03>  'コードファイルの内容を格納するための配列を初期化
04>  Erase strCodeString
05>  lngCodeIndex = 0

06>  'ファイルをオープンした後、その内容を配列に読み込む
07>  FileNumber = FreeFile
08>  Open CodeFileName For Input As #FileNumber
09>  Do While Not EOF(1)
10>    Line Input #FileNumber, CodeFile
11>    '最初の1文字が「#」でなければ、配列に読み込まない
12>    If Left(CodeFile, 1) = "#" Then
13>      strCodeString(lngCodeIndex) = CodeFile
14>      lngCodeIndex = lngCodeIndex + 1
15>    End If
16>  Loop
17>  'ファイルの終わりまで読みとった後、最後に"EOF"を追加する。(配列を最後まで読む時の、判定を簡単にするため)
18>  strCodeString(lngCodeIndex) = "EOF"
19>  Close #FileNumber


基本的にコメントの通り解釈して頂ければよいのですが、少しだけ補足しておきます。

9〜16行目で、開いたコードファイルを1行ずつ読み込んで、配列にコピーしています。
ただし、1文字目が「#」でない行に関しては、コピーを行いません。
その部分には、命令が記述されていないはずだからです。

18行目では、配列の最後に「これ以上のデータはありませんよ」という目印を入れています。
こうしておくと、配列を最後まで読むときのループ終了条件を、「この目印が出てくるまで読み込め」
とでき、処理を単純にする事ができます。

「配列が何個あるかを求め、その個数分だけ繰り返す」という方法もあるのですが、
個人的な好みの問題で、こういった方法を使用しています。

最後に、読み込んだコードファイルに従って、対応するフォームを開く処理を見ていきます。


frmMaferLite.frm ソースプログラム3
01>  '改造コード部分のみを配列に読み込む関数 CodeSet の戻り値を宣言し、関数を実行
02>  Dim retCode As Long
03>  retCode = CodeSet
04>  Select Case retCode
05>  Case 1
06>    'ファイル改造用のコードなので、それに対応したフォームを開く
07>    Me.Hide
08>    frmML_FileEdit.Show
09>    Exit Sub
10>  'Case 2
11>    'メモリ用のコードだった場合
12>  'Case 3
13>    'レジストリ用のコードだった場合
14>  Case -1
15>    '読み込んだファイルが、CodeSet 関数で正しく処理できなかった時
16>    MsgBox "読み込んだファイルは、コードファイルではありません", vbOKOnly + vbExclamation, "ファイル形式エラー"
17>  Case Else
18>  End Select

19>  Exit Sub
20>  ErrHandler:
21>  Select Case Err
22>  Case 53
23>    MsgBox "ファイルが存在しません", vbOKOnly + vbExclamation, "読み込みエラー"
24>  Case Else
25>    MsgBox "不明なエラーが発生しました" & vbCrLf & "エラー番号 " & Err.Number, vbOKOnly + vbExclamation, "不明なエラー"
26>  End Select
27>  End Sub


3行目で、「CodeSet」関数(自作関数)を呼び出し、その戻り値を「retCode」に格納しています。
この関数は、読みとったコードファイルを解析し、
・何の
・どの部分を
・どのように書き換えるか
を調べます。

この時の戻り値で、改造する対象が何なのかを判断し、対応する処理を行います。
「code1.txt」を開いた場合は、「sample1.txt」というファイルを書き換えますので、メイン画面を閉じて
「frmML_FileEdit」というフォームを開きます。

また、この関数は「MaferLite.bas」に記述されています。
詳しい説明は次回に行いますが、とりあえずどんなものかを確認しておいて下さい。
自作関数を簡単に表示するには、その関数名(ここでは「CodeSet」)にカーソルを合わせて、
「Shift」+「F2」キーを押して下さい。
そうすると、該当箇所にジャンプします。(ヘルプの呼び出しと同じようなもの)

10〜13行目は、将来、メモリやレジストリの書き換えに対応した時のために記述しておいたもので、
現在は使用していません。

20〜26行目は、エラーが起きたときの処理です。
frmMaferLite.frm ソースプログラム1の1行目で、エラーをトラップするための処理を記述しましたね。
こうしておくと、何らかのエラーが発生した時に、20行目にジャンプします。
そして、そのエラーの番号から、対応する処理(ここではメッセージ表示)を行っています。

注意する点は、19行目のように、必ずエラートラップ用のラベルの前に「Exit Sub」を記述するという事です。
もし、これを書かないと、エラーが発生しなかった場合でも、エラー処理が実行されてしまいます。


第7回はこれで終了です。
第8回は、この続きを解説していきます。



前に戻る     次に進む

講座の初めに戻る