(for Internet Explorer)
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 フォルダ