プロシージャに引数を渡すことに慣れています。代わりに、ParamArray
は、0個以上の引数を手続きに参照として渡す柔軟性を私に許しています。しかし、このアプローチでは、プロシージャの範囲を超えて1つ以上の変数への参照を保持する方法があるかどうか疑問に思っていました。VBA - 安全に変数参照を格納する
Array(ParamArray ArgList() As Variant)
だから、私は一緒に次のテストコード置く:私はそれがこのように宣言して見たときの希望の私の最初の兆しがVBA Array
機能でした残念ながら
Private Sub Test()
Dim a As Object
Dim b() As Variant
ParamArrayTest a
Debug.Print TypeName(a) ' Output is 'Dictionary'
b = Array(a) ' b should be like ParamArray ArgList()
Set b(0) = Nothing ' This should clear a
Debug.Print TypeName(a) ' Output is still 'Dictionary'
End Sub
Private Sub ParamArrayTest(ParamArray ArgList() As Variant)
Set ArgList(0) = CreateObject("Scripting.Dictionary")
End Sub
を、これはしませんでした期待どおりの仕事。引数がParamArray
経由でArray
関数に渡されたにもかかわらず、返された配列は参照ではなく値であるように見えます。
更なる研究により、私は文書化されていないVBA /StrPtr
/ObjPtr
の機能に導かれました。 API RtlMoveMemory
の機能と組み合わせて使用する例が多数見つかりました。しかし、私が読んだすべての記事は、アプリケーションを非常に簡単にクラッシュさせる可能性があるため、このアプローチを使用することを強く奨励しました。私のテストの中には、実際にアクセスがクラッシュしたものもあります。
私が持っていたもう一つのアイデアは、私が直接、別の変数の参照を割り当てることができるかどうかを確認することでした。
Private Sub Test()
Dim a As Object
Dim b As Variant
b = ByRef a ' Throws a compiler error
End Sub
を言えば十分で、コンパイラは、単にそれを許可しないでしょう。私の質問は、可変参照は、プロシージャの範囲(好ましくは別の変数)の範囲を超えて安全に保存/保存できるかどうかです。私は私が構築しようとしているものにいくつかの光を当てる場合、それは、より参考になることを決めた
EDIT
。
私は現在、すべてのフォーム/コントロールイベントを自分のモジュールのプロシージャに渡すラッパークラスを作成中です。これは、同じ制御構造を持ち、異なるソース表に接続する2つの形式で使用されます。コードは不完全ですが、私が克服しようとしている問題を説明するのに十分であるはずです。また、Database
は私のVBAプロジェクト名です。
コードへの4つの部分があります。
Form_TEST_FORM
- フォームモジュールPrivate Sub Form_Open(Cancel As Integer) FormHub.InitForm Me, Cancel End Sub
FormHub
- モジュールPublic Sub InitForm(_ ByRef Form As Access.Form, _ ByRef Cancel As Integer _ ) Dim Evt As Database.EventHandler Set Evt = New Database.EventHandler Evt.InitFormObject Form, Cancel FormList.Add Evt, Form.Name End Sub Private Function FormList() As VBA.Collection Static Init As Boolean Static Coll As VBA.Collection If Not Init Then Set Coll = New VBA.Collection Init = True End If Set FormList = Coll End Function
FormControl
- クラスモジュールはPublic Ptr As Variant ' Pointer to form control variable Public acType As Access.AcControlType
EventHandler
- クラスモジュールPrivate WithEvents Form As Access.Form Private WithEvents SForm As Access.SubForm Private CtrlList As VBA.Collection Private Sub Class_Initialize() InitCtrlList End Sub Public Sub InitFormObject(FormObj As Access.Form, ByRef Cancel As Integer) Dim ErrFlag As Boolean Dim Ctrl As Access.Control Dim FCtrl As Database.FormControl On Error GoTo Proc_Err Set Form = FormObj If Form.Controls.Count <> CtrlList.Count Then Err.Raise 1, , _ "Form has incorrect number of controls" End If ' This is where I want to validate the form controls ' and also initialize my event variables. For Each Ctrl In Form.Controls If Not CtrlExists(FCtrl, Ctrl.Name) Then Err.Raise 2, , _ "Invalid control name" ElseIf FCtrl.acType <> Ctrl.ControlType Then Err.Raise 3, , _ "Invalid control type" Else ' Initialize the correct variable with it's ' pointer. This is the part I haven't been ' able to figure out yet. Set FCtrl.Ptr = Ctrl End If Next Proc_End: On Error Resume Next If ErrFlag Then ClearEventVariables End If Set Ctrl = Nothing Set FCtrl = Nothing Exit Sub Proc_Err: ErrFlag = True Debug.Print "InitFormObject " & _ "Error " & Err & ": " & Err.Description Resume Proc_End End Sub Private Function CtrlExists(_ ByRef FCtrl As Database.FormControl, _ ByRef CtrlName As String _ ) As Boolean On Error Resume Next Set FCtrl = CtrlList(CtrlName) CtrlExists = Err = 0 End Function Private Sub InitCtrlList() Set CtrlList = New VBA.Collection CtrlList.Add SetCtrlData(SForm, acSubform), "SForm" End Sub Private Function SetCtrlData(_ ByRef Ctrl As Access.Control, _ ByRef acType As Access.AcControlType _ ) As Database.FormControl Set SetCtrlData = New Database.FormControl With SetCtrlData ' This assignment is where I need to keep a reference ' to the variable in the class. However, it doesn't ' work. Set .Ptr = Ctrl .acType = acType End With End Function Private Sub ClearEventVariables() Dim FormCtrl As Database.FormControl Set Form = Nothing For Each FormCtrl In CtrlList ' Assuming I was able to retain a reference to the ' class variable, this would clear it. Set FormCtrl.Ptr = Nothing Next End Sub Private Sub Class_Terminate() ClearEventVariables Set CtrlList = Nothing End Sub
Iは、簡単にするためにコード例1つの制御を使用します。しかし、アイデアは、フォームデザインが変更された場合に、コントロールを追加/削除するために変更する必要のあるコードの量を簡単にすることです。あるいは、私はプロジェクトにさらにフォームを追加する必要があります。
「*プロシージャの範囲外の1つ以上の変数への参照を保持する」ということはまったくどういう意味ですか?あなたの質問はむしろ不明です。 –
@ Mat'sMugたとえば、変数「ByRef」に変数を渡すと、手続き引数を変更することでソース変数の値を変更できます。しかし、プロシージャが終了するとすぐに、私はソース変数へのポインタを失います。私は安全にソース変数にポインタを格納したいので、その値を1つのプロシージャの範囲外に更新できます。この説明が理にかなっているかどうか教えてください。 –
"私はソース変数へのポインタが失われています"という部分は私には分かりません。プロシージャが終了すると、呼び出し側に戻ります。ここには、ByRefを渡していた変数があります。私はちょうどあなたが解決しようとしている問題を見ていない。 –