←
▼
▲
Case3
WScript.echo "End of Main"
WScript.echo "もし、ここ以降でデストラクターが動くときは、"+_
"プログラム終了時にすべてのオブジェクトを削除する"+_
"ことによるデストラクター呼び出しです。"
Sub Case3()
WScript.echo "Case3:"
Set a_object = new A_Class : a_object.CaseName = "Case3"
Set b_object = new B_Class : b_object.CaseName = "Case3"
Set destroyer = new_Destroyer( a_object )
Set a_object.Reference = b_object
Set b_object.Reference = a_object
End Sub
Function new_Destroyer( Target )
Set new_Destroyer = new DestroyerClass
Set new_Destroyer.Target = Target
End Function
Class DestroyerClass
Public Target
Private Sub Class_Terminate()
Me.Target.Destroy
End Sub
End Class
Class A_Class
Public CaseName
Public Reference
Public IsDestory '// Add
Private Sub Class_Terminate()
If not Me.IsDestory Then Me.Destroy '// Add
End Sub
Public Sub Destroy() '// Add
WScript.echo Me.CaseName +": A_Class::Class_Terminate"
Me.Reference = Empty '// Add
Me.IsDestory = True '// Add
End Sub
End Class
Class B_Class
Public CaseName
Public Reference
Private Sub Class_Terminate()
WScript.echo Me.CaseName +": B_Class::Class_Terminate"
End Sub
End Class
相互参照しているオブジェクトに、Class_Terminate を呼び出すきっかけを出す
オブジェクト。
ただし、ユーザーが DestroyerClass を作ることを忘れると削除されなくなるため、
推奨しません。
Case3:
Case3: A_Class::Class_Terminate
Case3: B_Class::Class_Terminate
End of Main
表示例:
検証コード
Destroyer
A
B
相互参照を切る
←
▼
▲
Class ClassA
Private Sub Class_Terminate()
WScript.Echo Err ' 0 と表示します
NO_OBJ.ERROR ' エラー
WScript.Echo Err ' 実行しない
End Sub
End Class
Dim m : Set m = new ClassA
m = Empty
'// ここで、エラーメッセージが表示されます。
'// On Error Resume Next のとき、または、デバッガに接続しているときは、
'// エラーメッセージが表示されません。
WScript.Echo Err ' 500 と表示します。 Resume Next したかのような動き
On Error GoTo 0
WScript.Echo Err ' 0 と表示します
Class_Treminate の中でエラーが発生したら、Class_Terminate の中は、一般の関数と同じ
動きをします(エラー時のようなリターンが発生します)が、すぐにエラーメッセージを表示して、
Class_Terminate を呼び出した場所の続きから実行します。(エラー時のようなリターンは、
発生しません)
このため、エラーが発生して Class_Treminate で必要な処理が実行されなかったことを
見逃す可能性が高く、問題です。 特に cscript.exe で実行したときは、On Error Resume
Next していないときは、エラーメッセージが表示されるのですが、続きの実行によって
スクロールアウトして、エラーが発生したことがユーザに知らされません。 そのまま、
たとえば誤った計算結果を使ってしまい、後で問題になるかも知れません。
この問題が発生しないよう、MsgBox や ErrorCheckInTerminate でエラーを確実にユーザ
に知らせてください。
Class ClassA
Private m_bFinished
Public Sub Finish()
WScript.Echo "Finish"
m_bFinished = True
End Sub
Private Sub Class_Terminate()
Dim en,ed : en = Err.Number : ed = Err.Description
On Error Resume Next '// This clears the error
If en <> 0 Then WScript.Echo "Cancel"
WScript.Echo "Release"
ErrorCheckInTerminate en
If en = 0 and not m_bFinished Then NotCallFinish
On Error GoTo 0 : If en <> 0 Then Err.Raise en,,ed '// This sets en again
End Sub
End Class
悪いコード - Class_Terminate の中
→ T_Finish.vbs
検証スクリプト
Sub NotCallFinish()
Stop : MsgBox "[ERROR] not call Finish" : WScript.Quit 1
End Sub
Sub ErrorCheckInTerminate( en )
If Err.Number <> 0 Then
Stop : MsgBox "ERROR(" & Err.Number & ") " & Err.Description & _
" in Class_Terminate"
End If
End Sub
WScript.Echo "Finish"
WScript.Echo "Cancel"
WScript.Echo "Release"
→ T_XML_Manually.vbs # [T_OpenForReplaceXML_Err_Manually]
→ T_TerminateRaise_Manually.vbs # Main
←
▼
▲
Class ItemClass
Public Default Property Get Value()
Value = "Value_Get"
End Property
End Class
Class DicClass
Public Default Property Get Item( Key )
Item = "Item( "+ Key +" )"
End Property
Public Property Let Item( Key, NewItem )
WScript.Echo Key +", "+ NewItem
End Property
Public Property Set Item( Key, NewItem )
WScript.Echo Key +", "+ TypeName( NewItem )
End Property
End Class
Set obj = new ItemClass
WScript.echo obj '// Property Get Value
Set obj = new DicClass
WScript.echo obj( "Key_Get" ) '// Property Get Item
obj( "Key_Let" ) = "NewItem_Let" '// Property Let Item
Set obj( "Key_Set" ) = new DicClass '// Property Set Item
Property Get Value に Default をつけた Default Property Get Value に変えると、
プロパティ名を省略してリードしたとき(Set を使わずに代入したとき)に、
Property Get Value 関数が呼ばれます。
ライトするときは、Property Get Value 関数や Property Set Value 関数は呼ばれません。
Property Get Item に Default をつけた Default Property Get Item に変えると、
Property Let Item と Property Set Item もデフォルトになり、それぞれの関数が呼ばれます。
と同等の(Key引数が追加された)プロパティでは、
←
▼
▲
Set obj = Wscript.CreateObject("Excel.Application")
With obj
.Visible = True
End With
←
▼
▲
VBScript など、Empty で必ず初期化されるクラスの場合、Empty ではないもの
のみ有効とする。
Dim configs = new TheConfigs
configs.m_Param1 = 10
configs.m_Param2 = "abc"
obj.SetConfigs configs
Class TheConfigs
Public m_Param1
Public m_Param2
Public m_Param3
End Class
configs.Param3 は Empty なので無効
サンプル
複数の .vbs ファイルで共有するときは、上記のクラスのオブジェクトを取得する
関数を用意するとよいでしょう。
クラスの存在チェックは、この取得関数を実行するときに行われます。 C言語
のように、ヘッダを通しておくような対応は不要です。
Class TheClass
Public m_Configs ' as TheConfigs
Private Sub Class_Initialize
Set Me.m_Configs = new TheConfigs
End Sub
Public Sub SetConfigs( Configs )
With Configs
If not IsEmpty( .m_Param1 ) Then Me.m_Param1 = .m_Param1
If not IsEmpty( .m_Param2 ) Then Me.m_Param2 = .m_Param2
If not IsEmpty( .m_Param3 ) Then Me.m_Param3 = .m_Param3
End With
End Sub
End Class
実装例
Class TheConfigs
Public m_Param1
Public m_Param2
Public m_Param3
Public Property Get m_Param4
m_Param4 = m_Param1 + m_Param2
End Property
End Class
部分Empty構造体パラメータのクラスは、そのまま設定値を格納するクラスとして
使うことができます。 派生属性を Get プロパティで定義するとよいでしょう。
メンバ変数ぱプロパティの名前の先頭に m_ が付いていると、grep 時に適切な
場所を見つけやすくなります。 ローカル変数やクラス名とバッティングしなくなり
ます。
←
▼
▲
オブジェクト指向を踏まえたプログラムを VBScript 言語で記述するときの独自標準です。
ver1.0 は、vbslib 3.00 に付属のドキュメントを参照してください。
関連
→ COOL : C 言語によるオブジェクト記述法
オブジェクトの配列を生成する
ブレークポイントなどデバッグ機能の有効無効を制御する
メソッドやプロパティのセット、Java のインターフェイスに相当
まず、言語仕様を踏まえる
オブジェクトのデータを XML 形式にしたもの
静的オブジェクトの取得、演算器要求
静的オブジェクトの一覧
委譲先のオブジェクト
名前の参照、一般名 (Name) と正式名 (TrueName)
オブジェクト・ファイルからオブジェクトを取得する
オブジェクト・フォルダからオブジェクトを取得する
オブジェクト・ファイルに関する情報
→ new_ClassA_Object
オブジェクトを生成する
ファイル形式のオブジェクトを操作する
メイン .vbs ファイルに記述するユーザー定義データ
動的に追加定義するメンバー
イベントに応答するメソッド
クラスの定数
←
▼
▲
使用例:
Dim objs : new_ClassA_Array objs, 3 '// [out] objs
定義例:
Sub new_ClassA_Array( out_Objs, N )
Dim i:ReDim out_Objs(n-1):For i=0 To N-1:Set out_Objs(i)=new ClassA :Next
End Sub
ClassA
ClassA
obj(0)〜obj(2) に、ClassA のオブジェクトを 3つ生成します。
ClassA
objs
objs
3
Sub new_ClassA_Array( out_Objs as array, N as variant )
複数のオブジェクトの生成
複数のオブジェクトの生成と、Array を使った値の初期化
objs
objs
ClassA
ClassA のオブジェクトを 1つ生成し、"ABC", 1 を使って値を設定します。
Dim objs : new_ClassA_Array objs, Array( "ABC", 1 ) '// [out] objs
使用例:
参考
ClassA のオブジェクトを 2つ生成し、1つ目のオブジェクトは、"ABC", 1 を使って値を設定し、
2つ目のオブジェクトは、"DEF", 2 を使って値を設定します。
Dim objs : new_ClassA_Array objs, Array( _
Array( "ABC", 1 ),_
Array( "DEF", 2 ) ) '// [out] objs
使用例:
複数のオブジェクトの生成と、XML を使った値の初期化
使用例:
ClassA のオブジェクトを 1つ生成し、"A", "1" を使って値を設定します。
objs
Dim objs : new_ClassA_Array objs, "<ClassA name='A' num='1'/>" '// [out] objs
Set out_Obj = objs(0)
文字列は XML とします。 ルートタグは省略できるようにします。
IXMLDOMElement の場合は、子ノードが自分のクラスなら生成します。 複数の場合もあり。
Dim objs : new_ClassA_Array objs, _
"<ClassA name='ABC' num='1'/>" +_
"<ClassA name='DEF' num='2'/>" '// [out] objs
ClassA のオブジェクトを 2つ生成し、1つ目のオブジェクトは、"ABC", "1" を使って値を設定し、
2つ目のオブジェクトは、"DEF", "2" を使って値を設定します。
使用例:
参考
←
▼
▲
Class ClassI '// defined_as_interface
Public Sub MethodA( Param1 ) : End Sub
Public Sub MethodB() : End Sub
End Class
1つのオブジェクトに複数のインターフェイスを取得でき、多態する記述法です。
多態(ポリモアフィズム)とは、同じ名前の関数やプロパティを呼び出しても、インスタンスに
よって、呼んだ先の処理内容が異なることです。
VBScript の変数は variant 型で、インターフェイスを定義しなくても多態することができますが、
プロパティやメソッドのセットを明示していた方が、アトム・クラスを作成しやすくなります。
→ ポリモアフィズム(多態性)
データ構造
Dim obj as ClassI
インターフェイスを
参照する変数
オブジェクトの
インターフェイス
オブジェクト(アトム)
オブジェクトのインターフェイス。
何もしないサンプル・クラスを記述することで、インターフェイスを明示します。
オブジェクトのクラス。アトム・クラス。
ClassI の定義をコピーして定義します。 インターフェイスと同じメソッド名があります。
Class ClassA '// has_interface_of ClassI
Public Sub MethodA( Param1 ) : echo "MethodA" : End Sub
Public Sub MethodB() : echo "MethodB" : End Sub
End Class
ClassA
ClassI
定義サンプル:
定義サンプル:
使用サンプル
Dim a : Set a = new ClassA
Dim b : Set b = new ClassB
FuncUsingClassI a
FuncUsingClassI b
Sub FuncUsingClassI( i ) : i.MethodA() : End Sub
ClassI を処理する関数へ、ClassA と ClassB のインスタンスを渡す
関連
参考
←
▼
▲
Function get_ObjectA() as ObjectA
関連
を取得します。 もし、存在しなければ、
関数にすることで、オブジェクト(インスタンス)をカプセル化します。
何回呼び出しても、同じオブジェクトを返します。 ユーザーは、生成、削除を意識しません。
オブジェクトの定義は、get_ClassA 関数にステップインすると分かります。
Function get_Object( Name as string ) as Object
Dim g_ClassA
Function get_ClassA() '// has_interface_of ClassI
If IsEmpty( g_ClassA ) Then _
Set g_ClassA = new ClassA : ErrCheck
Set get_ClassA = g_ClassA
End Function
Function get_Object( Name )
Dim get_func : Set get_func = GetRef( "get_" + Name )
Set get_Object = get_func()
End Function
Dim g_ClassA
Function get_ClassA() '// has_interface_of ClassI
If IsEmpty( g_ClassA ) Then
Set g_ClassA = new ClassC : With g_ClassA : ErrCheck
.Name = "ClassA"
.MethodA = GetRef( "ClassA_methodA" )
End With
End If
Set get_ClassA = g_ClassA
End Function
Sub ClassA_methodA( Me_, ParamA )
:
End Sub
定義サンプル: ClassA オブジェクト(ClassA クラスのインスタンス)を返す
定義サンプル: ClassC のインスタンスのプロパティを設定して返す
定義サンプル: クラス名を文字列で指定してインスタンスを返す
Dim g_obj as ClassI
インターフェイスを
参照する変数
オブジェクト(アトム)
get_ClassA 関数
クラスを新たに作成しなくても、GetRef でメソッドに多態性を持たせることができます。
ClassI
ClassA
ClassA
ClassA
ClassA
ClassA
ClassA
ClassA
→ ClassA_get マクロ (clib)
使用サンプル:
Dim sample : Set sample = get_Sample()
sample
sample
Sample
参考
などに入っている静的オブジェクト (または演算器的なオブジェクト)
Dim sample : Set sample = get_Object( "Sample" )
sample
sample
Sample
を返すか、エラーにします。
→ SuperClass_setCreatingSubClass (COOL)
Function get_ObjectA_withOption( Option_ as ObjectA_OptionClass ) as ObjectA
Set opt = new SampleOptionClass
opt.SettingA = 1
Dim sample : Set sample = get_Sample_withOption( opt )
←
▼
▲
get_Sample_FromFile( "Sample1.xml" ).Method1
Sample Sample1.xml Method1
Function get_ClassA_FromFile( Path as string ) as object
一般的なファイルを操作するオブジェクトを生成します。
【引数】
Path
返り値
ファイルのパス
ファイルをオブジェクトとして操作できるオブジェクト
サンプル:
一般的なファイル(*.xml)
一般スクリプトファイル(*.vbs)
ScriptA.vbs
Sample.xml
取得
←
▼
▲
Dim sample : Set sample = get_ObjectFromFile( "ObjectX_obj.vbs", "ObjectX" )
オブジェクト・ファイル(*_obj.vbs)
一般スクリプトファイル(*.vbs)
ScriptA.vbs
ObjectX_obj.vbs
多くのプログラムは、あるデータファイルを読み込んで処理しますが、VBScript では、データファイルの
代わりに、スクリプト・ファイルを指定して、その中で定義されているオブジェクトを使うこともできます。
sample
sample
使用サンプル: 特定のオブジェクトを取得する
get_ObjectFromFile 関数は、下記の実行に相当します。
include "ObjectX_obj.vbs"
Set get_ObjectFromFile = get_ObjectX()
参考
取得
get_ObjectX 関数の中に
オブジェクトの定義があります
←
▼
▲
使用サンプル: 特定のインターフェイスを持ったオブジェクトの一覧を取得する
参考
Dim samples
get_ObjectsFromFile "Lib\*_obj.vbs", "ClassI", samples '// [out] samples
samples
samples
定義サンプル
get_ObjectsFromFile 関数は、内部で "Lib\*_obj.vbs" にマッチしたファイルをインク
ルードして、それぞれの .vbs ファイルで定義されている get_StaticObjects 関数を
呼び出します。 get_StaticObjects 関数は、ClassI インターフェイスを持ったオブジェクト
を取得する get_Object 関数を呼び出します。
オブジェクト・ファイル(*_obj.vbs)
一般スクリプトファイル(*.vbs)
ScriptA.vbs
ObjectX_obj.vbs
多くのプログラムは、あるデータファイルを読み込んで処理しますが、VBScript では、データファイル
の代わりに、スクリプト・ファイルを指定して、その中で定義されているオブジェクトを使うこともできます。
ロード
フォルダを指定して、すべてのオブジェクトをリストアップすることができます。
ObjectX_obj.vbs
オブジェクト・フォルダ
サンプルファイル
→ T_NameList フォルダ
→ T_NameList_vbslib フォルダ
←
▼
▲
オブジェクト・ファイル(.vbsファイル) に入っている静的オブジェクトの一覧は、
get_StaticObjects という関数名で取得できるよう標準化します。
out_Obj に返すオブジェクトは、InterfaceName に入った名前のインターフェイスを
持っているもの、または、クラスが InterfaceName のものとします。
out_Obj が Empty を返すときは、対応するオブジェクトが存在しないことを示します。
対応する静的オブジェクトが複数あるときは、out_Obj に配列を返します。
get_StaticObjects が呼ばれるときのカレント・フォルダは、不定です。
Sub get_StaticObjects( InterfaceName as string, out_Objs as variant )
要求する静的オブジェクトのインターフェイスの名前
InterfaceName
【引数】
オブジェクト・ファイル(.vbsファイル) に入っている静的オブジェクトの一覧を取得します。
out_Obj
(出力) 静的オブジェクト、またはその配列
get_StaticObjects 関数は、
関数から呼ばれます。
処理フロー:
get_ObjectsFromFile
include (オブジェクト・ファイルの1つ)
For (オブジェクト・ファイルのループ)
get_StaticObjects
get_StaticObjects関数は、それぞれのオブジェクト・ファイルで定義します。
複数のオブジェクト・ファイルで定義しても、get_ObjectsFromFile は、それぞれの
get_StaticObjects 関数を区別して呼び出します。
get_StaticObjects 関数は、
をユーザーが使えるようにするために、
ライブラリが実装する関数の1つです。 ライブラリから見れば、get_StaticObjects
関数は、オブジェクト・ファイルの中で定義している静的オブジェクトの一覧を、
コール元へ渡す処理をします。
Sub get_StaticObjects( InterfaceName, out_Obj )
If IsEmpty( InterfaceName ) or InterfaceName = "ClassI" Then
Set out_Obj = get_ClassA()
ElseIf InterfaceName = "ClassI2" Then
out_Obj = Array( get_ClassA(), get_ClassB() )
End If
End Sub
定義サンプル:
get_Object
参考
サンプルファイル
→ T_NameList フォルダ
→ T_NameList_vbslib フォルダ