←
▼
▲
Class EventResponders
Public Responders
Private Sub Class_Initialize()
ReDim Responders(-1)
End Sub
Public Sub Add( Func, Object )
Dim res : Set res = new EventResponder
ReDim Preserve Responders( UBound( Responders ) + 1 )
Set Responders( UBound( Responders ) ) = res
res.Func = Func
res.Object = Object
End Sub
Public Sub Calls( Caller, Args )
Dim res
For Each res In Responders
res.Func res.Object, Caller, Args
Next
End Sub
End Class
Class EventResponder
Public Func
Public Object
End Class
イベントに応答する方法の1つとして、
すべてのイベントに応答することは、まれなので、メソッドが存在しないというエラーが発生
しないようにすべてのメソッドを記述する必要があるインターフェイスは、扱いづらいもの
です。
継承を使うと(多重継承が使える言語でも)、複数のインスタンスから発生するイベントに
応答することができません。
応答する処理では、アプリケーションのデータが必要になることが多いので、関数では
なくメソッド(オブジェクトをパラメーターに持った関数)をコールバックした方がよいでしょう。
応答するオブジェクトが複数であることは、めずらしくありません。
以上から、イベントに応答するときは、複数の登録されたメソッドを呼び出す機能を持った
EventResponders クラスを使うとよいでしょう。
がありますが、あるクラスの、
参考
←
▼
▲
Dim ClassA::Delegate as _
Function ( Caller as ClassA, ... )
Class ClassA
Public FuncA_Delegate ' as Function( Caller as ClassA )
Private Sub Class_Initialize()
Set Me.FuncA_Delegate = GetRef( "DefaultFunction" )
End Sub
End Class
Sub DefaultFunction( Caller ) : End Sub
Dim obj : Set obj = new ClassA
Set obj.FuncA_Delegate = GetRef( "ClassB_funcA" )
obj.Run '// call ClassA::FuncA_Delegate
Class ClassA
Public FuncA_Delegate ' as Function( Caller as ClassA )
Public Sub Run()
Me.FuncA_Delegate Me
End Sub
End Class
FuncA_Delegate
FuncA_Delegate
FuncA_Delegate 変数を宣言しています。
初期値は、通常、何もしない DefaultFunction 関数です。
ClassB_funcA 関数を、FuncA_Delegate 変数に代入しています。
通常、オブジェクトの使用者が代入します。
ClassB_funcA
FuncA_Delegate 変数に登録されている関数を呼び出しています。
通常、メンバー変数が所属するクラスが呼び出します。
DefaultFunction
FuncA_Delegate
FuncA_Delegate
通常、デリゲート(委譲)する関数は複数存在するため、ここで説明する
変数より、インターフェイスの使用を推奨します。
イベントに応答する場合、応答できるオブジェクトが複数になる可能性
があるため、ここで説明する変数より、複数の登録された関数を呼び
出すメンバー変数の使用を推奨します。
参考
参考
参考
→ デリゲート(C#)
←
▼
▲
PreField.OnEnevtA
PreField.m_Delegate = PostField
イベントがあったとき
委譲先を生成して双方向参照にする
PostField.OnEventA
同じインターフェイス (ClassI) を持つクラスが複数あるとき、それらのクラスが似ているときは、
共通のクラスに委譲するとよいでしょう。
委譲する(される)2つのオブジェクトの関係は、担当領域(WorkField)を分割しただけのもので
あり、親子関係ではないので、通常、m_Delegate プロパティで、双方向参照できるようにします。
担当領域の分割は、メンバ変数やメンバ関数をどちらのクラスに所属させるかということです。
ただし、複数のオブジェクトが、メンバ変数の値か、メンバ関数ポインタの値か、メソッドポインタ
の値だけ異なるのであれば、クラスは共通の ClassC クラスだけでよく、そのインスタンスを返す
関数を用意してください。委譲する必要はありません。
ClassI
ClassB
ClassI
ClassA
ClassC
m_Delegate
m_Delegate
FuncB
ClassI
ClassI
ClassC : ObjectB
FuncA
ClassC : ObjectA
function pointer
function pointer
m_Delegate
m_Delegate
get_ObjectA()
get_ObjectB()
PreField
PostField
PostField
PreField
new_ClassA
PostField.m_Delegate = PreField
(PreField が処理する)
または
初期化時、または委譲先が必要になったとき
ClassC.Param = "ClassA"
共通クラスのパラメータ設定
メソッド呼び出し、インターフェイス、関数ポインタなど
委譲を使うと、両方のクラスの依存関係が強まり、両方の定義が必要になってしまいます。
あるケースでは片方のクラスだけで十分である場合、冗長であってもメンバ変数やメンバ
関数を両方で持たせます。 また、共通のメンバ変数(ClassC に所属すべき変数)を、
あえて共通ではないクラス(ClassA, ClassB) のメンバ変数にしたりします。 適当なタイミング
で、冗長なデータの同期をとる SyncDelegete 関数を呼び出します。
ClassA
ClassC
m_Name
m_Name
m_LastDate
m_Delegate
←必要な冗長
SyncDelegete
SyncDelegate
冗長なデータの同期をとる
Property m_Delegate as variant
委譲先が複数あるときは、名前は m_Delegate でなくてもよい
検討中
委譲先となるユーザー定義オブジェクト。
←
▼
▲
Dim g_g : Sub GetMainSetting( g ) : If not IsEmpty(g_g) Then Set g=g_g : Exit Sub
Set g=CreateObject("Scripting.Dictionary") : Set g_g=g
'// または、Set g = new LazyDictionaryClass : Set g_g=g
'[Setting]
'==============================================================================
g("ExeName") = "Sample"
'// または、g("${ExeName}") = "Sample"
'==============================================================================
End Sub
Sub GetResetMainSetting( g ) : g_g = Empty : GetMainSetting g : End Sub
Sub Main( Opt, AppKey )
GetResetMainSetting g
echo g("ExeName")
'// または、echo g("${ExeName}")
End Sub
メイン *.vbs ファイルに記述するユーザー定義データは、GetMainSetting 関数で取得できるように
統一するとよいでしょう。
メインではない *.vbs ファイルは、
に記述してください。
ExeName
Sample
ExeName
vbslib の Test.vbs の中では、
に
その中で、特に定数は、
で取得できるようにしてください。
定義例、使用例:
などを記述してください。
GetMainSetting が定義されているスクリプトを ExecuteGlobal (vbslib の include、call_vbs など)
すると、GetMainSetting の定義が変わってしまいますが、初めて GetMainSetting を呼んだとき
の定義内容で g が初期化された後は、GetMainSetting を呼んでも g は変わりません。
なので、main 関数の最初で必ず呼び出してください。
Dim g_g : Sub GetMainSetting( g ) : If not IsEmpty(g_g) Then Set g=g_g : Exit Sub
Set g=CreateObject("Scripting.Dictionary") : Set g_g=g
call_vbs SearchParent( "Common.vbs" ), "Common_setVariables", g
'[Setting]
'==============================================================================
g("ExeName") = "Sample"
'==============================================================================
End Sub
複数のメイン *.vbs ファイルで共通の設定を1つのファイルにまとめるときは、vbslib の
メイン *.vbs ファイル:
Common.vbs ファイル:
Function Common_setVariables( g )
g("Config") = "Debug"
End Function
を使ってください。
関連
←
▼
▲
Property Get ClassA::xml() as string
使用例:
オブジェクトのデータを XML 形式にしたもの。
最後に改行は付きませんが、複数行になることはあります。
start CreateFile( "*.xml", obj.xml )
xml
obj の xml プロパティを、テンポラリファイルに出力して開く。
start
CreateFile
obj
オブジェクトのプロパティが多すぎて見にくいときは、xml プロパティとは別のプロパティ
で出力するプロパティを制限するとよいでしょう。
obj.XmlFilter = obj.F_GroupA
定義例
関連
←
▼
▲
Class ClassA
Public Name ' as string
Public DefinePath ' as string
Public Property Get xml() : xml=xml_sub(0) : CutLastOf xml,vbCRLF,Empty : End Property
Public Function xml_sub( Level )
xml_sub = GetTab(Level)+ "<"+TypeName(Me)+" Name='"+ XmlAttrA( Name ) + _
"' DefinePath='"+ XmlAttrA( DefineInfo.FullPath ) +"'/>"+ vbCRLF
End Function
End Class
Function GetTab( Level )
GetTab = String( Level*2, " " )
End Function
Sub CutLastOf( Str, LastStr )
Dim length = Len( LastStr )
If Right( Str, length ) = LastStr Then _
Str = Left( Str, Len( Str ) - length )
End Sub
Property Get xml
ClassA
出力例:
<ClassA Name="Object1" DefinePath="C:\FolderA\File1.txt"/>
関連
Function ClassA::xml_sub( Level as integer ) as string
Level の値に応じて行頭に空白が付き、最後に改行が付く xml プロパティを返します。
通常、
→ save (IXMLDOMDocument)
の内部で使います。
XML で使える文字に変換してください。
XML タグの属性の値
XML タグの外のテキスト
←
▼
▲
Public Sub loadXML( XmlObject )
m_Name = XmlObject.getAttribute( "name" )
m_Value = CInt2( XmlObject.getAttribute( "value" ) )
End Sub
Sub ClassA::loadXML( XmlObject as IXMLDOMElement )
DOM による XML 要素を使って、オブジェクトの属性値を設定します。
IXMLDOMElement
定義例:
関連
使用例:
sample.loadXML LoadXML( "sample.xml", Empty )
name
value
m_Name
m_Value
←
▼
▲
Option Explicit
Dim g_SrcPath
Class Sample_vbs '// has_interface_of DefineInfoClass
Public FullPath
Public DataPath
Private Sub Class_Initialize()
FullPath = g_SrcPath
DataPath = GetAbsPath( "..\Data", g_SrcPath )
End Sub
End Class
Dim g_Sample_vbs
Set g_Sample_vbs =_
new Sample_vbs
Class SampleObj
Public Property Get DefineInfo() : Set DefineInfo = g_Sample_vbs : End Property
End Class
オブジェクトを定義している
静的オブジェクトを定義している場所や、関連するファイルパスなどを参照します。
DefineInfo というプロパティ名は変えないでください。 DefineInfoClass は、FullPath プロパティ
のみを定義しているインターフェイスです。
関連
Dim g_SrcPath
Dim g_Sample_vbs : get_DefineInfoObject g_Sample_vbs, g_SrcPath
Class SampleObj
Public Property Get DefineInfo() : Set DefineInfo = g_Sample_vbs : End Property
End Class
FullPath プロパティしか無いときは、vbslib を使って下記のように記述することもできます。
Property DefineInfo as DefineInfoClass
一般名が Name プロパティに入っているオブジェクトの DefineInfo は、正式名が Name
プロパティに入っているオブジェクトと同じ内容にします。
定義例:
ClassA
DefineInfoClass
.DefineInfo
.FullPath
string
に関する情報です。
Class DefineInfoClass '// defined_as_interface
Public FullPath ' as string
End Class
データ構造
←
▼
▲
Class ClassA
Public m_DebugMode
Public F_BreakAtSetting '// Const
Private Sub Class_Initialize()
Me.F_BreakAtSetting = 1
End Sub
End Class
Me.m_DebugMode = Me.F_BreakAtSetting
Dim ClassA::m_DebugMode as integer
Dim ClassA::m_DebugMode_Param1 as string
サンプル:
m_DebugMode から始まるプロパティは、
デバッグ時のブレークポイントやデバッグ出力の有効無効を制御します。
m_DebugMode
←
▼
▲
ステートメント
Func param
関数名とパラメータの間は 2つの空白にする。
括弧のために Call を使うと、Call が意味的主役になって混乱するため、使わない。
VBScript のコードを、見やすいコード、必要な情報が表現されているコードにする方法です。
括弧の内側
Array( 1, 2 )
関数名とパラメータの区切りを明確にします。
基本的に空白を入れるが、パラメータの内容が無視できたり、関数とパラメータの
両方で1つのものを表現しているのなら入れなくてよい。例 Hex2Dec("3F")
関数コールの出力変数
Func param '// [out] param
コメント
'// comment
// は太線の輪郭に相当し、コメントであることを識別しやすくします。
いくつかの文からなる意味的なブロックの先頭行にコメントを書きます。
デバッグするときは、変数値の変化を追うので、出力を明確にします
関数定義の出力変数
Sub Func( ParamA, out_ParamB, in_out_ParamC )
出力変数は、out_ から始めます。
入出力変数は、in_out_ から始めます。
ローカル変数の大文字小文字
Dim a, i, long_name
小文字とアンダースコアだけ使えます。
中間的なものなので、なるべく短くします。
関数名と引数の大文字小文字
Sub Func( ParamA, ParamB )
関数名も引数も、単語の開始は大文字、2文字目以降は小文字にします。
引数も、関数名と同様に意味を明確にすることが重要です。
タブ
タブ文字は使わない。
エディタによってタブ幅が異なるとレイアウトがずれてしまいます。
コーディングルールは、必須にするとろくなことはありません。 必須にしてしまうと、ルールを作った
人の技術レベル(高い低いに関わらず)に引っ張られることになります。 たとえば、MS Office の
Visual Basic Editor の自動整形を使うと、以下のルールで埋めこまれる情報を失い、ソースコードから
必要な情報を得られなくなってしまいます。 逆に、以下のルールも状況によっては(ある標準に準拠
しないとお客が受け入れないなど政治的な理由などでは)自動整形ツールなどを通して、ルールから
外します。
Sub Func( ParamA, out_ResultDic )
いくつ処理したなど、処理内容の情報は、out_ResultDic という名前の辞書型引数で返す。
情報が不要のときは、呼び出す側で out_ResultDic = Empty を指定します。
Set out_ResultDic = CreateObject( "Scripting.Dictionary" )
out_ResultDic.Item( "OutputPath" ) = "file.txt"
報告を行う関数に記述するコードの例:
←
▼
▲
未対応
←
▼
▲
イベント(あるオブジェクトの状態変化)が発生したときに、応答するオブジェクトが複数で
あることは、めずらしくありません。
しかし、あるクラスの、すべてのイベントに応答することは、まれなので、通常、複数の
登録された関数を呼び出すメンバー変数を使用します。
→ 複数の登録された関数を呼び出すメンバー変数、イベント
参考
複数のメンバー関数
書きかけ
未対応
←
▼
▲
ActiveX COMオブジェクトを通じてシェルやアプリケーションを操作できます。
COM オブジェクトのインスタンスを返します
エクスプローラの操作
→ VBA
関連
参考
←
▼
▲
Dim excel
Set excel = WScript.CreateObject("Excel.Application")
excel.Visible = True
excel.SheetsInNewWorkbook = 1
excel.WorkBooks.Add()
新規ワークシートを作成する
Dim excel
Set excel = WScript.CreateObject("Excel.Application")
excel.Visible = True
Dim fs, path
Set fs = WScript.CreateObject( "Scripting.FileSystemObject" )
path = fs.GetAbsolutePathName( "sample.xls" )
excel.WorkBooks.Open( path ) ' フル・パスであること
エクセルのファイルを開く
関連
参考
→ Excel.Application オブジェクト
→ Excel の vbslib
Excel の vbslib を使うと、もっと簡単に記述できます。
←
▼
▲
Dim sh_ap
Set sh_ap = CreateObject( "Shell.Application" )
【引数】
ClassName
返り値
クラス名
ClassName に指定したクラスのインスタンス
Function CreateObject( ClassName as string ) as variant
サンプル:
COM オブジェクトのインスタンスを返します。
レジストリの、HKEY_CLASSES_ROOT 直下のキーで、CLSID キーを持っている
ものの一部を指定できます。
関連
→ ActiveXObject (JScript)
←
▼
▲
<job>
<reference object="VisualStudio.DTE.8.0"/>
<script language="VBScript">
Option Explicit
WScript.Echo vsBuildStateDone
</script>
</job>
sample.wsf
wsf ファイルの reference タグを使うと、COM オブジェクトで定義されている定数を使うことが
できるようになります。
CreateObject("VisualStudio.DTE.8.0") で Visual Studio の COM オブジェクトを取得できるとき、
次のように記述すると、vsBuildStateDone 定数(vsBuildState 列挙体の要素)などが使えるよう
になります。
→ クラスの定数
関連
ただし、wsf は、vbs_inc ほど柔軟に再利用できないので注意してください。
reference の値
<reference object="VisualStudio.DTE.8.0"/>
Visual Studio 2005
Excel
参照
<reference guid="{00020813-0000-0000-C000-000000000046}"/>