読者です 読者をやめる 読者になる 読者になる

カメニッキ

カメとインコと釣りの人です

エラー処理を考慮した、VB6でのプログラミング

仕事でしょうがなく使用していますが、例外処理も無く非常にやりづらいです…。

以下の本で勉強の以下のように書いていこうと思いました。
Visual Basic6エラーコーディング―生産性と品質を高める戦略とテクニック

ここで言う「エラーを考慮した」というのは、エラーが発生する可能性を十分に踏まえた上で、
・エラーが発生することをそもそも防ぐ
・プログラムの実行時にエラーが発生した場合、いち早く察知し呼び出し元へ通達させる
・クラッシュさせない
などになります。

前提として、以下を前提とします。
【変数について】
・常にOption Explicitステートメントを使用する…変数の宣言を強制
・変数のデータ型を明示的に指定する
・すべての変数は初期化した上で使用する
・一行に一つの変数を定義する

Dim hoge, fuga As String
と書くと、一見hogeとfugaというString型の変数を宣言しているように見えるが、実際はfugaのみString型で作成されhogeはVariant型になる。間違えやすいので注意。

・TypeNameやVarType関数を活用する
・列挙型を使用する
【引数について】
・ByVal(値渡し)ByRef(参照渡し)を明示する
・引数のデータ型を明示的に指定する
・受け取った引数は必ず検証する

呼び出し元が関数呼び出し時に渡す引数を検証してくれていることを期待(仮定)してはいけない

【配列について】
・添字の範囲を仮定しない

Option Baseステートメントで、配列の添字最小値が0となっていることがある。

・添字の範囲をハードコードしない
・Option Baseステートメントは使用しない
【コーディングについて】
・IfやSelect句でElseを使用する
・規定のプロパティ(Err.NumberをErrと省略しないなど)を使用しない
・定数を使用する
・式内でのデータ型混在をさせない

Dim i As Integer
For i to Lbound(hogeArray)
 log i & "ループ目"
Next
上記はエラーにならず期待通りに出力されるが、IntegerとStringが混在しているのでNG

演算子の優先順位を仮定しない

A = B + C * D

A = B + (C * D)
両者同じ意味だが、乗算が加算よりも優先されるとわかりきった状態でも明示的に括弧で囲む。

・開いたオブジェクトは自分でcloseしNothingを代入する

他にも色々あると思いますが、まぁこれくらいです。
で、肝心の書き方ですが参考にしていた本で推奨されていたことを割りと無視して以下のようにやろうかなと考えています。
賛否両論あると思いますし、明らかに不適切だ!って場合教えて欲しいです…。
例として、FTPを使用しサーバーへファイルをアップロードする関数です。

'接続先サーバー情報
'複数あるものとする
Const SERVER_ADDRESS_1 As String = "192.168.~~~"
Const SERVER_USER_1 As String = "hoge"
Const SERVER_PASS_1 As String = "fuga"

Const SERVER_ADDRESS_2 As String = "192.168.~~~"
Const SERVER_USER_2 As String = "ika"
Const SERVER_PASS_2 As String = "tako"

'引数1・・・接続先サーバーの情報を数値で指定
'引数2・・・アップロード元
'引数3・・・アップロード先
Function ftpUpload(ByVal targetServer As Integer, ByVal fromFile As String, ByVal toFile) As Boolean
 'ローカル変数よりも前にエラートラップを開始
 On Error GoTo errorhandler
 'ローカル変数宣言部
 Dim ftpObj As Object
 '戻り値の初期化
 ftpUpload = True
 '引数の検証
 If targetServer = xxxxxxxxxxxx Then
  '引数が不正だった場合、Err.Raiseでerrorhandlerへ飛ばす
  Err.Raise エラーナンバー, 発生場所情報, エラー詳細
 Else
  '引数がOKだった場合、何らかの処理
 End If

 'FTP接続オブジェクトの取得
 ftpObj = xxxxxxxxxxxxxx
 '正常にFTP接続オブジェクトが作成されたか検証
 If ftpObj = xxxxxxxxxxxxxx Then
  '作成できていない場合、同じくErr.Raiseでerrorhandlerへ飛ばす。ftpObj.GetReply()などでFTP応答メッセージをエラー情報へ付与してあげてもいいかも
  Err.Raise エラーナンバー, 発生場所情報, エラー詳細
 End If

 'アップロード処理などいろいろ。これ以降でも予期出来るエラーと出来ないエラーがあると思う。

Exit Function
errorhandler:
 ftpUpload = False
 'エラーログ出力用の関数など用意しておく
 'Err.Raiseで指定した引数はそれぞれ、Err.Number, Err.Source, Err.Descriptionに入っているはず。
 '詳細はマニュアルを確認で。
 errorLog Err.Number, Err.Source, Err.Description
 'エラーのクリアとトラップの無効化。これをやらないと、呼び出し元に戻ったあとでもErr.Numberなどの中身が残っている。エラートラップについては、プロシージャ単位なので、自動的に無効化されるが念のため明示的に記載しておく。
 On Error GoTo 0
End Function