訳あって、今どきVisualBasic 6(VB6)の仕事をしてます。
今後はもうVB6のプログラムを組むことはないと思うけど、調べたことも多いので無駄にならないようにまとめておきます。
普段JavaとかC#とかを使って開発している人が、どうしてもVB6を使わなければならなくなったときに役に立つかな。
また、一部のテクニックはVisual Basic for Applications( VBA )にも適用できるはずです。
いっぺんに書くと大変なので、3回に分けて以下の内容を書く予定。
- 1回目 言語のテクニック等
- シングルトンクラスの定義
- ヘンテコスコープ
- キャスト
- インスタンスの同一性検査
- しっかり評価
- 2回目 開発環境テクニック
- 3回目 VisualC++で作ったDLLとの連携
1回目 言語のテクニック等
VB6はオブジェクト指向開発には向かないけれど、VB6をあの手この手でオブジェクト指向っぽく使いました。
1回目はその辺をまとめてみます。
シングルトンクラスの定義
VB6でクラスを宣言し、GlobalMultiUseに設定すればシングルトンクラスが定義できると思ったら甘い。
GlobalMultiUseなクラスをつくっても、DLLを跨いだときにインスタンスが共有できない。返って標準モジュールだと共有される。
ただし、デバッグ実行すると共有される。(も~!意味不明!)
そういうわけで、シングルトンインスタンスが必要な場合は、全てのクラスインスタンスのメソッド実装を標準モジュールへのdelegateとして実装すれば実現できる。
例えばアプリケーション内で連番を管理するシングルトンクラスは以下のように宣言できる。
Singleton.cls クラスモジュール(GlobalMultiUse)
Public Function GetNext() As Integer
GetNext = LocalSingleton.GetNext()
End Function
''
' これがシングルトンクラスのコンストラクタに相当
Private Sub Class_Initialize()
Call LocalSingleton.InitializeLocalSingleton
End Sub
LocalSingleton.bas 標準モジュール
Private mCounter As Integer
Public Function GetNext() As Integer
mCounter = mCounter + 1
GetNext = mCounter
End Function
''
' メンバ変数を初期化
Public Sub InitializeLocalSingleton()
mCounter = 0
End Sub
ヘンテコスコープ
標準モジュール(.bas)とクラスモジュール(.cls)の間にはおかしなスコープが適用される。
知っていればどうと言うことはないが、ハマリ所なので押さえておくとよい。
同一プロジェクト内メソッドの呼び出し
↓呼びだし側/呼び出され側→ | .cls (GlobalMultiUse) | .cls (MultiUse) | .bas |
.cls (GlobalMultiUse) | ○ | ○ | ○ |
.cls (MultiUse) | × | ○ | ○ |
.bas | × | ○ | ○ |
同一プロジェクト内Enumの参照
↓参照側/被参照側→ | .cls (GlobalMultiUse) | .cls (MultiUse) | .bas |
.cls (GlobalMultiUse) | ○ | ○ | ○ |
.cls (MultiUse) | ○ | ○ | ○ |
.bas | ○ | ○ | ○ |
プロジェクトを跨ぐメソッドの呼び出し
↓呼びだし側/呼び出され側→ | .cls (GlobalMultiUse) | .cls (MultiUse) | .bas |
.cls (GlobalMultiUse) | ○ | ○ | × |
.cls (MultiUse) | ○ | ○ | × |
.bas | ○ | ○ | × |
プロジェクトを跨ぐEnumの参照
↓参照側/被参照側→ | .cls (GlobalMultiUse) | .cls (MultiUse) | .bas |
.cls (GlobalMultiUse) | ○ | ○ | × |
.cls (MultiUse) | ○ | ○ | × |
.bas | ○ | ○ | × |
キャスト
Javaを使っていたら簡単にキャストがかけるが、VB6だとそうもいかない。
ConcreteType tConcreteInstance = (ConcreteType)tAbstractInstance;
VBで同じ事をやるには以下のように書けばいい。
Dim tConcreteInstance As ConcreteType
Set tConcreteInstance = tAbstractInstance
キャストしつつのメソッド呼び出しは
((ConcreteType)tAbstractInstance).ConcreteTypeMethod();
Dim tConcreteInstance As ConcreteType
Set tConcreteInstance = tAbstractInstance
Call tConcreteInstance.ConcreteTypeMethod
こんな感じになりVB6は煩雑。
そこで、キャストを行うためのユーティリティメソッドを用意することにした。
' キャスト用メソッド定義
Public Function AsConcreteType(tObject As Object) As ConcreteType
Set AsConcreteType = tObject
End Function
' 呼び出し
Call AsConcreteType(tAbstractInstance).ConcreteTypeMethod
ちょっとは楽になった。
プリミティブ型については以下ようなキャストメソッドが用意されている。
- CInt Integer型へキャスト
- CLng Long型へキャスト
- CSng Single型へキャスト
- ・・・
インスタンスの同一性検査
関数VarPtr、ObjPtr、StrPtrを使うと変数やオブジェクトや文字列のアドレスを取得できる。ドキュメントには記載されていないが、開発環境上では入力補完してくれる。
そして、ObjPtrで得られる数値はインスタンスの同一性検査に利用できる。
しっかり評価
関数And、Orは左辺の真偽に関係なく必ず右辺を評価する。関数IIfは条件式の真偽に関係なく必ず真のときの式と偽のときの式を評価する。評価の省略を期待したコードを書くと痛い目にあうので注意。
一回目はこんなところで。
このほかにもVBのテクニックを知ってる人は教えてプリーズ。次回は以下の開発環境テクニックを書くッスよ~
- UnitTest
- 夜間 自動ビルド&自動テスト
- Subversionと連携する
- DLLのバージョンとregsvr32について
- コメントからドキュメントを生成する
- リファクタリング
6件のコメント
shimada · 2007-05-21 14:41
とりあえず、折りたたんで頂けると嬉しく思いますですはい。
squld · 2007-05-21 15:08
えー、この程度の量なら折りたたみ要らんでしょう。
でも、普段から長文読んでるからなぁ。私の感覚ずれてるかなぁ?
mori · 2007-05-21 18:22
TOPページはあくまIndexである、と、考えた場合、前文と本文の間で切るのは正しい気がしますね。
とりあえず、私が書く場合はそういう方針で行く予定。
squld · 2007-05-21 18:27
ぐぬぬ。多勢に無勢、非常に不利だ。
心が折れそうです。
squld · 2007-05-21 18:28
折れた。
koreyasu · 2007-05-23 00:43
VB6使うことがあれば目を通すよ(笑
現在コメントは受け付けていません。